頁面重繪與回流

一.什么是頁面的重繪與回流

瀏覽器在渲染一個(gè)頁面的時(shí)候,從加載到完成柠座,首先是構(gòu)建DOM樹片橡,然后根據(jù)DOM節(jié)點(diǎn)的幾何屬性生成渲染樹(不包括display:none,head節(jié)點(diǎn)但是會(huì)包括visibility:hidden節(jié)點(diǎn)),當(dāng)渲染樹構(gòu)建完成吹泡,頁面就根據(jù)DOM樹開始布局了经瓷,渲染樹也根據(jù)設(shè)置的樣式對(duì)應(yīng)的渲染這些節(jié)點(diǎn)。在這個(gè)過程中揭朝,回流與dom樹和渲染樹有關(guān),重繪與渲染樹有關(guān)潭袱。

比如我們刪除一個(gè)dom節(jié)點(diǎn),修改一個(gè)元素的寬高编丘,這樣就會(huì)導(dǎo)致頁面的布局發(fā)生變化彤悔,DOM樹的結(jié)構(gòu)發(fā)生變化,引起dom樹的重構(gòu)晕窑,重構(gòu)完成之后就會(huì)導(dǎo)致渲染樹的重新渲染,這個(gè)過程就叫做回流

當(dāng)我們修改一個(gè)元素的顏色蓝丙,這并不會(huì)影響頁面的布局望拖,但是渲染樹會(huì)重新渲染頁面的樣式顏色,這就是重繪

回流的代價(jià)是遠(yuǎn)遠(yuǎn)大于重繪的鸥跟,回流一定導(dǎo)致重繪盔沫,但是重繪不一定導(dǎo)致回流。

二.常見的場景

回流常見于元素的尺寸架诞,布局,隱藏等Dom結(jié)構(gòu)發(fā)生改變的情況
1.添加或者刪除可見的dom元素
2.元素位置改變
3.元素尺寸改變(邊距很泊,填充沾谓,邊框,高度和寬度)
4.內(nèi)容改變(內(nèi)容物引起的元素大小發(fā)生變化)
5.頁面渲染初始化
6.瀏覽器尺寸改變
7.計(jì)算元素的偏移量屬性(瀏覽器為了確保屬性值的正確性會(huì)回流得到最新值昏兆,所以最好使用一個(gè)變量記錄一下)

重繪常見于元素的顏色的樣式發(fā)生改變的情況
1.改變字體
2.增加或者移除樣式表
3.內(nèi)容變化(input輸入框)
4.激活CSS偽類
5.設(shè)置style屬性值
6.計(jì)算offsetWidth和offsetHeight屬性

三.如何優(yōu)化瀏覽器的回流與重繪

1.將那些改變樣式的操作集合在一次完事妇穴,直接改變className或者cssText
  • 使用cssText
const el = document.getElementById('test'); 
el.style.cssText += 'border-left: 1px; border-right: 2px; padding: 5px;'; 
  • 修改CSS的class
const el = document.getElementById('test'); 
el.className += ' active'; 
2.讓要操作的元素進(jìn)行離線處理隶债,處理完事以后再一起更新

(1)使用DocumentFragment進(jìn)行緩存操作饮潦,引發(fā)一次回流和重繪
(2)使用display:none,只引發(fā)兩次回流和重繪。道理跟上面的一樣回俐。因?yàn)?strong>display:none的元素不會(huì)出現(xiàn)在render樹

function appendDataToElement(appendToElement, data) {
    let li;
    for (let i = 0; i < data.length; i++) {
        li = document.createElement('li');
        li.textContent = 'text';
        appendToElement.appendChild(li);
    }
}
const ul = document.getElementById('list');
ul.style.display = 'none';
appendDataToElement(ul, data);
ul.style.display = 'block';

(3)使用cloneNode和replaceChild技術(shù)稀并,引發(fā)一次回流和重繪(將原始元素拷貝到一個(gè)脫離文檔流的節(jié)點(diǎn)中,修改節(jié)點(diǎn)之后忘瓦,再替換原始元素)

const ul = document.getElementById('list');
const clone = ul.cloneNode(true);
appendDataToElement(clone, data);
ul.parentNode.replaceChild(clone, ul);
3.不要經(jīng)常訪問會(huì)引起瀏覽器flush隊(duì)列的屬性引颈,非要高頻訪問的話建議緩存到變量;
4.將需要多次重排的元素凌停,position屬性設(shè)為absolute或fixed售滤,這樣此元素就脫離了文檔流,它的變化不會(huì)影響到其他元素完箩。例如有動(dòng)畫效果的元素就最好設(shè)置為絕對(duì)定位;
5.盡量不要使用表格布局阻逮,如果沒有定寬秩彤,表格一列的寬度由最寬的一列決定,那么很可能在最后一行的寬度超出之前的列寬,引起整體回流造成table可能需要多次計(jì)算才能確定好其在渲染樹中節(jié)點(diǎn)的屬性慷蠕,通常要花3倍于同等元素的時(shí)間。
6.避免觸發(fā)同步布局事件

