Flexbox 佈局完全指南(圖解 Flexbox 佈局詳細教程)
小編推薦: ofollow,noindex">掘金是一個面向程式設計師的高質量技術社群,從 一線大廠經驗分享到前端開發最佳實踐,無論是入門還是進階,來掘金你不會錯過前端開發的任何一個技術乾貨。
本文最後更新於 2018年11月15日。推薦姊妹篇: CSS Grid 佈局完全指南(圖解 Grid 詳細教程)
背景
Flexbox 佈局(也叫Flex佈局,彈性盒子佈局)模組( W3C 候選推薦,截止到2017年10月)旨在提供一個更有效地佈局、對齊方式,並且能夠使容器中的子元素大小未知或動態變化情況下仍然能夠分配好子元素之間的空間。
Flex 佈局的主要思想是使父容器能夠調節子元素的寬度/高度(和排列順序),從而能夠最好地填充可用空間(主要是為了適應所有型別的顯示裝置和螢幕尺寸)。flex布容器能夠放大子元素使之儘可能填充可用空間,也可以收縮子元素使之不溢位。
最重要的是,flexbox佈局與方向無關,不同於常規佈局(基於垂直的塊(block)和基於水平的內聯(inline))。 雖然傳統佈局適用於頁面,但它們對於大型或複雜的應用程式佈局來說缺乏靈活性(特別是在改變方向,調整大小,拉伸,收縮等方面)。
注: Flexbox佈局最適合應用程式的元件和小規模佈局,而Gird 佈局則適用於較大規模的佈局。 (愚人碼頭注:CSS Grid VS Flexbox 比較及適用情況可以檢視這篇文章 中 “CSS Grid VS Flexbox VS Table 佈局,比較及適用情況” 部分)。
基礎知識和術語
flexbox 佈局是一個完整的佈局模組而不是一個單獨的屬性,因此它涉及很多東西,包括它的整個屬性集。 其中有的屬性是在容器(container,也可以叫做父元素,稱為flex container)上設定的,有的則是在容器的子元素(item,也可以叫做子元素,稱為flex items)設定。
(愚人碼頭注:本文統一翻譯成 “flex 容器” 和 “flex 項” )。
如果 “常規”佈局基於 block(塊) 和 inline(內聯) 流動方向,flex 佈局則是基於 “flex-flow(彈性流動)” 方向。請在規範中看一下這個圖片,解釋flex佈局背後的主要思想。
在flex佈局中,flex 項(就是子元素)要麼按照 main axis
(主軸)(從 main-start
到 main-end
)排布,要麼按照 cross axis
(交叉軸) (從 cross-start
到 cross-end
)排布。
- main axis : flex 容器的主軸,flex 項沿著主軸排布,注意主軸不一定是水平的,主軸是水平還是垂直取決於
flex-direction
屬性(見下文)。 - main-start|main-end : 分別表示主軸的開始位置和結束位置,flex 項在容器中會從 main-start 到 main-end 排布。
- main size : flex 項佔據主軸的寬度或高度。flex 項的 main size 屬性是要麼是“寬度”,要麼是“高度”,這取決於主軸方向。
- cross axis : 垂直於主軸的軸線稱為交叉軸,其方向取決於主軸方向。
- cross-start|cross-end : 分別表示交叉軸的開始位置和結束位置。flex 項在交叉軸上的排布從 cross-start 開始位置到 cross-end 結束位置。
- cross size : flex 項佔據交叉軸的寬度或高度。flex 項的 cross size 屬性是要麼是“寬度”,要麼是“高度”,這取決於交叉軸方向。
父元素屬性(flex container)
display
用來定義一個 flex 容器。如果設定為 flex
則容器呈現為塊狀元素,設定為 inline-flex
則容器呈現為行內元素。它為所有直接子元素提供了 flex 上下文。
.container { display: flex; /* or inline-flex */ }
請注意,CSS 列對 flex 容器沒有影響。當然這是 Flexbox 佈局的開始。
flex-direction
flex-direction
屬性確立了主軸,從而定義了 flex 項在 flex 容器中的排布方向。 Flexbox 是單向佈局,有些時候我們也稱作一維佈局。 可以將 flex 項視為主要沿著水平行或垂直列排布。
.container { flex-direction: row | row-reverse | column | column-reverse; }
-
row
(預設值) :行排布。在ltr
(left to right, 從左到右)排版方式下,flex 項從左到右排列,在rtl
(right to left, 從右到左)排版方式下,flex 項從右到左排列。 -
row-reverse
: 反向行排布,即row
的反方向,在ltr
中從右向左,在rtl
中從左到右。 -
column
: 列排布,與row
相似,但是 flex 項從上到下排布。 -
column-reverse
: 反向列排布,即column
反方向,與row-reverse
相似,只是 flex 項從上到下排布。
flex-wrap
預設情況下,flex 項會盡可能地嘗試排在同一行上(行或列),通過設定 flex-wrap
來決定 flex 項是否允需要換行。
.container{ flex-wrap: nowrap | wrap | wrap-reverse; }
-
nowrap
(預設值) : 所有的 flex 項都會在同一行上排布,也就是我們常說的單行,或不換行。 -
wrap
: flex 項將從上到下根據實際情況排布再多行上,也就是我們常說的多行,或會換行。 -
wrap-reverse
: flex 項將 從下到上 根據實際情況排布再多行上折行。
flex-wrap 視覺化的示例:
See the Pen Flex-wrap: demo by feiwen8772 ( @feiwen8772 ) on CodePen .0
flex-flow (適用於父級 flex 容器)
這是 flex-direction
和 flex-wrap
屬性的縮寫形式。同時定義 flex 容器的主軸和交叉軸。預設是 row nowrap
。
flex-flow: <‘flex-direction’> || <‘flex-wrap’>
justify-content
justify-content
屬性定義了flex 項沿主軸方向的對齊方式。
當一行中的所有 flex 項都是固定大小,或者是靈活大小但已經達到最大 main size 時,它可以幫助分配主軸上的剩餘空間。當 flex 項溢位主軸的時候,它還可以用來控制flex 項的對齊方式。
.container { justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly; }
-
flex-start
(預設值) : flex 項從主軸的開始位置(main-start)開始排布。 -
flex-end
: flex 項從主軸的結束位置(main-end)開始排布 -
center
: flex 項沿主軸居中排布。 -
space-between
: flex 項沿主軸均勻排布,即我們常說的沿主軸 兩端對齊 ,第一個flex 項在主軸開始位置,最後一個flex 項在主軸結束位置。 -
space-around
: flex 項沿主軸均勻排布。要注意的是 flex 項看起來間隙是不均勻的,因為所有 flex 項兩邊的空間是相等的。第一項在容器邊緣有一個單位的空間,但是在兩個 flex 項之間有兩個單位的間隙,因為每個 flex 項的兩側都有一個單位的間隙。 -
space-evenly
: 任何兩個 flex 項之間的間距(以及到 flex 容器邊緣的空間)相等。(愚人碼頭注:該屬性以前很少看到,原因是以前瀏覽器不支援,chrome 也是 60 版本之後才支援。延伸一下,align-content: space-evenly
也是這個邏輯,大家可以檢視下面的demo。 )
See the Pen justify-content: space-evenly 和 align-content: space-evenly by feiwen8772 ( @feiwen8772 ) on CodePen .0
align-items
align-items
定義了 flex 項如何沿當前行在交叉軸上排布的預設行為。可以將其視為交叉軸(垂直於主軸)上的對齊方式。
.container { align-items: flex-start | flex-end | center | baseline | stretch; }
flex-start flex-end: center baseline stretch
See the Pen align-items:stretch 和 size by feiwen8772 ( @feiwen8772 ) on CodePen .0
align-content
當交叉軸上有剩餘空間時, align-content
可以設定 flex 容器中的 行 在交叉軸上如何分配剩餘空間,類似於 justify-content
在主軸上對齊單個 flex 項的方式。
注意:當只有一行 flex 項時,此屬性不起作用。
.container { align-content: flex-start | flex-end | center | space-between | space-around | stretch; }
flex-start flex-end center space-between space-around strech
flex 項屬性 (flex items)
order
預設情況下,flex 項按源(HTML結構)順序排布。但是, order
屬性可以控制它們在 flex 容器中的顯示順序。
.item { order: <integer>;/* 預設值是 0 */ }
flex-grow
flex-grow
定義了 flex 項在有可用剩餘空間時拉伸比例。它接受的值作為比例,無單位。它規定了 flex 項應該佔 flex 容器中可用空間的比例。
如果所有 flex 項的 flex-grow
都設定為 1
,則父容器中的剩餘空間將平均分配給所有子項。 如果其中一個子項的值為 2
,則該子項佔用的剩餘空間是其他子項的兩倍(或者至少會盡力獲得)。
.item { flex-grow: <number>; /* default 0 */ }
注:負值對於 flex-grow 無效。
愚人碼頭注,舉個例子幫助你理解:
比如我們得 flex 容器中有 6 個 flex 項,每個 flex 項的 flex-grow
初始值都是 1。如果我們將每個 flex 項的 flex-grow
相加起來,總和為 6。因此 flex 容器的總寬度被平均分成了 6 份。每個 flex 項增長到填充容器可用空間的1/6。
當我們將第 3 個 flex 項的 flex-grow
設定為 2 時,flex 容器現在被分成了 7 等份,因為所有 flex-grow
屬性是:1 + 1 + 2 + 1 + 1 + 1。第 3 個 flex 項佔了整個容器空間的 2/7,其他的佔了 1/7。
具體可以檢視 【Flex佈局教程】更多關於Flexbox佈局如何工作的 – 用大彩圖和GIF動畫解釋 中的 “屬性 #2: Flex Grow(拉伸)”
flex-shrink
flex-shrink
定義了 flex 項的收縮的能力。(愚人碼頭注:與 flex-grow
拉伸正好相反, flex-shrink
決定 flex 項允許收縮多少比例。)
.item { flex-shrink: <number>; /* default 1 */ }
注:負值對於 flex-shrink 無效。
flex-basis
flex-basis
定義了在分配剩餘空間之前 flex 項預設的大小。可以設定為某個長度值(e.g. 20%, 5rem,等)或者關鍵字。關鍵字 auto
意味著 flex 項會按照其本來的大小顯示(暫時由 main-size
關鍵字完成,直到棄用)。關鍵字 content
意味著根據內容來確定大小——這個關鍵字到目前沒有被很好地支援,所以測試起來比較困難,與 content
的類似的關鍵字還有 max-content
, min-content
, fit-content
。
.item { flex-basis: <length> | auto; /* default auto */ }
如果設定為 0
, 則 flex 項內容周圍的空隙不會根據 flex-grow
按比例分配,如果設定為 auto
,則 flex 項周圍額外的空襲會根據 flex-grow
按照比例分配,如下圖:
flex
flex
是 flex-grow
、 flex-shrink
、 flex-basis
三個屬性的縮寫。其中第二個和第三個引數( flex-shrink
和 flex-basis
)是可選的。預設值為 0 1 auto
。
.item { flex: none | [ < 'flex-grow'> < 'flex-shrink'>? || < 'flex-basis'> ] }
推薦使用縮寫形式而不是單獨地設定每一個屬性,縮寫形式中會更加智慧地計算出相關值。
align-self
align-self
屬性允許某個單獨的 flex 項覆蓋預設的對齊方式(或由 align-items
指定的對齊方式)。
具體的屬性值得含義可以參考 align-items
的解釋。
.item { align-self: auto | flex-start | flex-end | center | baseline | stretch; }
注: float
, clear
和 vertical-align
對 flex 項沒有任何作用。
示例
我們從一個非常非常簡單的例子開始,解決一個幾乎每天會遇到的問題:水平垂直居中。如果使用flexbox 佈局會非常簡單。
.parent { display: flex; height: 300px; /* 隨意設定大小 */ } .child { width: 100px;/* 隨意設定大小,比父元素要小 */ height: 100px; /* 同上 */ margin: auto;/* 見證奇蹟的時刻 */ }
這依賴於在 flex 容器中設定 margin
為 auto
會自動吸收額外空間。 因此,設定水平垂直的margin都為 auto
會使flex 項在水平垂直方向上都完美居中。
現在我們考慮用更多的屬性。考慮有 6 個有固定的尺寸的 flex 項,但是我們希望他們能夠在改變瀏覽器寬度的時候仍然可以在水平軸上完美地顯示(沒有使用媒體查詢(media queries))。
.flex-container { /* 首先我們先建立一個flex佈局上下文 */ display: flex; /* 然後我們定義flex方向和是否允許flex 項換行 * 注意這與以下程式碼等價: * flex-direction: row; * flex-wrap: wrap; */ flex-flow: row wrap; /* 然後我們定義在剩餘空間上flex 項如何排布 */ justify-content: space-around; }
完成。剩下的就是一些其他樣式如顏色的設定了。下面是在 CodePen 中實現的這個例子。一定要去CodePen,並嘗試調整你的視窗看看會發生什麼。
See the Pen Demo Flexbox 1 by CSS-Tricks ( @css-tricks ) on CodePen .0
讓我們再嘗試一些別的東西。假設我們有一個向右對齊的導航欄在我們網頁的最上端,但是我們希望它在中屏上顯示時為居中,在小屏上顯示為單列。同樣使用flex佈局,實現起來會很簡單。
/* 大屏 */ .navigation { display: flex; flex-flow: row wrap; /* 這裡設定對齊主軸方向的末端 */ justify-content: flex-end; } /* 中屏 */ @media all and (max-width: 800px) { .navigation { /* 當在中屏上,設定居中,並設定剩餘空間環繞在flex 項左右 */ justify-content: space-around; } } /* 小屏 */ @media all and (max-width: 500px) { .navigation { /* 在小屏上,我們不在使用行作為主軸,而以列為主軸 */ flex-direction: column; } }
See the Pen Demo Flexbox 2 by CSS-Tricks ( @css-tricks ) on CodePen .0
我們通過靈活使用 flexbox 佈局嘗試一些更好玩的佈局。來做一個移動優先的 3 列布局並帶有全屏寬的header和footer。
.wrapper { display: flex; flex-flow: row wrap; } /* 我們要告訴所有的flex 項寬度 100% */ .wrapper > * { flex: 1 100%; } /* 移動優先依賴於原始碼預設的渲染順序 * in this case: * 1. header * 2. nav * 3. main * 4. aside * 5. footer */ /* 中屏 */ @media all and (min-width: 600px) { /* 我們要告訴兩邊的sidebar共享一個行 */ .aside { flex: 1 auto; } } /* 大螢幕 */ @media all and (min-width: 800px) { /* 通過order設定各個面板的渲染順序 * 告訴主要面板元素佔用側欄兩倍的空間 */ .main { flex: 2 0px; } .aside-1 { order: 1; } .main{ order: 2; } .aside-2 { order: 3; } .footer{ order: 4; } }
See the Pen Demo Flexbox 3 by Chris Coyier ( @chriscoyier ) on CodePen .0
瀏覽器字首
Flexbox 佈局需要一些瀏覽器字首來最大力度地相容大多數的瀏覽器。Flex佈局的字首不只是在屬性前面新增瀏覽器字首,不同瀏覽器下的屬性名和屬性值都不同,這是因為Flexbox佈局的標準一直在變,一共有 “old”, “tweener”, 和 “new” 三個版本。
可能處理字首的最好方法是使用新的語法書寫CSS並通過 Autoprefixer 執行CSS,能夠很好地處理這個問題。
另外,這裡有一個Sass中 @mixin 來處理一些字首,也可以給你一些處理字首的啟發:
@mixin flexbox() { display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; } @mixin flex($values) { -webkit-box-flex: $values; -moz-box-flex:$values; -webkit-flex:$values; -ms-flex:$values; flex:$values; } @mixin order($val) { -webkit-box-ordinal-group: $val; -moz-box-ordinal-group: $val; -ms-flex-order: $val; -webkit-order: $val; order: $val; } .wrapper { @include flexbox(); } .item { @include flex(1 200px); @include order(2); }
相關屬性
其他資源
- 【Flex佈局教程】Flexbox佈局是如何工作的 – 用大彩圖和GIF動畫解釋
- 【Flex佈局教程】更多關於Flexbox佈局如何工作的 – 用大彩圖和GIF動畫解釋 – 【Flex佈局教程】CSS3 Flexbox屬性視覺化指南
- CSS3 Flexbox解決方案
- Flexbox at MDN
- Flexbox at Opera
- Diving into Flexbox by Bocoup
- Mixing syntaxes for best browser support on CSS-Tricks
- Flexbox by Raphael Goetter (FR)
- Flexplorer by Bennett Feely
Bugs
我見過的最棒的flexbox bug總結是Philip Walton 和 Greg Whitworth的 Flexbugs ,是開源的,你可以在上面跟蹤動態。
瀏覽器支援
首先看一下 flexbox 佈局的三個版本
- (new)是指標準中最近的語法(e.g. display:flex;)。
- (tweener)是指2011年以後非官方的臨時版本(e.g. display:flexbox;)。
- (old)是指2009年以後的舊語法(e.g. display:box;)
Chrome | Safari | Firefox | Opera | IE | Android | iOS |
---|---|---|---|---|---|---|
20- (old) 21+ (new) |
3.1+ (old) 6.1+ (new) |
2-21 (old) 22+ (new) |
12.1+ (new) | 10 (tweener) 11+ (new) |
2.1+ (old) 4.4+ (new) |
3.2+ (old) 7.1+ (new) |
Blackberry browser 10+ 支援新語法。
更多混合使用語法達到最佳瀏覽器相容,可以參考 這篇文章 (CSS-Tricks) 或者 這篇文章 (DevOpera) 。
原文連結: A Complete Guide to Flexbox
如果你覺得本文對你有幫助,那就請分享給更多的朋友
關注「前端乾貨精選」加星星,每天都能獲取前端乾貨
