写css最逃不开的应该是浏览器兼容问题了吧,因为css存在一些 未定义行为 ,各个浏览器都会按照自己的渲染规则来表现,就会存在表现不一致的情况,还有很多属性某些浏览器不支持,很多时候需要我们用更通用的方法来实现一些UI效果。本文重点来说说浏览器是如何把一个页面渲染出来的。
主要流程:
DOM生成、样式计算、布局、分层、图层绘制、栅格化、合成显示
下面主要讲css相关的几个步骤
我们书写的html最终都会被解析成一颗dom树,它来表达的dom结构能被浏览器所理解,那css做的就是赋予dom节点每个元素样式。当然,我们写的css也是不能直接被浏览器理解的,需要转化成styleSheets,我们在浏览器控制台输入document.styleSheets就能看到。
styleSheets要应用到各个元素上还需要两个步骤:
最后得出dom节点每个元素的具体样式。
得到dom树后,浏览器会遍历这棵树,把所有可见的节点加到布局树中,再进行布局计算,得到每个节点的坐标位置,保存在布局树中。
得到每个元素的具体位置后,还不能开始绘制页面,因为我们的页面并不是二维的,3D变换,z轴排序、页面滚动等效果都需要图层来实现。所以浏览器会为特定的节点生成专门的图层便于这些效果的实现。那什么样的节点会创建专门的图层呢,包括拥有层叠上下文属性的元素以及需要剪裁(clip)的地方,可以看一下 css(五)层叠
在浏览器开发者工具会有一个Layers标签,这里面可以直观地看到页面的分层情况
当改变了元素宽高或者几何位置的时候,就会触发 重排 ,需要走一遍完整的渲染过程,开销最大。
如果只是改变颜色,那么布局阶段就不需要执行,可以直接进入绘制阶段,所以叫 重绘 ,省去了布局和分层,效率会比重排要高一些。
而使用css的transform实现动画效果,则可以避开重绘和重排,只进行后续的合成操作,被称为 合成 ,能大大提升绘制效率。
Ps 合成操作实在非主线程(GPU进程)上执行的,不占用主线程资源
这里,我们就以最简单的情况(仅包含html、css)说明一下网页的渲染过程。
从处理HTML文件中的一串串字符开始:
当HTML转化成DOM后,接下来浏览器会处理CSS,与转换HTML十分类似。
最终就转成下面的CSSOM树:
从DOM树的根部开始,遍历每个可见节点 :
比如,以上DOM树和CSSOM树合并成渲染树的结果如下:
从渲染树我们可以知道哪些节点是可见的,以及它们的CSS计算样式和几何形状,当渲染树完成之后,就可以开始绘制页面。
上面的步骤1到4也被称为关键路径绘制(英文简称:CRP,具体概念可参考谷歌浏览器的说明: https://developer.mozilla.org/en-US/docs/Web/Performance/Critical_rendering_path ):
概括的说,关键路径绘制包括:
了解网页渲染过程,有助于我们优化网页,提示渲染速度。这个过程被称作 优化关键渲染路径 (使上述步骤1到4所花费的总时间最小化的过程)
优化关键渲染路径 可以使内容尽快呈现到屏幕上,以获得更好的用户体验,但它也是一个很深的课题,不同的浏览器有不同的做法,这是火狐浏览器关于关键渲染路径的文档( https://developer.mozilla.org/en-US/docs/Web/Performance/Critical_rendering_path )。
以上,便是笔者对网页渲染过程的简单见解,此文章由笔者参考资料并加上 自己的见解 得来,若其中有不准确的地方还请指正
https://blog.logrocket.com/how-browser-rendering-works-behind-the-scenes-6782b0e8fb10/
https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-tree-construction
https://stackoverflow.com/questions/27637184/what-is-dom-reflow/27637245#27637245