用五種方法來聊一聊傳說中的三欄布局


引言

  三欄布局是目前網站建設的主流布局,同時也是面試中必考的一個點,無論是PC端還是移動端三欄布局都是非常重要的一個CSS知識點,關於三欄布局的方案說的最爛的莫過於聖杯布局了,其主要的核心思想其實就只有一條:實現兩欄固定,中間自適應,保證頁面的布局不受窗口大小的變化而紊亂。本文總結了五種實現三欄布局的方法,包括主流的聖杯布局、雙飛翼布局,也包含了一些個人遐想的非主流布局,供同學們學習和參考。

一、聖杯布局

  聖杯布局的思想是將頁面縱向分為三個部分,即 header、container、footer,然后又將 container 定為三欄布局。在這里主要講解其中的 container 布局。

  首先在 container 里面有三欄,分別是 left、middle、right,注意這里 middle 需要放在最前面,保證可以得到優先渲染:

 1 <div class="grail-container">
 2     <div class="grail-middle">
 3         Grail main
 4     </div>
 5     <div class="grail-left">
 6         Grail left
 7     </div>
 8     <div class="grail-right">
 9         Grail right
10     </div>
11 </div>

  對於 container ,設置一個屬性 overflow: hidden; 讓其形成一個 BFC ,然后使其三欄浮動,並使用相對定位:

1 .grail-container {
2     overflow: hidden;
3 }
4 .grail-container>div {
5     position: relative;
6     float: left;
7     height: 100%;
8 }

  這時執行以下的步驟:

  ① 置 middle 的 width: 100%,給 left 和 right 定寬度,這里假設都是 width: 200px;

  ② 這時 left 被擠到下面去了,所以我們要把它拉回來,設置 margin-left: -100%;

  ③ 還有一個 right 沒有拉回來,同樣,設置 margin-left: 200px;,這里的長度等於 right 自身的長度

  ④ 這時 middle 的兩邊被 left 和 right 給覆蓋了,於是我們要把兩邊懟回來,設置 container padding: 0 200px 0 200px;

  ⑤ middle 懟回來了,可是 left 和 right 也跟着回來,所以現在我們要把 left 和 right 給懟回去,分別設置 left left: -200px;,right right: -200px;(這就是之前為什么要用相對定位)

 1 .grail-container {
 2     overflow: hidden;
 3     padding: 0 200px;
 4 }
 5 .grail-container>div {
 6     position: relative;
 7     float: left;
 8     height: 100%;
 9 }
10 .grail-middle {
11     width: 100%;
12     background-color: blue;
13 }
14 .grail-left {
15     width: 200px;
16     background-color: green;
17     margin-left: -100%;
18     left: -200px;
19 }
20 .grail-right {
21     width: 200px;
22     background-color: brown;
23     margin-left: -200px;
24     right: -200px;
25 }

  聖杯布局就完成了,不信拖拖看,是不是中間就自適應了?不過它有一個弊端,就是當拖到很小的時候,布局會亂,於是我們有了下面的布局:雙飛翼布局。

 二、雙飛翼布局

  雙飛翼布局使於淘寶,是淘寶團隊提出來的一種實現三欄布局的方案,其和聖杯布局是同門兄弟,同樣將頁面分為 header、container、footer ,不過在 container 里面有所區別。聖杯布局的缺陷在於內容區被 container 的 padding 夾在里面,使得頁面寬度過小時會出現布局紊亂,這時候雙飛翼布局就不使用 padding 來將內容區夾在里面,而是給內容區添加一個 main ,設置 margin 將頁面主動的撐開,其 DOM 結構與聖杯類似,區別在於在 middle 中多了一個 main:

 1 <div class="double-wing-container">
 2     <div class="double-wing-middle">
 3         <div class="double-wing-main">
 4             Double wing main.  
 5         </div>
 6     </div>
 7     <div class="double-wing-left">
 8         Double wing left.  
 9     </div>
