學好Flex布局並不容易

  • 2020 年 11 月 24 日
  • 筆記

1. Flex布局介紹

CSS的傳統布局解決方案,基於盒狀模型,依賴display屬性、position屬性、float屬性,對於一些特殊的布局,例如垂直居中,往往要想很多hack的方法來解決。

2009年,W3C提出了一種新的方案–Flex布局,可以簡便、完整、響應式地實現各種頁面布局。目前,它已經得到了所有瀏覽器的支持,這意味着,現在就能很安全地使用這項功能。Flex布局的主要思想是為容器賦予控制容器內元素的高度、寬度以及如何分割容器空間的能力。

Flex是Flexible Box的縮寫,表示「彈性布局」的意思,能夠為盒狀模型提供最大的靈活性。任何一個容器都可以指定為flex布局,使用flex布局以後,子元素的floatclearvertical-align元素都將失效。

.box {
    display: flex;
}

行內元素也可以使用Flex布局。

.box {
    display: inline-flex;
}

Webkit內核的瀏覽器,必須加上-webkit前綴。

.box{
  display: -webkit-flex; /* Safari */
  display: flex;
}

2. 基本概念

採用Flex布局的元素,稱為Flex容器(flex container),簡稱」容器」。它的所有子元素自動成為容器成員,稱為Flex項目(flex item),簡稱」項目」。容器默認存在兩根軸:水平的主軸(main axis)和垂直的交叉軸(cross axis)。主軸的開始位置(與邊框的交叉點)叫做main start,結束位置叫做main end;交叉軸的開始位置叫做cross start,結束位置叫做cross end。項目默認沿主軸排列。單個項目佔據的主軸空間叫做main size,佔據的交叉軸空間叫做cross size。

1baaa865d658f00e45697c2a61fa4ab3.png

下面對這幾個概念作簡要介紹:

  • 主軸 main-axis,flex容器的主軸是容器內項目 flex item的排列方向。主軸方向並不一定是水平的,這個由flex-direction屬性決定。
  • main-start | main-end ,容器內項目的排列是從main-start到main-end。
  • main-size
  • 交叉軸 cross axis 與主軸垂直的交叉軸,它的方向由主軸的方向決定
  • cross-start | cross-end
  • cross-size

3. Flex容器的屬性

Flex容器具有以下六個屬性。

  • display 該屬性決定flex布局的容器,display:flex;
  • flex-direction 該屬性決定主軸的方向(即項目的排列方向)
  • flex-wrap 該屬性決定flex元素的換行方式,默認情況下容器內項目總是傾向於排列在一行內
  • flex-flow 該屬性是directionwrap的組合屬性,默認值是row nowrap
  • justify-content 該屬性定義容器中項目在主軸上的對齊方式
  • align-items
  • align-content

3.1 flex-direction

flex-direction屬性決定主軸的方向(即容器元素的排列方向),有四個取值。

  • row(默認值),主軸為水平方向,起點在左端。
  • row-reverse,主軸為水平方向,起點在右端。
  • column,主軸為垂直方向,起點在上沿。
  • column-reverse,主軸為垂直方向,起點在下沿。
.box {
  flex-direction: row | row-reverse | column | column-reverse;
}

3.2 flex-wrap

熟悉wrap的同學應該知道,這個屬性是決定如何處理一行顯示不下的情況,有三個屬性:

  • nowrap 不換行
  • wrap 換行,第一行在上,往下折行
  • wrap-reverse 換行,第一行在下,往上折行
.box {
    flex-wrap: nowrap | wrap | wrap-reverse;
}

3.3 flex-flow

flex-flowflex-directionflex-wrap組合屬性的簡寫,默認值為row nowrap

.box {
    flex-flow: <flex-direction> || <flex-wrap>;
}

3.4 justify-content

