flex設計思想和語法簡介

輝衛無敵發表於2018-10-23

flex彈性盒子模型是新一代的佈局模式,在大部分情況下可以完全替代之前的display屬性 + position屬性 + float屬性的佈局方式,設計友好,目前相容性已經很好了,很多主流網站都已經開始採用。本文總結一下flex的設計思想和語法,以及在實際的佈局應用中為我們帶來了哪些便利。

flex設計思想

我們可以仔細想一下我們之前佈局的難點和麻煩的地方都有什麼,我總結了幾個:

  • 自適應,比如最簡單的左側是固定寬度導航欄,右側自適應填充剩餘空間。一般使用float和margin來實現或者利用BFC的特性來實現
  • 居中,特別是垂直居中,一行有多個高度不一致的專案,要垂直居中,一般結合line-height和vertical-align來實現
  • 水平等間距的多專案排列,最兩端的兩側沒有間距,通常使用負margin或者css選擇器來實現
  • 需要解決float造成的高度塌陷問題

其實floatpositionline-heightvertical-align設計之初並不是為了應對這種複雜佈局,只是比較適用於web1.0的圖文佈局介面。後來人以自己的聰明才智利用種種css特性,組合使用,實現了複雜的佈局方案。這種佈局方案相對比較複雜,需要很紮實的基本功,不是太容易理解。flex彈性佈局就是為了應對這種情況而生的。

對於上述種種不便,如果讓我們自己去要求有一種新的佈局方案,我們會怎麼要求,我希望的是這樣

  • 我希望可以定義某個元素自動擴大或者自動縮小,以實現自適應
  • 我希望可以定義行或者列的排列方式,從左邊開始、居中、等間隔、從右邊開始等,都可以任意設定
  • 我希望設定垂直方向和設定水平方向一樣簡單

我的要求就這麼簡單滿足著3條就可以解決我日常開發中的大部分問題,提高開發效率。flex的佈局設計就可以輕鬆滿足上述要求,而且還可以滿足我們更多的要求。

我們來了解一下flex的設計,首先我們瞭解一下2個概念:

  • flex容器:凡是設定了display: flex的元素都是flex容器
  • flex專案:所有flex容器的子元素都被稱為flex專案

flex 容器

flex容器預設有兩個軸線分別對應水平方向和垂直方向,叫做主軸和交叉軸。

flex設計思想和語法簡介

預設主軸是水平方向,交叉軸是垂直方向,但是我們也可以通過設定調換,所以在flex設計中水平方向和垂直方向是一樣容易設定的。我們可以在flex容器中設定主軸方向、排列方式。容器一共有6個css屬性可以設定,其實都是圍繞主軸方向、排列方式設定的。

  • flex-direction: 決定主軸方向,一共有4個值
    • row(預設): 主軸為水平方向,從左到右排列
    • row-reverse: 主軸為水平方向,從右到左排列
    • column:主軸為垂直方向,從上到下排列
    • column-reverse: 主軸為垂直方向,從下到上排列

flex設計思想和語法簡介

  • flex-wrap: 決定換行:

    • nowrap(預設):不換行
    • wrap: 超過主軸空間則換行
    • wrap-reverse: 超過主軸空間則換行,新行在前面
  • flex-flow: flex-direction屬性和flex-wrap屬性的簡寫形式,預設值為row nowrap

  • justify-content: 這個屬性就是決定主軸方向排列方式的,水平居中,等間隔排列都可以用它來實現,應用的比較多,有6個值:

    • flex-start(預設):左對齊
    • flex-end: 右對齊
    • center: 居中
    • space-between: 兩端對齊,專案間的間隔相等
    • space-around: 每個專案兩側的間隔相等。所以,專案之間的間隔比專案與邊框的間隔大一倍。
    • space-evenly: 專案沿主軸均勻分佈。

flex設計思想和語法簡介

  • align-items: 這個屬性決定交叉軸方向的排列方式,可以很方便地實現垂直居中,也有5個值,以從上到下的垂直方向為交叉軸方向:
    • flex-start: 上對齊
    • flex-end: 下對齊
    • center: 居中對齊
    • stretch(預設值): 拉伸,如果未設定高度或者高度設為為auto,則填充整個容器高度
    • baseline: 專案的第一行文字的基線對齊

flex設計思想和語法簡介

  • align-content: 該屬性定義了主軸有多根軸線時,多根軸線在交叉軸的排列方式。只有一根軸線,就是專案沒有換行時,該屬性不起作用。這裡比較複雜的一個地方是多軸線的問題,主軸一旦換行就會形成多個軸線,align-items仍然在每個軸線內起作用,而軸線的排列方式則由align-content來設定,和justify-content相對應。該屬性有6個值,以從上到下的垂直方向為交叉軸方向:
    • flex-start:上對齊
    • flex-end: 下對齊
    • center: 居中
    • space-between: 兩端對齊,專案間的間隔相等
    • space-around: 每個專案兩側的間隔相等。所以,專案之間的間隔比專案與邊框的間隔大一倍
    • stretch(預設值): 軸線佔滿整個交叉軸,strech屬性和其他屬性的不同之處在於,strech會自動擴充套件軸線的高度,而其他屬性都是以軸線實際佔用的位置進行排列。具體可以看下下面的例子。

