新的思考.
- CSS和JS在网页中的放置顺序
- 白屏和FOUC
- async和defer的作用和区别
- 网页的渲染机制
CSS和JS在网页中的放置顺序
通常情况,人们都会在
<head></head>
(Html头部位置)里面以<link>
来引入** Css **文件...** JavaScript **则不同,视情况而定:
通常的做法是将 JavaScript 代码放置在 HTML 文档的<head></head>
标签之间。因为 HTML 文档是由浏览器从上到下依次载入的,所以将 JavaScript 代码放置于<head></head>
标签之间,可以确保在需要使用脚本之前,已经被载入(最佳做法:只放置呈现页面效果实现类的 javascript)。
另一种方法:将 JavaScript 代码放置于 <body></body> 之间的。这样做的目的,是考虑到如果我们有一段 JavaScript 代码需要操作(动作、交互等) HTML 元素。但由于 HTML 文档是由浏览器从上到下依次载入的,为避免 JavaScript 代码操作 HTML 元素时,HTML 元素还未载入而报错(对象不存在),因此需要将这段代码写到 HTML 元素后面。
另外,运用得最多的一种,是引用外部 script 的使用...跟引入外部 css 一个道理。
- 引用好处:
- 便于管理..
- 避免在 JavaScript 代码里使用
- 避免使用难看的 CDATA
- 公共的 JavaScript 代码可以被复用于其他 HTML 文档,也利于 JavaScript 代码的统一维护
- HTML 文档更小,利于搜索引擎收录
- 可以压缩、加密单个 JavaScript 文件
- 浏览器可以缓存 JavaScript 文件,减少宽带使用(当多个页面同时使用一个 JavaScript 文件的时候,通常只需下载一次)
- 避免使用复杂的 HTML 实体,如可以直接使用 document.write(2>1) 而无需写作 document.write(2<1)
将 JavaScript 代码形成为外部文件,也会增加服务器的 HTTP 请求负担,在超高并发请求的环境下,这并不是一个好的策略。另外 在引用外部 js 文件时,需注意文件的正确路径。
- 加载异步:
<script defer src="script.js"></script>
<script async src="script.js"></script>
defer和asnyc是脚本异步加载的两种方式。
defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。
async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。
白屏和FOUC
白屏和FOUC(无样式内容闪烁)的产生主要与浏览器的渲染机制有关,有的浏览器是等待html和css全部加载完成后再进行渲染(白屏问题),有的浏览器是先显示已加载的html内容,等到css加载完成后重新对内容添加样式(FOUC问题)
白屏的产生
白屏的产生有三种情况:将css文件放在html文档的最后、使用@import引入css(因为通过@import引入的css文件会被最后加载,因此也会导致白屏)或者将js文件放在头部,而未使用defer或async延迟或异步加载js文件,导致js阻塞html和css的加载原理分析:
对于-webkit内核的浏览器(IE也会产生),在进行网页渲染时,会同时加载html和css分别构建DOM树和CSSOM,等两者都构建完成后,再绘制渲染树,然后将页面显示出来。如果在html中将css文件放置在文档最后,那么将会导致CSSOM晚于DOM树的建立,浏览器需要等待CSSOM建立,然后才进行网页内容的绘制,这个等待的过程,没有内容显示,就导致了白屏的产生,因此在开发中,需要将CSS放在head标签内,让其与html内容同时被加载。FOUC的产生
主要是由于浏览器先显示已加载的html内容,等到css加载完成后重新对内容添加样式导致的,主要代表有Firefox
async和defer的作用和区别
<pre><script src="script.js"></script>
</pre>
- 没有 defer 或 async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。
<script async src="script.js"></script>
- 有 async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。
<script defer src="myscript.js"></script>
- 有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。
然后从实用角度来说呢,首先把所有脚本都丢到 </body> 之前是最佳实践,因为对于旧浏览器来说这是唯一的优化选择,此法可保证非脚本的其他一切元素能够以最快的速度得到加载和解析。
网页的渲染机制
浏览器会解析这么三个东西:
一个是HTML/SVG/XHTML,解析他们会产生DOM tree
CSS文件,构建CSS Rule Tree(产生CSSOM:CSS object Model)
JavaScript脚本,主要通过DOM API 和CSSOM API来操作DOM树和CSS Rule Tree解析完成后,会通过DOM Tree和CSS Rule Tree来构建
Rendering Tree,注意:Rendering Tree并不等同于DOM Tree,因为像header和display:none相关的东西就没有必要放在Rendering 渲染树中了
CSS Rule Tree主要是为了将CSS Rule添加到Rendering Tree中的每一个element中,也就是DOM节点
然后计算每个DOM节点的位置,这个过程叫做layout
最后将页面绘制出来,呈现引擎会遍历Rendering Tree,由用户界面后端层将每个节点绘制出来。