發布日期:2015 年 3 月 20 日,上次更新日期:2025 年 5 月 7 日
版面配置是瀏覽器用來判斷元素幾何資訊的過程,包括元素的大小和網頁中的位置。每個元素都會根據所使用的 CSS、元素內容或父元素,提供明確或隱含的大小資訊。在 Chrome (以及 Edge 等衍生瀏覽器) 和 Safari 中,這個程序稱為「版面配置」。在 Firefox 中,這項功能稱為 Reflow,但實際上兩者處理程序相同。
與樣式計算方式類似,版面配置成本的立即考量重點如下:
- 需要版面配置的元素數量,這是網頁 DOM 大小的副產品。
- 版面配置的複雜度。
摘要
- 版面配置會直接影響互動延遲時間
- 版面配置通常會套用至整份文件。
- DOM 元素的數量會影響效能,因此請盡可能避免觸發版面配置。
- 避免強制同步版面配置和版面配置耗盡;請讀取樣式值,然後變更樣式。
版面配置對互動延遲的影響
使用者與網頁互動時,這些互動應盡可能快速。互動完成所需的時間 (結束時間為瀏覽器呈現下一個影格,以顯示互動結果) 稱為互動延遲。這是「與下一個顯示的內容互動」指標評估的網頁效能面向。
瀏覽器在回應使用者互動時,呈現下一個影格所需的時間,稱為互動的呈現延遲。互動的主要目的是提供視覺回饋,向使用者傳達發生的事件,而視覺更新可能需要進行一些版面配置工作才能達成這個目標。
為了盡可能降低網站的 INP,請盡量避免使用版面配置。如果無法完全避免版面配置,請務必限制版面配置作業,讓瀏覽器能快速顯示下一個影格。
。盡量避免使用版面配置
變更樣式時,瀏覽器會檢查是否有任何變更需要計算版面配置,以及是否需要更新該轉譯樹狀結構。您必須使用版面配置,才能變更「幾何屬性」,例如 width
、height
、left
或 top
。
.box {
width: 20px;
height: 20px;
}
/**
* Changing width and height
* triggers layout.
*/
.box--expanded {
width: 200px;
height: 350px;
}
版面配置的範圍幾乎總是整份文件。如果元素很多,您可能需要花費很長的時間來找出所有元素的位置和尺寸。
如果無法避免版面配置,請再次使用 Chrome 開發人員工具查看所需時間,並判斷版面配置是否導致瓶頸。首先,請開啟「開發人員工具」,前往「時間軸」分頁,按下「錄製」並與網站互動。停止錄製後,您會看到網站成效的詳細資料:

深入探討前述範例中的追蹤記錄,我們發現每個影格在版面配置中花費的時間超過 28 毫秒,而動畫在畫面上顯示一個影格只需要 16 毫秒,因此這個時間過長。您也可以看到,DevTools 會告訴您樹狀結構的大小 (在本例中為 1,618 個元素),以及需要排版的節點數量 (在本例中為 5 個)。
請注意,一般建議是盡可能避免使用版面配置,但有時無法避免使用版面配置。如果無法避免版面配置,請注意版面配置的成本與 DOM 大小有關。雖然這兩者之間並未緊密連結,但較大的 DOM 通常會產生較高的版面配置成本。
避免強制同步版面配置
將影格傳送至螢幕的順序如下:

首先執行 JavaScript,然後計算樣式,然後版面配置。不過,您可以透過 JavaScript 強制瀏覽器提早執行版面配置。這稱為「強制同步版面配置」 (或有時稱為「強制重新流動」)。
首先要注意的是,JavaScript 執行時,會將先前影格中的所有舊版版面配置值都列為已知,並可供查詢。舉例來說,如果您想在影格開始時輸出元素的高度 (我們稱之為「box」),可以編寫以下程式碼:
// Schedule our function to run at the start of the frame:
requestAnimationFrame(logBoxHeight);
function logBoxHeight () {
// Gets the height of the box in pixels and logs it out:
console.log(box.offsetHeight);
}
如果您在變更方塊的樣式「之前」要求方塊的高度,就會發生問題:
function logBoxHeight () {
box.classList.add('super-big');
// Gets the height of the box in pixels and logs it out:
console.log(box.offsetHeight);
}
接下來,為了回答高度問題,瀏覽器必須先套用樣式變更 (因為已新增 super-big
類別),再再執行版面配置。只有在這種情況下,才能傳回正確的高度。這項工作不必要且可能耗費心力。
因此,您應一律先批次讀取樣式 (瀏覽器可使用先前影格版面配置值),再執行任何寫入作業:
較有效率的舊版函式如下:
function logBoxHeight () {
// Gets the height of the box in pixels and logs it out:
console.log(box.offsetHeight);
box.classList.add('super-big');
}
在大多數情況下,您不必套用樣式,然後再查詢值;使用上一個影格中的值就足夠了。比瀏覽器更早同步執行樣式計算和版面配置,可能會造成瓶頸,因此通常不建議這麼做。
避免版面配置輾轉
有一種方法可以讓強制同步版面配置變得更糟:快速連續執行許多版面配置。請查看以下程式碼:
function resizeAllParagraphsToMatchBlockWidth () {
// Puts the browser into a read-write-read-write cycle.
for (let i = 0; i < paragraphs.length; i++) {
paragraphs[i].style.width = `${box.offsetWidth}px`;
}
}
這段程式碼會循環處理一組段落,並將每個段落的寬度設為與名為「box」的元素寬度相符。這看起來似乎沒什麼問題,但問題在於迴圈的每個疊代都會讀取樣式值 (box.offsetWidth
),然後立即使用該值更新段落的寬度 (paragraphs[i].style.width
)。在迴圈的下一個疊代中,瀏覽器必須考量到自上次要求 offsetWidth
(在前一個疊代中) 以來,樣式已變更,因此必須套用樣式變更並執行版面配置。這會在每個疊代都發生。
這個範例的修正方式是再次讀取,然後寫入值:
// Read.
const width = box.offsetWidth;
function resizeAllParagraphsToMatchBlockWidth () {
for (let i = 0; i < paragraphs.length; i++) {
// Now write.
paragraphs[i].style.width = `${width}px`;
}
}
找出強制同步版面配置和耗損
DevTools 提供「強制重新流」洞察資料,協助您快速找出強制同步版面配置 (也稱為「強制重新流」) 的情況:

您也可以使用 forcedStyleAndLayoutDuration
屬性,透過 Long Animation Frame API 指令碼歸因,在欄位中識別強制同步版面配置。