10     <div class="double-wing-right">
11         Double wing right
12     </div>
13 </div>
1 .double-wing-container {
2     overflow: hidden;
3 }
4 .double-wing-container>div {
5     position: relative;
6     float: left;
7     height: 100%;
8 }

  這時執行與聖杯布局類似的步驟:

  ① 置 middle 的 width: 100%,給 left 和 right 定寬度,這里假設都是 width: 200px;

  ② 這時 left 被擠到下面去了,所以我們要把它拉回來,設置 margin-left: -100%;

  ③ 還有一個 right 沒有拉回來,同樣,設置 margin-left: 200px;,這里的長度等於 right 自身的長度

  注意這里開始就有區別了:

  ④ 使用 main 把內容區撐開,設置 margin: 0 200px 0 200px;,同時設置 overflow: hidden; 使其形成一個 BFC

 1 .double-wing-container {
 2     overflow: hidden;
 3 }
 4 .double-wing-container>div {
 5     position: relative;
 6     float: left;
 7     height: 100%;
 8 }
 9 .double-wing-middle {
10     width: 100%;
11     background-color: gray;
12 }
13 .double-wing-left {
14     width: 200px;
15     background-color: orange;
16     margin-left: -100%;
17 }
18 .double-wing-right {
19     width: 200px;
20     background-color: red;
21     margin-left: -200px;
22 }
23 .double-wing-main {
24     height: 100%;
25     margin: 0 200px;
26     background-color: pink;
27     overflow: hidden;
28 }

  現在再試試,是不是比聖杯布局稍微好一點,在窗口寬度過小時不會出現排版混亂?其核心就是把內容部分從 middle 遷移到了 main。

  以上兩種布局方案已經適用於絕大部分場景,如果你只是想找一個三欄布局的解決方案,那么到此就夠了。不過,如果你想要的不只是這些,if you wanna more,那么就一起來聊一聊下面的布局方案。

  首先呢,我們的兩大三欄布局都有一個固定的模式,那就是兩欄固定,中間自適應,可是你有沒有想過,我們來實現一個三欄自適應的布局?那么大名鼎鼎的 Flex 布局就登場了,Flex 布局不光可以實現兩欄固定,中間自適應,也可以實現三欄自適應,甚至隨意固定,隨意自適應。

三、Flex 布局

  Flex 布局可謂 CSS3 提供一個布局神奇,將 CSS2 中的許多難點一網打盡。關於 Flex 布局的語法,這里就不做討論了,如果有不熟悉的同學可以先看看阮老師的文章:Flex 布局教程:語法篇 這篇文章講解的十分通俗易懂。在這里我們先照樣子實現一個三欄布局, 兩欄固定,中間自適應。

  首先,DOM 結構也是一樣的:

 1 <div class="flex-container">
 2     <div class="flex-middle">
 3         Flex main
 4     </div>
 5     <div class="flex-left">
 6         Flex left
 7     </div>
 8     <div class="flex-right">
 9         Flex right
10     </div>
11 </div>

  然后執行以下步驟:

  ① 設置 container 布局方式 display: flex; 

  ② 這時候設置 middle width: 100%; ,同時給兩欄定寬,這里假設都是 width: 200px;

  ③ 既然是兩欄固定,那么就不讓兩欄收縮,給 left 和 right 設置 flex-shrink: 0;

  ④ 由於 DOM 結構和我們實際的順序不一樣,這時我們來排個序 left order: 1;,middle order: 2;,right order: 3;

 1 .flex-container {
 2     display: flex;
 3 }
 4 .flex-container>div {
 5     height: 100%;
 6 }
 7 .flex-left {
 8     width: 200px;
 9     background-color: yellow;
10     order: 1;
11     flex-shrink: 0;
12 }
13 .flex-middle {
14     width: 100%;
15     background-color: gray;
16     order: 2;
17 }
18 .flex-right {
19     width: 200px;
20     background-color: red;
21     order: 3;
22     flex-shrink: 0;
23 }

  OK啦,現在拖動試一試。可以看出 flex 布局具有更強的適應性,在窗口寬度過小的時候不會造成頁面布局混亂。通過設置內容的伸縮,可以實現任意欄的固定和自適應,同時也可以實現三欄自適應,通過設置 flex 內容的 flex-shrinkflex-grow 可以實現自定義的適應性布局。接下來,咱們聊一聊一些個人的遐想,偏非主流的三欄布局。

四、絕對定位布局

  絕對定位其強大之處在於它的定位性能非常的優秀,這里我們就可以用絕對定位的自動伸縮性來實現一個三欄布局。

  DOM 結構依然不變:

 1 <div class="absolute-container">
 2     <div class="absolute-middle">
 3         Absolute main
 4     </div>
 5     <div class="absolute-left">
 6         Absolute left
 7     </div>
 8     <div class="absolute-right">
 9         Absolute right
