一篇完整的FlexBox布局指南
轉載請標注本文鏈接並附帶以下信息: 譯:Cydiacen 作者:CHRIS COYIER 原文:A Complete Guide to Flexbox 原文更新於 2016-11-19
譯者的話
出於提升自身英語水平和鞏固FlexBox的知識,於是打算翻譯一篇比較知名的FlexBox布局的文章,當然這篇文章之前網上已有大漠
的譯文,此次翻譯也有部分參考大漠
譯文的內容,於是在此貼上大漠
譯文的地址,以此致敬大佬。《一個完整的Flexbox指南》
為了不浪費大家時間,先說明下flexBox現在的兼容情況:
- (new)意味着已成為規范的新語法(比如:
display:flex;
) - (tweener)意味着是來自2011年一種臨時的非官方的語法(
display:flexbox;
) - (old)意味着來自2009年的老語法(
display:box;
)
Chorme | Safari | Firefox | Opera | IE | Android | IOS |
---|---|---|---|---|---|---|
20- (old) | 3.1+ (old) | 2-21 (old) | 12.1+ (new) | 10 (tweener) | 2.1+ (old) | 3.2+ (old) |
21+ (new) | 6.1+ (new) | 22+ (new) | 11+ (new) | 4.4+ (new) | 7.1+ (new) |
黑莓瀏覽器 10+ 支持新語法。
關於怎么樣混合語法可以得到更好的瀏覽器支持的信息,可以跳轉到《CSS-Tricks》或者《DevOpera》。
寫作背景
Flexbox(彈性盒子)布局模式(目前是個W3C規范草案)旨在為布局,對齊和分布容器內的子項提供一種更加高效的方式,即使這些玩意兒的大小是未知的或者動態變化的。(正如他的名字所示——Flex,彈性的意思)
Flex布局背后的主要思想是——給指定的容器提供修改其子項的寬、高乃至順序的能力,並且足夠完美的去填充可用的空間(主要是為了適應各種各樣的顯示設備和屏幕大小)。
一個使用了Flex布局的容器,將會擴展其子項以至於填充起可用的空間,或者縮小他們以防止溢出容器。
有一個相當重要的一點,FlexBox布局的方向不像常規布局(塊就是垂直從上到下,行就是水平從左到右),它是不可預知方向的。而那些常規的適合頁面布局,但對於作用在大型或者復雜的應用程序(特別是當他涉及到方向改變、大小變化、拉伸和收縮等)就缺乏靈活性。
注意: FlexBox布局最適用於應用程序的組件和小規模布局,而網格布局更適用於大規模的布局。
基本要素
因為FlexBox是一整個模塊並不是一個單獨的屬性,它涉及到很多東西包括它的所有設置屬性。一些屬性是需要被設置在容器(父級元素,稱為『彈性容器』),而一些其他的屬性需要被設置在子元素(稱為『彈性項』)中。
如果常規布局是基於塊布局與內聯布局的方向流的,那么彈性布局就是基於“flex-flow流”。請看一下來自W3C規范的這張圖,它解釋了彈性布局的主要思想。

基本上,彈性項(flex item)會沿着主軸方向(main-start
到main-end
)或側軸方向(cross-start
到cross-end
)排列。
- 主軸(
main axis
) - 彈性項主要是沿着彈性容器的主軸進行排列的。要注意一點,他不一定是水平的;這主要還是看flex-direction
屬性(見下文)。 main-start | main-end
- 彈性項將由main-start
到main-end
方向放置在容器內。main size
- 彈性項在主軸方向的寬度或高度就是主軸的尺寸。彈性項主要的大小屬性可以是寬度,也可以是高度屬性,由哪一個對着主軸方向決定。cross axis
- 與主軸垂直相交的軸線就是側軸。它的方向由主軸決定。cross-start | cross-end
- 彈性行是由彈性項填充起來的,它的配置是從容器的cross-start
開始,往cross-end
結束。cross size
- 彈性項在側軸方向的寬度或高度就是cross size
。cross size
根據側軸的方向來取決是寬度還是高度。
父級(彈性容器)屬性

display
這個屬性是定義在彈性容器上的;根據其值決定是內聯還是塊布局。這時它的直屬下級將會變成flex文檔流。
.container {
display: flex; /* or inline-flex */
}
需要注意CSS的columns在flex容器里沒有效果。
flex-direction

這個是建立在主軸上的,從而定義了彈性項放置在容器的方向。FlexBox是單方向的布局概念。可以將彈性項視為主要布置在水平行或垂直列中。
.container {
flex-direction: row | row-reverse | column | column-reverse;
}
row
(默認):在ltr
排版方式下從左向右排列;在rtl
排版方式下從右向左排列。row-reverse
:與row
排列方向相反,在ltr
排版方式下從右向左排列;在rtl
排版方式下從左向右排列。column
:類似於row
但是是頂部到底部column-reverse
:類似於row-reverse
但是是底部到頂部
flex-wrap

