烟消火灭网

浏览器拿到一段HTML字符串,不会直接把它变成你看到的页面。中间隔着一个叫“编译”的过程——虽然很多人更习惯叫它“解析”或“渲染”。 我最早意识到这件事,是写了一个 `` 标签却忘了闭合。页面没报错,

html编译

浏览器拿到一段HTML字符串,编译不会直接把它变成你看到的编译页面。中间隔着一个叫“编译”的编译过程——虽然很多人更习惯叫它“解析”或“渲染”。

我最早意识到这件事,编译是编译写了一个 `

` 标签却忘了闭合。页面没报错,编译但后面的编译所有元素都莫名其妙缩进了那个div里。打开开发者工具一看,编译浏览器已经自作主张帮我补上了 `
`,编译位置却不是编译我想要的。那一刻我才明白:浏览器不是编译老老实实读你的代码,它在“理解”你的编译代码。

从字符到树

HTML编译的编译第一步,是编译把一堆字节变成一棵树。听起来抽象,编译拆开看很具体。

网络传过来的HTML是一串字节。浏览器先按编码(通常是UTF-8)把它们转成字符,再把字符按标签规则切成一个个“词”——`

` 是一个词,`class="intro"` 是一个词,`>` 也是一个词。这个过程叫词法分析。接着语法分析上场,把这些词拼成节点:元素节点、文本节点、注释节点。遇到 `

` 就新建一个元素节点,遇到文字就挂一个文本节点上去。

但HTML不是编程语言,它没有严格的语法。你少写一个闭合标签,浏览器不会罢工。它有一套容错规则,比如 `

` 里面不能再套 `

`,遇到嵌套它会自动闭合前一个。这些规则写在HTML规范里,每个浏览器都得遵守。所以同一段“烂代码”在Chrome和Firefox里渲染出来基本一样,不是巧合。

DOM树不是终点

解析完,你得到一棵DOM树。但DOM树只描述了结构,不知道每个节点长什么样、放在哪里。样式计算紧接着开始。浏览器把CSS规则和DOM节点匹配,算出每个节点最终的颜色、字号、边距。这一步有个细节:选择器是从右往左匹配的。`.nav li a` 会先找到所有 ``,再往上查父级是不是 `

  • `,再往上是不是 `.nav`。这样设计是为了尽早排除不匹配的节点,速度更快。

    样式算完,进入布局阶段。浏览器遍历DOM树,计算每个盒子在屏幕上的确切位置和尺寸。这里有个容易踩的坑:如果你在JS里先读 `offsetHeight` 再改样式,再读一次,浏览器会强制同步布局两次。性能就是这么掉的。

    绘制与合成

    布局之后是绘制。浏览器把每个节点画成像素,填充颜色、边框、阴影、文字。但绘制不是直接画到屏幕上,而是分成多个图层。比如一个带动画的元素会被提升为独立图层,由GPU单独合成。这就是为什么 `transform` 动画比 `left` 动画流畅——前者只触发合成,后者要重新布局和绘制。

    最后,合成器把各图层按正确顺序拼起来,输出到屏幕。你看到页面了。

    一个真实的观察

    我做过一个测试:一个包含5000个 `

    ` 的页面,如果每个div都设置不同的 `box-shadow`,滚动会明显卡顿。打开Chrome的Performance面板,发现绘制时间占了帧时间的一大半。把阴影改成 `border` 或纯色背景后,帧率立刻回到60fps。这说明编译过程中的每一步都有成本,而成本往往藏在你不注意的样式属性里。

    HTML编译不是“把代码变成页面”这么简单。它是一连串决策:容错、匹配、计算、分层。浏览器替你做了很多选择,有些是规范要求的,有些是性能权衡。理解这些,你写HTML时就会少一点“为什么没生效”的困惑,多一点“我知道它接下来会做什么”的笃定。

  • 访客,请您发表评论:

    © 2026. sitemap