CSS Animation · 能力速览
一组可交互的 CSS 动画能力 demo,覆盖从最核心的八个 animation-* 子属性与 animation-composition,到 scroll-driven / view-driven 滚动驱动动画、@starting-style、多条动画合成与 offset 运动路径,以及动画事件与 Web Animations API;另有一页讲「怎样才算好动画」的七条设计准则,一页番外盘点 CSS 之外的动画技术(动图格式 / video / Lottie / SMIL / canvas)。每页都能直接查看效果、动手交互;顶部有「暂停全部动画」开关。
只需基础的 CSS 选择器与盒模型知识即可阅读,建议从「核心属性」开始;涉及自定义属性动画的部分,可先看 CSS 自定义属性系列的 @property 讲解。部分能力(scroll/view timeline、object-view-box、animation-composition 等)较新,以浏览器实现为准,建议用最新 Chromium 内核浏览。
核心属性:把一段 @keyframes 跑起来
name / duration / timing-function(含 cubic-bezier 与 steps)/ delay / iteration-count / direction / fill-mode / play-state 逐个讲,外加简写;末尾讲 animation-composition(replace / accumulate / add)——动画值与元素底样式同名相撞时如何合成,三块同底样式对照。逐帧雪碧图单独成页。
用 linear() 把弹簧物理烘焙进纯 CSS
cubic-bezier 只有四个控制点、最多拱一次,做不出 spring 的多次回弹。linear() 取多个等间距控制值、相当于手写一张缓动查找表——把弹簧方程按时间采样塞进去,真实物理就「焊死」进了一条纯 CSS 缓动,运行时零 JS。拖 stiffness / damping / mass 看曲线与回弹实时变化,旁边对照带过冲的 cubic-bezier;同一条缓动作用到 translate / scale / rotate。
逐帧雪碧图:三种切帧技法
雪碧图 + steps() 做翻页书式逐帧动画:为什么必须 jump-none;同一张奔跑皇后图用 background-position / overflow+translate / object-view-box 三法同台对照。再深入 object-view-box——替换元素的「取景框」,含可拖的取景框交互 demo、inset/xywh/rect 语法与降级。
none → block 也能动起来
先讲清 animation type:为什么 opacity 能补间、display 只能在 50% 跳变(discrete vs by-computed-value,带拖进度条 demo)。再到解法:@starting-style 给初始帧、transition-behavior: allow-discrete 让离散属性可过渡,transition 版与 animation 版并排。
Scroll Timeline:动画跟着滚动条走
把时间轴换成滚动进度。scroll-timeline-name/axis、匿名 scroll()(nearest/root/self)、animation-range、timeline-scope 提升作用域;多个可滚动框现场驱动进度条。
View Timeline:元素进出视口的进度
跟着「某个元素相对视口的位置」从 0% 到 100%。view-timeline-name/axis/inset、view()、以及 cover/contain/entry/exit 等 range 关键字;滚动让 subject 穿过视口,顶部实时显示百分比。
Scroll-Triggered:滚到某处触发一次动画
和「Scroll Timeline / View Timeline」两页的「进度型」不同,这是「触发型」:越过滚动位置就播放一段按时间走的动画(进入正放、离开倒放),是 IntersectionObserver 的纯 CSS 替代。新属性 animation-trigger / timeline-trigger / trigger-scope;附 IntersectionObserver 等价版可即时体验。
Scroll-Snap Rotator:「hello ___」滚动轮播
把一段流行的 GSAP 滚动轮播(pin + scrub)纯 CSS 复刻:左边 hello 用 position: sticky 钉住,右侧名字列 scroll-snap 吸附到正中,居中那个用 animation-timeline: view() 放大点亮——零 JS。附 @supports 降级。
Word Rotator:@counter-style 做纯 CSS 词轮播
「我们为 ___ 打造工具」末尾那个词不断切换的效果,零 JS 做到:把一组待轮播的词当成 @counter-style 的符号表(system: cyclic),再用一个被 @property 注册成 <integer> 的索引 --i 当下标,counter(i, words) 取第几个词。让 --i 沿时间轴走(@keyframes + steps()),词便逐个翻;关键在 --i 注册过才可被动画插值——附「注册 vs 未注册」对照。复刻 Frontend Masters 一文,可与滚动驱动的 scroll-snap-rotator 对照。
Text Morph:让一个词「变形」成另一个词
December → January 这类月份轮播里,字不是整块换掉,而是每个字各自搬家、就地换脸:量出逐字位置、把两串对齐成一组槽位(index 硬配 或 LCS 复用共有字)、每个字一条 transition-delay 交错开跑——过渡中字距被拉开又收拢,正是这个效果的招牌。三个 lab:朴素做法的对照、用负 animation-delay + paused 逐帧定格检视槽位、以及可调全部参数的完整轮播。JS 只负责量与排,插值全在 CSS。
Fit-to-Width:纯 CSS 让文本撑满宽度
把 view(inline) 反用成「在样式层读尺寸比例」的工具:文本 max-content 溢出 + scroll-snap 钉住起点,entry-crossing 区间的进度恰好 = 容器宽 ÷ 文本宽,拿它驱动 scale() 让一行字自动填满容器——零脚本、不硬编码 font-size。附 @supports 降级,可与 Text Layout 的 JS 测量版对照。
文字扫光:让一条亮带扫过字形
标题 / loading 文案上那道「高光划过文字」的效果:background-clip: text 把渐变灌进字形,再用 WAAPI 平移 background-position 让亮带扫过。可调时长 / 亮带宽度 / 角度 / 配色 / 间歇的现场 demo,并对照分析 gradient-shimmer 的三处设计——对称亮带渐变(color-mix in oklab)、随字号自适应的 spread、以及为何用 element.animate() 而非纯 @keyframes(间歇 / 离屏暂停 / 精确 cancel)。附 prefers-reduced-motion 与 CSS.supports 降级。
Scrubbable Stagger:单个进度值驱动错开动画
错开动画 (stagger) 传统靠给每个元素叠不同 animation-delay,那是时间、不能被外部进度拖着走。复刻 Frontend Masters 的思路:把延迟改写成进度维度的偏移——整组只由一个标量 --m (0→1) 驱动,第 i 个元素减去 i/k 偏移就起步更晚,于是这组级联可任意 scrub:接滑块、接滚动都行,正放 / 倒放 / 停在任意中间帧。封装用 @function --stagger,序号靠 sibling-index() 自取;末尾把驱动源从滑块换成 animation-timeline: scroll(),函数一字不改。需 Chromium 139+,否则 JS 按同式模拟。
多条动画与 Motion Path:沿曲线和任意路径运动
前半:逗号分隔写多条动画,不同属性各用各的 timing-function,合成单条动画做不到的曲线轨迹(直线 / 曲线 / 容器嵌套 / 独立 transform 属性四点对照)。后半:offset-path(path / ray / rect / inset / circle / xywh / border-box)+ offset-distance/position/anchor/rotate,7 个点沿 7 种路径同时运动。
动画事件 + 用 JS 控制动画
animationstart / iteration / end / cancel 四个事件 + 实时日志面板;再到 Web Animations API:getAnimations() 拿现成动画,以及 element.animate() 纯 JS 创建并控制(playbackRate / currentTime / finished)。
进阶:让「本来不能动」的东西动起来
@property 给自定义属性上类型,于是能动画渐变角度、计数数字等 transform 做不到的东西;interpolate-size: allow-keywords / calc-size() 让 height 真正过渡到 auto / fit-content(折叠面板平滑展开)。
控制无限动画:不跳变变速、平滑启停
无限动画的优雅控制:用 animation-composition: add 叠两层同名动画,启用第二层即提速而不跳位;再用一段 transition 当「刹车」,把急起急停做成渐入渐出。含通用 --s/abs()/sign()/mod() 写法的出处链接。
性能与取舍:该用 CSS 还是 JS?
差别不在语言、在线程:transform/opacity 能下合成线程,主线程阻塞也照样动;margin-left 这类每帧重排只能留在主线程。含「阻塞主线程」对照 demo、compositor 属性清单,以及 WAAPI / Motion / GSAP 的取舍建议。
尊重「减少动态效果」偏好
动画的无障碍素养:@media (prefers-reduced-motion: reduce) 命中时把大动作降级为轻动作(而非删光);含模拟开关对照 + matchMedia 实时读系统偏好。
好动画的七条准则
其余各页讲「能做什么」,这页反过来讲「怎样才算做得好」。整理自 Emil Kowalski《Great Animations》的七条准则:自然(spring 弹簧 + ease-out 对照)、快(<300ms / ease-out)、有目的(别给键盘操作加过渡)、高性能、可打断(transition vs @keyframes 半路打断对比)、无障碍、气质契合。最终以实际观感为准。
lerp 跟手:别把拖拽元素硬吸附在光标上
拖拽手感的小开关:每帧把元素位置直接赋成光标(snap,直接吸附)很生硬;改用 lerp 线性插值让它每帧只朝光标追近一段,就多出一点惯性缓冲。snap 与 lerp 同台追同一个光标 + 尾迹对照,可拖系数 t 体会「哪怕很高也仍比硬吸附柔和」;附 snap/lerp 只差一行的写法,以及按 dt 校正、掉帧不改手感的 frame-rate independent 版本。纯 rAF 驱动,与本系列纯 CSS 路子互补。
番外:CSS 之外,网页动画还有哪些做法?
盘点非 CSS 的动画技术并逐个上手:动图格式 GIF / APNG / WebP / AVIF(在浏览器里现场拼一个 APNG)、<video> + JS(MediaRecorder 现场录 WebM、requestVideoFrameCallback 逐帧)、Lottie 矢量 JSON(手写最小动画数据 + 运行时换色)、SVG SMIL(形变 / begin="click" / img 里也能动)、canvas 粒子,以及 GSAP / Motion / spring 物理一览与选型法则。
相关文档 / 链接
📐 规范 / 文档
- CSS Animations Module Level 1 drafts.csswg.org 规范本体:@keyframes 与八个 animation-* 子属性、动画事件。
- Scroll-driven Animations Module Level 1 drafts.csswg.org scroll-timeline / view-timeline / animation-timeline 的规范本体。
- MDN · CSS animations 模块 developer.mozilla.org 属性总览与示例。
- MDN · CSS scroll-driven animations developer.mozilla.org 滚动驱动动画总览。
- Can I use · CSS Animation caniuse.com 实时浏览器支持矩阵。
延伸阅读
- @property · MDN
- scroll-driven-animations.style · Bramus 交互教程 + 工具。
- animation-range cheatsheet · WebKit
- Time based CSS animations · yuanchuan.dev
- Spring physics in CSS · Carmen Ansio 用 linear() 把弹簧物理烘焙进纯 CSS 缓动(本系列 spring 页出处)。
- CSS Wrapped 2024 · chrome.dev
- Sprite Sheet Animations · Josh W. Comeau 雪碧图逐帧动画与 steps() 的图文详解。
- object-view-box · MDN
- Lottielab · lottielab.com web 端 Lottie 动画编辑器(番外页相关)。
- Replace GIFs with videos · web.dev