Flex很難?一文就足夠了

linwene發表於2019-01-03

Flexible Box 是什麼

Flex很難?一文就足夠了

  佈局的傳統解決方案,基於盒狀模型,依賴 display 屬性 + position屬性 + float屬性。它對於那些特殊佈局非常不方便,比如,垂直居中就不容易實現。所以在2009年,w3c提出了一種可以簡潔、快速彈性佈局的屬性,主要思想是給予容器控制內部元素高度和寬度的能力,這就是今天要說的Flexible Box,彈性佈局。

  由於瀏覽器的限制,在寫程式碼之前推薦查詢一下相容模式,瞭解下目前flex的支援程度,我們可以通過CanIuse這個網站來進行查詢,如下圖,可以看到,除了對於IE支援一般之外,其他瀏覽器大多沒啥毛病,但為了以防萬一,在寫程式碼的時候還是加上-webkit-這一字首以防萬一。

.box{
  display: -webkit-flex; /* Safari */
  display: flex;
}
複製程式碼

Flex很難?一文就足夠了

重點!flex一共有兩根軸:main axis(主軸)和cross axis(交叉軸),大家一般認為主軸就是水平,交叉軸就是垂直的。但是!這是錯誤的!請與水平垂直這兩個方位的概念區分開,這是一個方位,如果說當年定義的時侯為什麼不命名為vertical&horizon??原因就是main axis沒有一個固定的方位,所以請不要再通過水平垂直的方位來理解了。那麼主軸是怎麼區分的呢?其實很簡單按照當前flex的方向,是水平排列還是垂直排列。如果是水平排列(row),主軸就是水平的,交叉軸就是垂直的,反之亦然。這是一個很重要的概念。

Flex很難?一文就足夠了

注意,設為 Flex 佈局以後,子元素的float、clear和vertical-align屬性將失效。

屬性描述

父容器的屬性

flex-direction :該元素決定主軸的方向(即子元素的排列方向) 預設值 :row 適用於 :flex 容器

屬性 描述
row 主軸為水平方向,起點在左端。
row-reverse 主軸為水平方向,起點在右端。
column 主軸為垂直方向,起點在上沿。
column-reverse 主軸為垂直方向,起點在下沿。

Flex很難?一文就足夠了

Flex很難?一文就足夠了

Flex很難?一文就足夠了

flex-wrap :設定或檢索伸縮盒物件的子元素超出父容器時是否換行 預設值 :nowrap 適用於 :flex 容器

屬性 描述
nowrap 不換行(預設)
wrap 換行,第一行在上方
wrap-reverse 換行,第一行在下方

Flex很難?一文就足夠了

PS: flex-flow 屬性是 flex-direction 屬性和 flex-wrap 屬性的簡寫形式,預設值為 row nowrap

.box {
  flex-flow: flex-direction flex-wrap|initial|inherit;
}
複製程式碼

justify-content :定義了子元素在主軸上的對齊方式。 預設值 :flex-start 適用於 :flex 容器

屬性 描述
flex-start 左對齊
flex-end 右對齊
center 居中
space-between 兩端對齊,專案之間的間隔都相等
space-around 每個專案兩側的間隔相等。所以,專案之間的間隔比專案與邊框的間隔大一倍

Flex很難?一文就足夠了

align-items :定義了子元素在交叉軸上的對齊方式 預設值 :stretch 適用於 :flex 容器

屬性 描述
flex-start 交叉軸的起點對齊
flex-end 交叉軸的終點對齊
center 交叉軸的中點對齊
baseline 子元素第一行文字的基線對齊,如果子標籤內沒有內容,將按照每個 div 的底部對齊
stretch 如果專案未設定高度或設為auto,將佔滿整個容器的高度

align-items: stretch 時每個子元素的 height 必須為 auto 否則 height 屬性會覆蓋 stretch 的效果

Flex很難?一文就足夠了

Flex很難?一文就足夠了

如果 div 內沒有內容,或者子標籤內沒有內容,將按照每個 div 的底部對齊

Flex很難?一文就足夠了

align-content :定義多根軸線的對齊方式,如果子元素只有一根軸線,該屬性不起作用 預設值 :stretch 適用於 :多行的彈性盒模型容器

屬性 描述
flex-start 與交叉軸的起點對齊
flex-end 與交叉軸的終點對齊
center 與交叉軸的中點對齊
space-between 與交叉軸兩端對齊,軸線之間的間隔平均分佈
space-around 每根軸線兩側的間隔都相等。所以,軸線之間的間隔比軸線與邊框的間隔大一倍
stretch 軸線佔滿整個交叉軸

Flex很難?一文就足夠了

PS: 在上面的例子 flex-wrap 需設為 wrap, 且數量超出一行, 父容器的高度相對於子容器有多餘,才能看到效果

子元素的屬性

