跳至主要內容

浏览器

JowayYoung前端图形玩转CSS艺术之美大约 11 分钟约 3238 字

浏览器

渲染引擎

渲染引擎又名浏览器内核,指负责对网页语法解析并渲染成一张可视化页面的解析器。它是浏览器最核心最重要的部位,不同内核对网页语法的解析也有不同,因此同一网页语法在不同内核的浏览器中的渲染效果也可能不同,这就是常说的浏览器差异性

上述提到的世界五大浏览器,在自身的发展过程中都使用了一种或多种浏览器内核作为自身的渲染引擎。

  • Google Chrome:Webkit(前期)、Blink(后期)
  • Apple Safari:Webkit
  • Mozilla Firefox:Gecko
  • ASA Opera:Presto(前期)、Blink(后期)
  • Microsoft IExplorer:Trident
  • Microsoft Edge:Trident(前期)、Blink(后期)

IExplorerEdge同是微软公司开发的浏览器产品,鉴于IExplorer存在很多为人诟病的问题,在后续的系统升级中逐渐使用Edge取代IExplorerWindows上的位置

因此 20 多年的浏览器发展史里,被大规模使用的浏览器内核也就这五个。

  • Blink 内核:由谷歌公司和欧朋公司合作自研的内核,同时谷歌公司也将其作为开源内核架构Chromium的一部分发布,在Chrome 28+Opear 15+中被使用。
  • Webkit 内核:由苹果公司自研的内核,同时也是Blink内核的原型,在Chrome 1 ~ 28Safari 1+中被使用。
  • Gecko 内核:由网景公司自研的内核,先期在Navigator中使用,后期推广到Firefox上,在Firefox 1+中被使用。
  • Presto 内核:由欧朋公司自研的内核,其渲染性能达到极致但牺牲了兼容性,目前已经废弃,在Opear 7 ~ 14中被使用。
  • Trident 内核:由微软公司自研的内核,由于其被包含在全世界使用率最高的Windows操作系统中,导致十多年时间里一直称霸浏览器内核界,在IExplorer 4+中被使用。

渲染过程

要了解浏览器页面的渲染过程,首先得知道关键渲染路径。关键渲染路径指浏览器从最初接收请求得到 HTMLCSSJS 等资源,然后解析、构建、渲染、布局、绘制、合成,到最后呈现在用户眼前界面的整个过程

将关键渲染路径划分理解,那网页的渲染过程可分为以下部分:

  1. 解析文件
  • html 文件转换为 DOM
  • css 文件转换为 CSSOM
  • DOM 树和 CSSOM 树合并生成渲染树
  1. 绘制图层
  • 根据渲染树生成布局渲染树(回流)
  • 根据布局渲染树生成绘制渲染树(重绘)
  1. 合成图层:根据 绘制渲染树 合成 图层 显示在屏幕上

解析文件

HTML描述网页的结构,浏览器通过HTML解析器将 HTML 解析成DOM树结构。HTML 中所有内容皆为节点,各节点间拥有层级关系,彼此相连,构成 DOM

构建DOM树的过程:读取 HTML 的字节Bytes,将字节转换成字符Chars批注:在计算机屏幕上看到的是实体化的文字,而在计算机存储介质中存放的实际是二进制的比特流。 那么在这两者之间的转换规则就需要一个统一的标准,各种字符集标准就出现了 依据字符确定标签Tokens,将标签转换成节点Nodes,以节点为基准构建DOM 树

DOM树构建过程
DOM树构建过程

CSS 文档描述网页的表现,浏览器通过 CSS 解析器将 CSS 解析成 CSSOM 树结构,与 DOM 树结构比较像。CSS 中所有内容皆为节点,与 HTML 中的节点一一对应,各节点间拥有层级关系,彼此相连,构成 CSSOM

构建 CSSOM 树的过程:读取 CSS 文档的字节Bytes,将字节转换成字符Chars,依据字符确定标签Tokens,将标签转换成节点Nodes,以节点为基准构建 CSSOM 树。与 DOM 树的构建过程完全一致

