CSS 滚动驱动动画(scroll-timeline):无 JS 实现滚动特效

📅 2026/7/2 3:08:38
CSS 滚动驱动动画(scroll-timeline):无 JS 实现滚动特效
一、传统方案的痛点以前实现滚动动画需要 JavaScript 监听 scroll 事件12345678910window.addEventListener(scroll, () {constscrollTop window.scrollY;constprogress scrollTop / (document.body.scrollHeight - window.innerHeight);// 更新进度条progressBar.style.width ${progress * 100}%;// 视差效果parallaxElement.style.transform translateY(${scrollTop * 0.5}px);});问题性能开销大频繁触发需要手动计算代码复杂二、scroll-timeline 的解决方案CSS 滚动驱动动画让元素的动画进度与滚动位置绑定无需 JavaScript。基础语法123456789keyframes fade-in{from{ opacity: 0; transform: translateY(50px); }to { opacity: 1; transform: translateY(0); }}.element {animation: fade-inlinear;animation-timeline: scroll();/* 绑定到滚动 */}三、scroll() 函数scroll()创建一个滚动时间线将动画进度与滚动位置关联。语法1animation-timeline: scroll(scroller axis);参数scroller: 滚动容器nearest | root | selfaxis: 滚动方向block | inline | y | x12345678/* 最近的滚动祖先垂直方向 */animation-timeline: scroll(nearest block);/* 根滚动容器水平方向 */animation-timeline: scroll(root inline);/* 元素自身垂直方向 */animation-timeline: scroll(self y);四、实战案例案例 1滚动进度条1divclassprogress-bar/div12345678910111213141516.progress-bar {position:fixed;top: 0;left: 0;height: 4px;background: linear-gradient(to right, #4caf50, #2196f3);transform-origin: left;animation: grow-progress linear;animation-timeline: scroll(root block);}keyframes grow-progress {from{ transform: scaleX(0); }to { transform: scaleX(1); }}效果进度条宽度随页面滚动增长。案例 2滚动淡入123456789101112131415161718.fade-in-section {opacity: 0;transform: translateY(50px);animation: fade-inlinear;animation-timeline: view();/* 元素进入视口时触发 */}keyframes fade-in{from{opacity: 0;transform: translateY(50px);}to {opacity: 1;transform: translateY(0);}}案例 3视差滚动12345678910111213141516.parallax-bg {position:fixed;top: 0;width: 100%;height: 100vh;z-index: -1;animation: parallax linear;animation-timeline: scroll(root block);}keyframes parallax {to {transform: translateY(50%);}}案例 4图片缩放1234567891011121314151617.hero-image {width: 100%;height: 100vh;object-fit: cover;animation: zoom-outlinear;animation-timeline: scroll(root block);}keyframes zoom-out{from{transform: scale(1.2);}to {transform: scale(1);}}五、view() 函数view()创建一个视图时间线当元素进入/离开视口时触发动画。语法1animation-timeline: view(axis inset);123456789101112/* 元素进入视口时触发 */.element {animation: fade-inlinear;animation-timeline: view();}/* 设置触发范围 */.element {animation: fade-inlinear;animation-timeline: view(block 20% 20%);/* 在视口上下 20% 的范围内触发 */}六、animation-range控制动画在滚动范围内的哪个阶段执行。123456.element {animation: fade-inlinear;animation-timeline: view();animation-range: entry 0% entry 100%;/* 只在进入阶段执行动画 */}范围关键字entry: 元素进入视口exit: 元素离开视口contain: 元素完全在视口内cover: 整个过程12345678910111213/* 进入时淡入 */.fade-in{animation: fade linear;animation-timeline: view();animation-range: entry 0% entry 100%;}/* 离开时淡出 */.fade-out{animation: fade linear reverse;animation-timeline: view();animation-range: exit 0% exit 100%;}七、组合使用多个动画阶段12345678910111213141516171819.card {animation:slide-inlinear,rotate linear;animation-timeline: view();animation-range:entry 0% entry 50%,entry 50% entry 100%;}keyframes slide-in{from{ transform: translateX(-100%); }to { transform: translateX(0); }}keyframes rotate {from{ transform: rotate(0deg); }to { transform: rotate(360deg); }}视差分层1234567891011121314151617181920212223242526.layer-1 {animation: parallax-slow linear;animation-timeline: scroll();}.layer-2 {animation: parallax-medium linear;animation-timeline: scroll();}.layer-3 {animation: parallax-fast linear;animation-timeline: scroll();}keyframes parallax-slow {to { transform: translateY(20%); }}keyframes parallax-medium {to { transform: translateY(40%); }}keyframes parallax-fast {to { transform: translateY(60%); }}八、浏览器支持滚动驱动动画在现代浏览器中支持Chrome 115Edge 115Safari 尚未支持Firefox 尚未支持特性检测1234567891011121314supports (animation-timeline: scroll()) {/* 支持滚动动画 */.element {animation: fade-inlinear;animation-timeline: scroll();}}supports not (animation-timeline: scroll()) {/* 降级方案使用 JavaScript */.element {opacity: 1;}}Polyfill1script srchttps://flackr.github.io/scroll-timeline/dist/scroll-timeline.js/script九、性能优化1. 使用 transform 和 opacity1234567891011121314151617181920212223/* ✅ 性能好只触发合成 */keyframes good {from{opacity: 0;transform: translateY(50px);}to {opacity: 1;transform: translateY(0);}}/* ❌ 性能差触发重排 */keyframes bad {from{top: 50px;width: 100px;}to {top: 0;width: 200px;}}2. 使用 will-change12345.animated-element {will-change: transform, opacity;animation: fade-inlinear;animation-timeline: scroll();}3. 限制动画元素数量123456/* 只对可见区域的元素应用动画 */.element {animation: fade-inlinear;animation-timeline: view();animation-range: entry 0% cover 100%;}十、实用技巧1. 数字滚动计数1234567891011121314151617181920property --num {syntax:integer;initial-value: 0;inherits:false;}.counter {counter-reset: numvar(--num);animation: count linear;animation-timeline: view();}.counter::after {content: counter(num);}keyframes count {from{ --num: 0; }to { --num: 100; }}2. 文字逐字显示12345678910111213.text {animation: reveal linear;animation-timeline: view();}keyframes reveal {from{clip-path: inset(0 100% 0 0);}to {clip-path: inset(0 0 0 0);}}3. 图片模糊到清晰1234567891011.image {filter: blur(10px);animation: unblur linear;animation-timeline: view();}keyframes unblur {to {filter: blur(0);}}十一、与 JavaScript 对比