現(xiàn)代瀏覽器都會(huì)通過隊(duì)列化修改并批量執(zhí)行來優(yōu)化重排過程澎现。瀏覽器會(huì)將修改操作放入到隊(duì)列里,直到過了一段時(shí)間或者操作達(dá)到了一個(gè)閾值剑辫,才清空隊(duì)列。但是椎眯!當(dāng)你獲取布局信息的操作的時(shí)候胳岂,會(huì)強(qiáng)制隊(duì)列刷新,比如當(dāng)你訪問以下屬性或者使用以下方法:

  • offsetTop掌测、offsetLeft产园、offsetWidth、offsetHeight
  • scrollTop什燕、scrollLeft、scrollWidth仲义、scrollHeight
  • clientTop剑勾、clientLeft、clientWidth虽另、clientHeight
  • getComputedStyle()
  • getBoundingClientRect
function initP() {
    for (let i = 0; i < paragraphs.length; i++) {
        paragraphs[i].style.width = box.offsetWidth + 'px';
    }
}

改為

const width = box.offsetWidth;
function initP() {
    for (let i = 0; i < paragraphs.length; i++) {
        paragraphs[i].style.width = width + 'px';
    }
}

以上屬性和方法都需要返回最新的布局信息捂刺,因此瀏覽器不得不清空隊(duì)列,觸發(fā)回流重繪來返回正確的值族展。因此,我們?cè)谛薷臉邮降臅r(shí)候贵涵,最好避免使用上面列出的屬性,他們都會(huì)刷新渲染隊(duì)列宾茂。如果要使用它們,最好將值緩存起來

7.css3硬件加速欧聘,使用部分css3的屬性不會(huì)引發(fā)頁面的回流與重繪或者造成的影響比較小

四.瀏覽器渲染的過程

瀏覽器渲染過程

渲染過程大致如下:
1.解析HTML怀骤,生成DOM樹爱谁,解析CSS,生成CSSOM樹
2.將DOM樹和CSSOM樹結(jié)合访敌,生成渲染樹
3.回流(Layout):根據(jù)生成的渲染樹,進(jìn)行回流得到節(jié)點(diǎn)信息(位置爷抓,大凶杷堋)
4.重繪(Painting):根據(jù)渲染樹以及回流得到的幾何信息,得到節(jié)點(diǎn)的絕對(duì)像素
5.Display:將像素發(fā)送給GPU陈莽,展示在頁面上
生成渲染樹
生成渲染樹

1.從DOM樹的根節(jié)點(diǎn)開始遍歷每個(gè)可見節(jié)點(diǎn)。
2.對(duì)于每個(gè)可見的節(jié)點(diǎn)独柑,找到CSSOM樹中對(duì)應(yīng)的規(guī)則升酣,并應(yīng)用它們泳唠。
3.根據(jù)每個(gè)可見節(jié)點(diǎn)以及其對(duì)應(yīng)的樣式渠羞,組合生成渲染樹漠其。
不可見的節(jié)點(diǎn):(渲染樹只包含可見的節(jié)點(diǎn))

  • 一些不會(huì)被渲染出來的點(diǎn)瑞驱,比如:script窄坦,meta晰筛,link等
  • 一些通過css進(jìn)行隱藏的節(jié)點(diǎn)拴袭。比如display:none曙博。注意,利用visibility和opacity隱藏的節(jié)點(diǎn)般哼,還是會(huì)顯示在渲染樹上的惠窄。只有display:none的節(jié)點(diǎn)才不會(huì)顯示在渲染樹上。

學(xué)習(xí)鏈接:
1.https://www.cnblogs.com/dujingjie/p/5784890.html
2.https://www.cnblogs.com/wanan-01/p/7732340.html
3.https://zhuanlan.zhihu.com/p/22181897
4.https://zhuanlan.zhihu.com/p/52076790

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末楞卡,一起剝皮案震驚了整個(gè)濱河市脾歇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌池摧,老刑警劉巖激况,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異竭讳,居然都是意外死亡黔帕,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門呐芥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奋岁,“玉大人,你說我怎么就攤上這事闻伶。” “怎么了光绕?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵诞帐,是天一觀的道長。 經(jīng)常有香客問我停蕉,道長,這世上最難降的妖魔是什么菇晃? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任蚓挤,我火速辦了婚禮,結(jié)果婚禮上册着,老公的妹妹穿的比我還像新娘脾歧。我一直安慰自己,他們只是感情好鞭执,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布兄纺。 她就那樣靜靜地躺著,像睡著了一般估脆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上付材,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天圃阳,我揣著相機(jī)與錄音,去河邊找鬼富寿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛页徐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播窖贤,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼贰锁,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼滤蝠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起锣险,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤览闰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后崖咨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體油吭,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年歌豺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了心包。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡痕惋,死狀恐怖岭佳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情述寡,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布禀崖,位于F島的核電站螟炫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏昼钻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一仅财、第九天 我趴在偏房一處隱蔽的房頂上張望碗淌。 院中可真熱鬧,春花似錦亿眠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至倦始,卻和暖如春山卦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背账蓉。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國打工铸本, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留肮雨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓怨规,卻偏偏與公主長得像,于是被迫代替她去往敵國和親壳坪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子掰烟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355