核心概念
左右交錯時間軸的核心概念可以拆成四個部分:
- 中間一條垂直線
- 每個事件(Item)
- 左右交錯排列
- RWD(手機版改成單欄)
第一步:建立 Timeline 元件
建立
src/components/Timeline.astro先準備資料:
---const allPosts = Object.values(import.meta.glob('../pages/posts/**/*.md', {eager:true}))// 1. 先過濾掉「沒有寫 pubDate」的文章,避免後續噴錯
const validPosts = allPosts.filter(post => post.frontmatter && post.frontmatter.pubDate);
// 2. 依照日期由新到舊排序 (若要由舊到新,將 b 和 a 的位置互換即可)const sortedPosts = validPosts.sort((a, b) => { return new Date(b.frontmatter.pubDate).getTime() - new Date(a.frontmatter.pubDate).getTime();});---第二步:建立 HTML
每個事件都會有:
Timeline│├── item│ ├── circle│ └── card│├── item│├── itemHTML
<div class="timeline"> {sortedPosts.map((post:any) => ( <div class="item"> <a href={post.url}>
<div class="content"> <img src={post.frontmatter.image.url} alt={post.frontmatter.image.alt} class="poster"/> <span>{post.frontmatter.pubDate.toString().slice(0,10)}</span>
<h3>{post.frontmatter.title}</h3>
<p>{post.frontmatter.description}</p> </div> </a> </div> ))}</div>現在只有資料,接下來都是css。
第三步:畫中間那條線
先讓 timeline 有相對定位。
.timeline{ position:relative; max-width:1000px; margin:auto;}接著用 ::before 畫線。
.timeline::before{ content:""; position:absolute;
left:50%;
top:0; bottom:0;
width:4px;
background:#ccc;
transform:translateX(-50%);}畫面概念
│ │ │ │ │第四步:每個 item 只佔一半
.item{ position:relative;
width:50%;
padding:20px 40px;
box-sizing:border-box;}目前全部都在左邊。
□□□□□□□□
│ │第五步:奇數在左、偶數在右
利用 CSS:
.item:nth-child(odd){ left:0;}
.item:nth-child(even){ left:50%;}結果:
□□□ │
│ □□□
□□□ │
│ □□□這就是交錯排列。
第六步:加入卡片&海報
.content{
background:white;
padding:20px;
border-radius:10px;
box-shadow:0 4px 12px rgba(0,0,0,.15);
width: 100%; max-width: 360px;
}
.poster { width: 100%; aspect-ratio: 2 / 3; object-fit: cover;}
a { text-decoration: none; color: inherit;}變成
┌────────┐│2022 ││開始學習 │└────────┘
│第七步:加入圓點
利用 ::before
.item::before{
content:"";
position:absolute;
width:18px; height:18px;
border-radius:50%;
background:#3b82f6;
top:35px;}左邊:
.item:nth-child(odd)::before{
right:-9px;}右邊:
.item:nth-child(even)::before{
left:-9px;}畫面:
┌──────┐ ●│2022 │ │└──────┘ │ │ ● ┌──────┐ │2023 │ └──────┘第八步:加入箭頭(可選)
(實作這塊,有點跑掉,不加也挺好看的,所以先放著了哈哈)
左邊:
.item:nth-child(odd) .content::after{
content:"";
position:absolute;
right:-10px;
top:30px;
border-width:10px;
border-style:solid;
border-color:transparent transparent transparent white;}右邊:
.item:nth-child(even) .content::after{
content:"";
position:absolute;
left:-20px;
top:30px;
border-width:10px;
border-style:solid;
border-color:transparent white transparent transparent;}效果
┌───────┐▶ ●│ Card │ │└───────┘ │
│
● ◀┌───────┐ │ Card │ └───────┘第九步:手機版
手機不要左右交錯。
@media(max-width:768px){
.timeline::before{ left:25px;}
.item{ width:100%; left:0 !important; padding-left:60px; padding-right:20px;}
.item::before{ left:16px !important;}}手機會變成
●──────── Card
│
●──────── Card
│
●──────── Card最終結構
Timeline│├── 中央線│├── 左卡片│ ●│├──────────────│├──────●│ 右卡片│├──────────────│├── 左卡片│ ●│├──────●│ 右卡片只要新增資料,版面就會自動依序左右排列。
最後成果在首頁 Homepage
一些感想
原本是打算看網路上有沒有做好的模板,但找了一陣子沒看到,只好直接跟AI說需求,然後照著貼上去,出來的結果竟然還不錯有滿足我的需求。