天天看點

web 應用開發最佳實踐之一:避免大型、複雜的布局和布局抖動

布局是浏覽器計算元素幾何資訊的地方:即元素在頁面中的大小和位置。 每個元素都将具有基于所使用的 CSS、元素的内容或父元素的顯式或隐式大小資訊。 該過程在 Chrome、Opera、Safari 和 Internet Explorer 中稱為布局(Layout).

在 Firefox 中,它被稱為回流(reflow),但實際上過程是相同的。

與樣式計算類似,布局成本的直接關注點是:

需要布局的元素數量。

這些布局的複雜性。

簡而言之:

布局通常限定于整個文檔。

DOM 元素的數量會影響性能; 你應該盡可能避免觸釋出局。

評估布局模型性能; 新的 Flexbox 通常比舊的 Flexbox 或基于浮動的布局模型更快。

避免強制同步布局和布局抖動; 讀取樣式值然後進行樣式更改。

Avoid layout wherever possible

當您更改樣式時,浏覽器會檢查是否有任何更改需要計算布局,以及是否需要更新渲染樹。 更改“幾何屬性”,例如寬度、高度、左側或頂部都需要執行布局過程。

web 應用開發最佳實踐之一:避免大型、複雜的布局和布局抖動

布局幾乎總是作用于整個文檔。 如果您有很多元素,則需要很長時間才能弄清楚它們的位置和尺寸。

如果無法避免布局,那麼關鍵是再次使用 Chrome DevTools 來檢視需要多長時間,并确定布局是否是造成瓶頸的原因。 首先,打開 DevTools,轉到 Timeline 頁籤,點選記錄并與您的站點進行互動。 當您停止錄制時,您會看到您的網站表現的細分:

web 應用開發最佳實踐之一:避免大型、複雜的布局和布局抖動

在上例中深入研究幀時,我們看到在布局内部花費了超過 20 毫秒,當我們有 16 毫秒在動畫中在螢幕上顯示幀時,這太高了。 您還可以看到 DevTools 會告訴您樹的大小(在本例中為 1,618 個元素),以及需要布局的節點數量。

Avoid forced synchronous layouts

将網頁運送到螢幕具有以下順序:

web 應用開發最佳實踐之一:避免大型、複雜的布局和布局抖動

首先運作 JavaScript,然後是樣式計算,然後是布局。 但是,可以使用 JavaScript 強制浏覽器提前執行布局。 它被稱為強制同步布局。

首先要記住的是,當 JavaScript 運作時,前一幀中的所有舊布局值都是已知的,可供您查詢。 是以,例如,如果您想在幀的開頭寫出元素的高度(讓我們稱其為“框”),您可以編寫如下代碼:

web 應用開發最佳實踐之一:避免大型、複雜的布局和布局抖動

如果你在詢問高度之前改變了盒子的樣式,事情就會變得有問題:

web 應用開發最佳實踐之一:避免大型、複雜的布局和布局抖動

現在,為了回答高度問題,浏覽器必須先應用樣式更改(因為添加了超大類),然後運作布局。 隻有這樣,它才能傳回正确的高度。 這是不必要的并且可能是昂貴的工作。

是以,您應該始終批量讀取樣式并首先執行(浏覽器可以使用前一幀的布局值),然後執行任何寫入:

正确完成上述功能将是:

web 應用開發最佳實踐之一:避免大型、複雜的布局和布局抖動

在大多數情況下,您不需要應用樣式然後查詢值; 使用最後一幀的值就足夠了。 同步運作樣式計算和布局并早于浏覽器的預期是潛在的瓶頸,而不是您通常想要做的事情。

Avoid layout thrashing

有一種方法可以使強制同步布局變得更糟:快速連續地進行大量布局。 看看這段代碼:

web 應用開發最佳實踐之一:避免大型、複雜的布局和布局抖動

此代碼周遊一組段落并設定每個段落的寬度以比對名為“box”的元素的寬度。 它看起來無害,但問題是循環的每次疊代都會讀取一個樣式值(box.offsetWidth),然後立即使用它來更新段落的寬度(paragraphs[i].style.width)。 在循環的下一次疊代中,浏覽器必須考慮自上次請求 offsetWidth(在前一次疊代中)以來樣式已更改的事實,是以它必須應用樣式更改并運作布局。 這将在每次疊代中發生!。

此示例的修複方法是再次讀取然後寫入值:

web 應用開發最佳實踐之一:避免大型、複雜的布局和布局抖動

繼續閱讀