您的位置:新葡亰496net > 新葡亰官网 > 与超酷例子,css3硬件加速

与超酷例子,css3硬件加速

发布时间:2019-09-17 06:19编辑:新葡亰官网浏览(152)

    一篇文章说清浏览器解析和CSS(GPU)动画优化

    2017/01/10 · CSS · AR

    原文出处: 黑色的影子   

    相信不少人在做移动端动画的时候遇到了卡顿的问题,这篇文章尝试从浏览器渲染的角度;一点一点告诉你动画优化的原理及其技巧,作为你工作中优化动画的参考。文末有优化技巧的总结。

    因为GPU合成没有官方规范,每个浏览器的问题和解决方式也不同;所以文章内容仅供参考。

    1. 何为硬件加速

    动画卡顿是在移动web开发时经常遇到的问题,解决这个问题一般会用到css3硬件加速
    css3硬件加速这个名字感觉上很高大上,其实它做的事情可以简单概括为:通过GPU进行渲染,解放cpu。

    无线性能优化:Composite

    2016/04/26 · 基础技术 · 无线

    原文出处: 淘宝前端团队(FED)- 冬萌   

    图片 1

    一个 Web 页面的展示,简单来说可以认为经历了以下下几个步骤。

    图片 2

    • JavaScript:一般来说,我们会使用 JavaScript 来实现一些视觉变化的效果。比如做一个动画或者往页面里添加一些 DOM 元素等。
    • Style:计算样式,这个过程是根据 CSS 选择器,对每个 DOM 元素匹配对应的 CSS 样式。这一步结束之后,就确定了每个 DOM 元素上该应用什么 CSS 样式规则。
    • Layout:布局,上一步确定了每个 DOM 元素的样式规则,这一步就是具体计算每个 DOM 元素最终在屏幕上显示的大小和位置。web 页面中元素的布局是相对的,因此一个元素的布局发生变化,会联动地引发其他元素的布局发生变化。比如,`` 元素的宽度的变化会影响其子元素的宽度,其子元素宽度的变化也会继续对其孙子元素产生影响。因此对于浏览器来说,布局过程是经常发生的。
    • Paint:绘制,本质上就是填充像素的过程。包括绘制文字、颜色、图像、边框和阴影等,也就是一个 DOM 元素所有的可视效果。一般来说,这个绘制过程是在多个层上完成的。
    • Composite:渲染层合并,由上一步可知,对页面中 DOM 元素的绘制是在多个层上进行的。在每个层上完成绘制过程之后,浏览器会将所有层按照合理的顺序合并成一个图层,然后显示在屏幕上。对于有位置重叠的元素的页面,这个过程尤其重要,因为一旦图层的合并顺序出错,将会导致元素显示异常。

    当然,本文我们只来关注 Composite 部分。

    我们用到的css3动画属性有animation和transform,transform主要针对动画瞬间,animation则针对动画的流程。

    浏览器渲染

    提高动画的优化不得不提及浏览器是如何渲染一个页面。在从服务器中拿到数据后,浏览器会先做解析三类东西:

    • 解析html,xhtml,svg这三类文档,形成dom树。
    • 解析css,产生css rule tree。
    • 解析js,js会通过api来操作dom tree和css rule tree。

    解析完成之后,浏览器引擎会通过dom tree和css rule tree来构建rendering tree:

    • rendering tree和dom tree并不完全相同,例如:<head></head>或display:none的东西就不会放在渲染树中。
    • css rule tree主要是完成匹配,并把css rule附加给rendering tree的每个element。

    在渲染树构建完成后,

    • 浏览器会对这些元素进行定位和布局,这一步也叫做reflow或者layout。
    • 浏览器绘制这些元素的样式,颜色,背景,大小及边框等,这一步也叫做repaint。
    • 然后浏览器会将各层的信息发送给GPU,GPU会将各层合成;显示在屏幕上。

    就是将浏览器的渲染过程交给GPU处理,而不是使用自带的比较慢的渲染器。这样就可以使得animation与transition更加顺畅。

    现象

    通过对比不使用css3加速和使用css3加速两个例子,我们可以看到两者渲染的差异:

    图片 3

    不使用css3加速.png

    图片 4

    使用css3加速.png

    前者通过改变top和left属性进行动画,fps维持在47左右,cpu一直进行计算;后者通过transform实现,fps在62左右,cpu基本不需要计算。对比可知通过transform不仅提升了渲染性能,也解放了cpu。

    浏览器渲染原理

    在讨论 Composite 之前,有必要先简单了解下一些浏览器(本文只是针对 Chrome 来说)的渲染原理,方便对之后一些概念的理解。更多详细的内容可以参阅 GPU Accelerated Compositing in Chrome

    注:由于 Chrome 对 Blank 引擎某些实现的修改,某些我们之前熟知的类名有了变化,比如 RenderObject 变成了 LayoutObject,RenderLayer 变成了 PaintLayer。感兴趣的看以参阅 Slimming Paint。

    在浏览器中,页面内容是存储为由 Node 对象组成的树状结构,也就是 DOM 树。每一个 HTML element 元素都有一个 Node 对象与之对应,DOM 树的根节点永远都是 Document Node。这一点相信大家都很熟悉了,但其实,从 DOM 树到最后的渲染,需要进行一些转换映射。

    图片 5

    首先transform的值有

    渲染优化原理

    如上所说,渲染树构建完成后;浏览器要做的步骤:

    reflow——》repaint——》composite

    我们可以在浏览器中用css开启硬件加速,使GPU (Graphics Processing Unit) 发挥功能,从而提升性能

    原理

    DOM树和CSS结合后形成渲染树。渲染树中包含了大量的渲染元素,每一个渲染元素会被分到一个图层中,每个图层又会被加载到GPU形成渲染纹理。GPU中transform是不会触发 repaint 的,这一点非常类似3D绘图功能,最终这些使用 transform的图层都会由独立的合成器进程进行处理。

    通过chrome的timeline工具,绿色框代表需要repaint的部分,橙色框代表渲染图层,对比两者可知采用的css3硬件加速后,不会进行repaint操作,而只会产生一个渲染图层,GPU就负责操作这个渲染图层。

    图片 6

    不使用css3加速.png

    图片 7

    使用css3加速.png

    从 Nodes 到 LayoutObjects

    DOM 树中得每个 Node 节点都有一个对应的 LayoutObject 。LayoutObject 知道如何在屏幕上 paint Node 的内容。

    none 定义不进行转换。  
    matrix(n,n,n,n,n,n) 定义 2D 转换,使用六个值的矩阵。  
    matrix3d(n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n) 定义 3D 转换,使用 16 个值的 4x4 矩阵。  
    translate(x,y) 定义 2D 转换。  
    translate3d(x,y,z) 定义 3D 转换。  
    translateX(x) 定义转换,只是用 X 轴的值。  
    translateY(y) 定义转换,只是用 Y 轴的值。  
    translateZ(z) 定义 3D 转换,只是用 Z 轴的值。  
    scale(x,y) 定义 2D 缩放转换。  
    scale3d(x,y,z) 定义 3D 缩放转换。  
    scaleX(x) 通过设置 X 轴的值来定义缩放转换。  
    scaleY(y) 通过设置 Y 轴的值来定义缩放转换。  
    scaleZ(z) 通过设置 Z 轴的值来定义 3D 缩放转换。  
    rotate(angle) 定义 2D 旋转,在参数中规定角度。  
    rotate3d(x,y,z,angle) 定义 3D 旋转。  
    rotateX(angle) 定义沿着 X 轴的 3D 旋转。  
    rotateY(angle) 定义沿着 Y 轴的 3D 旋转。  
    rotateZ(angle) 定义沿着 Z 轴的 3D 旋转。  
    skew(x-angle,y-angle) 定义沿着 X 和 Y 轴的 2D 倾斜转换。  
    skewX(angle) 定义沿着 X 轴的 2D 倾斜转换。  
    skewY(angle) 定义沿着 Y 轴的 2D 倾斜转换。  
    perspective(n) 为 3D 转换元素定义透视视图。  

    reflow和repaint

    reflow和repaint都是耗费浏览器性能的操作,这两者尤以reflow为甚;因为每次reflow,浏览器都要重新计算每个元素的形状和位置。

    由于reflow和repaint都是非常消耗性能的,我们的浏览器为此做了一些优化。浏览器会将reflow和repaint的操作积攒一批,然后做一次reflow。但是有些时候,你的代码会强制浏览器做多次reflow。例如:

    JavaScript

    var content = document.getElementById('content'); content.style.width = 700px; var contentWidth = content.offsetWidth; content.style.backgound = 'red';

    1
    2
    3
    4
    var content = document.getElementById('content');
    content.style.width = 700px;
    var contentWidth = content.offsetWidth;
    content.style.backgound = 'red';

    以上第三行代码,需要浏览器reflow后;再获取值,所以会导致浏览器多做一次reflow。

    下面是一些针对reflow和repaint的最佳实践:

    • 不要一条一条地修改dom的样式,尽量使用className一次修改。
    • 将dom离线后修改
      • 使用documentFragment对象在内存里操作dom。
      • 先把dom节点display:none;(会触发一次reflow)。然后做大量的修改后,再把它显示出来。
      • clone一个dom节点在内存里,修改之后;与在线的节点相替换。
    • 不要使用table布局,一个小改动会造成整个table的重新布局。
    • transform和opacity只会引起合成,不会引起布局和重绘。

    从上述的最佳实践中你可能发现,动画优化一般都是尽可能地减少reflow、repaint的发生。关于哪些属性会引起reflow、repaint及composite,你可以在这个网站找到。

    现在大多数电脑的显卡都支持硬件加速。鉴于此,我们可以发挥GPU的力量,从而使我们的网站或应用表现的更为流畅。

    复合图层

    在原理中我们提到transform会创建一个图层,GPU会来执行transform的操作,这个图层且称为复合图层(composited layer)。
    虽然 Chrome 的启发式方法(heuristic)随着时间在不断发展进步,但是从目前来说,满足以下任意情况便会创建层:

    • 3D 或透视变换(perspective transform) CSS 属性
    • 使用加速视频解码的元素,如<video>
    • 拥有 3D (WebGL) 上下文或加速的 2D 上下文的元素,如<canvas>
    • 混合插件(如 Flash)
    • 对自己的 opacity 做 CSS 动画或使用一个动画 webkit 变换的元素
    • 拥有加速 CSS 过滤器的元素,如CSS filters
    • 元素有一个包含复合层的后代节点(换句话说,就是一个元素拥有一个子元素,该子元素在自己的层里)
    • 元素有一个 z-index 较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)

    如果页面建立了过多的复合图层,同样也会造成页面的卡顿。在CSS3硬件加速也有坑这篇文章中,作者介绍了由于z-index造成复合图层过多而引发的问题,在以后开发时可以借鉴。可以调试图层过多卡顿页面了解z-idnex对图层创建的影响。

    从 LayoutObjects 到 PaintLayers

    一般来说,拥有相同的坐标空间的 LayoutObjects,属于同一个渲染层(PaintLayer)。PaintLayer 最初是用来实现 stacking contest(层叠上下文),以此来保证页面元素以正确的顺序合成(composite),这样才能正确的展示元素的重叠以及半透明元素等等。因此满足形成层叠上下文条件的 LayoutObject 一定会为其创建新的渲染层,当然还有其他的一些特殊情况,为一些特殊的 LayoutObjects 创建一个新的渲染层,比如 overflow != visible 的元素。根据创建 PaintLayer 的原因不同,可以将其分为常见的 3 类:

    • NormalPaintLayer
      • 根元素(HTML)
      • 有明确的定位属性(relative、fixed、sticky、absolute)
      • 透明的(opacity 小于 1)
      • 有 CSS 滤镜(fliter)
      • 有 CSS mask 属性
      • 有 CSS mix-blend-mode 属性(不为 normal)
      • 有 CSS transform 属性(不为 none)
      • backface-visibility 属性为 hidden
      • 有 CSS reflection 属性
      • 有 CSS column-count 属性(不为 auto)或者 有 CSS column-width 属性(不为 auto)
      • 当前有对于 opacity、transform、fliter、backdrop-filter 应用动画
    • OverflowClipPaintLayer
      • overflow 不为 visible
    • NoPaintLayer
      • 不需要 paint 的 PaintLayer,比如一个没有视觉属性(背景、颜色、阴影等)的空 div。

    满足以上条件的 LayoutObject 会拥有独立的渲染层,而其他的 LayoutObject 则和其第一个拥有渲染层的父元素共用一个。

    animation的值有

    composite

    在reflow和repaint之后,浏览器会将多个复合层传入GPU;进行合成工作,那么合成是如何工作的呢?

    假设我们的页面中有A和B两个元素,它们有absolute和z-index属性;浏览器会重绘它们,然后将图像发送给GPU;然后GPU将会把多个图像合成展示在屏幕上。

    XHTML

    <style> #a, #b { position: absolute; } #a { left: 30px; top: 30px; z-index: 2; } #b { z-index: 1; } </style> <div id="#a">A</div> <div id="#b">B</div>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <style>
    #a, #b {
    position: absolute;
    }
     
    #a {
    left: 30px;
    top: 30px;
    z-index: 2;
    }
     
    #b {
    z-index: 1;
    }
    </style>
    <div id="#a">A</div>
    <div id="#b">B</div>

    图片 8

    我们将A元素使用left属性,做一个移动动画:

    XHTML

    <style> #a, #b { position: absolute; } #a { left: 10px; top: 10px; z-index: 2; animation: move 1s linear; } #b { left: 50px; top: 50px; z-index: 1; } @keyframes move { from { left: 30px; } to { left: 100px; } } </style> <div id="#a">A</div> <div id="#b">B</div>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <style>
    #a, #b {
    position: absolute;
    }
     
    #a {
    left: 10px;
    top: 10px;
    z-index: 2;
    animation: move 1s linear;
    }
     
    #b {
    left: 50px;
    top: 50px;
    z-index: 1;
    }
     
    @keyframes move {
    from { left: 30px; }
    to { left: 100px; }
    }
    </style>
    <div id="#a">A</div>
    <div id="#b">B</div>

    在这个例子中,对于动画的每一帧;浏览器会计算元素的几何形状,渲染新状态的图像;并把它们发送给GPU。(你没看错,position也会引起浏览器重排的)尽管浏览器做了优化,在repaint时,只会repaint部分区域;但是我们的动画仍然不够流畅。

    因为重排和重绘发生在动画的每一帧,一个有效避免reflow和repaint的方式是我们仅仅画两个图像;一个是a元素,一个是b元素及整个页面;我们将这两张图片发送给GPU,然后动画发生的时候;只做两张图片相对对方的平移。也就是说,仅仅合成缓存的图片将会很快;这也是GPU的优势——它能非常快地以亚像素精度地合成图片,并给动画带来平滑的曲线。

    为了仅发生composite,我们做动画的css property必须满足以下三个条件:

    • 不影响文档流。
    • 不依赖文档流。
    • 不会造成重绘。

    满足以上以上条件的css property只有transform和opacity。你可能以为position也满足以上条件,但事实不是这样,举个例子left属性可以使用百分比的值,依赖于它的offset parent。还有em、vh等其他单位也依赖于他们的环境。

    我们使用translate来代替left

    XHTML

    <style> #a, #b { position: absolute; } #a { left: 10px; top: 10px; z-index: 2; animation: move 1s linear; } #b { left: 50px; top: 50px; z-index: 1; } @keyframes move { from { transform: translateX(0); } to { transform: translateX(70px); } } </style> <div id="#a">A</div> <div id="#b">B</div>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <style>
    #a, #b {
    position: absolute;
    }
     
    #a {
    left: 10px;
    top: 10px;
    z-index: 2;
    animation: move 1s linear;
    }
     
    #b {
    left: 50px;
    top: 50px;
    z-index: 1;
    }
     
    @keyframes move {
    from { transform: translateX(0); }
    to { transform: translateX(70px); }
    }
    </style>
    <div id="#a">A</div>
    <div id="#b">B</div>

    浏览器在动画执行之前就知道动画如何开始和结束,因为浏览器没有看到需要reflow和repaint的操作;浏览器就会画两张图像作为复合层,并将它们传入GPU。

    这样做有两个优势:

    • 动画将会非常流畅
    • 动画不在绑定到CPU,即使js执行大量的工作;动画依然流畅。

    看起来性能问题好像已经解决了?在下文你会看到GPU动画的一些问题。

    2硬件加速原理

    启用

    如下几个css属性可以触发硬件加速:

    • transform
    • opacity
    • filter
    • will-change:哪一个属性即将发生变化,进而进行优化。

    上面的的例子中用到的是transform 2D,它是在运行时才会创建图层,因此在动画开始和结束时会进行repaint操作;而浏览器在渲染前就为transform 3D创建了图层。

    图片 9

    开始时的repaint

    图片 10

    结束时的repaint

    可以通过transform的3D属性强制开启GPU加速:

      transform: translateZ(0);
      transform: rotateZ(360deg);
    

    从 PaintLayers 到 GraphicsLayers

    某些特殊的渲染层会被认为是合成层(Compositing Layers),合成层拥有单独的 GraphicsLayer,而其他不是合成层的渲染层,则和其第一个拥有 GraphicsLayer 父层公用一个。

    每个 GraphicsLayer 都有一个 GraphicsContext,GraphicsContext 会负责输出该层的位图,位图是存储在共享内存中,作为纹理上传到 GPU 中,最后由 GPU 将多个位图进行合成,然后 draw 到屏幕上,此时,我们的页面也就展现到了屏幕上。

    渲染层提升为合成层的原因有一下几种:

    注:渲染层提升为合成层有一个先决条件,该渲染层必须是 SelfPaintingLayer(基本可认为是上文介绍的 NormalPaintLayer)。以下所讨论的渲染层提升为合成层的情况都是在该渲染层为 SelfPaintingLayer 前提下的。

    • 直接原因(direct reason)
      • 硬件加速的 iframe 元素(比如 iframe 嵌入的页面中有合成层)demo
      • video 元素
      • 覆盖在 video 元素上的视频控制栏
      • 3D 或者 硬件加速的 2D Canvas 元素
        • demo:普通 2D Canvas 不会提升为合成层
        • demo:3D Canvas 提升为合成层
      • 硬件加速的插件,比如 flash 等等
      • 在 DPI 较高的屏幕上,fix 定位的元素会自动地被提升到合成层中。但在 DPI 较低的设备上却并非如此,因为这个渲染层的提升会使得字体渲染方式由子像素变为灰阶(详细内容请参考:Text Rendering)
      • 有 3D transform
      • backface-visibility 为 hidden
      • 对 opacity、transform、fliter、backdropfilter 应用了 animation 或者 transition(需要是 active 的 animation 或者 transition,当 animation 或者 transition 效果未开始或结束后,提升合成层也会失效)
        • demo:animation
        • demo:transition图片 11
      • will-change 设置为 opacity、transform、top、left、bottom、right(其中 top、left 等需要设置明确的定位属性,如 relative 等)demo
    • 后代元素原因
      • 有合成层后代同时本身有 transform、opactiy(小于 1)、mask、fliter、reflection 属性 demo
      • 有合成层后代同时本身 overflow 不为 visible(如果本身是因为明确的定位因素产生的 SelfPaintingLayer,则需要 z-index 不为 auto) demo
      • 有合成层后代同时本身 fixed 定位 demo
      • 有 3D transfrom 的合成层后代同时本身有 preserves-3d 属性 demo
      • 有 3D transfrom 的合成层后代同时本身有 perspective 属性 demo
    • overlap 重叠原因为什么会因为重叠原因而产生合成层呢?举个简单的栗子。图片 12蓝色的矩形重叠在绿色矩形之上,同时它们的父元素是一个 GraphicsLayer。此时假设绿色矩形为一个 GraphicsLayer,如果 overlap 无法提升合成层的话,那么蓝色矩形不会提升为合成层,也就会和父元素公用一个 GraphicsLayer。图片 13此时,渲染顺序就会发生错误,因此为保证渲染顺序,overlap 也成为了合成层产生的原因,也就是如下的正常情形。图片 14当然 overlap 的原因也会细分为几类,接下来我们会详细看下。
      • 重叠或者说部分重叠在一个合成层之上。那如何算是重叠呢,最常见和容易理解的就是元素的 border box(content padding border) 和合成层的有重叠,比如:demo,当然 margin area 的重叠是无效的(demo)。其他的还有一些不常见的情况,也算是同合成层重叠的条件,如下:
        • filter 效果同合成层重叠 demo
        • transform 变换后同合成层重叠 demo
        • overflow scroll 情况下同合成层重叠。即如果一个 overflow scroll(不管 overflow:auto 还是 overflow:scrill,只要是能 scroll 即可) 的元素同一个合成层重叠,则其可视子元素也同该合成层重叠 demo
      • 假设重叠在一个合成层之上(assumedOverlap)。这个原因听上去有点虚,什么叫假设重叠?其实也比较好理解,比如一个元素的 CSS 动画效果,动画运行期间,元素是有可能和其他元素有重叠的。针对于这种情况,于是就有了 assumedOverlap 的合成层产生原因,示例可见:demo。在本 demo 中,动画元素视觉上并没有和其兄弟元素重叠,但因为 assumedOverlap 的原因,其兄弟元素依然提升为了合成层。需要注意的是该原因下,有一个很特殊的情况:如果合成层有内联的 transform 属性,会导致其兄弟渲染层 assume overlap,从而提升为合成层。比如:demo。
    animation: name duration timing-function delay iteration-count direction fill-mode play-state;这是简写
    

    GPU是如何合成图像的

    GPU实际上可以看作一个独立的计算机,它有自己的处理器和存储器及数据处理模型。当浏览器向GPU发送消息的时候,就像向一个外部设备发送消息。

    你可以把浏览器向GPU发送数据的过程,与使用ajax向服务器发送消息非常类似。想一下,你用ajax向服务器发送数据,服务器是不会直接接受浏览器的存储的信息的。你需要收集页面上的数据,把它们放进一个载体里面(例如JSON),然后发送数据到远程服务器。

    同样的,浏览器向GPU发送数据也需要先创建一个载体;只不过GPU距离CPU很近,不会像远程服务器那样可能几千里那么远。但是对于远程服务器,2秒的延迟是可以接受的;但是对于GPU,几毫秒的延迟都会造成动画的卡顿。

    浏览器向GPU发送的数据载体是什么样?这里给出一个简单的制作载体,并把它们发送到GPU的过程。

    • 画每个复合层的图像
    • 准备图层的数据
    • 准备动画的着色器(如果需要)
    • 向GPU发送数据

    所以你可以看到,每次当你添加transform:translateZ(0)will-change:transform给一个元素,你都会做同样的工作。重绘是非常消耗性能的,在这里它尤其缓慢。在大多数情况,浏览器不能增量重绘。它不得不重绘先前被复合层覆盖的区域。

    浏览器接收到页面文档后,会将文档中的标记语言解析为DOM树。DOM树和CSS结合后形成浏览器构建页面的渲染树。渲染树中包含了大量的渲染元素,每一个渲染元素会被分到一个图层中,每个图层又会被加载到GPU形成渲染纹理,而图层在GPU中transform 是不会触发 repaint 的,最终这些使用 transform 的图层都会由独立的合成器进程进行处理。

    注意事项
    • 不能让每个元素都启用硬件加速,这样会暂用很大的内存,使页面会有很强的卡顿感。
    • GPU渲染会影响字体的抗锯齿效果。这是因为GPU和CPU具有不同的渲染机制,即使最终硬件加速停止了,文本还是会在动画期间显示得很模糊。

    层压缩

    基本上常见的一些合成层的提升原因如上所说,你会发现,由于重叠的原因,可能随随便便就会产生出大量合成层来,而每个合成层都要消耗 CPU 和内存资源,岂不是严重影响页面性能。这一点浏览器也考虑到了,因此就有了层压缩(Layer Squashing)的处理。如果多个渲染层同一个合成层重叠时,这些渲染层会被压缩到一个 GraphicsLayer 中,以防止由于重叠原因导致可能出现的“层爆炸”。具体可以看如下 demo。一开始,蓝色方块由于
    translateZ 提升为了合成层,其他的方块元素因为重叠的原因,被压缩了一起,大小就是包含这 3 个方块的矩形大小。

    图片 15

    当我们 hover 绿色方块时,会给其设置 translateZ 属性,导致绿色方块也被提升为合成层,则剩下的两个被压缩到了一起,大小就缩小为包含这 2 个方块的矩形大小。

    图片 16

    当然,浏览器的自动的层压缩也不是万能的,有很多特定情况下,浏览器是无法进行层压缩的,如下所示,而这些情况也是我们应该尽量避免的。(注:以下情况都是基于重叠原因而言)

    • 无法进行会打破渲染顺序的压缩(squashingWouldBreakPaintOrder)示例如下:demo
    CSS
    
    #ancestor { -webkit-mask-image:
    -webkit-linear-gradient(rgba(0,0,0,1), rgba(0,0,0,0)); }
    #composited { width: 100%; height: 100%; transform: translateZ(0);
    } #container { position: relative; width: 400px; height: 60px;
    border: 1px solid black; } #overlap-child { position: absolute;
    left: 0; top: 0 ; bottom: 0px; width: 100%; height: 60px;
    background-color: orange; }
    
    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f6d201886f149137440-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d201886f149137440-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d201886f149137440-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d201886f149137440-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d201886f149137440-5">
    5
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d201886f149137440-6">
    6
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d201886f149137440-7">
    7
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d201886f149137440-8">
    8
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d201886f149137440-9">
    9
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d201886f149137440-10">
    10
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d201886f149137440-11">
    11
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d201886f149137440-12">
    12
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d201886f149137440-13">
    13
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d201886f149137440-14">
    14
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d201886f149137440-15">
    15
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d201886f149137440-16">
    16
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d201886f149137440-17">
    17
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d201886f149137440-18">
    18
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d201886f149137440-19">
    19
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d201886f149137440-20">
    20
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d201886f149137440-21">
    21
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d201886f149137440-22">
    22
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d201886f149137440-23">
    23
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d201886f149137440-24">
    24
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d201886f149137440-25">
    25
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d201886f149137440-26">
    26
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f6d201886f149137440-1" class="crayon-line">
      #ancestor {
    </div>
    <div id="crayon-5b8f6d201886f149137440-2" class="crayon-line crayon-striped-line">
        -webkit-mask-image: -webkit-linear-gradient(rgba(0,0,0,1), rgba(0,0,0,0));
    </div>
    <div id="crayon-5b8f6d201886f149137440-3" class="crayon-line">
      }
    </div>
    <div id="crayon-5b8f6d201886f149137440-4" class="crayon-line crayon-striped-line">
      
    </div>
    <div id="crayon-5b8f6d201886f149137440-5" class="crayon-line">
      #composited {
    </div>
    <div id="crayon-5b8f6d201886f149137440-6" class="crayon-line crayon-striped-line">
        width: 100%;
    </div>
    <div id="crayon-5b8f6d201886f149137440-7" class="crayon-line">
        height: 100%;
    </div>
    <div id="crayon-5b8f6d201886f149137440-8" class="crayon-line crayon-striped-line">
        transform: translateZ(0);
    </div>
    <div id="crayon-5b8f6d201886f149137440-9" class="crayon-line">
      }
    </div>
    <div id="crayon-5b8f6d201886f149137440-10" class="crayon-line crayon-striped-line">
     
    </div>
    <div id="crayon-5b8f6d201886f149137440-11" class="crayon-line">
      #container {
    </div>
    <div id="crayon-5b8f6d201886f149137440-12" class="crayon-line crayon-striped-line">
        position: relative;
    </div>
    <div id="crayon-5b8f6d201886f149137440-13" class="crayon-line">
        width: 400px;
    </div>
    <div id="crayon-5b8f6d201886f149137440-14" class="crayon-line crayon-striped-line">
        height: 60px;
    </div>
    <div id="crayon-5b8f6d201886f149137440-15" class="crayon-line">
        border: 1px solid black;
    </div>
    <div id="crayon-5b8f6d201886f149137440-16" class="crayon-line crayon-striped-line">
      }
    </div>
    <div id="crayon-5b8f6d201886f149137440-17" class="crayon-line">
     
    </div>
    <div id="crayon-5b8f6d201886f149137440-18" class="crayon-line crayon-striped-line">
      #overlap-child {
    </div>
    <div id="crayon-5b8f6d201886f149137440-19" class="crayon-line">
        position: absolute;
    </div>
    <div id="crayon-5b8f6d201886f149137440-20" class="crayon-line crayon-striped-line">
        left: 0;
    </div>
    <div id="crayon-5b8f6d201886f149137440-21" class="crayon-line">
        top: 0 ;
    </div>
    <div id="crayon-5b8f6d201886f149137440-22" class="crayon-line crayon-striped-line">
        bottom: 0px;
    </div>
    <div id="crayon-5b8f6d201886f149137440-23" class="crayon-line">
        width: 100%;
    </div>
    <div id="crayon-5b8f6d201886f149137440-24" class="crayon-line crayon-striped-line">
        height: 60px;
    </div>
    <div id="crayon-5b8f6d201886f149137440-25" class="crayon-line">
        background-color: orange;
    </div>
    <div id="crayon-5b8f6d201886f149137440-26" class="crayon-line crayon-striped-line">
      }
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>
    
    
    
    
    XHTML
    
    &lt;div id="container"&gt; &lt;div id="composited"&gt;Text behind
    the orange box.&lt;/div&gt; &lt;div id="ancestor"&gt; &lt;div
    id="overlap-child"&gt;&lt;/div&gt; &lt;/div&gt; &lt;/div&gt;
    
    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f6d201887b075031864-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d201887b075031864-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d201887b075031864-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d201887b075031864-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d201887b075031864-5">
    5
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d201887b075031864-6">
    6
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f6d201887b075031864-1" class="crayon-line">
    &lt;div id=&quot;container&quot;&gt;
    </div>
    <div id="crayon-5b8f6d201887b075031864-2" class="crayon-line crayon-striped-line">
      &lt;div id=&quot;composited&quot;&gt;Text behind the orange box.&lt;/div&gt;
    </div>
    <div id="crayon-5b8f6d201887b075031864-3" class="crayon-line">
      &lt;div id=&quot;ancestor&quot;&gt;
    </div>
    <div id="crayon-5b8f6d201887b075031864-4" class="crayon-line crayon-striped-line">
        &lt;div id=&quot;overlap-child&quot;&gt;&lt;/div&gt;
    </div>
    <div id="crayon-5b8f6d201887b075031864-5" class="crayon-line">
      &lt;/div&gt;
    </div>
    <div id="crayon-5b8f6d201887b075031864-6" class="crayon-line crayon-striped-line">
    &lt;/div&gt;
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>
    
    • video 元素的渲染层无法被压缩同时也无法将别的渲染层压缩到 video 所在的合成层上(squashingVideoIsDisallowed)demo
    • iframe、plugin 的渲染层无法被压缩同时也无法将别的渲染层压缩到其所在的合成层上(squashingLayoutPartIsDisallowed)demo
    • 无法压缩有 reflection 属性的渲染层(squashingReflectionDisallowed)demo
    • 无法压缩有 blend mode 属性的渲染层(squashingBlendingDisallowed)demo
    • 当渲染层同合成层有不同的裁剪容器(clipping container)时,该渲染层无法压缩(squashingClippingContainerMismatch)。示例如下:demo
    CSS
    
    .clipping-container { overflow: hidden; height: 10px;
    background-color: blue; } .composited { transform: translateZ(0);
    height: 10px; background-color: red; } .target { position:absolute;
    top: 0px; height:100px; width:100px; background-color: green; color:
    #fff; }
    
    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f6d2018880297868155-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2018880297868155-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d2018880297868155-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2018880297868155-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d2018880297868155-5">
    5
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2018880297868155-6">
    6
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d2018880297868155-7">
    7
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2018880297868155-8">
    8
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d2018880297868155-9">
    9
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2018880297868155-10">
    10
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d2018880297868155-11">
    11
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2018880297868155-12">
    12
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d2018880297868155-13">
    13
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2018880297868155-14">
    14
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d2018880297868155-15">
    15
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2018880297868155-16">
    16
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d2018880297868155-17">
    17
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2018880297868155-18">
    18
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d2018880297868155-19">
    19
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2018880297868155-20">
    20
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d2018880297868155-21">
    21
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2018880297868155-22">
    22
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d2018880297868155-23">
    23
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f6d2018880297868155-1" class="crayon-line">
    .clipping-container {
    </div>
    <div id="crayon-5b8f6d2018880297868155-2" class="crayon-line crayon-striped-line">
     
    </div>
    <div id="crayon-5b8f6d2018880297868155-3" class="crayon-line">
        overflow: hidden;
    </div>
    <div id="crayon-5b8f6d2018880297868155-4" class="crayon-line crayon-striped-line">
        height: 10px; 
    </div>
    <div id="crayon-5b8f6d2018880297868155-5" class="crayon-line">
        background-color: blue;
    </div>
    <div id="crayon-5b8f6d2018880297868155-6" class="crayon-line crayon-striped-line">
      }
    </div>
    <div id="crayon-5b8f6d2018880297868155-7" class="crayon-line">
     
    </div>
    <div id="crayon-5b8f6d2018880297868155-8" class="crayon-line crayon-striped-line">
      .composited {
    </div>
    <div id="crayon-5b8f6d2018880297868155-9" class="crayon-line">
     
    </div>
    <div id="crayon-5b8f6d2018880297868155-10" class="crayon-line crayon-striped-line">
        transform: translateZ(0); 
    </div>
    <div id="crayon-5b8f6d2018880297868155-11" class="crayon-line">
        height: 10px; 
    </div>
    <div id="crayon-5b8f6d2018880297868155-12" class="crayon-line crayon-striped-line">
        background-color: red;
    </div>
    <div id="crayon-5b8f6d2018880297868155-13" class="crayon-line">
      }
    </div>
    <div id="crayon-5b8f6d2018880297868155-14" class="crayon-line crayon-striped-line">
     
    </div>
    <div id="crayon-5b8f6d2018880297868155-15" class="crayon-line">
      .target {
    </div>
    <div id="crayon-5b8f6d2018880297868155-16" class="crayon-line crayon-striped-line">
     
    </div>
    <div id="crayon-5b8f6d2018880297868155-17" class="crayon-line">
        position:absolute; 
    </div>
    <div id="crayon-5b8f6d2018880297868155-18" class="crayon-line crayon-striped-line">
        top: 0px; 
    </div>
    <div id="crayon-5b8f6d2018880297868155-19" class="crayon-line">
        height:100px; 
    </div>
    <div id="crayon-5b8f6d2018880297868155-20" class="crayon-line crayon-striped-line">
        width:100px; 
    </div>
    <div id="crayon-5b8f6d2018880297868155-21" class="crayon-line">
        background-color: green;
    </div>
    <div id="crayon-5b8f6d2018880297868155-22" class="crayon-line crayon-striped-line">
        color: #fff;
    </div>
    <div id="crayon-5b8f6d2018880297868155-23" class="crayon-line">
      }
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>
    
    
    
    
    XHTML
    
    &lt;div class="clipping-container"&gt; &lt;div
    class="composited"&gt;&lt;/div&gt; &lt;/div&gt; &lt;div
    class="target"&gt;不会被压缩到 composited div 上&lt;/div&gt;
    
    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f6d2018884301689224-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2018884301689224-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f6d2018884301689224-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2018884301689224-4">
    4
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f6d2018884301689224-1" class="crayon-line">
    &lt;div class=&quot;clipping-container&quot;&gt;
    </div>
    <div id="crayon-5b8f6d2018884301689224-2" class="crayon-line crayon-striped-line">
      &lt;div class=&quot;composited&quot;&gt;&lt;/div&gt;
    </div>
    <div id="crayon-5b8f6d2018884301689224-3" class="crayon-line">
    &lt;/div&gt;
    </div>
    <div id="crayon-5b8f6d2018884301689224-4" class="crayon-line crayon-striped-line">
    &lt;div class=&quot;target&quot;&gt;不会被压缩到 composited div 上&lt;/div&gt;
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>
    
    
    本例中 .target 同 合成层 `.composited` 重叠,但是由于
    .composited`在一个 overflow: hidden 的容器中,导致 .target 和合成层有不同的裁剪容器,从而 `.target` 无法被压缩。`
    
    • 相对于合成层滚动的渲染层无法被压缩(scrollsWithRespectToSquashingLayer)示例如下:demo

    CSS

    body { height: 1500px; overflow-x: hidden; } .composited { width: 50px; height: 50px; background-color: red; position: absolute; left: 50px; top: 400px; transform: translateZ(0); } .overlap { width: 200px; height: 200px; background-color: green; position: fixed; left: 0px; top: 0px; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    body {
        height: 1500px;
        overflow-x: hidden;
      }
     
      .composited {
     
        width: 50px;
        height: 50px;
        background-color: red;
        position: absolute;
        left: 50px;
        top: 400px;
        transform: translateZ(0);
      }
     
      .overlap {
        width: 200px;
        height: 200px;
        background-color: green;
        position: fixed;
        left: 0px;
        top: 0px;
      }

    XHTML

    <div class="composited"></div> <div class="overlap"></div>

    1
    2
    <div class="composited"></div>
    <div class="overlap"></div>

    本例中,红色的 .composited提升为了合成层,绿色的.overlapfix 在页面顶部,一开始只有.composited合成层。

    ![]()

    当滑动页面,.overlap重叠到.composited上时,.overlap` 会因重叠原因提升为合成层,同时,因为相对于合成层滚动,因此无法被压缩。

    ![]()

    • 当渲染层同合成层有不同的具有 opacity 的祖先层(一个设置了 opacity 且小于 1,一个没有设置 opacity,也算是不同)时,该渲染层无法压缩(squashingOpacityAncestorMismatch,同 squashingClippingContainerMismatch)demo
    • 当渲染层同合成层有不同的具有 transform 的祖先层时,该渲染层无法压缩(squashingTransformAncestorMismatch,同上) demo
    • 当渲染层同合成层有不同的具有 filter 的祖先层时,该渲染层无法压缩(squashingFilterAncestorMismatch,同上)demo
    • 当覆盖的合成层正在运行动画时,该渲染层无法压缩(squashingLayerIsAnimating),当动画未开始或者运行完毕以后,该渲染层才可以被压缩 demo图片 17
    animation-name 指定要绑定到选择器的关键帧的名称
    animation-duration
    动画指定需要多少秒或毫秒完成
    animation-timing-function 设置动画将如何完成一个周期
    animation-delay 设置动画在启动前的延迟间隔。
    animation-iteration-count 定义动画的播放次数。
    animation-direction 指定是否应该轮流反向播放动画。
    animation-fill-mode 规定当动画不播放时(当动画完成时,或当动画有一个延迟未开始播放时),要应用到元素的样式。
    animation-play-state 指定动画是否正在运行或已暂停。
    initial 设置属性为其默认值
    inherit 从父元素继承属性

    隐式合成

    还记得刚才a元素和b元素动画的例子吗?现在我们将b元素做动画,a元素静止不动。

    图片 18

    和刚才的例子不同,现在b元素将拥有一个独立复合层;然后它们将被GPU合成。但是因为a元素要在b元素的上面(因为a元素的z-index比b元素高),那么浏览器会做什么?浏览器会将a元素也单独做一个复合层!

    所以我们现在有三个复合层a元素所在的复合层、b元素所在的复合层、其他内容及背景层。

    一个或多个没有自己复合层的元素要出现在有复合层元素的上方,它就会拥有自己的复合层;这种情况被称为隐式合成。

    浏览器将a元素提升为一个复合层有很多种原因,下面列举了一些:

    • 3d或透视变换css属性,例如translate3d,translateZ等等(js一般通过这种方式,使元素获得复合层)
    • <video><iframe><canvas><webgl>等元素。
    • 混合插件(如flash)。
    • 元素自身的 opacity和transform 做 CSS 动画。
    • 拥有css过滤器的元素。
    • 使用will-change属性。
    • position:fixed。
    • 元素有一个 z-index 较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)

    这看起来css动画的性能瓶颈是在重绘上,但是真实的问题是在内存上:

    CSS transform 会创建了一个新的复合图层,可以被GPU直接用来执行 transform 操作。

    参考文章:
    1. CSS动画之硬件加速:作者比较详细介绍了硬件加速,总结的很到位。
    2. CSS3硬件加速也有坑: 作者介绍了由于z-index造成复合图层过多,以后开发加以注意。
    3. 使用CSS3 will-change提高页面滚动、动画等渲染性能: will-change的介绍
    4. javascript性能优化-repaint和reflow:性能杀手以及优化方法。
    5. 两张图解释CSS动画的性能:比较详细对比了采用硬件加速和不采用硬件加速的流程差异。

    如何查看合成层

    使用 Chrome DevTools 工具来查看页面中合成层的情况。

    比较简单的方法是打开 DevTools,勾选上 Show layer borders

    图片 19

    其中,页面上的合成层会用黄色边框框出来。

    图片 20

    当然,更加详细的信息可以通过 Timeline 来查看。

    每一个单独的帧,看到每个帧的渲染细节:

    图片 21

    点击之后,你就会在视图中看到一个新的选项卡:Layers。

    图片 22

    点击这个 Layers 选项卡,你会看到一个新的视图。在这个视图中,你可以对这一帧中的所有合成层进行扫描、缩放等操作,同时还能看到每个渲染层被创建的原因。

    图片 23

    有了这个视图,你就能知道页面中到底有多少个合成层。如果你在对页面滚动或渐变效果的性能分析中发现 Composite 过程耗费了太多时间,那么你可以从这个视图里看到页面中有多少个渲染层,它们为何被创建,从而对合成层的数量进行优化。

    下面是一个简单的纯css3写出来的动画效果
    图片选择自己喜欢的就好
    

    内存占用

    使用GPU动画需要发送多张渲染层的图像给GPU,GPU也需要缓存它们以便于后续动画的使用。

    一个渲染层,需要多少内存占用?为了便于理解,举一个简单的例子;一个宽、高都是300px的纯色图像需要多少内存?

    300 300 4 = 360000字节,即360kb。这里乘以4是因为,每个像素需要四个字节计算机内存来描述。

    假设我们做一个轮播图组件,轮播图有10张图片;为了实现图片间平滑过渡的交互;为每个图像添加了will-change:transform。这将提升图像为复合层,它将多需要19mb的空间。800 600 4 * 10 = 1920000。

    仅仅是一个轮播图组件就需要19m的额外空间!

    在chrome的开发者工具中打开setting——》Experiments——》layers可以看到每个层的内存占用。如图所示:

    图片 24

    图片 25

    浏览器什么时候会创建一个独立的复合图层呢?事实上一般是在以下几种情况下:

    性能优化

    提升为合成层简单说来有以下几点好处:

    • 合成层的位图,会交由 GPU 合成,比 CPU 处理要快
    • 当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层
    • 对于 transform 和 opacity 效果,不会触发 layout 和 paint

    利用合成层对于提升页面性能方面有很大的作用,因此我们也总结了一下几点优化建议。

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>flower动画</title>
    </head>
    <style>
    *{margin: 0;padding: 0;}
    body,div{margin: 0;padding: 0;width: 100%;height: 100%;}
    a{text-decoration: none;color: #fff;}
    .flower{width: 250px;height: 250px;position: relative;float: left;margin: 10px 50px;}
    .picture img{border:solid 10px; border-radius: 50%;border-width: 10px;width: 250px;height: 250px;overflow: hidden;border-color: #fff;}
    .cover{width: 250px;height: 250px;border-radius: 50%;color: #000;position: absolute;}
    .cover h2{padding: 95px 0 0 60px;color: #fff;}
    .cover p{padding: 0 0 90px 90px;color: #fff;}
    .yellow-flower .cover{top: 10px;left:10px;background: #92ab24;z-index: -100;opacity: 0.7;}
    .write-flower .cover{top: 10px;left:10px;background: #6192dc;z-index: -100;opacity: 0.7;}
    .green-flower .cover{top: 10px;left:10px;background: #dcbcb0;z-index: -100;opacity: 0.7;}
    .red-flower .cover{top: 10px;left:10px;background: #4ba2a7;z-index: -100;opacity: 0.7;}
    .pink-flower .cover{top: 10px;left:10px;background:#d88b8b;z-index: -100;opacity: 0.7;}
    .purple-flower .cover{top: 10px;left:10px;background: #da7685;z-index: -100;opacity: 0.7;}
    .blue-flower .cover{top: 10px;left:10px;background: #a74ba4;z-index: -100;opacity: 0.7;}
    .orange-flower .cover{top: 10px;left:10px;background: #7fda76;z-index: -100;opacity: 0.7;}

    GPU动画的优点和缺点

    现在我们可以总结一下GPU动画的优点和缺点:

    • 每秒60帧,动画平滑、流畅。
    • 一个合适的动画工作在一个单独的线程,它不会被大量的js计算阻塞。
    • 3D“变换”是便宜的。

    缺点:

    • 提升一个元素到复合层需要额外的重绘,有时这是慢的。(即我们得到的是一个全层重绘,而不是一个增量)
    • 绘图层必须传输到GPU。取决于层的数量和传输可能会非常缓慢。这可能让一个元素在中低档设备上闪烁。
    • 每个复合层都需要消耗额外的内存,过多的内存可能导致浏览器的崩溃。
    • 如果你不考虑隐式合成,而使用重绘;会导致额外的内存占用,并且浏览器崩溃的概率是非常高的。
    • 我们会有视觉假象,例如在Safari中的文本渲染,在某些情况下页面内容将消失或变形。
    • 3D 或者 CSS transform
    • <video> 和 <canvas> 标签
    • CSS filters
    • 元素覆盖时,比如使用了 z-index 属性

    提升动画效果的元素

    合成层的好处是不会影响到其他元素的绘制,因此,为了减少动画元素对其他元素的影响,从而减少 paint,我们需要把动画效果中的元素提升为合成层。

    提升合成层的最好方式是使用 CSS 的 will-change 属性。从上一节合成层产生原因中,可以知道 will-change 设置为 opacity、transform、top、left、bottom、right 可以将元素提升为合成层。

    CSS

    #target { will-change: transform; }

    1
    2
    3
    #target {
      will-change: transform;
    }

    其兼容如下所示:
    图片 26

    对于那些目前还不支持 will-change 属性的浏览器,目前常用的是使用一个 3D transform 属性来强制提升为合成层:

    CSS

    #target { transform: translateZ(0); }

    1
    2
    3
    #target {
      transform: translateZ(0);
    }

    但需要注意的是,不要创建太多的渲染层。因为每创建一个新的渲染层,就意味着新的内存分配和更复杂的层的管理。之后我们会详细讨论。

    如果你已经把一个元素放到一个新的合成层里,那么可以使用 Timeline 来确认这么做是否真的改进了渲染性能。别盲目提升合成层,一定要分析其实际性能表现。

    .yellow-flower:hover .cover{animation:scale 0.5s 1 linear;z-index: 1;}
    .yellow-flower:hover .picture{animation:scale1 0.5s 1 linear;z-index: 1;}
    @keyframes scale{
    0%{transform:scale(0.2);opacity: 1;}
    50%{opacity: 0.5;}
    100%{transform:scale(1);opacity: 0.7;}
    }
    @keyframes scale1{
    0%{transform:scale(1);}
    100%{transform:scale(0);}
    }

    优化技巧

     

    使用 transform 或者 opacity 来实现动画效果

    文章最开始,我们讲到了页面呈现出来所经历的渲染流水线,其实从性能方面考虑,最理想的渲染流水线是没有布局和绘制环节的,只需要做合成层的合并即可:

    图片 27

    为了实现上述效果,就需要只使用那些仅触发 Composite 的属性。目前,只有两个属性是满足这个条件的:transforms 和 opacity。更详细的信息可以查看 CSS Triggers。

    注意:元素提升为合成层后,transform 和 opacity 才不会触发 paint,如果不是合成层,则其依然会触发 paint。具体见如下两个 demo。

    • demo 1:transform图片 28
    • demo 2:opacity图片 29

    可以看到未提升 target element 为合成层,transform 和 opacity 依然会触发 paint。

    .write-flower:hover .cover{animation:translate 0.5s 1 linear;z-index: 1;}
    @keyframes translate{
    0%{opacity: 0;top: -110%;}
    10%{}
    100%{top:10px;opacity: 0.7;}
    }

    避免隐式合成

    • 保持动画的对象的z-index尽可能的高。理想的,这些元素应该是body元素的直接子元素。当然,这不是总可能的。所以你可以克隆一个元素,把它放在body元素下仅仅是为了做动画。
    • 将元素上设置will-change CSS属性,元素上有了这个属性,浏览器会提升这个元素成为一个复合层(不是总是)。这样动画就可以平滑的开始和结束。但是不要滥用这个属性,否则会大大增加内存消耗。

    3 为什么硬件加速会使页面流畅

    减少绘制区域

    对于不需要重新绘制的区域应尽量避免绘制,以减少绘制区域,比如一个 fix 在页面顶部的固定不变的导航 header,在页面内容某个区域 repaint 时,整个屏幕包括 fix 的 header 也会被重绘,见 demo,结果如下:

    图片 30

    而对于固定不变的区域,我们期望其并不会被重绘,因此可以通过之前的方法,将其提升为独立的合成层。

    减少绘制区域,需要仔细分析页面,区分绘制区域,减少重绘区域甚至避免重绘。

    .green-flower:hover .cover{animation:skew 0.5s 1 linear;z-index: 1;}
    @keyframes skew{
    0%{opacity: 0;}
    50%{transform:rotate3d(0,1,0,180deg);opacity: 1}
    100%{opacity: 0.7;}
    }

    动画中只使用transform和opacity

    如上所说,transform和opacity保证了元素属性的变化不影响文档流、也不受文档流影响;并且不会造成repaint。有些时候你可能想要改变其他的css属性,作为动画。例如:你可能想使用background属性改变背景:

    CSS

    <div class="bg-change"></div> .bg-change { width: 100px; height: 100px; background: red; transition: opacity 2s; } .bg-change:hover { background: blue; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <div class="bg-change"></div>
    .bg-change {
      width: 100px;
      height: 100px;
      background: red;
      transition: opacity 2s;
    }
    .bg-change:hover {
      background: blue;
    }

    在这个例子中,在动画的每一步;浏览器都会进行一次重绘。我们可以使用一个复层在这个元素上面,并且仅仅变换opacity属性:

    XHTML

    <div class="bg-change"></div> <style> .bg-change { width: 100px; height: 100px; background: red; } .bg-change::before { content: ''; display: block; width: 100%; height: 100%; background: blue; opacity: 0; transition: opacity 20s; } .bg-change:hover::before { opacity: 1; } </style>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <div class="bg-change"></div>
    <style>
    .bg-change {
      width: 100px;
      height: 100px;
      background: red;
    }
    .bg-change::before {
      content: '';
      display: block;
      width: 100%;
      height: 100%;
      background: blue;
      opacity: 0;
      transition: opacity 20s;
    }
    .bg-change:hover::before {
      opacity: 1;
    }
    </style>

    因为 transform 属性不会触发浏览器的 repaint(重绘),而绝对定位absolute中的 left 和 top 则会一直触发 repaint(重绘)。

    合理管理合成层

    看完上面的文章,你会发现提升合成层会达到更好的性能。这看上去非常诱人,但是问题是,创建一个新的合成层并不是免费的,它得消耗额外的内存和管理资源。实际上,在内存资源有限的设备上,合成层带来的性能改善,可能远远赶不上过多合成层开销给页面性能带来的负面影响。同时,由于每个渲染层的纹理都需要上传到 GPU 处理,因此我们还需要考虑 CPU 和 GPU 之间的带宽问题、以及有多大内存供 GPU 处理这些纹理的问题。

    对于合成层占用内存的问题,我们简单做了几个 demo 进行了验证。

    demo 1 和 demo 2 中,会创建 2000 个同样的 div 元素,不同的是 demo 2 中的元素通过 will-change 都提升为了合成层,而两个 demo 页面的内存消耗却有很明显的差别。

    图片 31

    .red-flower:hover .cover{animation:red 0.8s 1 linear;z-index: 1;}
    @keyframes red{
    0%{opacity: 1;}
    35%{transform:translate(100%,0) rotate3d(0,1,0,90deg);transform-origin:0 0; transition:0.3s ease-in-out;}
    65%{transform:translate(-10%,0) rotate3d(0,1,0,90deg);transform-origin:0 0; transition:0.3s ease-in-out;}
    100%{opacity: 1;}
    }

    减小复合层的尺寸

    看一下两张图片,有什么不同吗?

    图片 32

    这两张图片视觉上是一样的,但是它们的尺寸一个是39kb;另外一个是400b。不同之处在于,第二个纯色层是通过scale放大10倍做到的。

    XHTML

    <div id="a"></div> <div id="b"></div> <style> #a, #b { will-change: transform; } #a { width: 100px; height: 100px; } #b { width: 10px; height: 10px; transform: scale(10); } </style>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <div id="a"></div>
    <div id="b"></div>
     
    <style>
    #a, #b {
    will-change: transform;
    }
     
    #a {
    width: 100px;
    height: 100px;
    }
     
    #b {
    width: 10px;
    height: 10px;
    transform: scale(10);
    }
    </style>

    对于图片,你要怎么做呢?你可以将图片的尺寸减少5%——10%,然后使用scale将它们放大;用户不会看到什么区别,但是你可以减少大量的存储空间。

    为什么 transform 没有触发 repaint 呢?简而言之,transform 动画由GPU控制,支持硬件加速,并不需要软件方面的渲染。

    防止层爆炸

    通过之前的介绍,我们知道同合成层重叠也会使元素提升为合成层,虽然有浏览器的层压缩机制,但是也有很多无法进行压缩的情况。也就是说除了我们显式的声明的合成层,还可能由于重叠原因不经意间产生一些不在预期的合成层,极端一点可能会产生大量的额外合成层,出现层爆炸的现象。我们简单写了一个极端点但其实在我们的页面中比较常见的 demo。

    CSS

    @-webkit-keyframes slide { from { transform: none; } to { transform: translateX(100px); } } .animating { width: 300px; height: 30px; background-color: orange; color: #fff; -webkit-animation: slide 5s alternate linear infinite; } ul { padding: 5px; border: 1px solid #000; } .box { width: 600px; height: 30px; margin-bottom: 5px; background-color: blue; color: #fff; position: relative; /* 会导致无法压缩:squashingClippingContainerMismatch */ overflow: hidden; } .inner { position: absolute; top: 2px; left: 2px; font-size: 16px; line-height: 16px; padding: 2px; margin: 0; background-color: green; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    @-webkit-keyframes slide {
        from { transform: none; }
        to { transform: translateX(100px); }
        }
        .animating {
        
        width: 300px;
        height: 30px;
        background-color: orange;
        color: #fff;
          -webkit-animation: slide 5s alternate linear infinite;
        }
     
      ul {
     
        padding: 5px;
        border: 1px solid #000;
      }
     
        .box {
     
        width: 600px;
        height: 30px;
        margin-bottom: 5px;
        background-color: blue;
        color: #fff;
        position: relative;
        /* 会导致无法压缩:squashingClippingContainerMismatch */
        overflow: hidden;
        }
     
        .inner {
          position: absolute;
          top: 2px;
          left: 2px;
          font-size: 16px;
          line-height: 16px;
          padding: 2px;
          margin: 0;
          background-color: green;
        }

    XHTML

    <!-- 动画合成层 --> <div class="animating">composited animating</div> <ul> <!-- assume overlap --> <li class="box"> <!-- assume overlap --> <p class="inner">asume overlap, 因为 squashingClippingContainerMismatch 无法压缩</p> </li> ... </ul>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <!-- 动画合成层 -->
    <div class="animating">composited animating</div>
    <ul>
      <!-- assume overlap -->
      <li class="box">
        <!-- assume overlap -->
        <p class="inner">asume overlap, 因为 squashingClippingContainerMismatch 无法压缩</p>
      </li>
      
      ...
    </ul>

    demo 中,.animating 的合成层在运行动画,会导致 .inner 元素因为上文介绍过的 assumedOverlap 的原因,而被提升为合成层,同时,.inner 的父元素 .box 设置了 overflow: hidden,导致 .inner 的合成层因为 squashingClippingContainerMismatch 的原因,无法压缩,就出现了层爆炸的问题。

    图片 33

    这种情况平时在我们的业务中还是很常见的,比如 slider list 的结构,一旦满足了无法进行层压缩的情况,就很容易出现层爆炸的问题。

    解决层爆炸的问题,最佳方案是打破 overlap 的条件,也就是说让其他元素不要和合成层元素重叠。对于上述的示例,我们可以将 .animation 的 z-index 提高。修改后 demo

    CSS

    .animating { ... /* 让其他元素不和合成层重叠 */ position: relative; z-index: 1; }

    1
    2
    3
    4
    5
    6
    7
    .animating {
      
      ...
      /* 让其他元素不和合成层重叠 */
      position: relative;
      z-index: 1;
    }

    此时,就只有 .animating 提升为合成层,如下:

    图片 34

    同时,内存占用比起之前也降低了很多。

    图片 35

    如果受限于视觉需要等因素,其他元素必须要覆盖在合成层之上,那应该尽量避免无法层压缩情况的出现。针对上述示例中,无法层压缩的情况(squashingClippingContainerMismatch),我们可以将 .boxoverflow: hidden 去掉,这样就可以利用浏览器的层压缩了。修改后 demo

    此时,由于第一个 .box 因为 squashingLayerIsAnimating 的原因无法压缩,其他的都被压缩到了一起。

    图片 36

    同时,内存占用比起之前也降低了很多。

    图片 37

    .pink-flower:hover .cover{animation:pink 0.8s 1 linear;z-index: 1;}
    .pink-flower:hover .picture{animation:pink1 0.8s 1 linear;z-index: 1;}
    @keyframes pink{
    0%{transform:scale(0.2);opacity: 1;}
    50%{opacity: 0.5;transform:scale(1) rotate(360deg);}
    100%{transform:scale(1) rotate(360deg);opacity: 0.7;}
    }
    @keyframes pink1{
    10%{transform:scale(0.8) translate(50%,0) rotate(180deg);}
    20%{transform:scale(0.6) translate(150%,0) rotate(180deg);}
    30%{transform:scale(0.4) translate(200%,0) rotate(180deg);}
    与超酷例子,css3硬件加速。40%{transform:scale(0.2) translate(250%,0) rotate(180deg);}
    50%{transform:scale(0.05) translate(300%,0) rotate(180deg);}
    60%{transform:scale(0.2) translate(-300%,0) rotate(180deg);}
    70%{transform:scale(0.4) translate(-250%,0) rotate(180deg);}
    80%{transform:scale(0.6) translate(-200%,0) rotate(180deg);}
    90%{transform:scale(0.8) translate(-150%,0) rotate(180deg);}
    100%{transform:scale(1) translate(-50%,0) rotate(180deg);}
    }

    用css动画而不是js动画

    css动画有一个重要的特性,它是完全工作在GPU上。因为你声明了一个动画如何开始和如何结束,浏览器会在动画开始前准备好所有需要的指令;并把它们发送给GPU。而如果使用js动画,浏览器必须计算每一帧的状态;为了保证平滑的动画,我们必须在浏览器主线程计算新状态;把它们发送给GPU至少60次每秒。除了计算和发送数据比css动画要慢,主线程的负载也会影响动画; 当主线程的计算任务过多时,会造成动画的延迟、卡顿。

    所以尽可能地使用基于css的动画,不仅仅更快;也不会被大量的js计算所阻塞。

     

    与超酷例子,css3硬件加速。最后

    之前无线开发时,大多数人都很喜欢使用 translateZ(0) 来进行所谓的硬件加速,以提升性能,但是性能优化并没有所谓的“银弹”,translateZ(0) 不是,本文列出的优化建议也不是。抛开了对页面的具体分析,任何的性能优化都是站不住脚的,盲目的使用一些优化措施,结果可能会适得其反。因此切实的去分析页面的实际性能表现,不断的改进测试,才是正确的优化途径。

    .purple-flower:hover .cover{animation:purple 0.5s 1 linear;z-index: 1;}
    .purple-flower:hover .picture{animation:purple1 0.5s 1 linear;z-index: 1;}
    @keyframes purple{
    0%{transform:scale(1.5);opacity: 0.2;}
    20%{transform:scale(1.4);opacity: 0.3;}
    40%{transform:scale(1.3);opacity: 0.4;}
    60%{transform:scale(1.2);opacity: 0.5;}
    80%{transform:scale(1.1);opacity: 0.6;}
    100%{transform:scale(1);opacity: 1;}
    }
    @keyframes purple1{
    0%{transform:scale(1);opacity: 1;}
    20%{transform:scale(0.8);opacity: 0.8;}
    40%{transform:scale(0.6);opacity: 0.6;}
    60%{transform:scale(0.4);opacity: 0.5;}
    80%{transform:scale(0.2);opacity: 0.3;}
    100%{transform:scale(0);opacity: 0;}
    }

    优化技巧总结

    • 减少浏览器的重排和重绘的发生。
    • 不要使用table布局。
    • css动画中尽量只使用transform和opacity,这不会发生重排和重绘。
    • 尽可能地只使用css做动画。
    • 避免浏览器的隐式合成。
    • 改变复合层的尺寸。

    浏览器什么时候会创建一个独立的复合图层呢?事实上一般是在以下几种情况下:

    参考

    • PaintLayer.h
    • PaintLayer.cpp
    • CompositingReasons.cpp
    • CompositingReasons.h
    • CompositingRequirementsUpdater.cpp
    • chrome layout test
    • Slimming Paint
    • The stacking contest
    • Blink Compositing Update: Recap and Squashing
    • GPU Accelerated Compositing in Chrome
    • CSS Triggers
    • google render performance

      1 赞 6 收藏 评论

    图片 38

    .blue-flower:hover .cover{animation:blue 0.8s 1 linear;z-index: 1;}
    .blue-flower:hover .picture{animation:blue1 0.8s 1 linear;z-index: 1;}
    @keyframes blue{
    20%{transform:scale(0.2) translate(-300%,300%);opacity: 0;}
    50%{transform:scale(0.3) translate(-200%,200%);opacity: 0.4}
    70%{transform:scale(0.5) translate(0,0);opacity: 0.7}
    100%{transform:scale(0.7) translate(0,0);opacity: 0.8}
    }
    @keyframes blue1{
    20%{transform:scale(0.7) translate(0,0);opacity: 1}
    50%{transform:scale(0.5) translate(0,0);opacity: 1}
    70%{transform:scale(0.3) translate(250%,-250%);opacity: 0.4}
    100%{transform:scale(0.2) translate(350%,-350%);opacity: 0;}
    }

    参考

    GPU合成主要参考:

    https://www.smashingmagazine….

    哪些属性会引起reflow、repaint及composite,你可以在这个网站找到:

    1 赞 2 收藏 评论

    图片 39

    3D 或者 CSS transform

    .orange-flower:hover .cover{animation:orange 0.5s 1 linear;z-index: 1;}
    .orange-flower:hover .picture{animation:orange1 0.5s 1 linear;z-index: 1;}
    @keyframes orange{
    0%{transform:rotate(180deg);}
    20%{transform:rotate(180deg) translate(10%,10%);opacity: 0.9;}
    40%{transform:rotate(180deg) translate(20%,20%);opacity: 0.8;}
    40%{transform:rotate(180deg) translate(30%,30%);opacity: 0.8;}
    60%{transform:rotate(180deg) translate(20%,20%);opacity: 0.7;}
    80%{transform:rotate(180deg) translate(10%,10%);opacity: 0.6;}
    100%{transform:rotate(180deg) translate(0,0);opacity: 0;}
    }
    @keyframes orange1{
    0%{transform:rotate(180deg);}
    20%{transform:rotate(180deg) translate(-10%,-10%);opacity: 0.9;}
    40%{transform:rotate(180deg) translate(-20%,-20%);opacity: 0.8;}
    40%{transform:rotate(180deg) translate(-30%,-30%);opacity: 0.8;}
    60%{transform:rotate(180deg) translate(-20%,-20%);opacity: 0.7;}
    80%{transform:rotate(180deg) translate(-10%,-10%);opacity: 0.6;}
    100%{transform:rotate(180deg) translate(0,0);opacity: 0;}
    }
    </style>
    <body>
    <div class="content">
    <div class="yellow-flower flower">
    <div class="picture">
    <img src="img/flash.jpg" alt="图片无法加载">
    </div>
    <div class="cover">
    <h2><a href="#">Come here</a></h2>
    <p><a href="#">you can</a></p>
    </div>
    </div>
    <div class="write-flower flower">
    <div class="picture">
    <img src="img/flash7.jpg" alt="图片无法加载">
    </div>
    <div class="cover">
    <h2>Come here</h2>
    <p>you can</p>
    </div>
    </div>
    <div class="green-flower flower">
    <div class="picture">
    <img src="img/flash2.jpg" alt="图片无法加载">
    </div>
    <div class="cover">
    <h2>Come here</h2>
    <p>you can</p>
    </div>
    </div>
    <div class="red-flower flower">
    <div class="picture">
    <img src="img/flash3.jpg" alt="图片无法加载">
    </div>
    <div class="cover">
    <h2>Come here</h2>
    <p>you can</p>
    </div>
    </div>
    <div class="pink-flower flower">
    <div class="picture">
    <img src="img/flash4.jpg" alt="图片无法加载">
    </div>
    <div class="cover">
    <h2>Come here</h2>
    <p>you can</p>
    </div>
    </div>
    <div class="purple-flower flower">
    <div class="picture">
    <img src="img/flash5.jpg" alt="图片无法加载">
    </div>
    <div class="cover">
    <h2>Come here</h2>
    <p>you can</p>
    </div>
    </div>
    <div class="blue-flower flower">
    <div class="picture">
    <img src="img/flash6.jpg" alt="图片无法加载">
    </div>
    <div class="cover">
    <h2>Come here</h2>
    <p>you can</p>
    </div>
    </div>
    <div class="orange-flower flower">
    <div class="picture">
    <img src="img/flash1.jpg" alt="图片无法加载">
    </div>
    <div class="cover">
    <h2>Come here</h2>
    <p>you can</p>
    </div>
    </div>
    </div>
    </body>
    </html>

    <video> 和 <canvas> 标签

     

    CSS filters

    元素覆盖时,比如使用了 z-index 属性

     

    4并不是所有的CSS属性都能触发GPU的硬件加速,实际上只有少数属性可以,比如下面的这些:

    transform

    opacity

    filter

     

     

    5.如何在桌面端和移动端用CSS开启硬件加速

    CSS animations, transforms 以及 transitions 不会自动开启GPU加速,而是由浏览器的缓慢的软件渲染引擎来执行。那我们怎样才可以切换到GPU模式呢,很多浏览器提供了某些触发的CSS规则。

    现在,像Chrome, FireFox, Safari, IE9 和最新版本的Opera都支持硬件加速,当它们检测到页面中某个DOM元素应用了某些CSS规则时就会开启,最显著的特征的元素的3D变换。

    例如:

    .cube {

       -webkit-transform: translate3d(250px,250px,250px)

       rotate3d(250px,250px,250px,-120deg)

       scale3d(0.5, 0.5, 0.5);

    }

    可是在一些情况下,我们并不需要对元素应用3D变换的效果,那怎么办呢?这时候我们可以使用个小技巧“欺骗”浏览器来开启硬件加速。

    虽然我们可能不想对元素应用3D变换,可我们一样可以开启3D引擎。例如我们可以用transform: translateZ(0); 来开启硬件加速 。

    .cube {

       -webkit-transform: translateZ(0);

       -moz-transform: translateZ(0);

       -ms-transform: translateZ(0);

       -o-transform: translateZ(0);

       transform: translateZ(0);

       /* Other transform properties here */

    }

    在 Chrome and Safari中,当我们使用CSS transforms 或者 animations时可能会有页面闪烁的效果,下面的代码可以修复此情况:

    .cube {

       -webkit-backface-visibility: hidden;

       -moz-backface-visibility: hidden;

       -ms-backface-visibility: hidden;

       backface-visibility: hidden;

       -webkit-perspective: 1000;

       -moz-perspective: 1000;

       -ms-perspective: 1000;

       perspective: 1000;

       /* Other transform properties here */

    }

    在webkit内核的浏览器中,另一个行之有效的方法是

    .cube {

       -webkit-transform: translate3d(0, 0, 0);

       -moz-transform: translate3d(0, 0, 0);

       -ms-transform: translate3d(0, 0, 0);

       transform: translate3d(0, 0, 0);

      /* Other transform properties here */

    }

    原生的移动端应用(Native mobile applications)总是可以很好的运用GPU,这是为什么它比网页应用(Web apps)表现更好的原因。硬件加速在移动端尤其有用,因为它可以有效的减少资源的利用(移动端本身资源有限)。

     

    6.使用硬件加速的问题

    使用硬件加速并不是十全十美的事情,比如:

    1内存。如果GPU加载了大量的纹理,那么很容易就会发生内容问题,这一点在移动端浏览器上尤为明显,所以,一定要牢记不要让页面的每个元素都使用硬件加速。

    2使用GPU渲染会影响字体的抗锯齿效果。这是因为GPU和CPU具有不同的渲染机制。即使最终硬件加速停止了,文本还是会在动画期间显示得很模糊。

     

    总结

    只对我们需要实现动画效果的元素应用以上方法,如果仅仅为了开启硬件加速而随便乱用,那是不明智的。

    小心使用这些方法,如果通过你的测试,结果确是提高了性能,你才可以使用这些方法。使用GPU可能会导致严重的性能问题,因为它增加了内存的使用,而且它会减少移动端设备的电池寿命。

     

    本文由新葡亰496net发布于新葡亰官网,转载请注明出处:与超酷例子,css3硬件加速

    关键词: