1态辛、CSS和JS在網(wǎng)頁中的放置順序是怎樣的麸澜?
(1)CSS
對于谷歌瀏覽器和Safari放在head
里或body
里都一樣。因為它是在全部的樣式表完全加載下來之后才開始渲染頁面奏黑,將內(nèi)容呈現(xiàn)在頁面上炊邦。
對于Firefox,head
標(biāo)簽中的<link rel="stylesheet">
行為與Chrome/Safari中完全一致熟史,這些link
標(biāo)簽全部加載完成之前馁害,頁面上不顯示內(nèi)容。而body
標(biāo)簽中的<link rel="stylesheet">
則不阻塞任何內(nèi)容顯示蹂匹,會出現(xiàn)FOUC無樣式內(nèi)容閃爍碘菜。
對于IE/Edge。未加載完成的<link rel="stylesheet">
標(biāo)簽只阻塞其后面的HTML內(nèi)容顯示,而對其前面的HTML內(nèi)容則不阻塞忍啸,所以如果將CSS放在前面head里則和Chrome一樣仰坦,如果放body里則會出現(xiàn)FOUC無樣式內(nèi)容閃爍。
綜上:如果你想讓頁面不閃爍放在head里计雌,如果你想讓頁面不白屏放在body里悄晃。
(2)JS
如果JS文件很小放在前面head里或后邊body閉合標(biāo)簽之前都可以。如果JS文件很大則應(yīng)該放在后面body的閉合標(biāo)簽之前凿滤。
因為在加載 JavaScript時會阻止其他內(nèi)容的下載妈橄,要等到JS文件下載解析完之后才會顯示網(wǎng)頁內(nèi)容。若JS文件很大放在前面就會導(dǎo)致加載時間較長鸭巴,網(wǎng)頁會一直白屏眷细。還有一個原因是因為JS一般會涉及到一些DOM操作,所以要等全部的dom元素都加載完再加載JS鹃祖。
2.為何出現(xiàn)白屏問題與FOUC無樣式內(nèi)容閃爍溪椎?
不同的瀏覽器對于CSS和HTML的處理方式不同,有的是等待CSS加載完成之后恬口,對HTML元素進(jìn)行渲染和展示(白屏問題)校读。有的是先對HTML元素進(jìn)行展示,然后等待CSS加載完成之后重新對樣式進(jìn)行修改(FOUC無樣式內(nèi)容閃爍)
Firefox祖能、Opere在加載樣式表的時候是邊加載邊渲染歉秫。這樣既有利也有弊:利在使得頁面可以盡快的開始渲染,而無須等待全部的樣式表都加載下來之后再開始渲染养铸;而弊端在于之前加載并渲染的樣式在后面又重新定義或者修改了布局樣式雁芙,那么將會造成一定程度上的閃爍(FOUC, 即钞螟, Flash of Unstyled Content兔甘,無樣式內(nèi)容閃爍),閃爍的程度主要看所 影響的元素的范圍和數(shù)目鳞滨。
而IE洞焙、Chrome、Safari則是在全部的樣式表完全加載下來之后才開始渲染頁面樣式將內(nèi)容呈現(xiàn)在頁面上拯啦,沒下載完之前頁面是空白的澡匪。這樣做也同樣是有利有弊:利在于可以避免 Firefox、Opera中出現(xiàn)的閃爍的問題(雖然在IE下閃爍是經(jīng)常的事情)褒链,可以確保樣式會統(tǒng)一解析并渲染頁面唁情;而弊端在于頁面全部樣式表的加載延遲了頁面渲染的時間,如果樣式表加載的時間較長甫匹,或者加載錯誤荠瘪,將會導(dǎo)致頁面一直處于空白狀態(tài)或者無樣式狀態(tài)夯巷。
導(dǎo)致白屏的原因:
樣式文件放在底部,對于IE瀏覽器哀墓,在某些場景下(新窗口打開,刷新等)頁面會出現(xiàn)白屏
使用 @import 標(biāo)簽, 即使 CSS 放入 link, 并且放在頭部,也可能出現(xiàn)白屏
把 JavaScript 放入頁面頂部也會導(dǎo)致白屏現(xiàn)象趁餐,在加載 JavaScript 時,會禁用并發(fā),并且阻止其他內(nèi)容的下載
導(dǎo)致FOUC的原因 :
- 把樣式放在底部,對于IE瀏覽器,在某些場景下(點擊鏈接,輸入URL,使用書簽進(jìn)入等),會出現(xiàn) FOUC 現(xiàn)象(逐步加載無樣式的內(nèi)容,等CSS加載后頁面突然展現(xiàn)樣式)。對于 Firefox 會一直表現(xiàn)出 FOUC 篮绰。
總結(jié):白屏問題與FOUC無樣式內(nèi)容閃爍只能二選一后雷,不可避免。
3吠各、async和defer的作用是什么臀突?有什么區(qū)別
1.<script src="script.js"></script>
沒有 defer 或 async,瀏覽器會立即加載并執(zhí)行指定的腳本贾漏,“立即”指的是在渲染該 script 標(biāo)簽之下的文檔元素之前候学,也就是會打斷后面HTML的解析,只有等該腳本執(zhí)行完成后纵散,瀏覽器才繼續(xù)解析后面的HTML文檔元素梳码。
2.<script defer src="myscript.js"></script>
有 defer,加載后續(xù)文檔元素的過程將和 script.js 的加載并行進(jìn)行(異步)伍掀,但是 script.js 的執(zhí)行要在所有元素解析完成之后掰茶,DOMContentLoaded 事件觸發(fā)之前完成。
3.<script async src="script.js"></script>
有 async蜜笤,加載和渲染后續(xù)文檔元素的過程將和 script.js 的加載與執(zhí)行并行進(jìn)行(異步)濒蒋。
然后從實用角度來說呢,首先把所有腳本都丟到 </body> 之前是最佳實踐把兔,因為對于舊瀏覽器來說這是唯一的優(yōu)化選擇沪伙,此法可保證非腳本的其他一切元素能夠以最快的速度得到加載和解析。
下圖可以非常好的表示這個過程的差別县好,其中:藍(lán)色線代表網(wǎng)絡(luò)讀取围橡,紅色線代表執(zhí)行時間,這倆都是針對腳本的聘惦;綠色線代表 HTML 解析。
上圖告訴我們以下幾個要點:
defer 和 async 在網(wǎng)絡(luò)讀饶琶取(下載)這塊兒是一樣的浦马,都是異步的(相較于 HTML 解析)
它倆的差別在于腳本下載完之后何時執(zhí)行灵寺,顯然 defer 是最接近我們對于應(yīng)用腳本加載和執(zhí)行的要求的
關(guān)于 defer,此圖未盡之處在于它是按照加載順序執(zhí)行腳本的禀酱。defer表示腳本可以延遲到文檔完全被解析和顯示之后在執(zhí)行。defer和async都是只對外部js腳本有效牧嫉,對嵌入腳本無效剂跟。
async 則是一個亂序執(zhí)行的主减途,反正對它來說腳本的加載和執(zhí)行是緊緊挨著的,所以不管你聲明的順序如何曹洽,只要它加載完了就會立刻執(zhí)行鳍置。async表示應(yīng)該立即下載腳本,但不妨礙頁面中的其他操作送淆,比如下載其他資源或等待加載其他腳本税产。
仔細(xì)想想,async 對于應(yīng)用腳本的用處不大偷崩,因為它完全不考慮依賴(哪怕是最低級的順序執(zhí)行)辟拷,不過它對于那些可以不依賴任何腳本或不被任何腳本依賴的腳本來說卻是非常合適的,最典型的例子:Google Analytics.
4.簡述網(wǎng)頁的渲染機(jī)制
(1) 解析 HTML 標(biāo)簽, 構(gòu)建 DOM 樹
(2) 解析 CSS 標(biāo)簽, 構(gòu)建 CSSOM 樹
(3) 把 DOM 和 CSSOM 組合成 渲染樹 (render tree)
(4) 在渲染樹的基礎(chǔ)上進(jìn)行布局, 計算每個節(jié)點的幾何結(jié)構(gòu)
(5)把每個節(jié)點繪制到屏幕上 (painting)