本文翻译自Ariya Hidayat的Hardware Accelerated CSS: The Nice vs The Naughty。感谢Kyle He帮助校对。

每个人都痴迷于60桢每秒的顺滑动画。为了实现这个顺滑体验现在用的最流行的一个做法就是使用『CSS硬件加速』。在一些极端例子中,强制使用translate3d意味着大大提高应用程序的性能。

现代浏览器大都可以利用GPU来加速页面渲染。在GPU的众多特性之中,它可以存储一定数量的纹理(一个矩形的像素点集合)并且高效地操作这些纹理(比如进行特定的移动、缩放和旋转操作)。这些特性在实现一个流畅的动画时特别有用。浏览器不会在动画的每一帧都绘制一次,而是生成DOM元素的快照,并作为GPU纹理(也被叫做层)存储起来。之后浏览器只需要告诉GPU去转换指定的纹理来实现DOM元素的动画效果。这就叫做GPU合成,也经常被称作『硬件加速』。

不幸的是,浏览器是一个很复杂的软件(Firefox有几百万行代码)。因此一句简单的『使用translate3d来提高性能』并不能囊括所有的情况。如果碰巧有效那不过是瞎猫碰上死耗子而已。所以有必要知道更多的运行机制,才能更好地处理实际情况。

想象使用GPU加速的动画就像是Vin Diesel(速度与激情的主角)开着Dominic标志性的汽车 —— Dodge Charger。它的定制900 hp引擎可以让它在一瞬间从0加速到60码。但是如果你开着它在拥挤的高速公路上又有什么用呢?这种情况下你选择的车辆Charger是正确的。但是问题是你还在一个拥堵的高速公路上。

GPU合成也是同样的道理。许多动画还是需要CPU的介入,这毕竟是浏览器工作的方式,你无法改变它。而连接CPU和GPU的总线的带宽不是无限的,所以需要关注数据在CPU和GPU之间的传输,要尽量避免造成通道的拥挤。换句话说你需要一直注意像素的传输

首先也是最重要的任务就是了解创建的合成层的数量。因为每一个层都对应了一个GPU纹理,所以有太多的层会消耗很多内存。这可能导致出现预期之外的行为,可能会导致潜在的崩溃。幸运的是你很容易就能通过浏览器来检查页面上的合成层数量。

  • 对于Firefox,打开about:config然后设置layers.draw-borders为true。
  • 如果是Chrome用户,打开chrome://flags/#composited-layer-borders启用,然后打开开发工具勾选Show composited layer borders
  • 对于Safari用户,先打开终端运行defaults write com.apple.Safari IncludeInternalDebugMenu 1。然后重新启动下Safari,菜单中找到一个开发菜单打开Web检查器就能在右边看到一个tab叫『层』了。选中之后你就可以在Web检查器的边栏中看到每个层的内存消耗。

当这些浏览器都正确的配置之后,每个DOM元素的合成层都会被标记一个额外的边框(你可以通过这个Spinning Cube Demo来测试下)。用这种方法就可以验证你的页面是否有太多的层。

另一个重点就是保持GPU和CPU之间的传输量达到最小值。换句话说,层的更新数量最好是一个理想的常量。每次合成层更新,一堆新的像素就可能需要传输给GPU。因此为了高性能,在动画开始之后避免层的更新也是很重要的(避免动画进行中时有其他层一直更新导致拥堵)。这可以通过选择恰当的CSS属性实现动画来解决:transformation(translate, scale, rotate)、opacity或者filters

如果你在使用Safari的web检查器,选择『层』标签后就能在侧栏看到『绘图』区域。这里的数字代表了Safari提交当前层的新纹理次数。在Colorful Boxes这个demo上试一试。这个demo中每个box都会不停地修改自己的背景颜色。不幸地是修改box的背景色会强制合成层更新纹理,因此它的『绘图』数量会不停的变大。如果只有一个盒子,那还没什么关系,如果是几百个盒子那就很容易达到GPU的瓶颈。当然这是一个极端的例子,只是提醒下你在这种情况下translate3d也救不了你。

需求是创造之源。合成层的限制也会引导我们创造更多令人惊讶的方法来利用浏览器的硬件加速特性。比如我们可以将UI的初始状态和结束状态放在同一个合成层中,然后通过剪切的方法来显示一部分并隐藏另一部分。还有一个类似的方法是通过两层叠加造成视觉错觉来实现一些特别的效果。通过修改两个层的透明度来实现动画效果,比如这个Glowing Effect demo。

另外一个常用的方法就是维护一个合成层池,这样也可以减少像素的传输。当有些层不需要的时候,它们不会被销毁。它们会被移到屏幕之外或者设置为透明的。在一些情况下,UI设计时可以规定一个固定的合成层数量。比如下面这个Cover Flow的例子,同时只能显示9张图片。即使它需要可以显示成千上万的书本封面(在左右滑动时),你也不需要一次性构建这么多合成层。只需要一个小小的修改,那就是在滑动时将旧图片的层移出作为新图片的层使用。用户根本不会感觉到变化。

同样不要忘记你必须使用性能检测工具(profiler)来检查你的理论是否成立。性能优化是非常严肃的话题,如果只是依靠自己的直觉那就很容易出错。Chrome的用户应该启用chrome://flags/#show-fps-counter。同样Firefox也要在about:config里面启用layers.acceleration.draw-fps。通过帧率来检测你的动画。如果帧率下降到60fps(或者没达到你要的效果),那么就该调查下原因。Chrome的Timeline特性或者Safari的Timeline面板都可以让你了解渲染过程中的细节:layout、painting和合成。