order :定義子元素的排列順序,數值越小,排列越靠前 預設值:0 適用於:flex子項和flex容器中的絕對定位子元素

Flex很難?一文就足夠了

PS:用整數值來定義排列順序,數值小的排在前面。元素的值可以為負值

flex-grow :定義子元素的放大比例 預設值 :0 適用於 :flex子項

<ul class="flex">
  <li>a</li>
  <li>b</li>
  <li>c</li>
</ul>
複製程式碼
.flex{display:flex;width:600px;margin:0;padding:0;list-style:none;}
.flex li {text-align:center;height:100px;}
.flex li:nth-child(1){width:200px;background-color:green;}
.flex li:nth-child(2){flex-grow:1;width:50px;background-color:yellow;}
.flex li:nth-child(3){flex-grow:3;width:50px;background-color:red;}
複製程式碼

flex-grow的預設值為0,如果沒有顯示定義該屬性,是不會擁有分配剩餘空間權利的。 本例中b,c兩項都顯式的定義了flex-grow,flex容器的剩餘空間分成了4份,其中b佔1份,c佔3分,即1:3 flex容器的剩餘空間長度為:600-200-50-50=300px,所以最終a,b,c的長度分別為: a: 50+(300/4)=200px b: 50+(300/4*1)=125px c: 50+(300/4*3)=275px

Flex很難?一文就足夠了

Flex很難?一文就足夠了

flex-shrink :定義子元素的收縮比例(與flex-grow相反) 預設值 :1 適用於 :flex子項

<ul class="flex">
  <li>a</li>
  <li>b</li>
  <li>c</li>
</ul>
複製程式碼
.flex{display:-webkit-flex;display:flex;width:400px;margin:0;padding:0;list-style:none;}
.flex li{width:200px;}
.flex li:nth-child(1){background:#888;}
.flex li:nth-child(2){background:#ccc;}
.flex li:nth-child(3){-webkit-flex-shrink:3;flex-shrink:3;background:#aaa;}
複製程式碼

flex-shrink的預設值為1,如果沒有顯示定義該屬性,將會自動按照預設值1在所有因子相加之後計算比率來進行空間收縮。
本例中c顯式的定義了flex-shrink,a,b沒有顯式定義,但將根據預設值1來計算,可以看到總共將剩餘空間分成了5份,其中a佔1份,b佔1份,c佔3分,即1:1:3
我們可以看到父容器定義為400px,子項被定義為200px,相加之後即為600px,超出父容器200px。那麼這麼超出的200px需要被a,b,c消化
通過收縮因子,所以加權綜合可得200*1+200*1+200*3=1000px;
於是我們可以計算a,b,c將被移除的溢位量是多少:
a被移除溢位量:(200*1/1000)*200,即約等於40px
b被移除溢位量:(200*1/1000)*200,即約等於40px
c被移除溢位量:(200*3/1000)*200,即約等於120px
最後a,b,c的實際寬度分別為:200-40=160px, 200-40=160px, 200-120=80px

Flex很難?一文就足夠了

Flex很難?一文就足夠了

Flex很難?一文就足夠了

PS:如果所有專案的 flex-shrink 屬性都為 1,當空間不足時,都將等比例縮小。如果一個專案的 flex-shrink 屬性為0,其他專案都為 1,則空間不足時,前者不縮小。負值對該屬性無效。

flex-basis :設定或檢索彈性盒伸縮基準值 預設值 :auto 適用於 :flex子項

Flex很難?一文就足夠了

flex-basis 控制元素的預設尺寸,然後再由其他 Flexbox 屬性控制,可以覆蓋 width 屬性

flex-basis 可以和 width 屬性互換

Flex很難?一文就足夠了

PS:flex-basis 是通過主軸 (main axis) 來影響元素尺寸的

Flex很難?一文就足夠了

align-self:允許單個子元素有與其他專案不一樣的對齊方式,可覆蓋align-items屬性 預設值 :auto 適用於 :flex子項

屬性 描述
auto 繼承父元素的"align-items"值,如果其沒有父元素,等同於"stretch"
flex-start 交叉軸的起點對齊
flex-end 交叉軸的終點對齊
center 交叉軸的中點對齊
baseline 第一行文字的基線對齊
stretch 如果專案未設定高度或設為auto,將佔滿整個容器的高度

父元素: align-items:flex-end
a: align-self: flex-end
b: align-self: center
c: align-self: flex-start
d: align-self: baseline; padding: 20px 10px
e: align-self: baseline
f: align-self: stretch
g: align-self: auto

Flex很難?一文就足夠了

Flex很難?一文就足夠了

未完待續...

參考

  1. CSS參考手冊
  2. Flex 佈局教程-阮一峰
  3. Even more about how Flexbox works — explained in big, colorful, animated gifs
  4. How Flexbox works — explained with big, colorful, animated gifs

相關文章