这篇文章我们将要来介绍CSS will-change 属性。will-change
属性是什么?我们要如何使用它呢?
背景
现在有许多开发者都会使用CSS3 transitions,transforms和animations来制作一些可以互动的动画效果,这些以前要使用javascript或Flash才能完成。现在我们可以使用CSS3来完成平滑和炫酷的动画效果。如果你使用过这些CSS3技术,你可能会看到过一些关于CPU,GPU和硬件加速之类的术语。让我们先来看看这些术语:
- CPU,中央处理单元(Central Processing Unit)的缩写。它是所以计算机都配备的硬件。
- GPU,图形处理单元(Graphics Processing Unit)的缩写。它是是硬件处理和绘制图形相关的模块。GPU的作用是处理复杂的图形计算和减轻CPU的工作量。
- 硬件加速是减轻CPU的工作量,将这些工作移动到专用模块上的术语。在使用CSS3 transitions,transforms和animations制作动画时,硬件加速是指将这些工作移到GPU上,减轻CPU的工作。
那么它是如何提高动画的质量和效率的呢?在Webkit内核的浏览器中,在执行以下CSS操作时经常会出现一些闪烁现象,例如2D transforms 和 animations。我们可以通过一个小技巧来解决这个问题。我们让浏览器认为我们当前正在执行的是一个3D transform操作,这样就会将这些操作转移到GPU中执行。因为3D transforms的操作会自动转移到GPU中执行。代码可以像下面这样:
.accelerate { -webkit-transform: translate3d(0, 0, 0); }
这是一个我们过去常用的小技巧。但是,这只是一个hack方法,现在,我们可以通过will-change
属性来帮助我们解决这些问题。
什么是will-change
?
W3C对will-change
的解释是:
The will-change
CSS property … allows an author to inform the UA ahead of time of what kinds of changes they are likely to make to an element. This allows the UA to optimize how they handle the element ahead of time, performing potentially-expensive work preparing for an animation before the animation actually begins.
这意味着它能取代通过3D transform的hack来强制将transforms转移到GPU上,我们可以使用一个专门的属性来通知浏览器关注特性的变化,以及相应的优化和分配内存。下面来看看如何使用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); }
上面的代码会在鼠标进入父元素时添加优化操作,并在鼠标移出时移出它。但是这意味着,每次鼠标进入父容器的时候,浏览器都会期待在元素上发生一次改变。
在我们创建一个全屏幻灯片或CSS翻页效果的时候,幻灯片总是需要改变图片的,所以像下面这样设置是非常合理的:
.slide { will-change: transform; }
总是移除will-change
当你使用完will-change
后一定要记得移除它。正如上面所说的,浏览器的优化是非常昂贵的,如果使用的不好,会造成相反的效果。我们可以使用javascript来处理它。下面是从MDN中易用的一个例子,这里有一个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
是一个非常新的属性,当前只有下面的浏览器支持这个属性。
- Chrome 36+
- Firefox 36+
- Opera 24+
- Android browser 37
- Chrome for Android 40
- Opera Mobile 24
完整的will-change
属性浏览器支持列表可以查看Can I Use
小结
CSS will-change
属性是一个可以优化动画效果的属性。但是如果使用不好,会得到相反的效果。下面有一些关于硬件加速和will-change
属性的文章,建议您都阅读一下:
- W3C:CSS Will Change Module Level 1
- Sara Soueidan:Everything You Need to Know About the CSS will-change Property
- MDN:CSS will-change
- HTML5 Rocks:High Performance Animations
文章翻译自:http://www.sitepoint.com/introduction-css-will-change-property/