📋 目錄
過去要實現「滾動觸發動畫」(scroll-triggered animations),你需要 JavaScript 動畫庫——GSAP、Framer Motion、Locomotive Scroll。這些庫很強大,但它們帶來的相依性和效能開銷,在某些場景下是不必要的。CSS Scroll-Driven Animations 是瀏覽器原生支援的功能,讓你用純 CSS 實現同樣的效果,而且效能更好。2026 年 Safari 18+ 正式支援後,覆蓋率超過 80%,是時候認真對待這項技術了。
前端工程師為什麼要關心 CSS 滾動動畫
多數前端工程師已經習慣用 JavaScript 處理滾動動畫。當你在一個專案裡加入 GSAP 的 ScrollTrigger 時,你獲得了一個完整的動畫解決方案,但同時也帶來了:
- bundle 體積增加:GSAP 約 60KB(壓縮後)
- 學習曲線:ScrollTrigger 的 API 文件雖然完整,但有門檻
- 效能考慮:JavaScript 驅動的動畫在主執行緒上運行
CSS Scroll-Driven Animations 的價值主張:如果你的需求在 CSS 能做到的範圍內,你就不需要 JS 庫。
瀏覽器支援
| 瀏覽器 | 支援版本 | 支援度 |
|---|---|---|
| Chrome | 115+ | ✅ 全面支援 |
| Edge | 115+ | ✅ 全面支援 |
| Safari | 18+ | ✅ 全面支援 |
| Firefox | 開發中 | ❌ |
覆蓋率約 80%+(以全球瀏覽器市場計)。如果你的用戶多數是 Safari 使用者,現在已經可以使用。如果需要支援 Firefox,可以考慮 GSAP fallback。
兩個核心語法:scroll() 和 view()
scroll():滾動容器內的動畫
scroll() 讓元素的動畫與特定滾動容器的進度掛鈎:
/* 當 #container 滾動時,.progress-bar 的寬度隨之變化 */
.progress-bar {
width: 100%;
animation: grow linear;
animation-timeline: scroll(#container); /* 綁定到 #container 的滾動 */
animation-range: 0% 100%; /* 從頭到尾全範圍 */
}
@keyframes grow {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
<div id="container">
<div class="progress-bar"></div>
</div>
view():元素進入視口的動畫
view() 監聽元素本身進入/離開視口(viewport)的狀態:
/* 當元素進入視口時,淡入 */
.fade-in-element {
animation: fade-in linear both;
animation-timeline: view(); /* 監聽元素自身 */
animation-range: entry 0% cover 50%; /* 從進場 0% 到覆蓋 50% */
}
@keyframes fade-in {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
animation-range:精確控制動畫時機
animation-range 是 Scroll-Driven Animations 最關鍵的功能,讓你控制動畫在哪個區間播放:
進場與退場
/* 進場(entry):元素從下方進入視口 */
.fade-in {
animation: fade linear both;
animation-timeline: view();
animation-range: entry 0% entry 100%; /* 元素完全進入視口 */
}
/* 退場(exit):元素離開視口 */
.fade-out {
animation: fade linear both;
animation-timeline: view();
animation-range: exit 0% exit 100%; /* 元素完全離開視口 */
}
/* 進場 + 退場 */
.both {
animation-range:
entry 0% entry 50%, /* 進來時 */
exit 50% exit 100%; /* 出去時 */
}
cover 的應用
cover N% 讓你根據元素覆蓋視口的程度來控制動畫:
/* 元素覆蓋視口 0% 到 100% 時,執行動畫 */
.zoom-effect {
animation: zoom linear both;
animation-timeline: view();
animation-range: cover 0% cover 100%;
}
@keyframes zoom {
from { transform: scale(0.8); }
to { transform: scale(1.2); }
}
實際應用場景
1. 進度條指示器
/* 頁面頂部的閱讀進度條 */
.progress-bar {
position: fixed;
top: 0;
left: 0;
height: 4px;
background: linear-gradient(90deg, #3b82f6, #8b5cf6);
width: 100%;
transform-origin: left;
animation: grow linear both;
animation-timeline: scroll(root block); /* 整個頁面的滾動 */
animation-range: 0% 100%;
}
@keyframes grow {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
2. Scrollytelling:元素逐個進場
/* 每個 .step 在進入視口時淡入並上移 */
.step {
min-height: 80vh;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
animation: step-enter linear both;
animation-timeline: view();
animation-range: entry 10% entry 60%; /* 10%-60% 視口覆蓋時 */
}
@keyframes step-enter {
from {
opacity: 0;
transform: translateY(60px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
3. 視差效果(Parallax)
/* 背景圖片比前景元素移動得慢,產生深度感 */
.parallax-bg {
position: absolute;
inset: -20%;
background-image: url('mountains.jpg');
background-size: cover;
animation: parallax linear both;
animation-timeline: scroll(root); /* 頁面整體滾動 */
animation-range: cover cover; /* 覆蓋整個視口 */
}
@keyframes parallax {
from { transform: translateY(0); }
to { transform: translateY(20%); } /* 20% 的視差偏移 */
}
4. 數字滾動效果
/* 數字隨著元素進入視口而「計數」 */
.stat-number {
font-size: 4rem;
font-weight: bold;
animation: count-up linear both;
animation-timeline: view();
animation-range: entry 0% cover 30%;
}
@keyframes count-up {
from { --count: 0; }
to { --count: 10000; }
}
與 GSAP 的實用比較
| 維度 | CSS Scroll-Driven | GSAP ScrollTrigger |
|---|---|---|
| bundle 體積 | 0KB | ~60KB |
| 主執行緒 | 外(瀏覽器paint) | 主執行緒(JavaScript) |
| 瀏覽器支援 | ~80% | 100% |
| 自訂彈性 | 有限 | 極高 |
| 複雜時間軸 | ❌ | ✅ |
| 學習成本 | 低 | 中 |
CSS 勝出的場景
- 簡單的進場/退場動畫
- 閱讀進度條
- 視差背景(不複雜的)
- 需要效能優先的長頁面
GSAP 仍然必要的場景
- 複雜的時間軸編排(多個動畫順序播放)
- 需要在特定時間點暫停/控制
- 滾動速度不是線性的(如加速/減速)
- 需要豐富的插件生態(如 DrawSVGPlugin)
Fallback 策略
Progressive Enhancement
/* 如果瀏覽器不支援,就用一般的 animation */
@supports (animation-timeline: scroll()) {
.progress-bar {
animation: grow linear both;
animation-timeline: scroll(root block);
animation-range: 0% 100%;
}
}
檢測支援
// JavaScript 檢測支援
const supportsScrollTimeline = CSS.supports('animation-timeline', 'scroll()');
if (!supportsScrollTimeline) {
// 使用 GSAP 或 Locomotive Scroll 作為 fallback
gsap.registerPlugin(ScrollTrigger);
}
總結:現在是開始使用的時機
CSS Scroll-Driven Animations 在 2026 年已經覆蓋了 80%+ 的瀏覽器。對於 Safari 用戶為主的產品,這已經不是「可以考慮」的技術,而是「可以開始用」的技術。
對於需要支援 Firefox 的產品,可以考慮 Progressive Enhancement 的策略:在支援的瀏覽器上用 CSS,不支援的用 JS fallback。
過去用 GSAP 處理的很多場景,現在 CSS 都能做到。當然,GSAP 不會消失——它的 API 豐富度、生態系、和跨瀏覽器一致性,仍然是 CSS Scroll-Driven Animations 短期內無法完全取代的。但對於簡單的滾動觸發動畫,現在沒有理由不用原生 CSS。
延伸閱讀
- 《View Transitions API 實戰》 — 另一個 CSS 動畫新技術
- 《CSS 2026 進化論》 — CSS 最新功能總覽
本文是「2026 CSS 實用技術」系列文章之一。