为了做好性能的回归测试,自动实现如上操作是很有必要的。这时Parashurambrowser-perf就会变得非常有用。几星期前他已经写过一些博文来介绍自动化测试网页性能。对于本文的情况,测量层数和层更新次数是非常有用的。有了这些数据你就可以在数值超过限制的时候告警。

已经有许多文章讲述过CSS硬件加速这个课题了,希望这篇文章能成为另一个快速帮助手册,教你如何正确地使用GPU合成来加速你的CSS动画。远离麻烦丝般顺滑!

CSS硬件加速的好与坏的更多相关文章

  1. 用CSS开启硬件加速来提高网站性能

    国外一篇文章,有点意思,转载过来,准备尝试下~ 中文地址:http://www.cnblogs.com/rubylouvre/p/3471490.html 原文地址:http://blog.teamt ...

  2. 用CSS开启硬件加速来提高网站性能(转)

    翻译文章,原文地址:http://blog.teamtreehouse.com/increase-your-sites-performance-with-hardware-accelerated-cs ...

  3. CSS开启硬件加速 hardware accelerated

    作者:孙志勇 微博 日期:2016年12月6日 一.时效性 所有信息都具有时效性.文章的价值,往往跟时间有很大关联.特别是技术类文章,请注意本文创建时间,如果本文过于久远,请读者酌情考量,莫要浪费时间 ...

  4. CSS开启硬件加速提高网站性能

    国外一篇文章,有点意思,转载过来,准备尝试下~ 中文地址:http://www.cnblogs.com/yzw7489757/ 原文地址:http://blog.teamtreehouse.com/i ...

  5. CSS动画原理及硬件加速

    一.图层 图层即层叠上下文,具体概念和应用大家可以看我之前转自张鑫旭大神博客的<CSS层叠上下文和层叠顺序>,这里我们简单复习一下产生层叠上下文的原因. 1.根层叠上下文 指的是页面根元素 ...

  6. 使用css来开启硬件加速来提高网站性能

    一.什么是硬件加速 硬件加速就是将浏览器的渲染过程交给GPU处理,而不是使用自带的比较慢的渲染器,这样就可以使得animation与transition更加顺畅.我们可以在浏览器中用css开启硬件加速 ...

  7. CSS开启硬件加速来提高网站性能

    原文永久链接 CSS animations, transforms 以及 transitions 不会自动开启GPU加速,而是由浏览器的缓慢的软件渲染引擎来执行. 那我们怎样才可以切换到GPU模式呢, ...

  8. css实现硬件加速

    原文请点击一下链接: http://blog.teamtreehouse.com/increase-your-sites-performance-with-hardware-accelerated-c ...

  9. css和js实现硬件加速渲染自定义滚动条

    听别人说用CSS的变换来实现渲染有硬件加速的效果,看到很多大网站都开始陆续使用上了,我也来说说怎么做,我这边实现的滚动条有自然滚动效果,看起来比较自然,说的再多不如直接写,让我们开始吧! 我们需要自己 ...

随机推荐

  1. 用Python调用阿里云的短信接口

    #!/usr/bin/env python# -*- coding:utf-8 -*-# Author:Frank import uuidimport datetimeimport hmacimpor ...

  2. python获取数据网页数据并创建文件夹保存(基于python3.6)

    from urllib.parse import urljoin import urllib.request from bs4 import BeautifulSoup import os impor ...

  3. SQlite的结构——存储管理

    在今天的商业应用中,主要有两种基本类型的DBMS(数据库管理系统)存储管理器: (1)DBMS直接与底层的面向磁盘的块模式设备驱动程序进行交互(通常称为原始模式访问); (2)DBMS使用标准的OS文 ...

  4. P1460 健康的荷斯坦奶牛 Healthy(DFS)

    思路:这道题还是用了小小的剪枝,这里要注意的是该题有很多中构建树的顺序,但是,在这众多顺序中不一定都能保证输出的方案字典序最小. 构建搜索树:如图构建 剪枝,emmm,看代码: #include< ...

  5. firewall

    翻译 public (active) 公共(防火墙) target: default 目标: 默认 icmp-block-inversion: no ICMP块反演:NO interfaces: et ...

  6. MemCache在.NET中使用Memcached.ClientLibrary详解 转发 https://www.cnblogs.com/li150dan/p/9529112.html

    本文说明:memcached分布式缓存的负载均衡配置比例,数据压缩,socket的详细配置等,以及在.net中的常用方法 首先下载客户端的3个dll,ICSharpCode.SharpZipLib.d ...

  7. 4939-Agent2-洛谷

    传送门 emm... 这次没有原题了 (因为我懒) 就是一道很简单的树状数组 真的很简单很简单 只用到了一点点的差分 注意注意: 只用树状数组,不用差分会t掉的 所以.. 我不仅t了 还wa了 emm ...

  8. python:面向对象编程之Zope.interface安装使用

    持续学习python+django中... 一.接口简述 在我们所熟知的面向对象编程语言中,大多提供了接口(interface)的概念.接口在编程语言中指的是一个抽象类型,是抽象方法的集合:它的特点如 ...

  9. WebApi测试工具:SAEA.RESTED

    写好一个Api接口不知道怎么测试?试试SAEA.RESTED吧——无需任何代码.不污染主项目.快速上手.不依赖IIS,可供多人共享使用!下面就跟着本文查看如何使用吧:1.下载安装:https://gi ...

  10. Jmeter自定义Java请求,继承AbstractJavaSamplerClient

    首先,使用Eclipse新建一个项目,然后从Jmeter的lib/ext目录下中拷贝ApacheJMeter_java.jar和ApacheJMeter_core.jar两个文件,然后引入这两个JAR ...