首先浏览器从上到下依次解析文档构建DOM树,如下:
CSSOM,即CSS对象模型(CSS Object Model),CSSOM树,与DOM树结构相似,只是另外为每一个节点关联了样式信息。
theme.css样式内容如下:
html, body {
width: 100%;
height: 100%;
background-color: #fcfcfc;
}
.title {
font-size: 20px;
}
.footer {
font-size: 12px;
color: #aaa;
}
构建CSSOM树如图:
上文已经阐述了文档解析时对脚本的处理,我们得知脚本加载,解析和执行会阻塞文档解析,而在特殊情况下样式的加载和解析也会阻塞脚本,所以现在推荐的实践是
DOM树和CSSOM树都构建完了,接着浏览器会构建渲染树:
渲染树,代表一个文档的视觉展示,浏览器通过它将文档内容绘制在浏览器窗口,展示给用户,它由按顺序展示在屏幕上的一系列矩形对象组成,这些矩形对象都带有字体,颜色和尺寸,位置等视觉样式属性。对于这些矩对象,FireFox称之为框架(frame),Webkit浏览器称之为渲染对象(render object, renderer),后文统称为渲染对象。
这里把渲染树节点称为矩形对象,是因为,每一个渲染对象都代表着其对应DOM节点的CSS盒子,该盒子包含了尺寸,位置等几何信息,同时它指向一个样式对象包含其他视觉样式信息。
每一个渲染对象都对应着DOM节点,但是非视觉(隐藏,不占位)DOM元素不会插入渲染树,如元素或声明display: none;的元素,渲染对象与DOM节点不是简单的一对一的关系,一个DOM可以对应一个渲染对象,但一个DOM元素也可能对应多个渲染对象,因为有很多元素不止包含一个CSS盒子,如当文本被折行时,会产生多个行盒,这些行会生成多个渲染对象;又如行内元素同时包含块元素和行内元素,则会创建一个匿名块级盒包含内部行内元素,此时一个DOM对应多个矩形对象(渲染对象)。
渲染树及其对应DOM树如图:
图中渲染树viewport即视口,是文档的初始包含块,scroll代表滚动区域,详见CSS之视觉格式化模型(Visual Formatting Model)
渲染树并不会包含显式或隐式地display:none;的标签元素。
布局(Layout)或回流(reflow,relayout)
创建渲染树后,下一步就是布局(Layout),或者叫回流(reflow,relayout),这个过程就是通过渲染树中渲染对象的信息,计算出每一个渲染对象的位置和尺寸,将其安置在浏览器窗口的正确位置,而有些时候我们会在文档布局完成后对DOM进行修改,这时候可能需要重新进行布局,也可称其为回流,本质上还是一个布局的过程,每一个渲染对象都有一个布局或者回流方法,实现其布局或回流。
HTML采用的是基于流的方式定位布局,其按照从左到右,从上到下的顺序进行排列,详见CSS定位机制。
对渲染树的布局可以分为全局和局部的,全局即对整个渲染树进行重新布局,如当我们改变了窗口尺寸或方向或者是修改了根元素的尺寸或者字体大小等;而局部布局可以是对渲染树的某部分或某一个渲染对象进行重新布局。
大多数web应用对DOM的操作都是比较频繁,这意味着经常需要对DOM进行布局和回流,而如果仅仅是一些小改变,就触发整个渲染树的回流,这显然是不好的,为了避免这种情况,浏览器使用了脏位系统,只有一个渲染对象改变了或者某渲染对象及其子渲染对象脏位值为”dirty”时,说明需要回流。
表示需要布局的脏位值有两种:
“dirty”–自身改变,需要回流
“children are dirty”–子节点改变,需要回流
布局是一个从上到下,从外到内进行的递归过程,从根渲染对象,即对应着HTML文档根元素,然后下一级渲染对象,如对应着元素,如此层层递归,依次计算每一个渲染对象的几何信息(位置和尺寸)。
几何信息-位置和尺寸,即相对于窗口的坐标和尺寸,如根渲染对象,其坐标为(0, 0),尺寸即是视口
尺寸(浏览器窗口的可视区域)。
每一个渲染对象的布局流程基本如:
1.计算此渲染对象的宽度(width);
2.遍历此渲染对象的所有子级,依次:
2.1设置子级渲染对象的坐标
2.2判断是否需要触发子渲染对象的布局或回流方法,计算子渲染对象的高度(height)
3.设置此渲染对象的高度:根据子渲染对象的累积高,margin和padding的高度设置其高度;
4.设置此渲染对象脏位值为false。
在渲染树布局完成后,再次操作文档,改变文档的内容或结构,或者元素定位时,会触发回流,即需要重新布局,如请求某DOM的”offsetHeight”样式信息等诸多情况:
1,DOM操作,如增加,删除,修改或移动;
2,变更内容;
3, 激活伪类;
访问或改变某些CSS属性(包括修改样式表或元素类名或使用JavaScript操作等方式);
浏览器窗口变化(滚动或尺寸变化)
$(‘body’).css(‘padding’); // reflow
$(‘body’)[0].offsetHeight; // relow
有过CSS3动画开发经验的同学可能会有经历,如下入场动画:
.slide-left {
-webkit-transition: margin-left 1s ease-out;
-moz-transition: margin-left 1s ease-out;
-o-transition: margin-left 1s ease-out;
transition: margin-left 1s ease-out;
}
然后执行如下脚本:
var $slide = $(‘.slide-left’);
$slide.css({
“margin-left”: “100px”
}).addClass(‘slide-left’);
$slide.css({
“margin-left”: “10px”
});
我们会发现并没有效果,为什么呢?因为对margin-left的修改并没有触发回流,元素margin-left值的改变被缓存,如果我们在中间强制触发回流:
var $slide = $(‘.slide-left’);
$slide.css({
“margin-left”: “100px”
});
console.log($slide.css(‘padding’);
$slide.addClass(‘slide-left’);
$slide.css({
“margin-left”: “10px”
});
再看就达到了预期效果。
最后是绘制(paint)阶段或重绘(repaint)阶段,浏览器UI组件将遍历渲染树并调用渲染对象的绘制(paint)方法,将内容展现在屏幕上,也有可能在之后对DOM进行修改,需要重新绘制渲染对象,也就是重绘,绘制和重绘的关系可以参考布局和回流的关系。
与布局相似,绘制也分为全局和局部绘制,即对整个渲染树或某些渲染对象进行绘制。
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
最后
总的来说,面试官要是考察思路就会从你实际做过的项目入手,考察你实际编码能力,就会让你在电脑敲代码,看你用什么编辑器、插件、编码习惯等。所以我们在回答面试官问题时,有一个清晰的逻辑思路,清楚知道自己在和面试官说项目说技术时的话就好了
,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频**
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
[外链图片转存中…(img-r9tm0yVr-1711177209297)]
最后
总的来说,面试官要是考察思路就会从你实际做过的项目入手,考察你实际编码能力,就会让你在电脑敲代码,看你用什么编辑器、插件、编码习惯等。所以我们在回答面试官问题时,有一个清晰的逻辑思路,清楚知道自己在和面试官说项目说技术时的话就好了
[外链图片转存中…(img-4tUtnCzB-1711177209298)]
[外链图片转存中…(img-34t987q6-1711177209299)]