左右交錯時間軸

用CSS做左右交錯時間軸

Written by Astro Learner

Published on: 2026-06-28

astro

css

blogging

The Astro logo on a dark background with a pink glow.

核心概念

左右交錯時間軸的核心概念可以拆成四個部分:

  1. 中間一條垂直線
  2. 每個事件(Item)
  3. 左右交錯排列
  4. 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

├── 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 只佔一半

.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說需求,然後照著貼上去,出來的結果竟然還不錯有滿足我的需求。