CSS中的will-change属性究竟有何作用?
我使用will-change属性已有相当长一段时间,但突然意识到自己从未真正理解它的具体功能。虽然知道它属于某种性能优化机制,但仅此而已。
will-change是什么?
这是给浏览器的提示,大致意思是“嘿,我即将对这些属性进行动画处理,请做好准备”。
浏览器可能响应为:将元素提升至独立的GPU合成层、预分配内存,或者完全无视该提示(若认为不值得响应)。
为何提前告知很重要?
浏览器在屏幕上绘制内容通常遵循以下三个步骤:
布局阶段
浏览器计算每个元素的大小与位置,如同在棋盘上摆放棋子。此步骤主要由CPU处理。
绘制阶段
元素填充像素、颜色、边框、阴影及图像,如同给棋子上色。此过程同样消耗CPU资源,并需额外内存存储绘制内容。
合成
最终,绘制完成的图层被传递给GPU。GPU将它们叠加组合,如同将完成的画作滑入玻璃板下方,最终在屏幕上呈现合成画面。此步骤主要依赖GPU处理。
若动画仅涉及合成器友好的属性(如transform和opacity),浏览器可跳过布局和绘制阶段,直接让GPU在合成步骤处理所有内容。
will-change 提示能触发什么?
will-change 提示告知浏览器:该元素可能需要独立的 GPU 层。若浏览器采纳,该元素将被提升至独立纹理层,此后任何变更都不会强制其兄弟元素重绘。
但最终决定权在浏览器:若收益微小或内存紧张,它可能忽略该提示。
浏览器还可能为预期变化预分配内存、优化渲染路径并准备GPU资源。
实际效果如何?
若无该提示,浏览器仅在动画启动时才将元素提升至独立图层。这种一次性图层提升可能导致动画初始帧出现轻微卡顿。
.animated-button {
transform: translateX(0px);
transition: transform 0.3s;
}
.animated-button:hover {
transform: translateX(24px);
}
启用will-change后,浏览器可在页面空闲时预先提升元素层级,因此当鼠标悬停按钮时,动画从首帧起便能流畅运行。
.animated-button {
will-change: transform;
transform: translateX(0px);
transition: transform 0.3s;
}
.animated-button:hover {
transform: translateX(24px);
}
是否应无条件使用will-change?
will-change能平滑动画效果、降低CPU占用并提升动画性能。
但其计算成本较高,初始层创建需耗费时间,因此应审慎适度使用。
/* Good - only on elements that will actually animate */
.animated-button {
will-change: transform;
}
/* Bad - on every element */
* {
will-change: auto;
}
需明确指定将变更的属性。这与transition-property原理相似——多数场景下应避免使用transition-property:all。
/* Good - specifying exactly what will change */
.animated-button {
will-change: transform, opacity;
}
/* Not Great - too broad */
.animated-button {
will-change: all;
}
属性
实际应用中可将任何有效CSS属性添加至will-change,但真正能显著提升效果的仅有少数几项。
包括transform、opacity以及模糊/亮度等filter效果。现代浏览器对clip-path和mask的处理也相当出色。针对这些属性,浏览器可在不重绘的情况下调用GPU进行运算。
scroll-position同样值得关注,尤其适用于仅需动画滚动偏移的情况。
.parallax-wrapper {
overflow: auto;
will-change: scroll-position;
}
而contents则告知浏览器:容器内部元素将频繁更新,但外部容器本身保持静止。
.virtual-list {
contain: content;
will-change: contents;
}
其他属性如top、background、border等虽可合法编写,但除占用额外内存外并无实际加速效果。
结论
will-change在各类动画中展现出强大效能,可视为动画的“加速模式”。但它并非魔法般的性能开关,更像是向浏览器发出预告信号。
适度使用并精准定位才是充分发挥其效能的关键。
在某些情况下,您可能甚至察觉不到差异——现代浏览器已具备卓越的优化能力。但对于需要从首帧起就保持流畅感的复杂动画而言,它能带来颠覆性的改变。




当你开始为具体实现而非API编写代码时,就存在风险。这种情况总是危险的。
虽然我理解这个观点——暗示具体实现方式——但我们真的需要这样做吗?换句话说,CSS是否是处理这类情况的合适场所?难道不该在浏览器实现层面更好地处理这些场景吗?
十年前我在Mozilla负责渲染栈开发并调优前端时,就曾提出will-change特性。
某些场景下这种预警机制至关重要。例如当低配移动设备搭载高分辨率屏幕时,你根本无法为意外出现的动画构建渲染层。此时内存占用极低,除非必要否则不应构建渲染层。若未提前预警,动画前几帧必将丢失,导致用户体验持续卡顿。
若非必要场景,我建议避免使用该特性。我至今仍在优化网页前端,几乎从不用这个属性——因为确实很少需要它。
我也觉得这像个泄露的抽象概念,但
will-change已存在十多年,且仅限于CSS动画部分,我实在想不出CSS还有哪个特性会这样运作。我不确定
will-change究竟是在为实现编码,还是在与物质现实互动。我已放弃学习任何新CSS特性,不再追逐那些只会制造更多问题、更多代码、更多混乱且难以维护的“解决方案”。它正变成我们不愿提及、不愿承认存在的庞然大物。对我个人而言,它至今仍存在着我们抱怨已久的种种问题——这些问题究竟存在多久了,谁又能说得清呢?
既然放弃学习,自然难以理解哪些问题已被解决(哪些仍待解决)。
你忽略的元解决方案之一是“基线”机制的建立,它能帮助开发者明确哪些特性和功能可安全使用。希望这个链接能帮到你!https://web.dev/baseline
基准线根本没用,你可能有个概念,但仍需查阅浏览器详细表格(在MDN上)才能深入了解。我决定有选择地学习——与其浪费时间死记硬背fit-content公式(简直疯了),我宁愿读数学书:
> 该公式表示 max(minimum, min(limit, max-content)),其中 minimum 代表 auto 模式下的最小值(通常但非必然等于 min-content 的最小值),limit 是作为参数传递给 fit-content() 的轨道尺寸函数。本质上是计算 minmax(auto, max-content) 与 minmax(auto, limit) 中的较小值。
我注意到滚动经过那个动画的 will-change 按钮时页面会卡顿。既然它使用了 will-change,对我来说似乎产生了反效果。
> 此时盒子开始填充像素、颜色、边框、阴影和图像。想象有人在给棋盘游戏棋子上色。这同样会消耗CPU资源,并占用额外内存存储绘制区域。
你确定这是CPU在处理吗?我以为CPU端只生成绘制命令列表,而GPU承担主要绘制工作。
至少在相当长一段时间内,该标志确实指示浏览器使用CPU渲染——因为GPU在处理动态内容时的初始化开销过高。
不过我的认知已过时且属二手信息。希望新一代GPU API能改变这种状况!
能否提供出处?我参与相关工作时从未见过这种情况。
文字渲染也适用吗?字形渲染机制复杂,我难以想象高质量GPU渲染器能因这点优势超越CPU渲染器。
近一年情况应该已改变?记得最近看到不少关于文字渲染终于能迁移到GPU处理的报道。
SDL3 TTF库的TextEngine API可构建针对CPU或GPU的字体图集(例如https://wiki.libsdl.org/SDL3_ttf/TTF_CreateGPUTextEngine)。虽然操作TTF_Text对象比直接处理char*更繁琐,但完全可行。
我唯一记得必须使用 will-change 的情况是为解决 Leaflet/WebKit 的这个问题:https://github.com/Leaflet/Leaflet/issues/8068