/* 关键帧:名字 + 若干进度点 */
@keyframes nudge { from { transform: translateX(0); } to { transform: translateX(28px); } }
.nudge { animation: nudge 1s ease-in-out infinite alternate; }
/* 隐式关键帧:0%/100% 只写一个也可以,另一个自动取元素的「当前计算值」 */
@keyframes half { 50% { transform: scale(1.2); } } /* 起终点由元素自身样式决定 */
animation 属性族(九件事)| 属性 | 取值 | 要点 |
|---|---|---|
animation-name | 关键帧名 / none | 多个动画用逗号并列 |
animation-duration | 时间 | 简写里第一个时间是时长、第二个是延迟,顺序反了含义就变 |
animation-timing-function | 缓动 | 它作用于每两个关键帧之间,也可以写在关键帧内部单独指定 |
animation-delay | 时间(可为负) | 负延迟 = 从动画中段开始播,做「错峰循环」非常有用 |
animation-iteration-count | 数字 / infinite / 小数 | 小数会播到该比例 |
animation-direction | normal/reverse/alternate/alternate-reverse | alternate 让来回共用一个关键帧定义 |
animation-fill-mode | none/forwards/backwards/both | forwards 结束后停在最后一帧;backwards 让延迟期间就显示第一帧(进入动画常配 both) |
animation-play-state | running/paused | 可被 CSS 类控制,无需 JS 计时 |
animation-composition | replace/add/accumulate | 与内联样式/其它动画叠加时不覆盖(新) |
优先级提醒:进行中的动画声明高于普通声明与 !important(第十二章的层叠表里排在最上)。所以「动画一跑,hover 就无效」是正常行为,要停下来必须先结束动画。
@keyframes rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
.item { animation: rise .5s ease-out both; }
/* 用自定义属性把延迟交给结构,避免给每一项写一条规则(第十四章的用法): */
.item { animation-delay: calc(var(--i, 0) * 80ms); } /* steps() 逐帧/* 淡入 + 平移循环同时挂:逗号分隔,第一个名字对应第一个时长 */
.multi { animation: fade-in .6s ease-out both, nudge 1.4s ease-in-out infinite alternate; }
/* 文字三点加载:给伪元素的 content 做关键帧(content 是少数可被 steps 离散插值的属性) */
@keyframes dots { 0%,20% { content: ""; } 40% { content: "."; } 60% { content: ".."; } 80%,100% { content: "..."; } }
.loading::after { content: ""; animation: dots 1.4s steps(1, end) infinite; }
/* 骨架屏:background-position 动画(见示例中的 shimmer 条) */
will-change 与合成层:先别急着写/* 作用:提前把元素提升为合成层,避免动画开始时才建层造成的一帧卡顿 */
.box { will-change: transform; }
/* 三条纪律:
① 只给「马上要动」的元素加,别全局加(每个合成层都吃显存,几十层就负收益);
② 动画结束后用 JS 移除,或写在 :hover 的下拉里(配合过渡);
③ 现代 Chrome/Edge/Safari 对 transform/opacity 动画已自动分层,实测收益常为零 → 先用 DevTools 的
Rendering → Paint flashing / Layers 面板确认,再决定加不加。
副作用:will-change 会创建层叠上下文(第十二章)与包含块,可能改变 fixed 的参考系。 */
在这个盒子内滚动,进度条会跟着滚动位置增长 —— 由 animation-timeline: scroll(self) 驱动,不需要任何 JS 监听 scroll。
滚动到底部时进度条应铺满。
.bar { animation: grow linear both; animation-timeline: scroll(self); }
/* 也可以用命名滚动轴 / 元素可见度:animation-timeline: view(block 20% 60%) */
/* 浏览器基线:scroll-driven animations 目前在 Chromium 系(Chrome/Edge 115+)可用,
Safari/Firefox 仍在演进 —— 属于渐进增强:不支持时元素按 both 停在末帧或首帧,
所以必须保证「动画不跑时视图也成立」。请以 caniuse 当前数据为准。 */
animation-name 拼写、duration 是否为 0、元素是否 display: none。animation-name),示例上方的复选框演示了这个手法。animation-fill-mode: forwards。transform/opacity(18a 第⑤节)。prefers-reduced-motion 关掉无限循环动画(第十三章)。