Flexible Box 模型,通常被稱為 flexbox,是一種一維的佈局模型。它給 flexbox 的子元素之間提供了強大的空間分佈和對齊能力。本文給出了 flexbox 的主要特性,更多的細節將在別的檔案中探索。
我們說 flexbox 是一種一維的佈局,是因為一個 flexbox 一次只能處理一個維度上的元素佈局,一行或者一列。作為對比的是另外一個二維佈局 CSS Grid Layout,可以同時處理行和列上的佈局。
Flexible Box 模型,通常被稱為 flexbox,是一種一維的佈局模型。它給 flexbox 的子元素之間提供了強大的空間分佈和對齊能力。本文給出了 flexbox 的主要特性,更多的細節將在別的檔案中探索。
我們說 flexbox 是一種一維的佈局,是因為一個 flexbox 一次只能處理一個維度上的元素佈局,一行或者一列。作為對比的是另外一個二維佈局 CSS Grid Layout,可以同時處理行和列上的佈局。
當使用 flex 佈局時,首先想到的是兩根軸線 — 主軸和交叉軸。主軸由 flex-direction
定義,另一根軸垂直於它。我們使用 flexbox 的所有屬性都跟這兩根軸線有關,所以有必要在一開始首先理解它。
主軸由 flex-direction
定義,可以取 4 個值:
row
row-reverse
column
column-reverse
如果你選擇了 row
或者 row-reverse
,你的主軸將沿著 inline 方向延伸。
選擇 column
或者 column-reverse
時,你的主軸會沿著上下方向延伸 — 也就是 block 排列的方向。
交叉軸垂直於主軸,所以如果你的flex-direction
(主軸) 設成了 row
或者 row-reverse
的話,交叉軸的方向就是沿著列向下的。
如果主軸方向設成了 column
或者 column-reverse
,交叉軸就是水平方向。
理解主軸和交叉軸的概念對於對齊 flexbox 裡面的元素是很重要的;flexbox 的特性是沿著主軸或者交叉軸對齊之中的元素。
另外一個需要理解的重點是 flexbox 不會對檔案的書寫模式提供假設。過去,CSS 的書寫模式主要被認為是水平的,從左到右的。現代的佈局方式涵蓋了書寫模式的範圍,所以我們不再假設一行文字是從檔案的左上角開始向右書寫,新的行也不是必須出現在另一行的下面。
你可以在接下來的文章中學到更多 flexbox 和書寫模式關係的詳細說明。下面的描述是來幫助我們理解為什麼不用上下左右來描述 flexbox 元素的方向。
如果 flex-direction
是 row
,並且我是在書寫英文,那麼主軸的起始線是左邊,終止線是右邊。
如果我在書寫阿拉伯文,那麼主軸的起始線是右邊,終止線是左邊。
在這兩種情況下,交叉軸的起始線是 flex 容器的頂部,終止線是底部,因為兩種語言都是水平書寫模式。
之後,你會覺得用起始和終止來描述比左右更合適,這會對你理解其他相同模式的佈局方法(例如:CSS Grid Layout)起到幫助的作用。
display
屬性值改為 flex
或者 inline-flex
。完成這一步之後,容器中的直系子元素就會變為 flex 元素。所有 CSS 屬性都會有一個初始值,所以 flex 容器中的所有 flex 元素都會有下列行為:flex-direction
屬性的初始值是 row
)。flex-basis
屬性為 auto
。flex-wrap
屬性為 nowrap
。這會讓你的元素呈線形排列,並且把自己的大小作為主軸上的大小。如果有太多元素超出容器,它們會溢位而不會換行。如果一些元素比其他元素高,那麼元素會沿交叉軸被拉伸來填滿它的大小。
更改 flex 方向 flex-direction在 flex 容器中新增 flex-direction
屬性可以讓我們更改 flex 元素的排列方向。設定 flex-direction: row-reverse
可以讓元素沿著行的方向顯示,但是起始線和終止線位置會交換。
把 flex 容器的屬性 flex-direction
改為 column
,主軸和交叉軸交換,元素沿著列的方向排列顯示。改為 column-reverse
,起始線和終止線交換。
下面的例子中,flex-direction
值為 row-reverse
。嘗試使用其他的值 row
,column
,column-reverse
,看看內容會發生什麼改變。
雖然flexbox
是一維模型,但可以使我們的flex
專案應用到多行中。在這樣做的時候,您應該把每一行看作一個新的flex
容器。任何空間分佈都將在該行上發生,而不影響該空間分佈的其他行。
為了實現多行效果,請為屬性flex-wrap
新增一個屬性值wrap
。現在,如果您的專案太大而無法全部顯示在一行中,則會換行顯示。下面的實時例子包含已給出寬度的專案,對於flex
容器,專案的子元素總寬度大於容器最大寬度。由於flex-wrap
的值設定為wrap
,所以專案的子元素換行顯示。若將其設定為nowrap
,這也是初始值,它們將會縮小以適應容器,因為它們使用的是允許縮小的初始Flexbox
值。如果專案的子元素無法縮小,使用nowrap
會導致溢位,或者縮小程度還不夠
在指南中您可以瞭解更多關於 flex-wrap
的資訊 Mastering Wrapping of Flex Items.
你可以將兩個屬性 flex-direction
和 flex-wrap
組合為簡寫屬性 flex-flow
。第一個指定的值為 flex-direction
,第二個指定的值為 flex-wrap
.
在下面的例子中,嘗試將第一個值修改為 flex-direction
的允許取值之一,即 row
, row-reverse
, column
或 column-reverse
, 並嘗試將第二個指定值修改為 wrap
或 nowrap
。
為了更好地控制 flex 元素,有三個屬性可以作用於它們:
在這裡,我們只會大概介紹一下它們的用法,更詳細的細節請參閱其它的文章。
在考慮這幾個屬性的作用之前,需要先了解一下 可用空間 available space 這個概念。這幾個 flex 屬性的作用其實就是改變了 flex 容器中的可用空間的行為。同時,可用空間對於 flex 元素的對齊行為也是很重要的。
假設在 1 個 500px 的容器中,我們有 3 個 100px 寬的元素,那麼這 3 個元素需要佔 300px 的寬,剩下 200px 的可用空間。在預設情況下,flexbox 的行為會把這 200px 的空間留在最後一個元素的後面。
如果期望這些元素能自動地擴充套件去填充滿剩下的空間,那麼我們需要去控制可用空間在這幾個元素間如何分配,這就是元素上的那些 flex
屬性要做的事。
flex-basis
flex-basis
定義了該元素的空間大小(the size of that item in terms of the space),flex 容器裡除了元素所佔的空間以外的富餘空間就是可用空間 available space。該屬性的預設值是 auto
。此時,瀏覽器會檢測這個元素是否具有確定的尺寸。在上面的例子中,所有元素都設定了寬度(width)為 100px,所以 flex-basis
的值為 100px。
如果沒有給元素設定尺寸,flex-basis
的值採用元素內容的尺寸。這就解釋了:我們給只要給 Flex 元素的父元素宣告 display: flex
,所有子元素就會排成一行,且自動分配小大以充分展示元素的內容。
flex-grow
flex-grow
若被賦值為一個正整數,flex 元素會以 flex-basis
為基礎,沿主軸方向增長尺寸。這會使該元素延展,並佔據此方向軸上的可用空間(available space)。如果有其他元素也被允許延展,那麼他們會各自佔據可用空間的一部分。
如果我們給上例中的所有元素設定 flex-grow
值為 1,容器中的可用空間會被這些元素平分。它們會延展以填滿容器主軸方向上的空間。
flex-grow 屬性可以按比例分配空間。如果第一個元素 flex-grow
值為 2,其他元素值為 1,則第一個元素將佔有 2/4(上例中,即為 200px 中的 100px), 另外兩個元素各佔有 1/4(各 50px)。
flex-shrink
flex-grow
屬性是處理 flex 元素在主軸上增加空間的問題,相反flex-shrink
屬性是處理 flex 元素收縮的問題。如果我們的容器中沒有足夠排列 flex 元素的空間,那麼可以把 flex 元素flex-shrink
屬性設定為正整數來縮小它所佔空間到flex-basis
以下。與flex-grow
屬性一樣,可以賦予不同的值來控制 flex 元素收縮的程度 —— 給flex-shrink
屬性賦予更大的數值可以比賦予小數值的同級元素收縮程度更大。
在計算 flex 元素收縮的大小時,它的最小尺寸也會被考慮進去,就是說實際上 flex-shrink 屬性可能會和 flex-grow 屬性表現的不一致。因此,我們可以在文章《控制 Flex 子元素在主軸上的比例》中更詳細地看一下這個演演算法的原理。
備註: 在給 flex-grow
和 flex-shrink
賦值時要注意比例。如果我們給所有 flex 元素的 flex 屬性賦值為 1 1 200px
,並且希望其中一個元素可以增加到 2 倍,我們可以給該元素的 flex 屬性賦值為2 1 200px
。當然,你也可以選擇賦值為 flex: 10 1 200px
和 flex: 20 1 200px
。
你可能很少看到 flex-grow
,flex-shrink
,和 flex-basis
屬性單獨使用,而是混合著寫在 flex
簡寫形式中。 Flex
簡寫形式允許你把三個數值按這個順序書寫 — flex-grow
,flex-shrink
,flex-basis
。
你可以在下面的範例中嘗試把 flex 簡寫形式中的數值更改為不同數值,但要記得第一個數值是 flex-grow
。賦值為正數的話是讓元素增加所佔空間。第二個數值是flex-shrink
— 正數可以讓它縮小所佔空間,但是隻有在 flex 元素總和超出主軸才會生效。最後一個數值是 flex-basis
;flex 元素是在這個基準值的基礎上縮放的。
大多數情況下可以用預定義的簡寫形式。在這個教學中你可能經常會看到這種寫法,許多情況下你都可以這麼使用。下面是幾種預定義的值:
flex: initial
flex: auto
flex: none
flex: <positive-number>
flex: initial
是把 flex 元素重置為 Flexbox 的初始值,它相當於 flex: 0 1 auto
。在這裡 flex-grow
的值為 0,所以 flex 元素不會超過它們 flex-basis
的尺寸。flex-shrink
的值為 1, 所以可以縮小 flex 元素來防止它們溢位。flex-basis
的值為 auto
. Flex 元素尺寸可以是在主維度上設定的,也可以是根據內容自動得到的。
flex: auto
等同於 flex: 1 1 auto
;和上面的 flex:initial
基本相同,但是這種情況下,flex 元素在需要的時候既可以拉伸也可以收縮。
flex: none
可以把 flex 元素設定為不可伸縮。它和設定為 flex: 0 0 auto
是一樣的。元素既不能拉伸或者收縮,但是元素會按具有 flex-basis: auto
屬性的 flexbox 進行佈局。
你在教學中常看到的 flex: 1
或者 flex: 2
等等。它相當於flex: 1 1 0
或者 flex: 2 1 0
。元素可以在 flex-basis
為 0 的基礎上伸縮。
嘗試在下面的範例中應用這些簡寫值。
Flexbox 的一個關鍵特性是能夠設定 flex 元素沿主軸方向和交叉軸方向的對齊方式,以及它們之間的空間分配。
align-items
align-items
屬性可以使元素在交叉軸方向對齊。
這個屬性的初始值為stretch
,這就是為什麼 flex 元素會預設被拉伸到最高元素的高度。實際上,它們被拉伸來填滿 flex 容器 —— 最高的元素定義了容器的高度。
你也可以設定align-items
的值為flex-start
,使 flex 元素按 flex 容器的頂部對齊,flex-end
使它們按 flex 容器的下部對齊,或者center
使它們居中對齊。在範例中嘗試——我給出了 flex 容器的高度,以便你可以看到元素在容器中移動。看看如果更改 align-items 的值為下列值會發生什麼:
stretch
flex-start
flex-end
center
justify-content
justify-content
屬性用來使元素在主軸方向上對齊,主軸方向是通過 flex-direction
設定的方向。初始值是flex-start
,元素從容器的起始線排列。但是你也可以把值設定為flex-end
,從終止線開始排列,或者center
,在中間排列。
你也可以把值設定為space-between
,把元素排列好之後的剩餘空間拿出來,平均分配到元素之間,所以元素之間間隔相等。或者使用space-around
,使每個元素的左右空間相等。
在範例中嘗試下列justify-content
屬性的值:
stretch
flex-start
flex-end
center
space-around
space-between
在以後的文章中,為了更好的理解它們怎麼使用,我們會更深入的探索這些屬性。然而,這些簡單的例子對大多數應用都很有幫助。