动效三件套 — 过渡、变换、动画¶
原书拆成第 14、15、16 三章,这里按依赖顺序合一章讲——三件工具是递进关系: 过渡管「两个状态之间怎么滑」,变换管「不打扰别人的移动方式」,动画管「多步时间线」。 三者共用同一条性能铁律,这也是全章最该带走的一条。
1. 这一章在全书链条里的位置¶
盒子(04)、站队(05)、皮(09)、浮雕(10)都做完,页面是静态的。 这一章让它动——也是「现代网页」和「2010 年网页」观感差距的最大来源。 三件的依赖关系:过渡最常动画的属性就是变换和透明度;动画的每一步,写的也常是变换—— 所以原书按 过渡 → 变换 → 动画 的顺序排章,本章照抄这个顺序。
2. 顶层全景:三件事,三个属性¶
过渡 transition A 状态 ────0.3s 滑动────▶ B 状态 (要有人触发:悬停/聚焦/加类)
变换 transform 挪动/旋转/缩放,布局算完之后才动,GPU 画 (不挤开邻居)
动画 animation @keyframes 画一条多步时间线,自己跑,可循环 (不靠触发,加载就能跑)
图说:过渡是「补间」,变换是「移动方式」,动画是「时间线」。三件共用铁律:
只动 transform 和 opacity。
3. 核心原理:过渡(transition)——让变化滑过去¶
没有过渡时,悬停变色是瞬间跳的;有了过渡,浏览器在两值之间插值 (interpolation,算中间值),变化就成了滑动1。
四个参数:
- transition-property:哪个属性参与过渡;
all表示全部。 - transition-duration:多长。书里的硬话:时长是唯一缺它就不动的参数——
不写时长,过渡等于没有2。单位必带(
0.3s或300ms;写transition: all 500;无效)3。 - transition-timing-function:速度曲线。默认
ease(慢起、快中、缓收);linear匀速;ease-in慢起;ease-out缓收;ease-in-out两头慢。 想「自然」,书里推荐 ease-in-out 一类4。 - transition-delay:开始前等多久(提示条常用 0.2s 防误触)。
什么能过渡、什么不能:数值类属性(颜色、尺寸、位置、透明度)能;
display、font-family 这类离散属性不能——display: none 到 display: block 没有中间值,
想要「淡入」得用 opacity + visibility 组合5。
主线例子的第一段:按钮悬停,全套走一遍¶
输入:一个按钮,悬停时变深蓝、轻微放大。
.button {
background-color: blue;
transition: background-color 0.2s, transform 0.2s; /* 两个属性各配时长 */
}
.button:hover {
background-color: darkblue;
transform: scale(1.05);
}
走一遍流程:鼠标进入 → 状态变化触发过渡6 → 颜色从蓝插值到深蓝,0.2 秒;
尺寸从 1 插值到 1.05,0.2 秒,两路并行、互不等待 → 鼠标离开,反向滑回。
transform: scale(1.05) 此刻先当黑盒(下一节打开),它只负责「放大而不挤开邻居」。
4. 核心原理:变换(transform)——不打扰别人的移动¶
为什么变换是高效率的代名词¶
普通的位置调整(改 top、left、margin)发生在布局阶段:盒子挪了,邻居的位置全要重算。 变换发生在布局算完之后:页面已经排好,浏览器只把画好的这一张「挪个位置、转个角度」, 不重排——而且这活通常交给 GPU(显卡)干,又快又顺7。 书里那个关键性质:把图片放大一倍,周围的文字纹丝不动8——这就是「布局后操作」 (post-layout)的字面意思。
四个函数与一个支点¶
| 函数 | 干什么 | 值 |
|---|---|---|
translate(x, y) |
平移 | px、%、rem |
rotate(角度) |
旋转 | deg(度)、turn(圈) |
scale(x, y) |
缩放 | 数字:2 双倍、0.5 一半9 |
skew(x, y) |
斜切 | deg |
外加 transform-origin:变换的支点,默认在元素正中心(50% 50%);
改成 left 就绕左边缘转——书里「门绕铰链转」的例子就是
transform-origin: left; + rotateY(-45deg)10。
主线例子的第二段:顺序敏感,一组坐标走两遍¶
输入:transform: translateX(100px) rotate(45deg) 和 transform: rotate(45deg) translateX(100px),
同一元素,两种写法。
先平移后旋转:向右挪 100px,再原地转 45° —— 落点 = (100, 0) 处的一个斜盒子
先旋转后平移:先转 45°(自身的 x 轴跟着转了),再沿「新的 x 轴」走 100px
—— 落点 = (70.7, 70.7) 处的一个斜盒子
图说:函数从左到右依次生效;旋转会带着自身的坐标轴一起转。
(70.7 ≈ 100 × cos45° = 100 × 0.707,坐标是为演示演算的)
书里把「函数顺序不同、结果不同」列为本章常见错误第一条11;
配套细节:多个函数之间用空格,不用逗号(scale(2) rotate(10deg))12。
另外两条小纪律:transform 对纯行内元素(span、a)无效,先给 display: inline-block13;
含字的元素大幅缩放,字会糊14。
3D 是 2D 的延伸:translate3d、rotateX/Y/Z,外加 perspective(600px) 给深度——
值越小透视越猛15。卡片翻转是招牌应用,本章知道有这些即可。
5. 核心原理:动画(animation)——自己跑的时间线¶
过渡要「状态变化」当发令枪;动画不用——页面加载就能跑,还能循环16。 两个部件:
@keyframes 定义时间线:在百分比刻度上写样式,浏览器补中间的帧17:
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
animation 属性把时间线接到元素上,八个小属性里常用的五个:
animation-name(接哪条时间线,名字大小写敏感,对不上就静默不跑18)、
animation-duration(时长,同样必带单位19)、
animation-iteration-count(次数,infinite 无限循环)、
animation-direction(alternate 往返着播)、
animation-fill-mode(见下)。简写一行:
animation: pulse 2s ease-in-out infinite;20。
主线例子的第三段:加载圆点,全参数走一遍¶
.dot {
width: 20px; height: 20px; background: blue; border-radius: 50%;
animation: bounce 0.5s ease-in-out infinite alternate;
}
@keyframes bounce {
from { transform: translateY(0); }
to { transform: translateY(-20px); }
}
走一遍:页面加载即开跑(无触发);0.5 秒一个来回;alternate 让相邻两圈方向相反——
上去、回来、再上去,无缝循环21;ease-in-out 两头慢,模拟重力加减速。
改 infinite 为 3 就跑三圈;删 alternate 每圈都从头瞬移回起点。
fill-mode: forwards,防弹回。 默认下动画跑完,元素弹回动画前的样式22——
淡入场景(从透明到实)跑完又闪回透明,灵异现象的常见来源。animation-fill-mode: forwards
让元素停在最后一帧23:
.fade-in { animation: fadeIn 1s ease forwards; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
配套小常识:简写里两个时间值,第一个是时长、第二个是延迟24;
animation-play-state: paused 可以中途暂停(JS 开关动画用)。
6. 作者的判断与证据¶
- 「只动画 transform 和 opacity,其余属性只在没办法时才动」——三章法里唯一逐字重复的铁律 (过渡章、动画章各一遍),理由是它们不触发重新布局(re-layout),卡顿的根源25。 这是全书少数带机制解释(而非纯经验)的断言。
- 「时长必须带单位、名字必须对得上」——事实性纪律318。
- 「想自然就用 ease-in-out」——品味断言4。
- 证据类型:机制解释 + 经验断言,是全书「为什么」给得最多的一个部分。
7. 边界与局限¶
- 没讲
will-change(提前告诉浏览器哪个属性要动)与合成层概念——性能进阶的钥匙,本书未收。 - 没讲
cubic-bezier()自定义曲线(速度曲线只能选关键字,做不了弹跳感)。 - 滚动驱动动画(scroll-driven animations)2023 年起已可用,本书完全未提。
- 没讲「过渡中断」(悬停快速进出时过渡如何衔接)与 JavaScript 的 transitionend 事件。
判断(我们的,不是书里的): 「布局后操作」是这一章(也是三件套)的概念核心—— transform 高效的全部理由都压在这四个字上,本书给了 GPU 一句、给了「不挤开邻居」一例, 算讲到位了。最值得补的是 cubic-bezier:不会自定义曲线,「自然感」调校永远差最后一档。 如果错,会错在: 对纯静态页面开发者,自定义曲线与 will-change 确实用不上, 速查书按「常用面」裁剪是合理口径。
8. 可带走的¶
- 过渡四参数:属性、时长、曲线、延迟;时长是唯一不能省的2。
display不能过渡;淡入淡出用 opacity + visibility5。- transform 在布局后生效,不挤开邻居、走 GPU——放大旋转首选它78。
- 函数从左到右依次生效,顺序不同结果不同;函数间用空格1112。
- transform-origin 换支点:
left绕左缘转10。 - 动画两部件:@keyframes 画时间线,animation 接上去;名字大小写敏感18。
forwards防弹回;alternate+infinite做无缝往返2123。- 铁律:只动 transform 和 opacity25。
9. 原文地图¶
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 过渡定义(插值) | Chapter 14: Transitions | text/15-ch01-1-chapter-overview.txt:7(搜「smoothly」);:23 搜「Interpolation」 |
| 时长是唯一必需 | 同上 | text/15-ch01-1-chapter-overview.txt:27(搜「needs a duration」) |
| 可过渡与不可过渡 | 同上 | text/15-ch01-1-chapter-overview.txt:25(搜「Transitionable Properties」) |
| 速度曲线五值 | 同上 | text/15-ch01-1-chapter-overview.txt:59(搜「timing-function」) |
| 漏单位无效 | 同上 | text/15-ch01-1-chapter-overview.txt:146(搜「500」) |
| 悬停按钮模式 | 同上 | text/15-ch01-1-chapter-overview.txt:115(搜「Smooth Button Hover」) |
| display 不能过渡 | 同上 | text/15-ch01-1-chapter-overview.txt:142(搜「display: none」) |
| 60fps 与重排 | 同上 | text/15-ch01-1-chapter-overview.txt:144(搜「60fps」) |
| 变换不扰动布局 | Chapter 15: Transforms | text/16-ch01-1-chapter-overview.txt:7(搜「without affecting」);:19 搜「Post-Layout」 |
| GPU 硬件加速 | 同上 | text/16-ch01-1-chapter-overview.txt:21(搜「GPU」) |
| scale 2 与 0.5 | 同上 | text/16-ch01-1-chapter-overview.txt:39(搜「double size」) |
| transform-origin 默认中心 | 同上 | text/16-ch01-1-chapter-overview.txt:68(搜「transform-origin」);:74 搜「50% 50%」 |
| 顺序敏感 | 同上 | text/16-ch01-1-chapter-overview.txt:111(搜「Function Order」) |
| 空格不用逗号 | 同上 | text/16-ch01-1-chapter-overview.txt:113(搜「commas」) |
| keyframes 与百分比 | Chapter 16: Animations | text/17-ch01-1-chapter-overview.txt:21(搜「Keyframes」);:31 搜「@keyframes」 |
| 动画不靠触发 | 同上 | text/17-ch01-1-chapter-overview.txt:23(搜「Timeline」) |
| 控制属性表 | 同上 | text/17-ch01-1-chapter-overview.txt:53(搜「The name of the @keyframes」) |
| 弹跳圆点模式 | 同上 | text/17-ch01-1-chapter-overview.txt:97(搜「Bouncing」) |
| forwards 防弹回 | 同上 | text/17-ch01-1-chapter-overview.txt:81(搜「fill-mode」);:132 搜「Snap-Back」 |
| 简写两个时间值 | 同上 | text/17-ch01-1-chapter-overview.txt:134(搜「first time value」) |
| 只动 transform/opacity | 同上 | text/17-ch01-1-chapter-overview.txt:136(搜「GPU Properties」) |
-
出处:「Chapter 14: Transitions」(
text/15-ch01-1-chapter-overview.txt:7,搜「smoothly」)。原文:「CSS Transitions allow you to change property values smoothly (from one value to another) over a given duration.」插值概念见第 23 段:「The browser calculates the intermediate values between the start and end states.」 ↩ -
出处:「Chapter 14: Transitions」(
text/15-ch01-1-chapter-overview.txt:27,搜「needs a duration」;:156搜「only required」)。原文:「Every transition needs a duration (e.g., 0.3s). Without it, the change remains instantaneous.」 ↩↩ -
出处:「Chapter 14: Transitions」(
text/15-ch01-1-chapter-overview.txt:146,搜「500」)。原文:「Always include the unit (s or ms). Writing transition: all 500; will not work; it must be 500ms.」 ↩↩ -
出处:「Chapter 14: Transitions」(
text/15-ch01-1-chapter-overview.txt:59,搜「timing-function」)。原文五个值:ease(默认,慢起快中缓收)、linear、ease-in、ease-out、ease-in-out;第 158 段:「Use ease-in-out for movements that look more natural to the human eye.」 ↩↩ -
出处:「Chapter 14: Transitions」(
text/15-ch01-1-chapter-overview.txt:142,搜「display: none」)。原文:「You cannot transition display: none to display: block. Use opacity and visibility instead if you want a fade effect.」 ↩↩ -
出处:「Chapter 14: Transitions」(
text/15-ch01-1-chapter-overview.txt:21,搜「State Change」)。原文:「Transitions are triggered when an element's state changes (e.g., hovering, focusing, or adding a class via JavaScript).」 ↩ -
出处:「Chapter 15: Transforms」(
text/16-ch01-1-chapter-overview.txt:21,搜「GPU」)。原文:「Browsers typically use the GPU (Graphics Processing Unit) to handle transforms, which makes them much smoother than animating properties like top or width.」 ↩↩ -
出处:「Chapter 15: Transforms」(
text/16-ch01-1-chapter-overview.txt:19,搜「Post-Layout」)。原文:「Post-Layout Manipulation: Transforms do not push other elements around. If you scale an image to double its size, the surrounding text stays exactly where it is.」 ↩↩ -
出处:「Chapter 15: Transforms」(
text/16-ch01-1-chapter-overview.txt:39,搜「double size」)。原文:「Values: Numbers (e.g., 2 is double size, 0.5 is half).」 ↩ -
出处:「Chapter 15: Transforms」(
text/16-ch01-1-chapter-overview.txt:81,搜「Rotate from the left edge」)。原文:「/* Rotate from the left edge instead of the center */ transform-origin: left; transform: rotateY(-45deg);」 ↩↩ -
出处:「Chapter 15: Transforms」(
text/16-ch01-1-chapter-overview.txt:111,搜「Function Order」)。原文:「transform: translateX(100px) rotate(45deg); produces a different result than transform: rotate(45deg) translateX(100px);. Transformations are applied from left to right.」 ↩↩ -
出处:「Chapter 15: Transforms」(
text/16-ch01-1-chapter-overview.txt:113,搜「commas」)。原文:「Do not use commas between functions. It should be transform: scale(2) rotate(10deg);, not scale(2), rotate(10deg);.」 ↩↩ -
出处:「Chapter 15: Transforms」(
text/16-ch01-1-chapter-overview.txt:115,搜「non-replaced inline elements」)。原文:「The transform property does not work on non-replaced inline elements (like or ). You must change them to display: inline-block or display: block first.」 ↩ -
出处:「Chapter 15: Transforms」(
text/16-ch01-1-chapter-overview.txt:117,搜「blurry」)。原文:「Be careful when scaling up elements containing text; the text may look blurry if it is scaled significantly.」 ↩ -
出处:「Chapter 15: Transforms」(
text/16-ch01-1-chapter-overview.txt:60,搜「perspective」)。原文:「perspective(value): Gives a 3D element a sense of depth (smaller values = more intense perspective).」 ↩ -
出处:「Chapter 16: Animations」(
text/17-ch01-1-chapter-overview.txt:23,搜「Timeline」)。原文:「Unlike transitions, animations do not require a state change (like a hover) to start; they can trigger as soon as the page loads.」 ↩ -
出处:「Chapter 16: Animations」(
text/17-ch01-1-chapter-overview.txt:21,搜「Keyframes」)。原文:「You define the styles at specific percentages (e.g., 0%, 50%, 100%) and the browser fills in the gaps.」 ↩ -
出处:「Chapter 16: Animations」(
text/17-ch01-1-chapter-overview.txt:128,搜「case-sensitive」)。原文:「If your animation isn't working, check that the animation-name exactly matches the name used in @keyframes (they are case-sensitive).」 ↩↩↩ -
出处:「Chapter 16: Animations」(
text/17-ch01-1-chapter-overview.txt:130,搜「invalid」)。原文:「Like transitions, you must include s or ms. animation-duration: 2; is invalid.」 ↩ -
出处:「Chapter 16: Animations」(
text/17-ch01-1-chapter-overview.txt:69,搜「animation (Shorthand)」)。原文语法:animation: [name] [duration] [timing-function] [delay] [iteration-count] [direction] [fill-mode];↩ -
出处:「Chapter 16: Animations」(
text/17-ch01-1-chapter-overview.txt:105,搜「infinite alternate」)。原文模式:「Using alternate direction and infinite loops for a smooth bounce.」 ↩↩ -
出处:「Chapter 16: Animations」(
text/17-ch01-1-chapter-overview.txt:132,搜「Snap-Back」)。原文:「By default, an element resets to its original CSS when an animation ends.」 ↩ -
出处:「Chapter 16: Animations」(
text/17-ch01-1-chapter-overview.txt:81,搜「fill-mode」)。原文:「it tells the element to stay at its final keyframe style rather than snapping back to its original state.」 ↩↩ -
出处:「Chapter 16: Animations」(
text/17-ch01-1-chapter-overview.txt:134,搜「first time value」)。原文:「In the shorthand, the first time value is always the duration, and the second is the delay.」 ↩ -
出处:「Chapter 14: Transitions」(
text/15-ch01-1-chapter-overview.txt:144,搜「60fps」)与「Chapter 16: Animations」(text/17-ch01-1-chapter-overview.txt:136,搜「layout recalculations」)。原文:「try to limit transitions to transform and opacity. Transitions on width, height, or margin cause the browser to 're-layout' the page, which can be laggy.」 ↩↩