先记住这个答案
all 的含义是「所有可过渡属性都参与」,但浏览器只会为值真正发生变化的属性创建过渡。和显式列出相同属性相比,样式计算和合成开销几乎相同。差异主要在三处:all 无法为不同属性设置不同时长和缓动;后续新增样式可能被意外触发过渡;监听大量布局类属性会放大意外过渡的代价。工程上推荐只列出需要过渡的属性,把 all 留给属性集合稳定的简单微交互。
all只让变化的属性产生过渡,开销接近显式列表all不能按属性区分时长与缓动- 新增样式可能被
all意外触发过渡 - 性能关键在属性类型而非写法本身
浏览器怎么处理 all 的
transition-property 的初始值就是 all。它的含义是所有可动画属性在值变化时都可触发过渡。浏览器在每次样式重算时对比前后的计算值,发现某个被监听属性变化且可插值时才创建过渡对象。所以 all 并不会给所有属性每秒插值,只是扩大了「变更检测」的候选集。这部分检测本身就是廉价的查表与比较操作。
真正的帧开销取决于被触发过渡的属性类型。过渡 transform 和 opacity 时通常只更新合成层,不进入布局与绘制阶段;过渡 width、margin 等布局属性时,每帧的插值结果会迫使浏览器重新计算布局。这一层面上显式列表与 all 没有本质区别,区别只在于显式列表像白名单,挡住了不该被过渡的属性被自动接管。
侧边栏收展中 all 引发的意外过渡
考虑一个后台系统:侧边栏原本只过渡 transform 实现滑入滑出,开发者写了 transition: all .3s。半年后同事给同一容器补了 width 从 240px 到 64px 的折叠样式。宽度变化被 all 静默接管,每帧插值 width 触发整页布局重算,低端设备上收展明显掉帧。排查时发现元凶不在新代码,而在旧的 all。
.sidebar {
transform: translateX(0);
transition: transform 0.3s ease; /* 只监听 transform */
}
.sidebar.collapsed {
transform: translateX(-176px);
}
/* 反例:后续任何属性改动都会被接管 */
.sidebar-bad {
transition: all 0.3s ease;
}第一种写法只监听 transform,后续加 width 或 padding 不会触发动画。第二种 all 会把新增属性的变更全部变成过渡,布局属性被插值时引起逐帧重排。
什么时候 all 可以接受
all 可以用的场景边界比较清晰:元素属性集合小且稳定、只涉及 transform 和 opacity 这类合成友好的属性、团队不会给该选择器追加布局类样式。比如一个纯展示图标只过渡放大和透明度,写 all 与写两个属性在性能面板里看不出差别。
必须改写法的场景有三种:需要不同属性用不同时长和缓动时,all 语义上做不到;选择器作用在会被频繁迭代的通用容器上时,all 会把未来改动变成回归风险;元素数量大且被过渡的是布局属性时,先用性能面板确认瓶颈,再考虑改为合成属性方案。
容易答错的地方
- 以为 all 会对所有属性逐帧插值所以一定更慢
- 浏览器只给计算值真正变化的属性创建过渡,未变化的属性不参与插值。
all与列出同一组属性的帧开销基本相同,慢的根源是被过渡属性的类型,而非all本身。 - 性能差就删掉过渡改成瞬时切换
- 如果瓶颈是布局属性被逐帧插值,正确做法是把动画改到
transform或opacity上并保持过渡。删除过渡牺牲了交互体验,却没解决样式架构的问题。
面试官还会怎么问?
all 会影响合成层创建吗?
不会。层提升由 will-change、3D 变换、进行中的 transform 或 opacity 动画等因素触发。transition-property 取什么值只决定哪些变更会产生过渡,不改变分层策略。
想给不同属性配不同时长该怎么写?
不能用 all,要在 transition 简写中逐项声明,比如 transition: width .2s linear, opacity .4s ease。每组对应独立的时长、缓动和延迟。
怎么验证 all 是不是真的造成了性能问题?
用开发者工具录制动画期间的主线程活动。如果每帧出现大量 Layout 或 Paint,说明被过渡的是布局或绘制属性。再检查该属性是否因 all 被意外接管。如果帧内几乎没有主线程开销,all 就不是问题来源。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。