CSSOM树结构
CSSOM树结构

::: tip 扩展阅读

CSS 对象模型 CSSOM 是什么?open in new window

Constructing the Object Modelopen in new window

:::

在构建 DOM 树的过程中,当HTML解析器遇到<script>时会立即阻塞 DOM 树的构建,将控制权移交给浏览器的JS引擎,等到JS引擎运行完毕,浏览器才会从中断的地方恢复 DOM 树的构建。<script>的脚本加载完毕,JS引擎通过DOM APICSSOM API操作 DOM 树和 CSSOM 树。为何会产生渲染阻塞呢?其根本原因在于:JS 操作 DOM 后,浏览器无法预测未来 DOM 的具体内容,为了防止无效操作和节省资源,只能阻塞 DOM 树的构建

解析文件
解析文件

浏览器的渲染引擎将 DOM 树和 CSSOM 树合并生成渲染树,只渲染需显示的节点及其样式。DOM 树CSSOM 树渲染树三者的构建并无先后条件先后顺序,并非完全独立而是存在交叉并行构建的情况。因此会形成一边加载,一边解析,一边渲染的工作现象

绘制图层

进入绘制阶段,遍历渲染树,调用渲染器的paint()在屏幕上绘制内容。根据 渲染树布局计算样式,即每个节点在页面中的布局、尺寸等几何属性。HTML 默认是流式布局,CSSJS 会打破这种布局,改变 DOM 的几何属性和外观属性。在绘制过程中,根据渲染树布局,再根据布局绘制,这就是常听常说的回流重绘

在此涉及到两个核心概念:回流重绘。笔者用两句精简的话分别概括它们。

  • 回流:几何属性需改变的渲染
  • 重绘:更改外观属性而不影响几何属性的渲染

当生成渲染树后,至少会渲染一次。在后续交互过程中,还会不断地重新渲染。这时只会回流重绘或只有重绘。因此引出一个定向法则:回流必定引发重绘,重绘不一定引发回流

在下一章中,笔者会安排整章篇幅讲述回流重绘以及如何让回流重绘的影响最小化。相信下一章提及的属性排序应该较少同学了解过或使用过,敬请期待。

合成图层

将回流重绘生成的图层逐张合并并显示在屏幕中。上述几个步骤并非一次性顺序完成,若改动DOM/CSSOM,上述过程会被重新执行,实际上CSSJS往往会多次改动DOM/CSSOM。简而言之,用户的交互操作引发了网页的重渲染。

兼容性

兼容性又名网站兼容性或网页兼容性,指网页在各种浏览器上的显示效果可能不同而产生浏览器和网页间的兼容问题

说到兼容性,就不得不推荐一个专门为前端开发者定制可查询CSS/JS特性在各种浏览器中兼容性的网站Caniuseopen in new window,它可很好地保障网页在不同浏览器间的兼容性。有了这个工具可快速地了解使用到的代码在各个浏览器中的效果

产生浏览器间的兼容问题,正是上述谈到的渲染引擎而导致的。在网站的设计和开发中,做好浏览器兼容才能让网站在不同浏览器间都能显示正常。浏览器对标准的更好兼容能够给用户带来更好的使用体验,当然无法奢求浏览器厂商能统一所有浏览器标准,所以前端开发者只能自己着手解决

以下聊聊处理 CSS 兼容性的三种方式,相对处理 JS 兼容性来说简单到不得了,这也是普遍前端开发者认为 CSS 简单的原因之一

磨平浏览器默认样式

每个浏览器的 CSS 默认样式不尽相同,所以最简单最有效的方式就是对其默认样式初始化。以下贴一个各位同学都会的初始化代码。简单暴力但不明确,*通配符可是有执行性能问题的。

* {
  margin: 0;
  padding: 0;
}

