瀏覽器渲染一個頁面都幹了哪些事
【編者按】其實,有關網頁渲染的文章很多,但是相關資訊比較分散,且論述並不是很完整。如果要想對這個主題有個大致的瞭解,我們還得學習很多知識。因此,Web開發者Alexander Skutin 決定寫一篇文章。他相信,這篇文章不僅能幫助初學者,也能對那些想要重新整理知識結構的高階前端開發者有所裨益。原文地址
譯文如下:
網頁渲染必須在很早的階段進行,可以早到頁面佈局剛剛定型。因為樣式和指令碼都會對網頁渲染產生關鍵性的影響。所以專業開發者必須瞭解一些技巧,從而避免在實踐的過程中遇到效能問題。
這篇文章不會研究瀏覽器內部的詳細機制,而是提出一些通用的規則。畢竟,不同瀏覽器引擎的工作機制各不相同,這無疑會讓開發者對瀏覽器特性的研究變得更加複雜。
瀏覽器是如何完成網頁渲染?
首先,我們回顧一下網頁渲染時,瀏覽器的動作:
- 根據來自伺服器端的HTML程式碼形成文件物件模型(DOM)
- 載入並解析樣式,形成CSS物件模型。
- 在文件物件模型和CSS物件模型之上,建立一棵由一組待生成渲染的物件組成的渲染樹(在Webkit中這些物件被稱為渲染器或渲染物件,而在Gecko中稱之為“frame”。)渲染樹反映了文件物件模型的結構,但是不包含諸如標籤或含有display:none屬性的不可見元素。在渲染樹中,每一段文字字串都表現為獨立的渲染器。每一個渲染物件都包含與之對應的DOM物件,或者文字塊,還加上計算過的樣式。換言之,渲染樹是一個文件物件模型的直觀展示。
-
對渲染樹上的每個元素,計算它的座標,稱之為佈局。瀏覽器採用一種流方法,佈局一個元素只需通過一次,但是表格元素需要通過多次。
-
最後,渲染樹上的元素最終展示在瀏覽器裡,這一過程稱為“painting”。
當用戶與網頁互動,或者指令碼程式改動修改網頁時,前文提到的一些操作將會重複執行,因為網頁的內在結構已經發生了改變。
重繪
當改變那些不會影響元素在網頁中的位置的元素樣式時,譬如background-color(背景色), border-color(邊框色), visibility(可見性),瀏覽器只會用新的樣式將元素重繪一次(這就是重繪,或者說重新構造樣式)。
重排
當改變影響到文字內容或結構,或者元素位置時,重排或者說重新佈局就會發生。這些改變通常由以下事件觸發:
- DOM操作(元素新增,刪除,修改,或者元素順序的改變);
- 內容變化,包括表單域內的文字改變;
- CSS屬性的計算或改變;
- 新增或刪除樣式表;
- 更改“類”的屬性;
- 瀏覽器視窗的操作(縮放,滾動);
- 偽類啟用(:懸停)。
瀏覽器如何優化渲染?
瀏覽器儘可能將重繪/重構 限制在被改變元素的區域內。比如,對於位置固定或絕對的元素,其大小改變隻影響元素本身及其子元素,然而,靜態定位元素的大小改變會觸發後續所有元素的重流。
另一種優化技巧是,在執行幾段JavaScript程式碼時,瀏覽器會快取這些改變,在程式碼執行完畢後再將這些改變經一次通過加以應用。舉個例子,下面這段程式碼只會觸發一個重構和重繪:
- var $body = $('body');
- $body.css('padding','1px');// reflow, repaint
- $body.css('color','red');// repaint
- $body.css('margin','2px');// reflow, repaint
- // only 1 reflow and repaint will actually happen
然而,如前所述,改變元素的屬性會觸發強制性的重排。如果我們在上面的程式碼塊中加入一行程式碼,用來訪問元素的屬性,就會發生這種現象。
- var $body = $('body');
- $body.css('padding','1px');
- $body.css('padding');// reading a property, a forced reflow
- $body.css('color','red');
- $body.css('margin','2px');
其結果就是,重排發生了兩次。因此,你應該把訪問元素屬性的操作都組織在一起,從而優化網頁效能。(你可以在JSBin查到更為詳細的例子)
有時,你必須觸發一個強制性重排。比如,我們必須將同樣的屬性(比如左邊距)兩次賦值給同一個元素。起初,它應該設定為100px,且不帶動效。接著,它必須通過過渡(transition)動效改變為50px。你現在可以在JSbin上學習這個例子,不過我會在這兒更詳細地介紹它。
首先,我們建立一個帶過渡效果的CSS類:
- .has-transition {
- -webkit-transition: margin-left 1s ease-out;
- -moz-transition: margin-left 1s ease-out;
- -o-transition: margin-left 1s ease-out;
- transition: margin-left 1s ease-out;
- }
然後繼續執行:
- // our element that has a "has-transition" class by default
- var $targetElem = $('#targetElemId');
- // remove the transition class
- $targetElem.removeClass('has-transition');
- // change the property expecting the transition to be off, as the class is not there
- // anymore
- $targetElem.css('margin-left',100);
- // put the transition class back
- $targetElem.addClass('has-transition');
- // change the property
- $targetElem.css('margin-left',50);
然而,這個執行無法奏效。所有改變都被快取,只在程式碼塊末尾加以執行。我們需要的是強制性的重排,我們可以通過以下更改加以實現:
- // remove the transition class
- $(this).removeClass('has-transition');
- // change the property
- $(this).css('margin-left',100);
- // trigger a forced reflow, so that changes in a class/property get applied immediately
- $(this)[0].offsetHeight;// an example, other properties would work, too
- // put the transition class back
- $(this).addClass('has-transition');
- // change the property
- $(this).css('margin-left',50);
現在程式碼如預期那樣執行了。
有關效能優化的實際建議
總結現有的資料,我提出以下建議:
- 建立有效的HTML和CSS檔案,不要忘記指明文件的編碼方式。樣式應該包含在標籤內,指令碼程式碼則應該加在標籤末端。
-
儘量簡化和優化CSS選擇器(這種優化方式幾乎被使用CSS前處理器的開發者統一忽視了)將巢狀程度保持在最低水平。以下是CSS選擇器的效能排名(從最快者開始)
- 識別器:#id
- 類:.class
- 標籤:div
- 相鄰兄弟選擇器:a + i
- 父類選擇器:ul> li
- 通用選擇器:*
- 屬性選擇:input[type="text"]
- 偽類和偽元素:a:hover
你應該記住,瀏覽器在處理選擇器時依照從右到左的原則,因此最右端的選擇器應該是最快的:#id或則.class:
- div *{...}// bad
- .list li {...}// bad
- .list-item {...}// good
- #list .list-item {...} // good
-
1.在你的指令碼程式碼中,儘可能減少DOM操作。快取所有東西,包括元素屬性以及物件(如果它們被重用的話)。當進行復雜的操作時,使用“孤立”元素會更好,之後可以將其加到DOM中(所謂“孤立”元素是與DOM脫離,僅儲存在記憶體中的元素)。
-
2.如果你使用jQuery來選擇元素,請遵從jQuery選擇器最佳實踐方案。
-
3.為了改變元素的樣式,修改“類”的屬性是奏效的方法之一。執行這一改變時,處在DOM渲染樹的位置越深越好(這還有助於將邏輯與表象脫離)。
-
4.儘量只給位置絕對或者固定的元素新增動畫效果。
-
5.在使用滾動時禁用複雜的懸停動效(比如,在中新增一個額外的不懸停類)。讀者可以閱讀關於這個問題的一篇文章。
想了解更多的細節問題,大家也可以看看這兩篇文章:
相關推薦
瀏覽器渲染一個頁面都幹了哪些事
【編者按】其實,有關網頁渲染的文章很多,但是相關資訊比較分散,且論述並不是很完整。如果要想對這個主題有個大致的瞭解,我們還得學習很多知識。因此,Web開發者Alexander Skutin 決定寫一篇文章。他相信,這篇文章不僅能幫助初學者,也能對那些想要重新整理知識結構的
瀏覽器輸入url後都幹了些什麼?
我們在瀏覽器中輸入網址。 瀏覽器查詢域名對應的IP地址 -DNS查詢過程為: -瀏覽器快取->系統快取->路由器快取->ISP DNS快取->遞迴搜尋 -遞迴搜尋過程
輸入一個url到瀏覽器頁面展示都經歷了哪些過程
在日常的瀏覽器訪問過程中,我們肯定會訪問n多頁面,但是我們輸入一個網址後是如何變成一個頁面展示在我們面前,從一個url到頁面的展示這個過程中,我們的瀏覽器都經歷了一些什麼? 步驟 → 1- 輸入網址 → 2- 快取解析 →
從輸入一個url到瀏覽器頁面展示都經歷了哪些過程
面試的時候有些面試官會問這個問題,可按如下流程作答: 1、首先,在瀏覽器位址列中輸入url 2、瀏覽器先檢視瀏覽器快取-系統快取-路由器快取,如果快取中有,會直接在螢幕中顯示頁面內容。若沒有,則跳到第三步操作。 3、在傳送http請求前,需要域名解析(DNS解析),解析
從瀏覽器位址列裡輸入一個URL開始,到出現整個頁面,網路上都發生了什麼事?
最近談到這個問題,覺得自己不能夠清楚的講明白這個過程的一些細節,所以差了些資料,覺得如下的解答還是比較詳細的,後期還會慢慢完善這個過程中不足的地方。回車前: 1. 如果用某些輸循入法輸入, 它會按標準結果、快取匹配、傳送到去端匹配, 給你幾個聯想結果。 你對結果的修改會反
從瀏覽器輸入域名到展示頁面都發生了什麽
blog 展示 完成 結果 pos 組成 大致 域名解析 服務 DNS域名解析先找本地hosts文件,檢查對應域名ip的關系,有則想ip地址發送請求,沒有再去找DNS服務器 建立TCP連接拿到服務器IP後,向服務器發送求求,三次握手,建立TCP連接簡單理解三次握手:客戶
關於類、方法、對象(實例):通過一個例子看一下self都做了哪些事情
就會 就是 style 寫代碼 obj 這一 charm self 將不 我們在定義一個類時,經常會在類的各個方法中看到self,那麽在程序執行時self到底起了什麽作用,什麽時候要加self,這一點需要我們思考並好好理解。之前在學習時沒有想這麽多,加之用p
一個程式在執行main函式之前都幹了些什麼?
《一 》怎麼執行程式(如何把程式載入到記憶體上 首先記憶體需要的是資料和指令(機器語言)但是程式是高階語言, 1:先通過編譯連結生成.exe檔案(.exe檔案在磁碟中儲存,且.exe檔案中是機器語言) 2:.exe檔案通過mmap函式對映到虛擬記憶體上 3:再通過分段
月薪3萬的程序員都避開了哪些坑?
女人 沒有 是什麽 導致 即使 -1 不知道 準備 很快 程序員薪水有高有低,有的人一個月可能拿30K、50K,有的人可能只有2K、3K。同樣有五年工作經驗的程序員,可能一個人每月拿20K,一個拿5K。是什麽因素導致了這種差異?我特意總結了容易導致薪水低的九大行為
你都付出了哪些努力
經理 逆向分析 有客 過程 思考 可能 日程 print 機會 我們常常會在一件事情的結果不如人意時感到委屈和憤懣(尤其是被別人指摘時):我已經非常努力了啊,為什麽會這樣! 但是,你有客觀地思考過這幾個問題嗎: 你究竟付出了哪些努力呢? 你是不是在
點擊頁面的按鈕,使之打開一個新窗口,加載一個頁面的方法有哪些呢?
body del .html blank oca pos type target put 1.<base target="_blank" /> 頁面只要有a標簽,都會打開一個新的頁面; 2.<input type=‘button‘ value=‘new‘
9大Python最常用的數據分析庫,在2018都做了哪些更新?
包括 有用 樣式 代數 scrip 小部件 很快 scipy 圖庫 1. NumPy 一般我們會將科學領域的庫作為清單打頭,NumPy是該領域的主要軟件庫之一。它旨在處理大型的多維數組和矩陣,並提供了很多高級的數學函數和方法,因此可以用它來執行各種操作。 在
記錄一下從9.25-10.19出發去沈陽區域賽前俺都幹了些啥
多校 博客 區域 區域賽 實驗 女生 打了 bsp 一點 9.25: 前幾天打了2017年西安,南寧兩場區域賽,被虐的說不出話來,覺得自己啥也不會,特別西安線段樹專場,覺得線段樹應該惡補一下,南寧場覺得也不是那麽簡單,可也要快速出四題才能拿銅,這意味著我要麽得寫出pell方
為了完畢月入三萬的目標,我都做了哪些準備?
1 我覺得像我這般年紀的(29歲)。有相對紮實技術功底的(就不自謙了)。對賺錢有著強烈慾望的程式猿,應該定一個切實的小目標——五年內月入三萬! 之所以要定這個目標,最基本的原因是老婆的批評刺痛了我——一個身強力壯的年輕男子(腦子也還好使),不想方設法的多掙點錢,
周志華等提出RNN可解釋性方法,看看RNN內部都幹了些什麼
選自 ArXiv,作者:Bo-Jian Hou, Zhi-Hua Zhou,機器之心編譯,參與:思源、曉坤。 除了數值計算,你真的知道神經網路內部在做什麼嗎?我們一直理解深度模型都靠裡面的運算流,但對於是不是具有物理意義、語義意義都還是懵懵懂懂。尤其是在迴圈神經網路中,我們只知道每一個時間步它都在利
我學Python都看了哪些書
前言 2017年11月29日,自己曾在公眾號內寫過一篇《聊聊我的R語言學習路徑和感受》的文章,受到了很多朋友的關注和讚揚,同時,也有其他公眾號在幫忙轉載。當然,也有很多朋友也給我留言,能不能聊聊關於Pyt
http請求過程(訪問一個頁面,發生了怎樣的網路請求?)
域名解析->域名 ->快取->根域dns->頂級域dns->本域dns->伺服器IP 1.搜尋瀏覽器自身DNS快取,如果不存在或者過期(>60s)放棄 2.搜尋作業系統自身的dns快取 3.讀取本地的HOST檔案 4.瀏覽器發起一個DNS的
雲吶IT互動服務檯V3.5.0版本都更新了哪些功能
雲吶it互動服務檯具體功能更新內容如下: 【Web端版本更新內容】 1、新增網頁組建、微信接入、app-SDK、小程式四種渠道進行快速報障 2、新增在專案中生成對應的服務報表功能; 3、新增資產可分類設定自定義欄位功能; 4、當員工不在職時,可將其待辦的工作批量轉交給他人;
swoft| 原始碼解讀系列二: 啟動階段, swoft 都幹了些啥?
date: 2018-8-01 14:22:17title: swoft| 原始碼解讀系列二: 啟動階段, swoft 都幹了些啥?description: 閱讀 sowft 框架原始碼, 瞭解 sowft 啟動階段的那些事兒 小夥伴剛接觸 swoft 的時候會感覺 壓力有點大, 更直觀的說法是 難. 開發
maven打war包的過程中,都用了哪些外掛呢?
一、maven生命週期 http://ifeve.com/introduction-to-the-lifecycle/ https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html &nbs