彈性項默認會全部集中在一行。你可以使用這個屬性來改變這種情況,讓他們根據你的需要進行自動換行。文檔方向在這里也起作用,決定了新的一行被堆疊的方向。
.container{
flex-wrap: nowrap | wrap | wrap-reverse;
}
nowrap
(默認):單行顯示。在ltr
排版下,項目自左向右;在rtl
下,自右向左wrap
:多行顯示。在ltr
排版下,項目自左向右;在rtl
下,自右向左wrap-reverse
:多行顯示。與wrap
相反
flex-flow(定義在彈性容器中)
這個是flex-direction
和flex-wrap
屬性的縮寫版,它同時定義了彈性容器的主軸和側軸。默認是row nowrap
。
flex-flow: <‘flex-direction’> || <‘flex-wrap’>
justify-content

這屬性是用來定義主軸上的對齊方式的。當所有的彈性項在一行並且無法彈性伸展,或者可伸展但是達到了最大尺寸,它能幫助分配剩下的多余空間。並且當他們行內溢出時,這個屬性也可以對項目對齊施加一些控制。
.container {
justify-content: flex-start | flex-end | center | space-between | space-around;
}
flex-start
(默認):子項會從一行的起始處開始放置flex-end
:子項會從一行的結尾處開始放置center
:子項會集中在一行的中央space-between
:子項會被均勻的分布在行內;首項放置在一行的開始,尾項放置在一行的結束space-around
:子項會均勻的按照同等距離分布在一行。需要注意的是,在視覺上會覺得並不等距,因為所有子項在兩側都需要加上同等的空間。首項會與容器開始邊緣有一個單位空間的距離,但是與下一項會有兩個單位空間的距離,因為下一項也有它自己的適配空間。
align-items

這用來定義彈性項目在彈性容器的當前側軸上的默認行為。可以認為是側軸版的justity-content
。
.container {
align-items: flex-start | flex-end | center | baseline | stretch;
}
flex-start
:彈性項在側軸起點邊的外邊距緊靠住該行在側軸起始的邊。flex-end
:彈性項在側軸起點邊的外邊距緊靠改行在側軸結尾的邊。center
:彈性項會被放置在側軸的中央。baseline
:彈性項會根據他們的基線對齊。stretch
(默認):在側軸方向上拉伸彈性項以致填充滿彈性容器。(任遵從min-width/max-width
)
align-content