以下推荐两种磨平浏览器默认样式的方式,在接入其他css文件前将其导入,天下太平,大家都不能拼爹了,都是在同一起跑线上,IExplorer同学你可别抢跑哇,大家都盯着你呢!

normalize.css:懒人必备的浏览器默认样式库,接近40k的 Star,说明大部分人都是懒人 reset.css:其实就是笔者自定义的默认样式,各位同学也可自行为项目撰写一份默认样式

在项目入口文件的其他css文件前导入:

import 'path/to/normalize.css';
// 或
import 'path/to/reset.css';

插入浏览器私有属性

通常编写 CSS 都会在一些 CSS3 属性前加入-webkit--moz--ms--o-,这些奇形怪状写到手软的东西就是浏览器私有属性。样式少还好,样式多那就欲哭无泪了 😂。

出现这些私有属性,是因为制定 CSS 标准的 W3C 其动作就像蜗牛一样慢,量产一个属性是需走一个很严格很复杂的流程。一个成熟且被大众肯定的属性,浏览器厂商会加大其支持力度而铺路,但为了避免日后 W3C 公布标准时有所变更,就加入一个本厂商的私有属性提前支持该属性,待 W3C 公布该属性标准后,再让新版浏览器支持标准属性。

对于编写私有属性的顺序需特别注意:兼容性写法放到前面,标准写法放到最后。在浏览器解析 CSS 过程中,若标准属性无法使用则使用当前浏览器对应的私有属性。

/* Chrome、Safari、New Opera、New Edge */
-webkit-transform: translate(10px, 10px);
/* Firefox */
-moz-transform: translate(10px, 10px);
/* IExplorer、Old Edge */
-ms-transform: translate(10px, 10px);
/* Old Opera */
-o-transform: translate(10px, 10px);
/* 标准 */
transform: translate(10px, 10px);

当然不是所有的 CSS3 属性都需补齐-webkit--moz--ms--o-,上述 Demo 只是一个示例,真正的transform私有属性只有-webkit--ms-。这些需查看Caniuse确保正确的编写,若想偷懒也可全部写上

每个 CSS3 属性都编写这么一堆兼容性代码,无疑是对生命最大的浪费。在使用 Webpack 打包项目代码的过程中,可接入postcss-loaderopen in new windowpostcss-preset-envopen in new windowpostcss-preset-env内置了autoprefixer,它会依据Caniuse所提供的数据对代码里的 CSS3 属性批量添加私有属性

批注:vue-cli 脚手架项目已内置 autoprefixer;vite 内置了 postcss,但没有内置 autoprefixer,究其原因 vue-cli 是脚手架工具而非打包工具,它是更上层的应用,vite 是打包工具

CSS Hack

CSS Hack指针对不同浏览器编写不同 CSS,让它能够同时兼容不同浏览器,在不同浏览器中渲染想要的效果。当然也可反过来利用CSS Hack为不同版本的浏览器定制不同效果。

在一些老旧网站的html文件css文件里可能会看到以下代码,没错,这就是CSS Hack。现在可能很多同学都不会遇到这种写法,毕竟很多公司的产品都放弃了IExplorer 8以下的兼容,这些痕迹都已经成为历史。很多同学没想过 5 年到 10 年前的前端开发者是多么苦逼的,光兼容IExplorer就已经够烦了,还连续兼容几个版本。

<head>
  <!--[if IE]>
    <style>
      .elem {
        background-color: #f66;
      }
    </style>
  <![endif]-->
</head>
.elem { background-color: #f66; /* IExplorer 8+ */ *background-color: #f66; /* IExplorer 7 */ _background-color: #f66;
/* IExplorer 6 */ }

所以现在也不会推荐去学习这些CSS Hack,有一个基本的了解即可。上述CSS Hack写法只是最简单的几行代码,其实还存在一些更难的表达式。当然也不推荐这种写法,毕竟不符合大名鼎鼎的雅虎军规Avoid CSS Expressions

上次编辑于: