近年来,我们一直看到硬件加速以及它如何帮助我们提高网页的动画性能,使网页动画在联通上看起来更好、更流畅。 我认为很多经验不足的工程师不知道硬件加速是如何工作的以及我们如何使用它来帮助我们使动画看起来更流畅。
CSS3硬件加速也称为GPU加速,是一种利用GPU进行渲染,减少CPU运算的优化方案。 由于GPU中的transform3d等CSS属性不会触发重绘,因此可以极大地提高网页的性能。
GPU硬件加速是指利用GPU的图形性能css3 加速,将浏览器中的一些图形操作交给GPU。 由于GPU是专门为处理图形而设计的,因此在速度和耗煤方面都更加高效。
左边元素的动画是通过left/top操作位置实现的css3 加速,右边元素的动画是通过transform:translate实现的。 你可以打开chrome的“Paintflashing”来查看,红色部分就是正在重绘的内容。
从demo中可以看到,左侧图形在运动时内层有红色边框,说明该元素在不断重绘,但可以看出在运动时存在丢帧现象运动过程,具体表现为运动不连贯和轻微闪烁。
那么transform是如何防止动画重画的呢? 最直接的答案是,transform会直接使用硬件加速,在GPU上运行,避免软件渲染。
硬件加速的工作原理
之前学习flash的时候就知道动画是由图片一帧一帧组成的,在浏览器中也是一样。 我们首先看一下浏览器每一帧都做了什么。
动画和视口
浏览器获取到RenderTree后(详细知识请参考浏览器重排与重绘的深入理解),渲染树中包含了大量的渲染元素,每个渲染元素都会被分配到一个视口,每个视口将被加载到GPU以生成渲染纹理。 这里的技巧是,通过变换的图层将使用GPU进行渲染,因此不需要重新绘制,这与3D绘图功能非常相似,最后这个使用变换的视口将由一个单独的合成器进程。
流程如下:
渲染树->渲染元素->视口->GPU渲染->浏览器复合视口->生成最终的屏幕图像。
在chromedevtools中,可以打开Rendering中的Layerborders来查看视口纹理。
其中,黑色边框表示该元素进行了3D变换,这意味着它是在新的复合层(composited layer)中渲染的,白色网格表示普通渲染层。
在本文开头给出的示例中,CSS 变换直接在 GPU 上创建一个新层。 我们还可以打开Layerborders,(这个选项可以帮助我们看到什么是单独的图层,打开这个选项后,单独的图层会有黑色边框。)可以观察到,使用transform:translate动画元素,有黑色边框,可以看出是复合层。
在GPU渲染过程中,一些元素由于遵守个别规则,会被提升为独立层(蓝色边框部分)。 一旦独立,就不会影响其他DOM的布局,所以我们可以利用这个规则,主动将经常变化的DOM改进为独立的一层,这样可以在浏览器的一帧内减少Layout和Paint的时间。
创建单独的视口
哪些规则可以让浏览器主动帮我们创建独立的层呢?
开启GPU加速
CSS动画、变换和转场不手动启用GPU加速,而是通过浏览器的平滑软件渲染引擎执行。 那么如何才能实现GPU加速呢? 许多浏览器提供了触发此模式的单独规则。
例如,使用translate3d()、rotate3d()、scale3d(),我们可以使用GPU加速。
以下 css 属性可以触发硬件加速:
因此,为了让页面更加流畅、高性能的动画,我们可以使用GPU来处理。
如果有一些元素不需要使用上述属性,需要触发硬件加速效果,例如:某些情况下,我们不想对元素应用3D变换效果,但仍想实现GPU加速,则可以通过一些小方法来诱导浏览器启用硬件加速。
变换:平移Z(0)
这个说法是可以在桌面端和联通端触发GPU加速。 这是一个非常有效的方法(包括所有浏览器前缀):
使用硬件加速时的注意事项
大多数重要问题都与视频内存有关。 GPU 处理过多的内容可能会导致视频内存问题。 这会导致联通端和联通端浏览器崩溃。 因此,硬件加速通常不会用于所有元素。 (开启硬件加速过多可能会消耗更多显存,所以什么时候开启硬件加速、开启多少元素硬件加速,需要用测试结果来说话。)
抗锯齿对GPU渲染字感无效。 这是由于GPU和CPU的算法不同造成的。 所以如果在动画结束时不关闭硬件加速,字体就会变得模糊。
原文链接:
今天给大家分享一个简单的CSS动画:
具体疗效如下:
最需要的样式是:clip,也是本教程的核心
W3C 将其定义为:
好了简单的css3动画,预览完毕,我们开始本次内容讲解:
首先是HTML的布局:由于前后都添加了CSS伪类的边框,所以这次的布局非常简单
只需要一个 div:
[HTML]纯文本查看复制代码
好的,下一步是为其添加样式:
首先是div本身的样式。 在这里,我向正文添加了背景颜色,并清除了随之而来的边距。
[CSS]纯文本视图复制代码
body { margin: 0; background: #333; } .box { width: 200px; height: 200px; box-sizing: border-box; border: 1px solid #cb6341; position: fixed; left: 50%; top: 50%; margin-top: -100px; margin-left: -100px; }
这时候我们已经可以看到div的基本形状了,下一步就是利用CSS中before和after的伪类给它添加内边框
[CSS]纯文本视图复制代码
.box:after, .box:before { content: ''; width: 220px; height: 220px; box-sizing: border-box; border: 1px solid; position: absolute; top: -5%; left: -5%; animation: boxBorder 6s linear infinite; } .box:before { animation-delay: -3s; }
我需要解释一下上面的代码:
首先,这次没有设置边框的颜色,是为了在接下来的动画中动态改变yanse
其次,在before中加入动画延迟,使form和after重叠在一起。
好了,接下来就是本教程的核心内容了,动画!如果理解的话可以去W3C预览
[CSS]纯文本视图复制代码
@keyframes boxBorder { 0% { border-color: #fff; clip: rect(0, 220px, 2px, 0); } 25% { border-color: yellow; clip: rect(0px, 2px, 220px, 0) } 50% { border-color: blue; clip: rect(218px, 220px, 220px, 0) } 75% { border-color: green; clip: rect(0, 220px, 220px, 218px) } 100% { border-color: #fff; clip: rect(0, 220px, 2px, 0) } }
说明:这里的border-color上面没有设置,这里添加一下,是为了让它的颜色发生变化
Clip是裁剪后的图像:括号中的4个值分别代表上、右、下、左
有兴趣的朋友可以自己研究一下~
最后贴上全部代码:
ps:上面的代码包括一开始gif动画演示的代码,以及div中间有两个椭圆的代码。 代码原理类似简单的css3动画,就不单独下拉了
至此,本教程就结束了,谢谢大家~
[HTML]纯文本查看复制代码
Document body { margin: 0; background: #333; } .box { width: 200px; height: 200px; box-sizing: border-box; border: 1px solid #cb6341; position: fixed; left: 50%; top: 50%; margin-top: -100px; margin-left: -100px; } .box:after, .box:before { content: ''; width: 220px; height: 220px; box-sizing: border-box; border: 1px solid; position: absolute; top: -5%; left: -5%; animation: boxBorder 6s linear infinite; } .box:before { animation-delay: -3s; } .box .icon { position: absolute; top: 50%; left: 50%; width: 100px; height: 100px; margin-top: -50px; margin-left: -50px; animation: iconBox 3s linear infinite; } .box .icon:after, .box .icon:before { content: ""; width: 40%; height: 100%; box-sizing: border-box; border-radius: 50%; border: 2px solid #fff; position: absolute; top: 0; left: 30px; animation: iconBorder 3s linear infinite; } .box .icon:after { transform: rotate(60deg); } .box .icon:before { transform: rotate(-60deg); } .box .icon2:before { transform: rotate(0deg); } .box .icon2:after { height: 10px; width: 10px; background-color: #fff; transform: translate(12px, -6px); border: 3px solid #333; box-sizing: content-box; animation: iconYuan 3s linear infinite 0.6s; } @keyframes iconBox { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes iconBorder { 0% { border-color: #fff; } 30% { border-color: yellow; } 60% { border-color: blue; } 100% { border-color: red; } } @keyframes iconYuan { 0% { background-color: #fff; } 30% { background-color: yellow; } 60% { background-color: blue; } 100% { background-color: red; } } @keyframes boxBorder { 0% { border-color: #fff; clip: rect(0, 220px, 2px, 0); } 25% { border-color: yellow; clip: rect(0px, 2px, 220px, 0) } 50% { border-color: blue; clip: rect(218px, 220px, 220px, 0) } 75% { border-color: green; clip: rect(0, 220px, 220px, 218px) } 100% { border-color: #fff; clip: rect(0, 220px, 2px, 0) } }