目录:
1、浏览器内核及特性2、DOM模型CSSOM(CSS Object Model)DOM标准3、DOM树4、RenderObject 基础类5、RenderLayer6、这是一个分界线7、GraphicsLayersGraphicsContext提升动画效果的元素8、拓展9、参考链接
1、浏览器内核及特性
在浏览器中,有一个模块是将页面变成可视化,这就是浏览器内核,通常也称为渲染引擎。
目前,主流的渲染引擎包括Trident、Gecko和Webkit,它们分别是IE、火狐和chrome的内核;
在表1-4中仅仅只是列出了其中一小部分使用WebKit引擎作为内核的浏览器;
一般而言, 渲染引擎包含下图所描述的众多功能模块:
其他还有绘图模块、网络等并没有在图中直接表示出来;
细化一点如下,实线表示普遍共享,虚线表示该部分模块在不同浏览器使用的WebKit内核中的实现是不一样的:
WebCore部分包含了目前被各个浏览器所使用的WebKit共享部分,这些都是加载和渲染网页的基础部分,具体包括HTML解释器,CSS解释器,SVG,DOM,渲染树,以及Inspector。
WebKit中对JavaScript引擎的调用是独立于引擎的,在Google的Chromium开源项目中,它被替换为V8引擎;
WebKit Ports:由于各自需求不同,或者操作系统不同,或者依赖模块不同,操作系统的开发者需要WebKit设计和定义成一套灵活的框架结构,不同的厂商基于框架结构,完成基于自身操作系统和依赖模块的实现。比如Qt移植表示的是WebKit的Qt版,被Qt项目所使用。
渲染过程如下,实现表示先后顺序:
在渲染完成之后,用户可能需要跟渲染的结果进行交互,或者网页自身有动画操作,一般而言,这需要持续的重复渲染过程。
2、DOM模型
CSSOM(CSS Object Model)
CSS对象模型,它的思想是在DOM中的一些节点接口中,加入获取和操作CSS属性或者接口的JavaScript接口,因而JavaScript可以动态操作CSS样式。
对于内部和外部的样式表,CSSOM定义了样式表的接口,称为“CSSStyleSheet”,这是一个可以在JavaScript代码中访问的接口。借助于该接口,开发者可以在JavaScript中获取样式表的各种信息,例如CSS的“href”。开发者可以通过document.stylesheets查看当前网页中包含的所有CSS样式表。
DOM标准
Dom定义的是一组与平台、语言无关的接口,该接口允许编程语言动态访问和更改结构化文档;
Dom规范的演进过程:
3、DOM树
HTML代码经过WebKit解释之后,生成DOM树;
网页中的内容在内部存储为称为DOM树的节点对象树。
页面上的每个HTML元素以及元素之间出现的文本都与节点相关联。
DOM树的顶级节点始终是文档节点。
ps:
JavaScript代码可能会调用例如document.write()来修改文档结构,所以JavaScript代码的执行会阻碍后面节点创建同时阻碍后面资源下载,所以使用JavaScript有以下两点建议:
1、将“script”元素加上“async”属性,表明这是一个可以异步执行的JavaScript代码;
2、另外一种方法是将“script”元素放在"body"元素的最后,这样他就不会阻碍其他资源的并发下载。
4、RenderObject 基础类
DOM树构建完成之后,WebKit所要做的事情就是为DOM树节点构建RenderObject。
对于可视化节点,WebKit会给它们建立相应的RenderObject对象。一个RenderObject对象保存了为绘制DOM节点所需要的各种信息,例如样式布局信息,经过WebKit的处理之后,RenderObject对象知道如何绘制自己。
5、RenderLayer
![](https://a77db9aa-a-7b23c8ea-s-sites.googlegroups.com/a/chromium.org/dev/developers/design-documents/gpu-accelerated-compositing-in-chrome/the_compositing_forest.png?attachauth=ANoY7crdXD1CI96BJDKEaY7wEaFiFisxJJE9ouR6F7lbvVf-dw9IoCJIyHMSEc7azCmnkK-RTaycJ9qnsd7m-GG_d4KfjH_KJpMiSmH6p1x1Brit4XJS_sLEoH8IGlJzDV5moeqAvNbG7t3HP-zKFGBawH2cEklY3ycsSpxJAAvQTgyHYH2XqF47nI7FJ7ZGggilMfY79dcYv4pmcMSQuSOXS9u-DO_DXd9HhJXzsFkJsasMWoaRU27E4IJA8L3dNvLnmvEw545b0zVOnB1nS1MAWp_qWUp1G5D55-5r3GixHEdNHayMfjjxAM2xwhmrRM_DQOQpvd05&attredirects=0)
所有RenderObject对象构成了一棵树,类似于DOM树;
RenderLayer是基于RenderObject树建立起来的一棵树,他们是一对多的关系;
RenderLayers的存在可以让页面元素以正确的顺序显示重叠元素或有半透明效果的元素等等;
哪些情况下RenderObject节点需要建立新的RenderLayer呢?
其中:显式的指定CSS位置的RenderObject节点,比如relative,absolute,或者transform
某RenderObject节点的后代都属于该节点,也就是同属于同一个RenderLayer,除非后代又生成了新的RenderLayer;
RenderLayers也形成树层次结构。根节点是对应于页面中根元素的RenderLayer,每个节点的后代是可视地包含在父层中的层。
6、这是一个分界线
为什么说这是一个分界线?
此图是从CSS和DOM树到绘图上下文,可见得出RenderLayer树后,就可以绘制上下文了。
上面的也就是我们常见的软件渲染,而接下来文章将要介绍的就是硬件加速的部分。
为什么要有硬件加速呢?
现代浏览器开启GPU加速,webkit渲染过程:style -> Layout(reflow发生在这) -> Paint(repaint发生在这) -> Composite。GPU加速就是在Composite部分,也就是比如transform属性开启了GPU加速,那么transform的过程中,可以避开reflow和repaint。
我们知道,reflow和repaint都是耗费浏览器性能的操作,这两者尤以reflow为甚;因为每次reflow,浏览器都要重新计算每个元素的形状和位置。
而硬件加速可以避过这两步达到想要的效果。是不是很棒啊~
使用GPU进行硬件加速
使用GPU来合成网页的内容可以带来非常显着的加速。
硬件合成的好处有三种:
在涉及大量像素的绘图和合成操作中,GPU上的合成页面层可以实现比CPU(在速度和功耗方面)更好的效率。硬件专为这些类型的工作负载而设计。
GPU上已有的内容(如加速视频,Canvas2D或WebGL)不需要昂贵的回读。
CPU和GPU之间的并行性,可以同时操作以创建高效的图形管道。
7、GraphicsLayers
在没有硬件加速的情况下,浏览器通常是依赖于CPU来渲染生成网页的内容,大致的做法是遍历这些层,然后按照顺序把这些层的内容依次绘制在一个内部存储空间上(例如bitmap),最后把这个内部表示显示出来,这种做法就是软件渲染(SoftwaRerendering)。
随着GPU硬件能力的增强,包括在很多小型设备上也是如此,浏览器可以借助于其处理图形方面的性能来对渲染实现加速。此时不再将所有层绘制到一起,而是进行分层渲染,合成之后再显示到屏幕上。
这也就是GraphicsLayers的出现。
每个RenderLayer不是有自己的GraphicsLayer(如果它是合成层)就是有第一个祖先的GraphicsLayer。
每个GraphicsLayer都有一个GraphicsContext,用于绘制相关的RenderLayers。合成器最终负责将GraphicsContexts的位图输出组合到后续合成过程中的最终屏幕图像中。
理论上每一个RenderLayer都可以将自己绘制成一个单独的背景表面,但实际上这在内存方面可能非常浪费。在当前的Blink实现中,RenderLayer必须满足以下条件之一才能获得自己的合成层:
![](http://ww1.sinaimg.cn/large/ec07bbd2gy1fu9a22bom4j213s07wwgx.jpg)
3D 或透视变换(perspective、transform) CSS 属性
使用加速视频解码的 元素
拥有 3D (WebGL) 上下文或加速的 2D 上下文的 元素
混合插件(如 Flash)
对自己的 opacity 做 CSS 动画或使用一个动画变换的元素
拥有加速 CSS 过滤器的元素
元素有一个包含复合层的后代节点(换句话说,就是一个元素拥有一个子元素,该子元素在自己的层里)
元素有一个 z-index 较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)
为了防止“层爆炸”,当许多元素位于具有直接合成原因的图层顶部时,Blink会将多个RenderLayers重叠为直接合成原因RenderLayer,并将它们“压缩”到单个后备存储中。
每个GraphicsLayer都在Chrome中使用Chrome合成器层实现Web *图层。这些最终的“cc层”(cc = Chrome合成器)就是真正知道如何操作的合成器。
GraphicsContext
在WebKit中,绘图操作被定义了一个抽象层,这就是绘图上下文,所有绘图的操作都是在该上下文中来进行的。
绘图上下文可以分为两种类型,第一种是用来绘制2D图形的上下文,称之为2D绘图上下文(GraphicsContext);第二种是绘制3D图形的上下文,称之为3D绘图上下文(GraphicsContext3D)。这两种都是抽象基类,也就是说他们只提供接口,因为WebKit需要支持不同的移植,而这两个抽象基类的具体绘制规则则由不同的移植提供不同的实现,每个移植使用的实际绘图类非常不一样,依赖的图形率也不一样。
RenderObject知道如何在显示表面上绘制节点的内容。它通过向GraphicsContext发出必要的绘制调用来实现。
提升动画效果的元素
在 Chrome 中,存在有不同类型的层: RenderLayer(负责 DOM 子树),GraphicsLayer(负责 RenderLayer 的子树),其中 GraphicsLayer 层是作为纹理(texture)上传给 GPU 的。
这里的纹理指的是 GPU 的一个术语:可以把它想象成一个从主存储器(例如 RAM)移动到图像存储器(例如 GPU 中的 VRAM)的位图图像(bitmap image)。一旦它被移动到 GPU 中,你可以将它匹配成一个网格几何体(mesh geometry),在 Chrome 中使用纹理来从 GPU 上获得大块的页面内容。通过将纹理应用到一个非常简单的矩形网格就能很容易匹配不同的位置(position)和变形(transformation),这也就是 3D CSS 的工作原理。
而 transform 移动元素时就是移动这些生成的 GraphicsLayer 层从而避免了浏览器大量的reflow(relayout)而提升性能的。
合成层的好处是不会影响到其他元素的绘制,因此,为了减少动画元素对其他元素的影响,从而减少 paint,我们需要把动画效果中的元素提升为合成层。
提升合成层的最好方式是使用 CSS 的 will-change 属性。
will-change 设置为 opacity、transform、top、left、bottom、right 可以将元素提升为合成层。
#target { will-change: transform;}复制代码
其兼容如下所示:
对于那些目前还不支持 will-change 属性的浏览器,目前常用的是使用一个 3D transform 属性来强制提升为合成层:
#target { transform: translateZ(0);}复制代码
但需要注意的是,不要创建太多的渲染层。因为每创建一个新的渲染层,就意味着新的内存分配和更复杂的层的管理。
8、拓展
会触发reflow和repaint的操作:
当你增加、删除、修改 DOM 结点时,会导致 Reflow 或 Repaint。
当你移动 DOM 的位置,或是搞个动画的时候。
当你修改 CSS 样式的时候。
当你 Resize 窗口的时候(移动端没有这个问题),或是滚动的时候。
当你修改网页的默认字体时。
注:display:none 会触发 reflow,而 visibility:hidden 只会触发 repaint,因为没有发现位置变化。
9、参考链接
《WebKit技术内幕朱永盛》