flex設計思想和語法簡介

例子:

<div class="outer">
  <div class="inner">hello</div>
  <div class="inner">nihao</div>
  <div class="inner">wobuhao</div>
</div>
複製程式碼
.outer{
  display: flex;
  background: blue;
  height: 400px;
  flex-wrap: wrap;
  align-items: stretch;
  align-content: stretch;
}
.inner{
  width: 650px;
  background: orange;
}
複製程式碼

效果如下:

flex設計思想和語法簡介

如果我們把align-content設定為space-between,則效果如下:

flex設計思想和語法簡介

如果我們把align-content設定為stretch,同時align-items設定為center,則效果如下,說明align-items在單個軸線內起作用:

flex設計思想和語法簡介

你可以自己去試一試!

容器上的屬性都已經介紹完了,主要就是設定主軸方向和兩個軸的排列方式。

flex專案

下面我們介紹一下flex專案上的屬性,flex容器上主要設定了排列方式,flex專案上則主要設定了專案的大小。同樣flex-專案上有6個css屬性可以設定:

  • order: 定義專案的排列順序。數值越小,排列越靠前,預設為0

  • flex-grow: 定義專案的放大比例,該值越大,放大的比例越大,0表示不放大,預設值為0。這個屬性和下一個flex-shrink很重要,需要深入理解。這個有一個很容易誤解的點,就是放大比例是參考誰來放大的。注意不是參考主軸寬度,而是參考剩餘寬度,也就是容器寬度減去專案總寬度。當然了,如果專案總寬度加起來比容器寬度大,那就不存在放大這一說了,有剩餘空間的情況下才會去放大。假如一行有n專案,n個專案的放大比例分別為grow1,grow2...grown,則第m(m<=n)個專案的放大空間為:

    space = growm/(grow1+grow2+...grown) * (容器寬度-專案總寬度)

    由此也可以知道為什麼0表示不放大,知道了明確的換算公式,我們在設定大小時才不會亂。

  • flex-shrink: 定義專案的縮小比例,該值越大,縮小的比例越大,0表示不縮小,預設為1。縮小比例的參考系則是專案總寬度減去容器寬度,也就是說容器寬度容納不下專案了,專案才會去縮小。這裡和flex-grow不一樣的地方是,縮小空間不止和flex-shrink的值有關,還和專案的寬度有關。假如一行有n個專案,n個專案的flex-shrink值分別為shrink1,shrink2...shrinkn,n個專案的寬度分別為width1,width2...widthn,則第m(m<=n)個專案的縮小空間為:

    space = (shrinkm * widthm)/(shrink1 * width1 + shrink2 * width2 +...shrinkn * widthn) * (專案總寬度-容器寬度)

  • flex-basis: 定義了專案在主軸上的所佔據的空間大小,預設值為auto。我們之前說的放大縮小,都要依賴於專案總寬度的計算。這個專案總寬度就是依據flex-basis算出來的。那如果專案本來就設定了width或者height,那專案寬度或者高度由誰來決定那?答案是flex-basis,flex-basis的優先順序高於width或者height,但是低於min-widht或者max-height,仍受最大最小寬度的限制。比如下面的例子:

<div class="outer">
  <div class="inner">
    
  </div>
</div>
複製程式碼
.outer{
  display: flex;
  height: 300px;
  background: blue;
}
.inner{
  width: 300px;
  flex-basis: 500px;
  background: yellow;
}
複製程式碼

效果如下:

flex設計思想和語法簡介

可以看出專案的寬度是由flex-basis決定的。另外當flex-basisauto時,則表示專案佔據主軸空間的大小為專案本來的大小,此時width便會起作用。

  • flex: flex屬性是flex-grow,flex-shrinkflex-basis的簡寫,預設值為0 1 autoflex的值使用起來比較複雜,可以看下面這段程式碼,基本包含所有情況。
/* Basic values */
flex: auto; /* 1 1 auto,該放大放大,該縮小縮小 */ 
flex: none; /* 0 0 auto,既不縮小,也不放大 */ 

/* One value, unitless number: flex-grow */
flex: 2;

/* One value, width/height: flex-basis */
flex: 10em;
flex: 30px;

/* Two values: flex-grow | flex-basis */
flex: 1 30px;

/* Two values: flex-grow | flex-shrink */
flex: 2 2;

/* Three values: flex-grow | flex-shrink | flex-basis */
flex: 2 2 10%;
複製程式碼
  • align-self: 和align-items作用一樣,只不過該屬性設定在專案上,可以對單個專案設定,允許我們設定某些專案的排列方式和其他不同。align-self多了一個auto屬性,表示繼承父元素的align-items屬性。

相關文章