10     </div>
11 </div>

  注意我們需要將 container 的 postion: relative; ,因為絕對定位元素的參照物為第一個 postion 不為 static 的祖先元素,同時需要使 left 向左浮動,right 向右浮動,同時使 middle 絕對定位,並把左右兩邊撐開:

 1 .absolute-container {
 2     position: relative;
 3     overflow: hidden;
 4 }
 5 .absolute-container>div {
 6     height: 100%;
 7 }
 8 .absolute-left {
 9     float: left;
10     width: 200px;
11     background-color: blue;
12 }
13 .absolute-middle {
14     position: absolute;
15     left: 200px;
16     right: 200px;
17     top: 0;
18     bottom: 0;
19     background-color: pink;
20 }
21 .absolute-right {
22     float: right;
23     width: 200px;
24     background-color: brown;
25 }

  注意絕對定位元素的高度需要設 top: 0 bottom: 0 來使其高度撐開。現在試一試是不是同樣也實現了三欄布局,不過這種布局方案有一個致命的缺點,就是中間的內容區完全依賴於兩欄的高度,如果兩欄的高度不夠,那么中間內容區的高度也會隨着壓縮,所以這種方案在很多場景下並不適合。下面我們來聊一個較強一點的非主流三欄布局。

五、table-cell 三欄布局

   在前三種三欄布局方案中,我們三欄的高度取決於各自的內容區,也就是說如果中間內容多,兩邊內容少的情況下,頁面的高度取決於內容區,同時兩欄的高度不會增加,這是當今絕大多數的網站所采用的主流布局。第四種方案中的致命缺陷為中間內容區的高度取決於兩欄的最高點。現在我們討論一種非主流的三欄布局方案,表格布局,使其三欄高度統一,這種布局方案主要是利用了表格布局的伸縮性。首先 DOM 結構有所改變,middle 不能放在最前面了:

 1 <div class="table-cell-container">
 2     <div class="table-cell-left">
 3          Table cell left
 4     </div>
 5     <div class="table-cell-middle">
 6          Table cell main
 7     </div>
 8     <div class="table-cell-right">
 9          Table cell right
10     </div>
11 </div>

  這時執行以下步驟:

  ① 將 left、middle、right 都設置為表格單元 display: table-cell;

  ② 給 left 和 right 定寬,這里假設 width: 200px;,同時設置 middle width: 100%; 

  ③ 這時候由於 middle 把兩欄都給擠到兩邊去了,所以這時候我們要把兩欄給擠回來,設置 min-width: 200px;

 1 .table-cell-container {
 2     position: relative;
 3     overflow: hidden;
 4 }
 5 .table-cell-container>div {
 6     height: 100%;
 7     display: table-cell;
 8 }
 9 .table-cell-left {
10     width: 200px;
11     min-width: 200px;
12     background-color: red;
13 }
14 .table-cell-middle {
15     margin: 0 200px;
16     width: 100%;
17     background-color: brown;
18 }
19 .table-cell-right {
20     min-width: 200px;
21     width: 200px;
22     background-color: yellow;
23 }

  OK ,現在試一試是不是同樣的是一個三欄布局,而且這種布局方案中的三欄高度是統一的,但是其缺陷就是 middle 不能夠像其他三欄布局那樣放在最前面得到最先渲染。

總結

  三欄布局的方式其實有很多,不過只要掌握了其核心思想就可以實現自定義的三欄布局。聖杯布局運用的很廣泛,不過其致命的缺點就是 middle 區域占用空間過寬時會把兩欄給擠下去,也就是當窗口 size 過小時,而雙飛翼布局正是彌補了這一缺點。如果項目不考慮低版本 IE 的兼容性的話,建議還是使用 Flex  布局,simple and powerful,如果你想試試新鮮,也可以嘗嘗表格布局,你可以在下面隨意拖動觀察不同布局方案的區別:

References:

  [1] 張鑫旭 . CSS深入理解流體特征和BFC特性下多欄自適應布局

  [2] 阮一峰 . Flex 布局教程:語法篇

  [3] 張鑫旭 . 我熟知的三種三欄網頁寬度自適應布局方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM