CSS動畫滾動前端開發CSS Scroll-Driven Animations2026

CSS Scroll-Driven Animations 實戰:不需要 JavaScript 的滾動動畫

整理 CSS Scroll-Driven Animations 的核心 API:animation-timeline、scroll() 和 view() 函式。實作進度條、視覺揭示、Sticky Header 效果,以及與 IntersectionObserver 的比較。

· 4 分鐘閱讀

過去十年,每當你需要「隨著滾動執行動畫」時,幾乎一定需要 JavaScript:監聵 scroll 事件、計算元素位置、触發 CSS 類切換。IntersectionObserver 緩解了部分壓力,但對於「進度條跟著滾動走」這類簡單需求,仍然需要湋雜的計算。CSS Scroll-Driven Animations 改變了這一切——現在,你只需要一行 CSS。


核心概念:時間線不再是時間,是滾動

傳統 CSS Animation:

/* 傳統動畫:由「經過的時間」驅動 */
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

.element {
  animation: fadeIn 1s ease-out;
}

Scroll-Driven Animation:

/* 滾動驅動動畫:由「滾動進度」驅動 */
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

.element {
  animation: fadeIn linear;
  animation-timeline: scroll();  /* 滾動進度取代時間 */
}

當使用者滾動頁面時,animation-timeline: scroll() 讓動畫的進度直接映射到滾動位置——不需要 JavaScript,不需要 scroll 事件監聽。


三種時間線設定方式

方式一:animation-timeline: scroll()

最簡單的形式。用 scroll() 函式指定哪個滾動軸(block、inline、x、y):

.progress-bar {
  animation: grow linear;
  animation-timeline: scroll();  /* 預設:nearest 祖先的 block 軸 */
}

/* 明確指定 */
.progress-bar {
  animation-timeline: scroll(y);  /* 垂直滾動 */
}

scroll() 的四種參數:

參數作用
scroll()最近的祖先滾動容器的 block 軸
scroll(block)block 軸(預設,垂直)
scroll(inline)inline 軸(水平)
scroll(x)明確 X 軸
scroll(y)明確 Y 軸

方式二:命名時間線(推薦)

用命名方式連接 scroll container 和動畫元素:

/* 1. 命名時間線 */
.scroller {
  scroll-timeline-name: --progress-timeline;
  /* 或寫成屬性:*/
  /* scroll-timeline: --progress-timeline block; */
}

/* 2. 元素使用這個時間線 */
.progress-bar {
  animation: grow linear;
  animation-timeline: --progress-timeline;  /* 引用 scroller 的時間線 */
}

好處:可以明確指定「哪個滾動區塊控制哪個動畫」,避免意外的祖父元素時間線。

方式三:view():視圖時間線(最强大)

view() 讓元素的動畫由「自己在視口中的可見程度」來控制:

.reveal-element {
  animation: slideIn linear;
  animation-timeline: view();  /* 當元素進入視口,動畫從 0% 到 100% */
}

實作一:進度條

最經典的用例——一個 <progress> 元素,跟著整頁滾動從 0% 長到 100%:

<style>
  @keyframes progress {
    from { transform: scaleX(0); }
    to { transform: scaleX(1); }
  }

  .scroll-progress {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 4px;
    background: #3b82f6;
    transform-origin: left center;

    animation: progress linear;
    animation-timeline: scroll();  /* 跟著整頁滾動 */
  }
</style>

<div class="scroll-progress"></div>

十行 CSS,不需要 JavaScript。


實作二:視圖時間線揭示效果

當元素進入視口時,淡入並稍微向上移動——過去需要 IntersectionObserver:

<style>
  @keyframes reveal {
    from {
      opacity: 0;
      transform: translateY(30px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  .card {
    animation: reveal linear;
    animation-timeline: view();   /* 由視圖中的位置決定進度 */
    /* 也可以設定範圍:*/
    /* animation-range: entry 0%; entry 25%; */
  }

  /* 也可以設定只在進入時有效:*/
  .card-enter-only {
    animation-range: entry 0%; entry 25%;
  }
</style>

<section>
  <div class="card">卡片 1</div>
  <div class="card">卡片 2</div>
  <div class="card">卡片 3</div>
</section>

animation-range 讓你精確控制「動畫在哪個進度區間播放」:

  • entry 0%:元素完全離開視口底部
  • entry 100%:元素完全進入視口頂部
  • cover 0% 100%:元素完整穿越視口的整個過程

實作三:Sticky Header 樣式變化

當 Header 變成 Sticky 時,改變背景和字體大小:

<style>
  @keyframes headerStyle {
    from {
      background: transparent;
      padding: 1.5rem 2rem;
    }
    to {
      background: rgba(255, 255, 255, 0.95);
      padding: 0.75rem 2rem;
      box-shadow: 0 1px 3px rgba(0,0,0,0.1);
    }
  }

  .site-header {
    position: sticky;
    top: 0;
    z-index: 100;

    animation: headerStyle linear;
    animation-timeline: view();   /* 當 header 在視口中滑過時 */
    animation-range: exit 0% exit 20%;
  }
</style>

<header class="site-header">
  <nav>...</nav>
</header>

animation-range:精確控制播放時機

範圍值意義
normal預設 0% 到 100%
entry 0%元素剛進入視口
entry 100%元素完全進入視口
exit 0%元素剛離開視口
exit 100%元素完全離開視口
cover 0% 100%元素穿越整個視口的全過程
contain 0% 100%元素在視口中的整段時間
/* 動畫只在元素完整處於視口中時播放 */
.fade-while-visible {
  animation: fade linear;
  animation-timeline: view();
  animation-range: contain 0% contain 100%;
}

與 JavaScript 方案的比較

維度Scroll-Driven AnimationsIntersectionObserverJS Scroll Listener
JavaScript不需要需要需要
性能原生 compositor thread觀測性,較好最差(每次 scroll 都觸發)
精確度依賴瀏覽器實現良好完全控制
支援觸發次數每幀一次每次 entrance/exit每次 scroll
瀏覽器支援全部主流(2024+)全部主流全部

瀏覽器支援

截至 2026 年,所有主流瀏覽器都完整支援 Scroll-Driven Animations:

瀏覽器支援版本
Chrome115+(2023年8月)
Edge115+(與 Chrome 同步)
Firefox123+(2024年3月)
Safari17.4+(2024年3月)

可以用以下方式檢測支援:

if (CSS.supports('animation-timeline', 'scroll()')) {
  // 使用 Scroll-Driven Animations
  document.documentElement.style.animationTimeline = 'scroll()';
} else {
  // 回退到 IntersectionObserver 或 JS
}

總結:什麼時候用?

用 Scroll-Driven Animations:

  • 進度條、可視化進度指示
  • 視圖進入/離開揭示效果(替代 IntersectionObserver)
  • Sticky 區塊的樣式動畫
  • 讀取進度指示器
  • 簡單的 parallax 效果

仍然需要 JavaScript:

  • 需要根據滾動位置做非線性的計算(如複雜的 parallax 深度)
  • 需要操作 DOM 的實際屬性(不只是 transform/opacity)
  • 需要與使用者輸入同步(如拖曳)

CSS Scroll-Driven Animations 不是要取代所有的滾動 JavaScript,而是讓「常見的滾動動畫模式」用純 CSS 實現——這佔了過去 80% 的使用場景。


延伸閱讀


本文基於 MDN CSS Scroll-Driven Animations 整理,已獲所有主流瀏覽器支援(Chrome 115+、Firefox 123+、Safari 17.4+)。