justify-content定義項目在主軸上的對齊方式,還能夠幫助我們分配容器項目以外的剩餘空間,即便是沒有剩餘空間。有以下屬性:

  • flex-start(默認值): 主軸的起點對齊
  • flex-end: 主軸的終點對齊
  • center: 沿主軸居中對齊
  • space-between: 兩端對齊,項目之間的間隔相等
  • space-around: 每個項目兩側的間隔相等,所以項目之間的間隔比左右兩邊的間隔大一倍
  • space-evenly: 每個項目的間隔以及兩側的間隔都相等
  • start: 容器內的項目堆在書寫方向writing-mode的開始
  • end: 容器內的項目堆在書寫方向writing-mode的結束
  • lfet: 容器內的項目堆在容器的左邊
  • right: 容器內的項目堆在容器的右邊
  • safe:
  • unsafe:

注意不同瀏覽器對這些屬性的支持程度還不太一樣,space-between從未在Edge瀏覽器上獲得過支持,最安全的幾個屬性是flex-startflex-endcenter

image.png

.box {
    justify-content: flex-start | flex-end | center | space-between | space-around;
}

3.5 align-items

align-items 該屬性決定項目在交叉軸上如何對齊,有以下屬性:

  • flex-start 交叉軸的起點對齊
  • flex-end 交叉軸的終點對齊
  • center 交叉軸的中間對齊
  • start 書寫方向的起點對齊
  • end 書寫方向的終點對齊
  • baseline 項目的第一行文字的基線對齊
  • stretch(默認值) 如果項目未設置高度或設為auto,項目將佔滿整個容器的高度,這樣做兩列布局再也不用發愁高度不一致了。

在flex布局中有主軸和側軸的區分,和我們一般認為的橫軸為主軸、縱軸為側軸的固定認知不同,flex布局中主軸和側軸會發生變化,這是由之前flex-direction屬性決定的。當flex-direction:row的時候,主軸就是橫軸,要調整元素在橫軸的排列就需要使用justify-content屬性。當flex-direction:column的時候,主軸就是縱軸,要調整元素在橫軸的排列就需要使用align-items屬性。

3.6 align-content

這個屬性決定當容器在交叉軸方向還有剩餘空間時,項目的排列方式。

這個屬性在只有一行容器內項目時無效,在設置了nowrap時也無效。

  • flex-start
  • flex-end
  • center
  • space-between
  • space-around
  • space-evenly
  • stretch
  • baseline

4. 項目的屬性

項目包括6個屬性

  • order 該屬性定義項目的排列順序。數值越小,排列越靠前,默認為0。通過css就能控制DOM元素的順序,簡直太方便了。
  • flex-grow 該屬性定義項目放大的比例,默認為0,也就是項目的大小不會發生縮放。
  • flex-shrink
  • flex-basis
  • flex
  • align-self

4.1 order

order 屬性定義項目的排列順序。數值越小,排列越靠前,默認為0。通過css就能控制DOM元素的順序,簡直太方便了。

.item {
    order: <integer>;
}

4.2 flex-grow

flex-grow屬性定義項目相對於其他項目進行擴展的量,默認為0。注意:如果項目不是flex item,則 flex-grow 屬性不起作用。如果所有的項目都設置為1,則每個項目分到的空間都一樣。如果有一個設置為2,則它分到的空間要比其他項目多一倍。負數無效。

.item {
    flex-grow: <number>;

4.3 flex-shrink

flex-shrink 屬性定義項目相對於其他項目縮小的比例。負數無效。

.item {
    flex-shrink: <number>
}

4.4 flex-basis

flex-basis 屬性定義了在分配多餘空間之前,項目佔據的主軸空間(main size)。瀏覽器根據這個屬性,計算主軸是否有多餘空間。它的默認值為auto,即項目的本來大小。

.item {
    flex-basis: <length> | auto;
}

4.5 flex

flex屬性是flex-grow,flex-shrink,flex-basis組合,默認值為0 1 auto後兩個屬性可選。

.item {
    flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}

4.6 align-self屬性

align-self屬性允許單個項目有與其他項目不一樣的對齊方式,可覆蓋align-items屬性。默認值為auto,表示繼承父元素的align-items屬性,如果沒有父元素,則等同於stretch。屬性支持的值包括:

  • auto
  • flex-start
  • flex-end
  • center
  • baseline
  • stretch

5. 瀏覽器支持

flexbox從出現到現在經歷了多個版本,下圖new的含義表示現在的語法display:flex;tweener表示2011年後出現的一個非官方的寫法display:flexbox;old表示2009年出現後的舊語法display:box;

image.png