关于CSS的will-change属性的介绍

发布于 栗子酱

在这篇文章中,我们将研究CSS中的will-change这个属性,研究它是什么,何时、如何使用它以及如何不使用它。这儿有许多关于wil-change的技术文章,所以在这篇文章中,我将参考大量的这些资源,并且在文章的末尾编辑一份列表。通过一些简单例子,这篇文章将作为重要部分的概述。

##一些背景

现在许多的前端工程师正在利用CSS3的transitiontransformanimation来添加一个新的无需js库和Flash的应用交互层。现在我们能够使用最轻量的CSS代码来实现漂亮的动画效果了。 如果你已经试验和利用过这些CSS3的属性,你可能碰到类似CPU、GPU和硬件加速等术语。让我们快速的掌握这些术语:

  • CPU即中央处理器,它的功能主要是解释计算机指令以及处理计算机软件中的数据,也被称为主板。
  • GPU即图形处理器,是与处理和绘制图形相关的硬件。GPU是专为执行复杂的数学和几何计算而设计的,有了它,CPU就从图形处理的任务中解放出来,可以执行其他更多的系统任务。
  • 硬件加速是指在计算机中透过把计算量非常大的工作分配给专门的硬件来处理来减轻CPU的工作量的技术。在CSS transition, transformanimation的世界里,他暗示我们应该卸载进程到GPU,因此加快速度。这种情况通过向它自己的层叠加元素,当加载动画的时候可以加速渲染。

怎样改善动画的性能和质量?首先,在基于webkit的浏览器,我们在执行一些CSS的操作经常会看见闪烁,即二维变换和动画。在过去,我们通过欺骗浏览器一点点解决实现。我们会使浏览器执行3D变换,因此减轻了工作量到GPU上。这是因为3D转换是自动移到那里的。这导致我们的做一些挂羊头卖狗肉的事就像这样:

.accelerate {
  -webkit-transform: translate3d(0, 0, 0);
}

还有一些类似的技巧,但是在大部分情况下,有很多相同的技巧,但对于此类问题的大部分,这种方式就可以解决。然而, 这是一种非正常的实现方式,当我们正确使用的时候,will-change属性将极大的帮助我们。让我们一起探讨一下吧。

will-change是什么?

通过W3C编辑的草案:

will-change属性,允许作者提前告知浏览器的默认样式,那他们可能会做出一个元素。它允许对浏览器默认样式的优化如何提前处理因素,在动画实际开始之前,为准备动画执行潜在昂贵的工作。

这意味着不是通过一个3D变换迫使我们转换到GPU,而是我们现在可以使用一个专用的属性来通知浏览器留意接下来的变化,从而优化和分配内存。在我们得到所有令人兴奋的东西之前,我们需要理解怎样使用will-change

will-change的使用方法

will-change在一定的时间里使用是唯一有效的。我们不能运用一些类似will-change的属性:变换一个已经变换的元素,这样是毫无意义的。Sara Soueidan在Opera blog上讨论关于它的一些奇妙的细节,所以确保要检查出来,但关键需要注意的是这些:

  • 我们可以使用这个属性让浏览器提前了解预期的元素变换。
  • 它允许浏览器提前做好适当的优化,使之最后能够快速和流畅的渲染。
  • 正如前面所提到的那样,浏览器需要预先知道改变的发生。这意味着当浏览器在变化时我们不得不提前做好准备。

在考虑了以上几点之后,让我们一起来看看这个不会有任何效果的例子:

.will-change:active {
  will-change: transform;
  transition: transform 0.3s;
  transform: scale(1.5);
}

当我们通知浏览器的时候,变化已经发生,完全抵消了will-change的全部意义。当预期的改变发生时,如果我们想要让浏览器提前了解,我们就必须在合适的时间通知它。 为了使元素达到激活的状态,它必须先被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属性的方法。第一个例子中,我们就能够看到,因为这个属性只能从hover中添加。但是如果我们想要的变化实际是发生在hover的时候呢?你可能会想这样做:

.will-change {
  will-change: transform;
  transition: transform 0.3s;
}
.will-change:hover {
  transform: scale(1.5);
}

这虽然会导致内存消耗的增长,因为我们强迫浏览器认为元素随时可能会改变。我们可以解决这个问题,而不是通过寻找父容器上的一个hover事件:

.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的时候请记住移除它。正如我上面提到的,浏览器优化是一件耗费进程并且如果使用不当会产生不良影响的事。我们可以用JS处理它,并且我们将从MDN中引用一个脚本来构建一个粗略的例子。想象我们有一个在类里面的元素,当我们点击的时候,它会产生变化。我们的CSS看起来是这样的:

.element {
  transition: transform 0.5s;
}
.element.clicked {
  transform: scale(1.5);
}

如果我们想要告知浏览器为点击元素后发生的相应变化做好优化准备,我们可以这样做:

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';
}

当然,当元素被点击的时候,你必须使用必要的JS来添加正确的clicked类,但是上述脚本提醒了你如何让浏览器为变化做好准备,和一旦变化完成就释放内存的方法。当鼠标进入元素的时候,will-change属性被添加。当鼠标点击后,变化发生(通过对应的脚本),动画事件将被发送。在动画效果结束时,我们将移除will-change属性,再一次释放内存。

浏览器支持

will-change属性相当新,所以目前支持该属性的有下列浏览器:

  • Chrome 36 及以上
  • Firefox 36 及以上
  • Opera 24 及以上
  • Android browser 37
  • Chrome for Android 40
  • Opera Mobile 24

Internet Explorer 是唯一缺少该属性支持的浏览器,当我在写这篇文章的时候,will-change刚被列入考虑名单

###总结

CSS 的will-change属性能做的只是尽可能的好,因为它也有坏处。这句话的意思不是阻止你去使用它,只是作为一个忠告。在现代应用程序版本中没有理由不去考虑它,念及我已经指出的潜在问题。我希望你能明悉浏览器优化这块世界,并且可以利用这方面的知识推进到未来的项目。

这儿有一些探讨关于硬件加速和will-change属性细节的文章。我推荐你去读这些文章,从而巩固你对这部分CSS的理解。

本文根据@Nick Salloum的《An Introduction to the CSS will-change Property》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://www.sitepoint.com/introduction-css-will-change-property/

栗子酱

在校学生,本科软件工程专业,重度拖延症患者QAQ ,热爱前端,喜欢设计,正朝着成为一名优秀的前端工程师努力中。微博@_栗子酱。

如需转载,烦请注明出处:https://www.fedev.cn/css3/introduction-css-will-change-property.htmlnike air max 1 zappos