前言
突然有一天,腦之裡不知怎地蹦出一個詞,「雙飛翼」,這是很久以前的淘寶提出的一種三欄佈局優化方案,然而,時間久了已經不記得(換句話說是不理解)為啥要提出這個佈局了,昨天在 SF 上發起了一個提問,但良久未有人答覆,幸得@王能全是誰 提醒,終於回想起「雙飛翼」的完整意義了。謹以此文同大家分享這段心路歷程。
聖盃 & 雙飛翼
說到「雙飛翼」就不得不提及「聖盃」,兩者均為三欄佈局的優化解決方案如下圖
常規情況下,我們的佈局框架使用以下寫法,從上到下,從左到右。
<header>header</header>
<section>
<aside>left</aside>
<section>main</section>
<aside>right</aside>
</section>
<footer>footer</footer>複製程式碼
問題倒是沒什麼問題,然而,如果我們希望中部 main 部分優先顯示的話,是可以做佈局優化的。
因為瀏覽器渲染引擎在構建和渲染渲染樹是非同步的(誰先構建好誰先顯示),那麼將<section>main</section>
部分提前即可優先渲染。
<header>header</header>
<section>
<section>main</section>
<aside>left</aside>
<aside>right</aside>
</section>
<footer>footer</footer>複製程式碼
於是乎,國外的前輩就提出了「聖盃」佈局,目的就是通過 css 的方式配合上面的 DOM 結構,優化 DOM 渲染。
我們來簡要地瞭解一下「聖盃」佈局,這不是重點。
聖盃佈局
<template>
<header>header</header>
<section class="wrapper">
<section class="col main">main</section>
<aside class="col left">left</aside>
<aside class="col right">right</aside>
</section>
<footer>footer</footer>
</template>
<style>
/* 以下為簡碼,僅保留關鍵部分 */
header,footer {height: 50px;}
.wrapper {padding: 0 100px 0 100px; overflow:hidden;}
.col {position: relative; float: left;}
.main {width: 100%;height: 200px;}
.left {width: 100px; height: 200px; margin-left: -100%;left: -100px;}
.right {width: 100px; height: 200px; margin-left: -100px; right: -100px;}
</style>複製程式碼
使用了 relative 相對定位
、float
(需要請浮動,此處使用 overflow:hidden;
方法)和 負值 margin
,將 left 和 right 部分「安裝」到 wrapper
的兩側,顧名「聖盃」。具體的思路我就不再做贅述了,網上到處都是解釋。
聖盃有問題
當然,正常情況下是沒有問題的,但是特殊情況下就會暴露此方案的弊端,如果將瀏覽器無線變窄,「聖盃」將會「破碎」掉。如圖,當 main
部分的寬小於 left
部分時就會發生布局混亂。
於是,淘寶軟對針對「聖盃」的缺點做了優化,並提出「雙飛翼」佈局。
雙飛翼佈局
同樣的我們來看簡碼
<template>
<header>header</header>
<section class="wrapper">
<section class="col main">
<section class="main-wrap">main</section>
</section>
<aside class="col left">left</aside>
<aside class="col right">right</aside>
</section>
<footer>footer</footer>
</template>
<style>
/* 以下為簡碼,僅保留關鍵部分 */
header,footer {height: 50px;}
.wrapper {padding: 0; overflow:hidden;}
.col {float: left;}
.main {width: 100%;}
.main-wrap {margin: 0 100px 0 100px;height: 200px;}
.left {width: 100px; height: 200px; margin-left: -100%;}
.right {width: 100px; height: 200px; margin-left: -100px;}
</style>複製程式碼
同樣使用了 float
和 負值 margin
,不同的是,並沒有使用 relative 相對定位
而是增加了 dom 結構,增加了一個層級。確實解決了聖盃佈局的缺陷。
為什麼要設計「雙飛翼」佈局
雙飛翼佈局表面上看是很優秀,但是細細想來,為什麼要多加一層 dom 樹節點,這豈不是增加了 css 樣式規則表和 dom 樹合併成佈局樹的計算量嗎?
好像絕對定位也可以解決這個問題
細想想,我們可以使用絕對佈局,將左右側邊欄定位到到兩側啊?好像也不會出現聖盃佈局的毛病?
<template>
<header>header</header>
<section class="wrapper">
<section class="col main">main</section>
<aside class="col left">left</aside>
<aside class="col right">right</aside>
</section>
<footer>footer</footer>
</template>
<style>
/* 以下為簡碼,僅保留關鍵部分 */
header,footer { height: 50px;}
.wrapper { position: relative;}
.main { height: 200px; margin:0 100px;}
.left, .right{ width: 100px; height: 200px; position: absolute; top: 0;}
.left{ left: 0;}
.right{ right: 0;}
</style>複製程式碼
沒有使用 float
(不用請浮動)也沒有 負值 margin
,僅僅使用了 absolute 絕對定位
,好像更優秀呢?
但是細細想想,單純的絕對定位有一個問題,「高度不可控」,我們假設,如果 left
部分的高度高於 main
,是不是 left
沒有能力撐起整個 wrapper
?
「四不四」~~!
那麼我們再來看看雙飛翼和聖盃的情況
都是下圖。
「應戳死聽」~~!
那這麼看來,所有的方案都或多或少存在一些問題。綜合來看,不管 left
, main
, right
的大小高低如何,「雙飛翼」佈局都能正常顯示,嗯~~確實很優秀。
錘子和釘子
綜上所見,「雙飛翼」佈局更勝一籌。但是,這是一個「錘子和釘子」的問題,我們應該拿著釘子找錘子,而不是拿著錘子找釘子,因為,當你有了最大的錘子,看到什麼都是釘子。
唉~,我又在裝逼了。 \( ̄︶ ̄)/
說白了,就是,對症下藥,沒有最好的方案,只有最適合的。關於三欄佈局,我幫大家列出一個對照表,以便大家快速選擇。
優點 | 缺點 | |
---|---|---|
聖盃 | 結構簡單,無多餘 dom 層 | 中間部分寬度小於左側時佈局混亂 |
絕對定位 | 結構簡單,且無需清理浮動 | 兩側高度無法支撐總高度 |
雙飛翼 | 支援各種寬高變化,通用性強 | dom 結構多餘層,增加渲染樹生成的計算量 |
以上為個人理解,如有不對或可補充之處,還請指點。
另外關於 CSS 佈局方案,和前端效能優化部分,移駕一下文章
多行多列類佈局方案總結
前端效能優化總結
轉載請標明出處
作者:木羽 zwwill
首發地址:github.com/zwwill/blog…