CSS will-change 属性用于告诉浏览器某个元素上会发生哪些变化,以便浏览器可以在元素属性真正发生变化之前提前做好对应的优化准备工作。
通过will-change
属性,你可以告诉浏览器,元素的哪些属性即将发生变化,浏览器会对相应的属性变化做出提前的优化。这种优化可以将一部分复杂的计算工作提前准备好,使页面的反应更为快速灵敏。
使用will-change
属性需要注意以下几点:
- 不要将 will-change 应用到太多元素上:浏览器已经尽力尝试去优化一切可以优化的东西了。有一些更强力的优化,如果与
will-change
结合在一起的话,有可能会消耗很多机器资源,如果过度使用的话,可能导致页面响应缓慢或者消耗非常多的资源。 - 有节制地使用:通常,当元素恢复到初始状态时,浏览器会丢弃掉之前做的优化工作。但是如果直接在样式表中显式声明了
will-change
属性,则表示目标元素可能会经常变化,浏览器会将优化工作保存得比之前更久。所以最佳实践是当元素变化之前和之后通过JS脚本来切换will-change
的值。 - 不要过早应用
will-change
优化:如果你的页面在性能方面没什么问题,则不要添加will-change
属性来榨取一丁点的速度。will-change
的设计初衷是作为最后的优化手段,用来尝试解决现有的性能问题。它不应该被用来预防性能问题。过度使用will-change
会导致大量的内存占用,并会导致更复杂的渲染过程,因为浏览器会试图准备可能存在的变化过程。这会导致更严重的性能问题。 - 给它足够的工作时间:这个属性是用来让页面开发者告知浏览器哪些属性可能会变化的。然后浏览器可以选择在变化发生前提前去做一些优化工作。所以给浏览器一点时间去真正做这些优化工作是非常重要的。使用时需要尝试去找到一些方法提前一定时间获知元素可能发生的变化,然后为它加上
will-change
属性。
will-change
属性只能在特定的时间内发生作用。我们不能够在一个已经transform的元素上使用will-change: transform。
我们要注意以下几点:
- 我们使用这个属性通知浏览器,让浏览器提前知道元素的哪些属性是将要发生的。
- 这将允许浏览器预先做出适当的优化,最终使动画得到快速和流畅的渲染。
例如下面使用will-change
属性的方法是没有任何效果的:
.will-change:active { will-change: transform; transition: transform 0.3s; transform: scale(1.5); }
上面的代码中,是在一个变化已经发生的时候,才去通知浏览器。will-change
属性没有起到相应的作用。如果我们希望浏览器预先知道要发生的变化,我们要在正确的时间通知它。
一个元素要达到active
状态,它必须先经过hover
状态,所以我们的代码应该这样写:
.will-change { transition: transform 0.3s; } .will-change:hover { will-change: transform; } .will-change:active { transform: scale(1.5); }
浏览器会尽可能的对元素将要发生的变化进行优化。浏览器为了释放内存会尽可能的移除一些优化操作。在一个元素上直接使用will-change
属性,会强制浏览器去对它进行优化,这有可能会照成内存的浪费。因此,我们要在正确的时间里对元素添加和移除will-change属性
。正如上面的例子一样,will-change
只会在鼠标滑过元素的时候才被添加。如果我们想要transform发生在鼠标hover
时该怎么呢?你可能会这样写代码:
.will-change { will-change: transform; transition: transform 0.3s; } .will-change:hover { transform: scale(1.5); }
上面的代码会增加内存的使用,因为我们强制浏览器认为元素会在所有的时间里都会发生改变。我们可以在元素的父元素上制作鼠标悬停事件来解决这个问题:
.will-change-parent:hover .will-change { will-change: transform; } .will-change { transition: transform 0.3s; } .will-change:hover { transform: scale(1.5); }
上面的代码会在鼠标进入父元素时添加优化操作,并在鼠标移出时移出它。但是这意味着,每次鼠标进入父容器的时候,浏览器都会期待在元素上发生一次改变。
当你使用完will-change
属性之后一定要记得移除它。正如上面所说的,浏览器的优化是非常昂贵的,如果使用的不好,会造成相反的效果。我们可以使用javascript来处理它。
例如有一个class为.element
的元素,当我们点击它的时候,它会发生transform。CSS代码类似下面的样子:
.element { transition: transform 0.5s; } .element.clicked { transform: scale(1.5); }
如果我们需要通知浏览器来响应优化元素点击后的transform效果,我们可以像下面这样做:
var el = document.querySelector('.element'); el.addEventListener('mouseenter', hintBrowser); el.addEventListener('animationEnd', removeHint); function hintBrowser() { this.style.willChange = 'transform'; } function removeHint() { this.style.willChange = 'auto'; }
上面的代码只是一个片段,你需要添加必要的javascript来在元素被点击的时候添加相应的clicked
class。但是我们从上面的代码中可以观察到浏览器是如何为将要发生的改变做准备工作的,还有在改变完成之后是如何释放内存的。当鼠标进入元素中的时候,元素被添加will-change
属性。当元素被点击,transform被执行的时候,将会发出animation事件。在animationEnd
的时候,will-change
属性被移除,内存被释放。
官方语法
will-change: auto | <animateable-feature># // 其中#表示你可以使用多个animatable-features,各个值之间使用逗号来分隔。 <animateable-feature> = scroll-position | contents | <custom-ident>
参数:
- auto:表示没有指定元素的哪些属性会变化,浏览器不会对任何的变化做出优化工作。
- scroll-position:表示开发者希望改变滚动条的位置或者使之产生动画。
- contents:表示开发者希望改变元素内容中的某些东西,或者使它们产生动画。
- <custom-ident> (<user-ident>):表示开发者希望改变指定的属性名或者使之产生动画。如果属性名是简写,则代表所有与之对应的简写或者全写的属性。
示例代码
will-change: contents; will-change: scroll-position; will-change: opacity; /* 多个值 */ will-change: contents, transform; will-change: scroll-position, opacity;
浏览器支持
CSS3 will-change
属性的浏览器兼容性列表如下: