在 CSS flexbox 佈局出現以前,如果要控制 HTML 元素的佈局,要用到很多種奇葩的方式。在水平方向上得用float
控制左右對齊,稍一不注意,就會有浮動的元素飛來飛去~。在垂直方向上就更是百家爭鳴了:要麼手動計算高度然後算出中心點,要麼用 line-height
和 height
的結合,要麼用十之八九不生效的 vertical-align
屬性等等等等。自從 flex-box 出現以後,一切似乎就豁然開朗了,水平垂直各種花式對齊,空間分配由你做主。當然,要用好它,用對它也不是一件容易的事,今天就給你說說 flex-box 佈局,看完之後你也能熟練的運用它!
2 分鐘視訊入門版:2 分鐘掌握 CSS Grid 佈局
真實 HTML 程式碼(非圖片)示例版:請點此訪問(示例都是真實的 HTML 程式碼,可以使用 chrome 開發者工具檢視屬性。
開啟 Flexbox 佈局
假設有下邊這麼一個 html 結構:
<div class="flex">
<div class="flex1">Flex 1</div>
<div class="flex2">Flex 2</div>
<div class="flex3">Flex 3</div>
</div>
複製程式碼
一個div
容器包含了三個 div
子元素,按照預設的佈局方式進行排列。因為 div
是塊級元素,每個 div
佔了整個一行的空間:
如果要開啟容器的 flex 佈局,只需要在 css 裡邊給 .flex
設定 display: flex
屬性,同時為了演示效果,我給它加上了 100px 的高度:
display: flex;
height: 100px;
複製程式碼
可以看到裡邊的三個元素自動變成了一行,因為 flex 預設是按行進行排列的。Flexbox 佈局是一維佈局方式,要麼按行排列,要麼按列排列。
對齊方式
Flex 佈局有一個隱式的座標空間,水平方向有一條主軸(main-axis),垂直方向上有一條交叉軸(cross-axis):
justify-content
控制主軸(即水平方向)對齊方式使用justify-content
屬性,它有下邊幾種對齊方式:
flex-start
flex-start
是預設值,如果是從左到右的文字閱讀習慣(LTR),就是靠左對齊。因為預設的對齊方式,所以跟上邊的例子沒有什麼區別:
justify-content: flex-start;
複製程式碼
center
居中對齊,此時整個 flex 容器被居中到了頁面中間:
flex-end
靠右對齊:
space-between
兩端對齊,這種對齊方式是第一個和最後一個元素貼邊,中間的元素平分剩餘的空間:
space-evenly
分散對齊,所有的元素都平分空間:
space-around
跟space-evenly
類似,但是左右兩邊的留白為平分空間的 1/2.
align-items
控制交叉軸方向(即垂直方向)上的對齊方式使用align-items
屬性,有下邊幾種對齊方式:
stretch
stretch
是 align-items
的預設值,它會自動把子元素拉伸成容器的高度,所以之前的例子裡子元素在垂直方向上都佔滿了容器,只要改變容器的align-items
的值,它就會變成內容的高度。stretch
對齊效果如下:
flex-start
靠上對齊,在交叉軸開始的最上方,可以看到子元素不再佔滿容器寬度:
center
居中對齊:
flex-end
靠下對齊:
baseline
基線對齊,如果子元素文字尺寸和行高不同,則子元素會按照文字的基線進行對齊:
.flex2 {
font-size: 24px;
}
複製程式碼
如果是 flex-start
對齊方式:
align-content
本小節在下邊講到折行時再介紹
子元素覆蓋對齊方式
子元素可以通過設定 align-self
來控制自己在交叉軸上的對齊方式,例如把 .flex3
子元素在垂直方向上靠下對齊:
.flex {
display: flex;
align-items: flex-start;
}
.flex3 {
align-self: flex-end;
}
複製程式碼
在水平方向上控制子元素對齊並沒有justify-self
屬性,而是使用margin
屬性,通過把左或右邊距設定為auto
來控制水平對齊,比如把 flex3
放到最右邊:
.flex3 {
margin-left: auto;
}
複製程式碼
排列方式
flex 支援按行排布,也支援按列排布。按列排布時,主軸和交叉軸換了方向,但是 align-items 和 justify-content 控制的軸線不變,即 align-items
還是控制交叉軸,justify-content
控制主軸:
所以說,在水平方向上對齊變成了使用align-items
,垂直方向則用justify-content
。
要使 flex 按列排布,只需要設定:
flex-direction: column;
複製程式碼
來看幾個例子:
水平居中對齊
.flex {
display: flex;
flex-direction: column;
align-items: center;
}
複製程式碼
垂直居中對齊
.flex {
display: flex;
flex-direction: column;
justify-content: center;
}
複製程式碼
另外 flex 佈局也可以支援反向按行和列布局,相當於按容器中心線進行 180 度翻轉:
row-reverse
.flex {
display: flex;
flex-direction: row-reverse;
}
複製程式碼
column-reverse
列模式下會垂直翻轉:
.flex {
display: flex;
flex-direction: column-reverse;
}
複製程式碼
空間佔比
子元素可以通過設定flex
屬性來調整空間的佔比,例如讓 flex2
在水平方向上佔據其他子元素的 2 倍大小,可以設定:
.flex1,
.flex3 {
flex: 1;
}
.flex2 {
flex: 2;
}
複製程式碼
Flex-basis
在介紹 flex-basis 之前,先講一個概念 main size
,即主軸方向的尺寸,那麼,在行排布模式下,也就是水平方向的尺寸,其實就是子元素的寬度,而在列模式下,它是子元素的高度,相對應的也有cross size
,即行模式下是子元素的高度,列模式下是寬度。
而flex-basis
是用來設定main size
的,它的優先順序會高於width
。它的預設值是auto
,即在行模式下,如果子元素設定了寬度,它就取自這個寬度值,沒有設定的話,就是內容的寬度。使用 flex-basis
,可以同時管理行模式下的寬度和列模式下的高度。
來看一個例子,把之前的子元素改成固定寬度,比如 200px
:
.flex > * {
flex-basis: 200px;
}
複製程式碼
這樣每個子元素寬度變為了 200px:
如果再新增 width
屬性,發現並不會生效:
.flex > * {
flex-basis: 200px;
width: 250px;
}
複製程式碼
但是,可以通過設定 min-width
來強制設定最小寬度:
.flex > * {
flex-basis: 200px;
min-width: 250px;
}
複製程式碼
同理的,在列模式下,flex-basis
變成了高度,因為容器高度為 100px
,這裡把子元素高度設定成了 30px
總計 90px
來效果:
.flex {
flex-direction: column;
}
.flex > * {
flex-basis: 30px;
}
複製程式碼
同樣的,也可以用min-height
來控制最小高度。
縮放
(後續例子都假設是行模式)之前的小節簡單說了一下 flex 子元素空間的佔比,這裡把縮放單獨拿出來是為了說明:除了調整 flex 子元素的增長之外,也可以調整收縮,以及flex
屬性背後的原理(下一小節)。
flex-grow
先看一下增長,flex-grow
,這個屬性是說 flex 容器在有剩餘空間的時候,子元素佔據剩餘空間的佔比。例如,給.flex2
子元素設定:
.flex2 {
flex-grow: 1;
}
複製程式碼
其它的元素保持預設的寬度(即內容的寬度,flex-basis 為 auto),那麼 .flex2
就會自動增長並佔據整個剩餘空間:
如果把三個元素全部設定成 1,那麼所有元素都會自動增長,並各自佔據 1/3 的空間:
使用 flex-grow
就能夠自由的調整元素的空間佔比了,非常適合一些浮動的佈局。
flex-shrink
子元素的收縮是說:當它們的寬度超過 flex 容器之後,該如何進行收縮。通過 flex-shrink
來設定一個數值,數值越大,收縮程度也越大,比如flex-shrink: 2
的元素會比flex-shrink:1
收縮的值大 2 倍:
.flex1,
.flex3 {
flex-basis: 600px;
flex-shrink: 1;
}
.flex2 {
flex-basis: 600px;
flex-shrink: 2;
}
複製程式碼
這裡為了方便演示,我把所有的 flex 子元素的 main size (寬度) 都設定成了 600px。在我的顯示器下,flex 容器的寬度是 728px,三個子元素總和 1800px,顯然超出了容器的寬度,那麼根據上邊定義的收縮規則,.flex2
將收縮 2 倍於 .flex
和 .flex3
收縮的空間。下邊的例子中,.flex1
和 .flex3
的寬度變成了 332px
,相比於 600px
收縮了 268px
,那麼 .flex2
就要收縮 536px (268px * 2)
的寬度,那麼它最後就會剩下 64px (600px - 536px)
的寬度:
再說 flex 屬性
說完flex-grow
、flex-shrink
和 flex-basis
之後,再來看一下這個 flex
屬性,它其實是前邊三個屬性的縮寫,預設值是 0 1 auto
,即不增長,但收縮,收縮比例為 1,flex-basis 為 auto,即取自使用者定義的寬度或內容的寬度。
flex 的值可以是下邊幾種:
- 指定一個數字 - 例如
flex: 1
,就等同於是flex: 1 1 0
,即自動縮放,比例為 1,flex-basis 為 0。 - auto - 等同於
flex: 1 1 auto
。 - 指定兩個數字 - 第一個為
flex-grow
,第二個,如果是數字則認為是flex-shrink
,如果是寬度,則是flex-basis
。 - 指定三個值 - 分別為
flex-grow
,flex-shrink
和flex-basis
。
所以說,通過flex
屬性可以方便的同時設定flex-grow
、flex-shrink
和 flex-basis
這三個值。
折行
如果子元素有固定寬度,並且超出了容器的寬度,還不允許收縮的話,那麼可以使用flex-wrap
屬性來讓元素進行折行排列,使得每行的元素都不超過容器的寬度。這裡跟 css grid 佈局的主要區別是,它無法控制單獨控制行、列的佔比,比如跨行、誇列,也不能自由定位元素到特定的位置。下邊的示例新增了 2 個元素,一共 5 個,每個元素的 main size 為 300px,然後超出寬度後折行:
.flex {
flex-wrap: wrap;
}
.flex > * {
flex-shrink: 0;
flex-basis: 300px;
}
複製程式碼
align-content
如果 flex 容器開啟了折行,那麼兩行及以上的內容可以通過align-content
屬性來控制各行之間在交叉軸上的排列規則,它的取值和 justify-content
基本相同,這裡演示其中幾個,還是使用之前三個元素的 flex 容器,每個容器寬度為 300px,超出後換行:
.flex {
display: flex;
flex-wrap: wrap;
}
.flex > * {
flex-basis: 300px;
}
複製程式碼
center
垂直居中:
space-between
兩端對齊:
巢狀的 flex 容器的問題
如果 HTML 結構複雜,有巢狀的 flex 容器,很有可能會遇到巢狀的 flex 容器並不能自動收縮的問題,即使設定了flex-shrink
。比如有下邊一個 html 結構:
<div class="flex">
<div class="flex1">Flex 1</div>
<div class="flex2">Flex 2</div>
<div class="flex3">Flex 3</div>
<div class="flex4">
<p>
這是一段很長很長很長很長很長很長很長很長很長很長很長很長長很長很長很長很長很長長很長很長很長很長很長的文字
</p>
</div>
</div>
複製程式碼
這裡給之前的 flex 容器新增了一個新的子元素.flex4
,這 4 個子元素都設定成flex: 1
來平分空間,但是 .flex4
自己本身也是一個flex
佈局的容器,裡邊有一長串文字,我想讓它超長之後自動顯示省略號,它的 CSS 程式碼:
.flex {
display: flex;
}
.flex > * {
flex: 1;
}
.flex4 {
display: flex;
flex: 1;
}
.flex4 > p {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
複製程式碼
可以看到,最後本應該佔 1/4 空間的.flex4
,因為文字不能換行,直接把 flex 容器撐開了,並且把其他的三個子元素擠成了最小空間,它本應該把文字截短並顯示省略號,這是為什麼呢?原來,flex 容器的 min-width
屬性值為 auto,是由瀏覽器自行計算的,在這裡它取了<p>
元素的寬度,使得寬度成為了一整行 <p>
的寬度。那麼要解決這個問題,可以把.flex4
這個巢狀 flex 容器的 min-width
改為0
,即最小寬度是0
,那麼就可以正常收縮了:
.flex4 {
display: flex;
flex: 1;
min-width: 0;
}
複製程式碼
總結
到這裡,整個 flex 佈局就介紹完了,還是有不少東西的,但不難。相信通過例項你一定可以掌握它的用法,下邊總結一下要點:
- 開啟 flex 佈局使用
display: flex
屬性。 - flex 佈局有主軸和交叉軸,分別使用
justify-content
和align-items
控制對齊方式。 - 支援按行或列進行排列,使用
flex-direction
,另外也支援row-reverse
和column-reverse
反向排列。 - 子元素可以通過
flex
簡寫形式,或者flex-grow
,flex-shrink
,flex-basis
來調整元素的空間佔比和縮放。 - 通過
flex-wrap
可以設定 flex 子元素折行顯示。 - 巢狀
flex
容器的縮放問題。
你學會了嗎?如果有問題,請留下評論吧。