這個屬性會根據在側軸上的額外空間來排列容器的行,類似於justify-content
在主軸在對齊單個彈性項的方式。
注意,這個屬性對於只有單行的彈性項來說是沒有效果的。
.container {
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
flex-start
:行會緊靠容器的起始位flex-end
:行緊靠容器的結束位center
:行緊靠容器的中間位space-between
:每行會均勻分布;首行在容器起始處而最后行在容器結束處space-around
:每行根據相同的距離均勻的分布stretch
(默認):每行將會伸展以占用剩余的空間。
子項(彈性項)的屬性

order

一般來說,彈性項會按照文檔流的順序進行布局。然而,order
屬性可以控制他們出現在彈性容器中的順序。
.item {
order: <integer>;
}
flex-grow

這個屬性給予彈性項在需要的時候可以伸展的能力。它接收一個不帶單位的值作為比例。它規定了在容器內的彈性項可以占用多少的可用空間。
如果所有的子項都設置了flex-grow
為1,那么容器內的剩余空間會被均勻的分配給所有自項。如果其中一項的值為2,那么這項的占用空間會是其他項的兩倍。
.item {
flex-grow: <number>; /* default 0 */
}
設置負數是無效的。
flex-shrink
這定義了彈性項在需要的時候具有伸展的能力。
.item {
flex-shrink: <number>; /* default 1 */
}
負數是無效的。
flex-basis
這定義了,當一個元素在被分配到剩余空間之前的默認大小。它可以是一個長度(如:20%,5rem等)或者一個關鍵字。auto
關鍵字的意思就是『按照我的寬度和高度屬性調整尺寸』(他會暫時根據main-size
來布局大小直到被棄用)。如果使用關鍵字content
,意思就是『基於內容調整大小』——不過這個關鍵字並一定能很好的工作,因此很難去測試或者知曉它的兄弟們max-content
,min-content
和fit-content
做了什么。
.item {
flex-basis: <length> | auto; /* default auto */
}
如果設置為0,額外空間內容不會被分解開來。如果設置成auto
,額外空間會基於它的flex-grow
的值進行分布。

flex
這是flex-grow
,flex-shrink
和flex-basis
組合縮寫版。第二個和第三個參數(flex-shrink
和flex-basis
)是可選的。默認是0 1 auto
。
推薦你使用的這種縮寫屬性,這比設置單獨屬性更好。可以智能的通過縮寫形式設置值。
align-self

用來在單獨的伸縮項目上覆寫默認的對齊方式。
請看下align-items
的解釋,幫助你了解可用值。
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
注意,float
,clear
和vertical-align
在彈性項中會失效。
例子
讓我們從一個非常非常簡單的例子開始,解決一個非常日常的問題:完美居中。如果你使用flexBox
布局,這將會變得非常簡單。
.parent {
display: flex;
height: 300px; /* Or whatever */
}
.child {
width: 100px; /* Or whatever */
height: 100px; /* Or whatever */
margin: auto; /* Magic! */
}
這個依賴於設置margin
值為auto
值,會自動獲取彈性容器的額外空間。因此設置垂直方向margin
為auto
可以讓彈性項完美的居中在兩個軸。
現在讓我們使用下一些其他屬性。
考慮使用一個包含六個項的列表,並且為了視覺審美給他設置了一個固定大小尺寸,但他們也有可能可以自動獲取尺寸大小。我們想要他們可以均勻的,並且完美分布在水平軸上,並且當我改變瀏覽器的大小,他們還是可以很好的展示(不需要引用媒體查詢!)。
.flex-container {
/* 我們先創建一個彈性布局環境*/
display: flex;
/* 然后如果我們允許子項換行可以定義flow-direction
* 記住這相等於:
* flex-direction: row;
* flex-wrap: wrap;
*/
flex-flow: row wrap;
/* 然后我們再定義怎么樣分布剩余的空間 */
justify-content: space-around;
}
完工。其他的一切不過是美化樣式。下面提供一些html,css代碼,可以在codePen
調試並且改變下瀏覽器的大小看看會發生什么。
codePen
<ul class="flex-container">
<li class="flex-item">1</li>
<li class="flex-item">2</li>
<li class="flex-item">3</li>
<li class="flex-item">4</li>
<li class="flex-item">5</li>
<li class="flex-item">6</li>
</ul>
SASS:
@import "compass/css3";
.flex-container {
padding: 0;
margin: 0;
list-style: none;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row wrap;
justify-content: space-around;
}
.flex-item {
background: tomato;
padding: 5px;
width: 200px;
height: 150px;
margin-top: 10px;
line-height: 150px;
color: white;
font-weight: bold;
font-size: 3em;
text-align: center;
}
讓我們再嘗試下其他東西。想象下,我們的網站所有頁面頭部都有個右對齊布局的導航,但是我們想讓他在中等大小的屏幕中居中顯示並且在小屏幕設備中單行顯示。非常簡單。
/* Large */
.navigation {
display: flex;
flex-flow: row wrap;
/* This aligns items to the end line on main-axis */
justify-content: flex-end;
}
/* Medium screens */
@media all and (max-width: 800px) {
.navigation {
/* When on medium sized screens, we center it by evenly distributing empty space around items */
justify-content: space-around;
}
}
/* Small screens */
@media all and (max-width: 500px) {
.navigation {
/* On small screens, we are no longer using row direction but column */
flex-direction: column;
}
}
讓我們再來試試一些更加靈活性的彈性項!關於移動先行,3列布局與頁眉頁腳全屏。和獨立的文檔順序。
.wrapper {
display: flex;
flex-flow: row wrap;
}
/* We tell all items to be 100% width */
.header, .main, .nav, .aside, .footer {
flex: 1 100%;
}
/* We rely on source order for mobile-first approach
* in this case:
* 1. header
* 2. nav
* 3. main
* 4. aside
* 5. footer
*/
/* Medium screens */
@media all and (min-width: 600px) {
/* We tell both sidebars to share a row */
.aside { flex: 1 auto; }
}
/* Large screens */
@media all and (min-width: 800px) {
/* We invert order of first sidebar and main
* And tell the main element to take twice as much width as the other two sidebars
*/
.main { flex: 2 0px; }
.aside-1 { order: 1; }
.main { order: 2; }
.aside-2 { order: 3; }
.footer { order: 4; }
}
Flexbox前綴
Flexbox
接受一些運營商前綴以支持可以在更多的瀏覽器上使用。它不僅只包括在屬性前添加前綴,它也有完全不同的屬性名字和值名字。這是因為Flexbox
規范隨着時間一直在變化,因此有了old
,tweener
和new
版本。
當然最好的方式是使用最新的語法,並且通過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);
}
相關屬性
-
Grid 屬性的年度條目,比如 grid-row/grid-column
Bugs
Flex當然不是沒有bug,我見過的關於這些bug收集最好的是Philip Walton
和 Greg Whitworth
的FlexBugs。