1. 介绍
现代的 CSS 渲染器执行许多复杂的优化以快速、高效地渲染网页。 然而,实施这些优化往往需要不小的启动成本, 这可能会对页面的响应速度产生负面影响。
然而,将元素设置在新的层中是一个相对昂贵的操作, 这可能会延迟transform动画开始的时间,延迟时间长到足以被用户注意到。
本规范中定义的will-change属性允许作者提前声明哪些属性可能会在未来发生变化, 这样 UA 可以在需要之前设置适当的优化。 这种方式确保当实际的变化发生时, 页面可以快速响应。
1.1. 值的定义
本规范遵循CSS 属性定义惯例,并使用值定义语法,引用了 [CSS-VALUES-3]中的定义。 本规范未定义的值类型在 CSS 值与单位模块中定义 [CSS-VALUES-3]。 结合其他 CSS 模块可能扩展这些值类型的定义。
除了它们定义中列出的特定属性值之外, 本规范中定义的所有属性 还接受CSS-wide 关键词作为属性值。 为了可读性,它们没有被显式重复。
1.2. 正确使用 will-change
will-change属性, 像所有性能提示一样, 可能有些难以掌握如何“正确”使用, 尤其是它几乎不会产生作者可以直接检测到的效果。 然而,有一些简单的“应该做”和“不应该做”, 希望可以帮助开发者更好地直观了解如何正确使用 will-change。
不要在过多属性或元素上滥用will-change
看到will-change时,常见的反应是认为像这样的代码是个好主意:
* { will-change: transform, opacity /* , ... */; }
毕竟,这告诉浏览器提前优化所有内容, 这肯定有好处,对吧?
错了。浏览器已经尽力优化所有内容。 明确地告诉它这样做并没有任何帮助, 事实上,可能会带来很大的危害; 与will-change 关联的某些强效优化会使用大量机器资源, 如果像这样过度使用,可能会导致页面变慢,甚至崩溃。
此外,will-change确实有一些副作用, 而且页面很可能不会想要在每个元素上都应用这些副作用。
谨慎在样式表中使用 will-change
在样式表中直接使用 will-change 暗示目标元素总是在几秒内发生变化。 这通常不是你真正想表达的含义; 相反,will-change通常应通过脚本在变化发生前后切换 (参见不要在已停止变化的元素上浪费资源)。 但是,在某些常见情况下,在样式表中直接使用 will-change是合适的。
body > .sidebar { will-change: transform; /* 将使用 'transform' 将侧边栏 滑出用户请求的内容。 */ }
由于这是对少数元素的限制, 优化的应用频率较低并不会造成很大影响。
.cats-flying-around-the-screen { will-change: left, top; }
给 will-change足够的时间生效
另一个常见的不良模式是在开始动画或属性更改will-change帮助优化之前, 立即应用它。 不幸的是,大多数优化需要时间才能生效, 因此如果这么做,will-change几乎没有作用。 相反,找到某种方式至少稍微提前预测变化, 然后再设置 will-change。
.element { transition: opacity .2s; opacity: 1; } .element:hover { will-change: opacity; } .element:active { opacity: .3; }
然而,如果效果发生在 hover 上,这样的规则是无效的。 在这种情况下,通常仍然可以找到一些方法在操作发生前进行预测。 例如,hover 祖先元素可能会提供足够的提前时间:
.element { transition: opacity .2s; opacity: 1; } .container:hover > .element { will-change: opacity; } .element:hover { opacity: .3; }
不要在已停止变化的元素上浪费资源
由于浏览器用于更改某些属性的优化代价较大, 浏览器通常会在正常情况下尽快移除这些优化并恢复到正常行为。 但是,will-change通常会覆盖这种行为, 使得优化持续的时间远长于浏览器通常情况下的时间。
因此,每当你将will-change添加到某个元素时, 尤其是通过脚本时, 不要忘记在元素完成变化后移除它, 以便浏览器可以恢复被优化占用的资源。
2. 提示未来行为: will-change 属性
名称: | will-change |
---|---|
值: | auto | <animateable-feature># |
初始值: | auto |
适用于: | 所有元素 |
是否继承: | 否 |
百分比: | 不适用 |
计算值: | 指定的值 |
规范顺序: | 按语法顺序 |
动画类型: | 不可动画化 |
<animateable-feature> = scroll-position | contents | <custom-ident>
will-change 属性为用户代理提供渲染提示, 告知作者预计将对元素进行哪些类型的更改。 这样,用户代理可以提前进行必要的优化,以平滑渲染这些更改, 避免当作者开始更改或动画化该功能时出现“卡顿”。
值有以下含义:
- auto
- 表示没有特定的意图; 用户代理应应用其通常使用的任何启发式方法和优化。
- scroll-position
-
表示作者预计在不久的将来会动画化或更改元素的滚动位置。
例如, 浏览器通常只渲染可滚动元素的“滚动窗口”中的内容, 以及窗口外的一部分内容, 在跳过渲染所节省的内存和时间与平滑滚动效果之间取得平衡。 浏览器可能会将此值作为信号,扩展滚动窗口周围已渲染内容的范围, 以便可以顺利地进行更长时间/更快的滚动。
- contents
-
表示作者预计在不久的将来会动画化或更改元素内容的某些部分。
例如,浏览器经常随着时间推移“缓存”元素的渲染, 因为大多数东西不会经常更改, 或者只会更改它们的位置。 然而,如果一个元素的内容不断变化, 生成和维护该缓存是浪费时间。 浏览器可能会将此值作为信号,减少对该元素的缓存, 或完全避免缓存,而是持续从头渲染该元素。
此值主要用于帮助浏览器优化基于JS的内容动画, 这些动画每秒更改元素内容的多个方面。 当使用声明式动画时,浏览器已经自动执行这种优化。
注意: 此值基本上适用于声明它的元素的整个子树, 因为它表明浏览器应该计算出*任何*后代都可能以某种方式更改。 在文档结构较高的元素上使用它可能对页面性能非常不利; 尽量只在文档树中“底部”的元素上使用此值, 包含尽可能少的文档内容。
- <custom-ident>
-
如果 <custom-ident> 与内置CSS属性的名称进行 ASCII不区分大小写 匹配,
它表示作者预计在不久的将来会动画化或更改元素上给定名称的属性。
如果给定的属性是简写,
则表示预计其展开后的所有长写属性也会更改。
例如, 设置 will-change: background; 等同于设置 will-change: background-image, background-position, ...,涵盖所有 background 展开的属性。
此处使用的 <custom-ident> 排除了关键字 will-change、none、all、 auto、scroll-position 和 contents, 以及通常从 <custom-ident> 中排除的关键字。
注意: 大多数属性在指定时不会产生任何效果, 因为用户代理不会为大多数属性的更改执行任何特殊优化。 不过,指定它们是 安全的; 它们只是不产生任何效果。
指定自定义属性不会产生任何效果, 这意味着通过自定义属性发生的效果 不会被视为以下规则中条件所述的任何非初始值导致的某些行为。
注意: 指定一个不被识别为属性的值是可以的; 它只是不产生任何效果。 这允许您安全地指定存在于某些用户代理中的 新 属性, 而不会对不知道该属性的旧版用户代理产生负面影响。
例如, 浏览器通常会以非常不同的方式处理设置了非初始值的 transform 的元素, 可能会将它们渲染到它们自己的“GPU层”, 或者使用其他机制,使快速执行 transform 可以实现的转换更容易。 浏览器可能会将 transform 值作为信号, 表示它应该立即将该元素提升为其自己的层, 在元素开始变换之前, 避免涉及重新渲染旧层和新层的延迟。
如果某个属性的非初始值会在元素上创建堆叠上下文, 则在 will-change 中指定该属性时, 必须在元素上创建堆叠上下文。
如果某个属性的非初始值会使该元素生成绝对定位元素的包含块, 则在 will-change 中指定该属性时, 必须使该元素生成绝对定位元素的包含块。
如果某个属性的非初始值会使该元素生成固定定位元素的包含块, 则在 will-change 中指定该属性时, 必须使该元素生成固定定位元素的包含块。
如果某个属性的非初始值会导致元素的渲染发生差异 (例如对文本使用不同的抗锯齿策略), 当该属性在 will-change 中被指定时, 用户代理应使用该备用渲染, 以避免属性最终更改时出现突然的渲染差异。
例如, 将 opacity 设置为 1 以外的任何值 都会在元素上创建堆叠上下文。 因此,设置 will-change: opacity 也会创建堆叠上下文, 即使 opacity 当前 仍等于 1。
will-change 属性本身不会对指定的元素产生 直接 影响, 除了上述创建堆叠上下文和包含块的情况。 它只是对用户代理的渲染提示, 允许用户代理在某些类型的更改实际发生之前, 设置可能会非常昂贵的优化。
3. 安全性考量
本文件未提出任何安全性问题
4. 隐私考量
本文件未提出任何隐私问题
5. 致谢
感谢 Benoit Girard 最早提出了 will-animate 属性, 并完成了大量初期设计工作。
6. 更改
自 2015年12月3日CR版本起的更改:
-
添加了安全性和隐私章节
-
澄清了未知值是可以接受的,并且没有任何影响
-
明确规定属性名使用ASCII不区分大小写匹配
-
将 will-change 属性的动画类型更改为不可动画化
-
从属性定义表中删除了 "媒体:" 条目,与其他CSS规范一致
-
细微的编辑澄清和标记改进
自 2014年4月29日工作草案版本起的更改:
-
增加了解释部分,提供了如何正确使用 will-change 的指导。
-
明确了简写属性的行为