用CSS做左右交錯時間軸
Written by Astro Learner
Published on: 2026-06-28

左右交錯時間軸的核心概念可以拆成四個部分:
建立
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();
});
---
每個事件都會有:
Timeline
│
├── item
│ ├── circle
│ └── card
│
├── item
│
├── item
HTML
<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{
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說需求,然後照著貼上去,出來的結果竟然還不錯有滿足我的需求。