flex彈性盒子模型是新一代的佈局模式,在大部分情況下可以完全替代之前的display屬性 + position屬性 + float屬性的佈局方式,設計友好,目前相容性已經很好了,很多主流網站都已經開始採用。本文總結一下flex的設計思想和語法,以及在實際的佈局應用中為我們帶來了哪些便利。
flex設計思想
我們可以仔細想一下我們之前佈局的難點和麻煩的地方都有什麼,我總結了幾個:
- 自適應,比如最簡單的左側是固定寬度導航欄,右側自適應填充剩餘空間。一般使用float和margin來實現或者利用BFC的特性來實現
- 居中,特別是垂直居中,一行有多個高度不一致的專案,要垂直居中,一般結合line-height和vertical-align來實現
- 水平等間距的多專案排列,最兩端的兩側沒有間距,通常使用負margin或者css選擇器來實現
- 需要解決float造成的高度塌陷問題
其實float
、position
、line-height
、vertical-align
設計之初並不是為了應對這種複雜佈局,只是比較適用於web1.0的圖文佈局介面。後來人以自己的聰明才智利用種種css特性,組合使用,實現了複雜的佈局方案。這種佈局方案相對比較複雜,需要很紮實的基本功,不是太容易理解。flex彈性佈局就是為了應對這種情況而生的。
對於上述種種不便,如果讓我們自己去要求有一種新的佈局方案,我們會怎麼要求,我希望的是這樣
- 我希望可以定義某個元素自動擴大或者自動縮小,以實現自適應
- 我希望可以定義行或者列的排列方式,從左邊開始、居中、等間隔、從右邊開始等,都可以任意設定
- 我希望設定垂直方向和設定水平方向一樣簡單
我的要求就這麼簡單滿足著3條就可以解決我日常開發中的大部分問題,提高開發效率。flex的佈局設計就可以輕鬆滿足上述要求,而且還可以滿足我們更多的要求。
我們來了解一下flex的設計,首先我們瞭解一下2個概念:
- flex容器:凡是設定了
display: flex
的元素都是flex容器
- flex專案:所有
flex容器
的子元素都被稱為flex專案
flex 容器
flex容器
預設有兩個軸線分別對應水平方向和垂直方向,叫做主軸和交叉軸。
預設主軸是水平方向,交叉軸是垂直方向,但是我們也可以通過設定調換,所以在flex設計中水平方向和垂直方向是一樣容易設定的。我們可以在flex容器
中設定主軸方向、排列方式。容器一共有6個css屬性可以設定,其實都是圍繞主軸方向、排列方式設定的。
flex-direction
: 決定主軸方向,一共有4個值- row(預設): 主軸為水平方向,從左到右排列
- row-reverse: 主軸為水平方向,從右到左排列
- column:主軸為垂直方向,從上到下排列
- column-reverse: 主軸為垂直方向,從下到上排列
-
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: 專案沿主軸均勻分佈。
align-items
: 這個屬性決定交叉軸方向的排列方式,可以很方便地實現垂直居中,也有5個值,以從上到下的垂直方向為交叉軸方向:- flex-start: 上對齊
- flex-end: 下對齊
- center: 居中對齊
- stretch(預設值): 拉伸,如果未設定高度或者高度設為為
auto
,則填充整個容器高度 - baseline: 專案的第一行文字的基線對齊
align-content
: 該屬性定義了主軸有多根軸線時,多根軸線在交叉軸的排列方式。只有一根軸線,就是專案沒有換行時,該屬性不起作用。這裡比較複雜的一個地方是多軸線的問題,主軸一旦換行就會形成多個軸線,align-items
仍然在每個軸線內起作用,而軸線的排列方式則由align-content
來設定,和justify-content
相對應。該屬性有6個值,以從上到下的垂直方向為交叉軸方向:- flex-start:上對齊
- flex-end: 下對齊
- center: 居中
- space-between: 兩端對齊,專案間的間隔相等
- space-around: 每個專案兩側的間隔相等。所以,專案之間的間隔比專案與邊框的間隔大一倍
- stretch(預設值): 軸線佔滿整個交叉軸,strech屬性和其他屬性的不同之處在於,strech會自動擴充套件軸線的高度,而其他屬性都是以軸線實際佔用的位置進行排列。具體可以看下下面的例子。
例子:
<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;
}
複製程式碼
效果如下:
如果我們把align-content
設定為space-between
,則效果如下:
如果我們把align-content
設定為stretch
,同時align-items
設定為center
,則效果如下,說明align-items
在單個軸線內起作用:
你可以自己去試一試!
容器上的屬性都已經介紹完了,主要就是設定主軸方向和兩個軸的排列方式。
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-basis
決定的。另外當flex-basis
為auto
時,則表示專案佔據主軸空間的大小為專案本來的大小,此時width
便會起作用。
flex
: flex屬性是flex-grow
,flex-shrink
和flex-basis
的簡寫,預設值為0 1 auto
。flex
的值使用起來比較複雜,可以看下面這段程式碼,基本包含所有情況。
/* 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
屬性。