CSS 雖然初衷是用來美化 HTML 文檔的,但實際上随着 float、position 等屬性的出現,它已經可以起到調整文檔渲染結構的作用了,而随着彈性盒子以及網格布局的推出,CSS 将承擔越來越重要的布局功能。漸漸地我們發現 HTML 标簽決定了頁面的邏輯結構,而 CSS 決定了頁面的視覺結構。
這一課時我們先來分析常見的布局效果有哪些,然後再通過代碼來實作這些效果,進而幫助你徹底掌握 CSS 布局。
我們通常提到的布局,有兩個共同點:
大多數用于 PC 端,因為 PC 端螢幕像素寬度夠大,可布局的空間也大;
布局是有限空間内的元素排列方式,因為頁面設計橫向不滾動,縱向無限延伸,是以大多數時候讨論的布局都是對水準方向進行分割。
實際上我們在讨論布局的時候,會把網頁上特定的區域進行分列操作。按照分列數目,可以大緻分為 3 類,即單列布局、2 列布局、3 列布局。
單列布局
單列布局是最常用的一種布局,它的實作效果就是将一個元素作為布局容器,通常設定一個較小的(最大)寬度來保證不同像素寬度螢幕下顯示一緻。
示例網站
拉勾,藍色區域為布局容器,水準居中對齊,寬度 1260px:
谷歌搜尋,藍色區域為布局容器,水準左對齊,寬度 652px:
一些網站會将單列布局與其他布局方式混合使用,比如拉勾網
首頁的海報和左側标簽就使用了 2 列布局,這樣既能向下相容窄螢幕,又能按照主次關系顯示頁面内容。
這種布局的優勢在于基本上可以适配超過布局容器寬度的各種顯示螢幕,比如上面的示例網站布局容器寬度為 700px,也就是說超過 700px 寬度的顯示螢幕上浏覽網站看到的效果是一緻的。
但它最大的缺點也是源于此,過度的備援設計必然會帶來浪費。例如,在上面的例子中,其實我的螢幕寬度是足夠的,可以顯示更多的内容,但是頁面兩側卻出現了大量空白區域,如果在 4k 甚至更寬的螢幕下,空白區域大小會超過頁面内容區域大小!
2 列布局
2 列布局使用頻率也非常的高,實作效果就是将頁面分割成左右寬度不等的兩列,寬度較小的列設定為固定寬度,剩餘寬度由另一列撐滿。為了描述友善,我們暫且稱寬度較小的列父元素為次要布局容器,寬度較大的列父元素為主要布局容器。
示例網站
Ant Design 文檔,藍色區域為主要内容布局容器,側邊欄為次要内容布局容器。
這種布局适用于内容上具有明顯主次關系的網頁,比如 API 文檔頁面中左側顯示内容導航,右側顯示文檔描述;又比如背景管理系統中左側顯示菜單欄,右側顯示配置頁面。相對于單列布局,在螢幕寬度适配方面處理得更好。當螢幕寬度不夠時,主要内容布局容器優先顯示,次要内容布局容器改為垂直方向顯示或隐藏,但有時候也會和單列布局搭配使用,作為單列布局中的子布局使用。
3 列布局
3 列布局按照左中右的順序進行排列,通常中間列最寬,左右兩列次之。
示例網站
登入 GitHub 後,藍色區域為寬度最大的中間列。
CSDN 首頁,這是 3 列布局的第二種實作方式,藍色部分就是 2 列布局的主要布局容器,而它的子元素又使用了 2 列布局。
3 列布局和 2 列布局類似,也有明确的主次關系,隻是關系層次增加了一層。下面我們來看看如何實作這些布局。
布局實作
單列布局沒有太多技術難點,通過将設定布局容器(最大)寬度以及左右邊距為 auto 即可實作,我們重點讨論 2 列和 3 列布局。關于這兩種布局,在網上可以找到很多實作方式,我們是不是隻要把這些方式收集起來然後都記住就行了呢?
當然不是!
我們要做的是通過歸納法,找到這些方式的共同實作步驟,隻要把這些步驟記住了,就能做到舉一反三。
你可以試着自己先整理一下,或者直接看我整理好的結果。
要實作 2 列布局或 3 列布局,可以按照下面的步驟來操作:
(1)為了保證主要布局容器優先級,應将主要布局容器寫在次要布局容器之前。
(2)将布局容器進行水準排列;
(3)設定寬度,即次要容器寬度固定,主要容器撐滿;
(4)消除布局方式的副作用,如浮動造成的高度塌陷;
(5)為了在窄屏下也能正常顯示,可以通過媒體查詢進行優化。
根據以上操作步驟,先來看一個使用 flex 布局實作 2 列布局的例子。
第 1 步,寫好 HTML 結構。這裡為了檢視友善,我們為布局容器設定背景顔色和高度。
主要布局容器 次要布局容器
第 2 步,将布局容器水準排列:
主要布局容器 次要布局容器
第 3 步,調整布局容器寬度:
主要布局容器 次要布局容器
第 4 步,消除副作用,比如浮動造成的高度塌陷。由于使用 flex 布局沒有副作用,是以不需要修改,代碼和效果圖同第 3 步。
第 5 步,增加媒體查詢。
主要布局容器 次要布局容器
下面再來個複雜些的 3 列布局的例子。
第 1 步,寫好 HTML 結構,為了辨認友善,我們給布局容器設定背景色和高度:
main left right
第 2 步,讓布局容器水準排列:
main left right
第 3 步,調整寬度,将主要布局容器 main 撐滿,次要布局容器 left 固定 300px,次要布局容器 right 固定 200px。
這裡如果直接設定的話,布局容器 left 和 right 都會換行,是以我們需要通過設定父元素 wrap 内邊距來壓縮主要布局 main 給次要布局容器留出空間。同時通過設定次要布局容器邊距以及采用相對定位調整次要布局容器至兩側。
main left right
第 4 步,消除副作用。我們知道使用浮動會造成高度塌陷,如果在父元素後面添加新的元素就會産生這個問題。是以可以通過僞類來清除浮動,同時減小頁面寬度,還會發現次要布局容器 left 和 right 都換行了,但這個副作用我們可以在第 5 步時進行消除。
main left right
第 5 步,利用媒體查詢調整頁面寬度較小情況下的顯示優先級。這裡我們仍然希望優先顯示主要布局容器 main,其次是次要布局容器 left,最後是布局容器 right。
main left right
這種 3 列布局的實作,就是流傳已久的“聖杯布局”,但标準的聖杯布局沒有添加媒體查詢。
延伸1:垂直方向的布局
垂直方向有一種布局雖然使用頻率不如水準方向布局高,但在面試中很容易被問到,是以這裡特意再補充講解一下。
這種布局将頁面分成上、中、下三個部分,上、下部分都為固定高度,中間部分高度不定。當頁面高度小于浏覽器高度時,下部分應固定在螢幕底部;當頁面高度超出浏覽器高度時,下部分應該随中間部分被撐開,顯示在頁面最底部。
這種布局也稱之為”sticky footer“,意思是下部分粘黏在螢幕底部。要實作這個功能,最簡單的就是使用 flex 或 grid 進行布局。下面是使用 flex 的主要代碼:
...
代碼實作思路比較簡單,将布局容器的父元素 display 屬性設定成 flex,伸縮方向改為垂直方向,高度撐滿頁面,再将中間布局容器的 flex 屬性設定為 1,讓其自适應即可。
如果要考慮相容性的話,其實作起來要複雜些,下面是主要代碼:
将上部分布局容器與中間布局容器放入一個共同的父元素中,并讓父元素高度撐滿,然後設定内下邊距給下部分布局容器預留白間,下部分布局容器設定上外邊距“嵌入”父元素中。進而實作了随着中間布局容器高度而被撐開的效果。
延伸2:架構中栅格布局的列數
很多 UI 架構都提供了栅格系統來幫助頁面實作等分或等比布局,比如 Bootstrap 提供了 12 列栅格,elment ui 和 ant design 提供了 24 列栅格。
那麼你思考過栅格系統設定這些列數背後的原因嗎?
首先從 12 列說起,12 這個數字,從數學上來說它具有很多約數 1、2、3、4、6、12,也就是說可以輕松實作 1 等分、2 等分、3 等分、4 等分、6 等分、12 等分,比例方面可以實作 1:11、1:5、1:3、1:2、1:1、1:10:1、1:4:1 等。如果換成 10 或 8,則可實作的等分比例就會少很多,而更大的 16 似乎是個不錯的選擇,但對于常用的 3 等分就難以實作。
至于使用 24 列不使用 12 列,可能是考慮寬螢幕(PC 端螢幕寬度不斷增加)下對 12 列難以滿足等分比例需求,比如 8 等分。同時又能夠保證相容 12 列情況下的等分比例(友善項目遷移和替換)。
總結
通過這一講,我們學習了幾種常見布局,包括單列、2 列、3 列及垂直三欄布局,同時思考每種布局的優缺點和使用場景,并且對 2 列布局和 3 列布局實作方法歸納成了 5 個步驟,最後布置一道思考題:你還想到了使用哪些方法來實作 2 列或 3 列布局?