浏览器渲染原理及流程

本文详细阐述了浏览器的加载、解析、渲染流程,包括DOM和CSSOM的构建、回流与重绘的概念及其影响因素。介绍了如何通过理解这些原理来优化页面性能,如合理安排CSS和JS的加载位置,避免不必要的回流和重绘,以及DOM树和渲染树的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么要了解浏览器加载、解析、渲染这个过程?

  • 了解浏览器如何进行加载,我们可以在引用外部样式文件,外部js时,将他们放到合适的位置,使浏览器以最快的速度将文件加载完毕。
  • 了解浏览器如何进行解析,我们可以在构建DOM结构,组织css选择器时,选择最优的写法,提高浏览器的解析速率。
  • 了解浏览器如何进行渲染,明白渲染的过程,我们在设置元素属性,编写js文件时,可以减少”重绘“”重新布局“的消耗。

渲染主流程

渲染引擎首先通过网络获得所请求文档的内容,下面是渲染引擎在取得内容之后的基本流程:
解析html以构建dom树->构建render树->布局render树->绘制render树

html的渲染过程就是:

  1. 将html代码按照深度优先遍历来生成DOM树。
  2. css文件下载完后也会进行渲染,生成相应的CSSOM。
  3. 当所有的css文件下载完且所有的CSSOM构建结束后,就会和DOM一起生成Render Tree。
  4. 接下来,浏览器就会进入Layout环节,将所有的节点位置计算出来。
  5. 最后,通过Painting环节将所有的节点内容呈现到屏幕上。

解释下几个概念:
在这里插入图片描述
DOM:Document Object Model,浏览器将HTML解析成树形的数据结构,简称DOM。
CSSOM:CSS Object Model,浏览器将CSS解析成树形的数据结构,简称CSSOM。
Render Tree:DOM和CSSOM合并成Render Tree。
layout:有了Render Tree,浏览器已经能知道网页中有哪些节点,各个节点的CSS定义以及他们的从属关系,从而去计算出Render Tree每个节点的具体位置
painting:按照算出来的规则,通过显卡,把内容画到屏幕上。

回流(reflow)和重绘(repaint)

reflow(回流):当浏览器发现某个部分发生了点变化影响布局(如:尺寸、位置、隐藏/显示等),需要倒回去重新渲染,这个回退的过程叫回流。reflow会从这个root frame开始递归往下,依次计算所有的节点几何尺寸和位置。鼠标滑过、点击……只要这些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引起它内部、周围甚至整个页面的重新渲 染。通常我们都无法预估浏览器到底会 reflow 哪一部分的代码,它们都彼此相互影响着。

通常有以下事件触发回流:

  • 网页初始化时
  • DOM操作(元素添加、删除、修改、元素顺序变化)
  • 内容变化,包括表单域内文本改变
  • CSS属性的计算或改变
  • 添加或删除样式表
  • 更改“类”属性
  • 浏览器窗口的缩放、滚动等
  • 伪类激活(例如:hover悬停)

注意:JS 获取 Layout 属性值(如:offsetLeft、scrollTop、getComputedStyle 等)也会引起回流。因为浏览器需要通过回流计算最新值
回流必将引起重绘,而重绘不一定会引起回流

repaint(重绘):是在一个元素的外观被改变,但是没有改变布局的情况下发生。如果只是改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,将只会引起浏览器屏幕的一部分要重画。

注意:
  • display:none 的节点不会被加入Render Tree,而visibility: hidden 则会,所以,如果某个节点最开始是不显示的,设为display:none是更优的。
  • display:none 会触发 reflow(元素原来的位置不保留),而 visibility:hidden 只会触发 repaint(仅仅为视觉上的不可见,原来的位置仍然保留着),因为没有发现位置变化。
