编程语言研究书库

动效三件套 — 过渡、变换、动画

动效三件套 — 过渡、变换、动画

原书拆成第 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。

四个参数:

.card {
  transition: background-color 0.3s ease;
  /*          └ 属性      └ 时长  └ 速度曲线(可省,默认 ease) */
}
  • 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. 可带走的

  1. 过渡四参数:属性、时长、曲线、延迟;时长是唯一不能省的2。
  2. display 不能过渡;淡入淡出用 opacity + visibility5。
  3. transform 在布局后生效,不挤开邻居、走 GPU——放大旋转首选它78。
  4. 函数从左到右依次生效,顺序不同结果不同;函数间用空格1112。
  5. transform-origin 换支点:left 绕左缘转10。
  6. 动画两部件:@keyframes 画时间线,animation 接上去;名字大小写敏感18。
  7. forwards 防弹回;alternate + infinite 做无缝往返2123。
  8. 铁律:只动 transform 和 opacity25。

9. 原文地图

主题原书章原文位置
过渡定义(插值)Chapter 14: Transitionstext/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: Transformstext/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: Animationstext/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」)

Footnotes

  1. 出处:「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.」 ↩

  2. 出处:「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.」 ↩ ↩2

  3. 出处:「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.」 ↩ ↩2

  4. 出处:「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.」 ↩ ↩2

  5. 出处:「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.」 ↩ ↩2

  6. 出处:「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).」 ↩

  7. 出处:「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.」 ↩ ↩2

  8. 出处:「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.」 ↩ ↩2

  9. 出处:「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).」 ↩

  10. 出处:「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);」 ↩ ↩2

  11. 出处:「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.」 ↩ ↩2

  12. 出处:「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);.」 ↩ ↩2

  13. 出处:「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.」 ↩

  14. 出处:「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.」 ↩

  15. 出处:「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).」 ↩

  16. 出处:「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.」 ↩

  17. 出处:「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.」 ↩

  18. 出处:「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).」 ↩ ↩2 ↩3

  19. 出处:「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.」 ↩

  20. 出处:「Chapter 16: Animations」(text/17-ch01-1-chapter-overview.txt:69,搜「animation (Shorthand)」)。原文语法:animation: [name] [duration] [timing-function] [delay] [iteration-count] [direction] [fill-mode]; ↩

  21. 出处:「Chapter 16: Animations」(text/17-ch01-1-chapter-overview.txt:105,搜「infinite alternate」)。原文模式:「Using alternate direction and infinite loops for a smooth bounce.」 ↩ ↩2

  22. 出处:「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.」 ↩

  23. 出处:「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.」 ↩ ↩2

  24. 出处:「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.」 ↩

  25. 出处:「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.」 ↩ ↩2

On this page