ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
## 基于渲染流程的 CSS 优化建议 ### 8.3.1 CSS 选择符是从右到左进行匹配的 ~~~ #myList li {} ~~~ 浏览器必须遍历页面上每个 li 元素,并且每次都要去确认这个 li 元素的父元素 id 是不是 myList ### 8.3.2 具体优化 1. 避免使用通配符,只对需要用到的元素进行选择 2. 关注可以通过继承实现的属性,避免重复匹配重复定义。 3. 少用标签选择器。如果可以,用类选择器替代 4. 不要画蛇添足,id 和 class 选择器不应该被多余的标签选择器拖后腿 5. 减少嵌套。后代选择器的开销是最高的,因此我们应该尽量将选择器的深度降到最低(最高不要超过三层),尽可能使用类来关联每一个标签元素 ## 8.4 告别阻塞:CSS 与 JS 的加载顺序优化 HTML、CSS 和 JS,都具有阻塞渲染的特性。 HTML 阻塞,天经地义——没有 HTML,何来 DOM?没有 DOM,渲染和优化,都是空谈。 ### 8.4.1 CSS 的阻塞 在刚刚的过程中,我们提到 DOM 和 CSSOM 合力才能构建渲染树。这一点会给性能造成严重影响:默认情况下,CSS 是阻塞的资源。浏**览器在构建 CSSOM 的过程中,不会渲染任何已处理的内容。即便 DOM 已经解析完毕了,只要 CSSOM 不 OK,那么渲染这个事情就不 OK**(这主要是为了避免没有 CSS 的 HTML 页面丑陋地“裸奔”在用户眼前)。 **只有当我们开始解析 HTML 后、解析到 link 标签或者 style 标签时,CSS 才登场,CSSOM 的构建才开始**。很多时候,DOM 不得不等待 CSSOM。因此我们可以这样总结: > CSS 是阻塞渲染的资源。需要将它尽早、尽快地下载到客户端,以便缩短首次渲染的时间。 尽早(将 CSS 放在 head 标签里)和尽快(启用 CDN 实现静态资源加载速度的优化) ### 8.4.2 JS 的阻塞 **JS 的作用在于修改**,它帮助我们修改网页的方方面面:内容、样式以及它如何响应用户交互。这“方方面面”的修改,本质上都是对 DOM 和 CSSDOM 进行修改。因此 JS 的执行会阻止 CSSOM,在我们不作显式声明的情况下,它也会阻塞 DOM。 **JS 引擎是独立于渲染引擎存在的**。我们的 JS 代码在文档的何处插入,就在何处执行。当 HTML 解析器遇到一个 script 标签时,它会暂停渲染过程,将控制权交给 JS 引擎。JS 引擎对内联的 JS 代码会直接执行,对外部 JS 文件还要先获取到脚本、再进行执行。等 JS 引擎运行完毕,浏览器又会把控制权还给渲染引擎,继续 CSSOM 和 DOM 的构建。 因此与其说是 JS 把 CSS 和 HTML 阻塞了,不如说是 JS 引擎抢走了渲染引擎的控制权。 ### 8.4.3 JS的三种加载方式 **正常模式** 这种情况下 JS 会阻塞浏览器,浏览器必须等待 index.js 加载和执行完毕才能去做其它事情。 ~~~ <script src="index.js"></script> ~~~ **async(异步) 模式** async 模式下,JS 不会阻塞浏览器做任何其它的事情。它的加载是异步的,当它加载结束,JS 脚本会立即执行。 ~~~ <script async src="index.js"></script> ~~~ **defer(延缓) 模式** efer 模式下,JS 的加载是异步的,执行是被推迟的。等整个文档解析完成、DOMContentLoaded 事件即将被触发时,被标记了 defer 的 JS 文件才会开始依次执行。 ~~~ <script defer src="index.js"></script> ~~~ 从应用的角度来说,一般当我们的脚本与 DOM 元素和其它脚本之间的依赖关系不强时,我们会选用 async;当脚本依赖于 DOM 元素和其它脚本的执行结果时,我们会选用 defer。