如何最小化重绘(repaint)和回流(reflow)
  • 需要要对元素进行复杂的操作时,可以先隐藏(display:“none”),操作完成后再显示
  • 需要创建多个 DOM 节点时,使用 DocumentFragment 创建完后一次性的加入 document
  • 缓存 Layout 属性值,如:var left = elem.offsetLeft; 这样,多次使用 left 只产生一次回流
  • 尽量避免用 table 布局(table 元素一旦触发回流就会导致 table 里所有的其它元素回流)
  • 避免使用 css 表达式(expression),因为每次调用都会重新计算值(包括加载页面)
  • 尽量使用 css 属性简写,如:用 border 代替 border-width, border-style, border-color 批量修改元素样式:elem.className 和 elem.style.cssText 代替 elem.style.xxx
DOM 树和渲染树的区别
  • DOM 树与 HTML 标签一一对应,包括 head 和隐藏元素
  • 渲染树不包括 head 和隐藏元素(… display=none),大段文本的每一个行都是独立节点,每一个节点都有对应的 css 属性;还有像一些节点的位置为绝对或浮动定位(需要css知识理解),这些节点会在文本流之外,因此会在两棵树上的不同位置,渲染树标识出真实的位置,并用一个占位结构标识出他们原来的位置。
浏览器解析css选择器
  • 浏览器按“从右向左”读取。意味着在选择器 ul > li a[title=”home”] 中,首先被解析的是a[title=”home”]
  • ID选择符最高效,通配选择符效率最低,解析速度由快到慢依次是:ID、class、tag和universal ;
  • 不要用标签修饰id选择器 (永远不要这样做ul#main-navigation{}ID已经是唯一的,不需要Tag来标识,这样做会让选择器变慢。)
  • 后代选择器是最糟糕的 html body ul li a { }
  • • 6.CSS3的效率问题(CSS3选择器(比如:nth-child)能够漂亮的定位我们想要的元素,又能保证我们的CSS整洁易读。但是这些神奇的选择器会浪费很多的浏览器资源。);
  • 我们知道#ID速度是最快的,那么我们都用ID,是不是很快。但是我们不应该为了效率而牺牲可读性和可维护性。

#test p{ color:#999999}
正解:遍历是自右向左,也就是先查询到p元素,再找到上一级id为test的元素。

#main-navigation {   }      /* ID (最快) */
body.home #page-wrap {   }  /* ID */
.main-navigation {   }      /* Class */
ul li a.current {   }       /* Class *
ul {   }                    /* Tag */
ul li a {  }                /* Tag */
* {   }                     /* 通配 (最慢) */

关于浏览器加载css和js

当我们的浏览器获得html文件后,会自上而下的加载,并在加载过程中进行解析和渲染。
加载说的就是获取资源文件的过程,如果在加载的过程中,遇到外部css文件和图片,浏览器会另外发出一个请求,来获取css文件和相应的图片,这个请求是异步的,并不会影响html文件
但是如果遇到javascript文件,html文件会挂起渲染的线程,等待javascript加载完毕后,html文件再继续渲染。

为什么html需要等待javascript呢?

因为javascript可能会修改DOM,导致后续的html资源白白加载,所以html必须等待javascript文件加载完毕后,再继续渲染。这也就是为什么javascript文件要写在底部body标签前的原因。

css,js会影响dom吗?

首先必须明白浏览器从获取到代码到页面展示过程发生了什么,首先是解析DOM,生成DOM树,解析CSS文件,生成CSS树,然后DOM树和DOM树合并生成渲染树,再渲染生成页面。 结论1:由于DOM解析和CSS解析是分开的,所以CSS文件并不会阻塞DOM的解析。

页面渲染需要DOM树和DOM树合并生成渲染树,所以CSS文件会阻塞页面渲染。 结论2:CSS文件会阻塞页面渲染。

对于JS,首先要知道JS是单线程执行的,JS可以对DOM的结构进行操作,比如删除、修改、新增dom。所以遇到JS文件,页面会停止DOM解析,如果不停止DOM解析,即一边执行JS,一边解析DOM,解析完DOM之后,发现JS修改了DOM结构,那么之前解析的DOM不就白费了吗?浏览器才不会这么傻呢?所以 结论3:遇到JS文件,页面会停止DOM解析

JS文件还会去读取CSS,所以执行JS还必须等到CSS文件解析完之后,这就相等与CSS文件阻塞了JS 结论4:CSS文件会阻塞JS

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值