重学前端 - 浏览器部分-工作流程-css渲染

概述

浏览器使用 HTTP 协议或者 HTTPS 协议,向服务端请求页面的过程。今天我们主要来看阶段二:如何解析请求回来的 HTML 代码,DOM 树又是如何构建的。

解析代码

HTML 的结构不算太复杂,我们日常开发需要的 90% 的“词”(指编译原理的术语 token,表示最小的有意义的单元),种类大约只有标签开始、属性、标签结束、注释、CDATA 节点几种。

构建 DOM 树

接下来我们要把这些简单的词变成 DOM 树,这个过程我们是使用栈来实现的,(JavaScript 中的栈只要用数组就可以)。
构建 DOM 树的流程大致如下:

  1. 栈顶元素就是当前节点;
  2. 遇到属性,就添加到当前节点;
  3. 遇到文本节点,如果当前节点是文本节点,则跟文本节点合并,否则入栈成为当前节点的子节点;
  4. 遇到注释节点,作为当前节点的子节点;
  5. 遇到 tag start 就入栈一个节点,当前节点就是这个节点的父节点;
  6. 遇到 tag end 就出栈一个节点(还可以检查是否匹配)。

css的渲染

上述 DOM 的构建过程中,实际上信息是不全的,它只有节点和属性,不包含任何的样式信息。

首先要理解CSS 规则是 DOM 树构建好了以后,再进行选择并给它添加样式的。实际上,这个过程并不是这样的。

构建 DOM 的过程是:从父到子,从先到后,一个一个节点构造,并且挂载到 DOM 树上的,在这个过程中,我们依次拿到上一部构造好的元素,去检查它匹配到了哪些规则,再根据规则的优先级,做覆盖和调整。(所谓的选择器,应该被理解成“匹配器”才更合适。)

目前css选择器的各种符号如下:

空格: 后代,选中它的子节点和所有子节点的后代节点。
>: 子代,选中它的子节点。
+:直接后继选择器,选中它的下一个相邻节点。
~:后继,选中它之后所有的相邻节点。
||:列,选中表格中的一列。

CSS选择器的出现顺序,必定跟构建 DOM 树的顺序一致。这是一个 CSS 设计的原则,即保证选择器在 DOM 树构建到当前节点时,已经可以准确判断是否匹配,不需要后续节点信息。这就决定未来也不可能会出现“父元素选择器”这种东西,因为父元素选择器要求根据当前节点的子节点,来判断当前节点是否被选中,而父节点会先于子节点构建。