這張主要分5個環節尋行漸近的回答,分別是【什麼是DOCTYPE及作用】、【瀏覽器渲染過程】、【重繪Reflow】、【重繪Repaint】,很多都是直接通過本人用大白話講。
一、什麼是DOCTYPE及作用
1.DTD(文檔類型定義):DTD就是告訴瀏覽器我是什麼類型,瀏覽器根據這個判斷用什麼來解析渲染它。而DOCTYPE就是告訴瀏覽器是哪個DTD(文檔類型)
比如:
① h5方式的,<!DOCTYPE html>,其中html就是DTD的其中一種類型
②HTML4.01 Strict(記住這個就行,下面太長記不住)
<!DOCTYPE HTMLPUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
③傳統模式 Transitional(記住這個就行,下面太長記不住)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
二、瀏覽器渲染過程
我們來看一張圖
我們介紹流程:
①首先HTML通過HTML解析器變成DOM Tree。
②樣式表通過css解析器變成CSS Rules Tree。
③DOM Tree 與CSS Tree 合併成爲Render Tree
④ Layout佈局Render Tree
⑤Painting繪製Render Tree
一些重要的概念:
DOM Tree:瀏覽器將HTML解析成樹形的數據結構。
CSS Rule Tree:瀏覽器將CSS解析在樹形的數據結構.
Render Tree:DOM和CSSOM(CSS Object Model:CSS對象模型)合併後生成Render Tree.
layout:有了Render Tree,瀏覽器已經能知道網頁中有哪些節點,各個節點的CSS的定義以及他們的從屬關係,從而去計算出每個節點的屏幕中的位置.
painting:按照算出來的規則,通過顯卡,把內容畫到屏幕上.
reflow(重繪):當瀏覽器發現某個部分發生了點變化影響了佈局,需要倒回去重新渲染,稱此爲回退的過程,叫reflow.reflow會從<html>這個root frame開始遞歸往下,依次計算所有的結點幾何尺寸和位置。feflow幾乎是無法避免的.
三、重排Reflow
repaint(重排):也叫回流,DOM結構中的各個元素都有自己的盒子(模型),這些都需要瀏覽器通過各種樣式計算結果將元素放到它該出現的位置,這個過程叫做重排。
怎麼會觸發重排:
- dom元素的位置和尺寸大小的變化
- dom元素的增加和刪除
- 僞類的激活
- 窗口大小的變化
- 增加和刪除class樣式
- 動態計算修改css樣式
當然,我們的瀏覽器不會每一次reflow都立刻執行,而是會積攢一批,這個過程也被成爲異步reflow,或者增量異步reflow。但是有些情況瀏覽器是不會這麼做的,比如:resize窗口,改變了頁面默認的字體,等。對於這些操作,瀏覽器會馬上進行reflow。
四、重繪Repaint
Repaint(重繪):指css樣式的改變,但元素的大小和尺寸不變,而導致節點的重新繪製。
怎麼樣子又會觸發重繪:
任何對元素樣式,如background-color
、border-color
、visibility
等屬性的改變。css 和 js 都可能引起重繪。
如何儘量減小重繪:
就是先生成DOM片段,然後一次性加入到這個節點。
代碼示例:
$('body').css('color', 'red'); // repaint
$('body').css('margin', '2px'); // reflow, repaint
var bstyle = document.body.style; // cache
bstyle.padding = "20px"; // reflow, repaint
bstyle.border = "10px solid red"; // 再一次的 reflow 和 repaint
bstyle.color = "blue"; // repaint
bstyle.backgroundColor = "#fad"; // repaint
bstyle.fontSize = "2em"; // reflow, repaint
// new DOM element - reflow, repaint
document.body.appendChild(document.createTextNode('dude!'));
注意點:
1.display:none的節點不會被加入Render Tree,而visibility:hidden則會,所以如果某個節點最開始是不顯示的,設爲display:none是最好的
參考文章:
https://segmentfault.com/a/1190000016458627#item-4