flex布局(轉(zhuǎn))

容器屬性

flex-flow

flex-direction

flex-wrap

justify-content

align-items

align-content

元素屬性

order

flex-grow

flex-shrink

flex-basis

flex

align-self

一、flex彈性盒模型

對(duì)于某個(gè)元素只要聲明了display: flex;,那么這個(gè)元素就成為了彈性容器,具有flex彈性布局的特性。

每個(gè)彈性容器都有兩根軸:主軸和交叉軸,兩軸之間成90度關(guān)系。注意:水平的不一定就是主軸。

每根軸都有起點(diǎn)和終點(diǎn),這對(duì)于元素的對(duì)齊非常重要。

彈性容器中的所有子元素稱為<彈性元素>,彈性元素永遠(yuǎn)沿主軸排列。

彈性元素也可以通過(guò)display:flex設(shè)置為另一個(gè)彈性容器,形成嵌套關(guān)系。因此一個(gè)元素既可以是彈性容器也可以是彈性元素

彈性容器的兩根軸非常重要,所有屬性都是作用于軸的。下面從軸入手,將所有flex布局屬性串起來(lái)理解。

二、主軸

flex布局是一種一維布局模型,一次只能處理一個(gè)維度(一行或者一列)上的元素布局,作為對(duì)比的是二維布局CSS Grid Layout,可以同時(shí)處理行和列上的布局。

也就是說(shuō),flex布局大部分的屬性都是作用于主軸的,在交叉軸上很多時(shí)候只能被動(dòng)地變化。

1. 主軸的方向

我們可以在彈性容器上通過(guò)flex-direction修改主軸的方向。如果主軸方向修改了,那么:

交叉軸就會(huì)相應(yīng)地旋轉(zhuǎn)90度。

彈性元素的排列方式也會(huì)發(fā)生改變,因?yàn)?b>彈性元素永遠(yuǎn)沿主軸排列。

flex-direction:row

flex-direction:column

flex-direction:row-reverse

flex-direction:column-reverse

2. 沿主軸的排列處理

彈性元素永遠(yuǎn)沿主軸排列,那么如果主軸排不下,該如何處理?

通過(guò)設(shè)置flex-wrap: nowrap | wrap | wrap-reverse可使得主軸上的元素不折行、折行、反向折行。

默認(rèn)是nowrap不折行,難道任由元素直接溢出容器嗎?當(dāng)然不會(huì),那么這里就涉及到元素的彈性伸縮應(yīng)對(duì),下面會(huì)講到。

wrap折行,顧名思義就是另起一行,那么折行之后行與行之間的間距(對(duì)齊)怎樣調(diào)整?這里又涉及到交叉軸上的多行對(duì)齊。

wrap-reverse反向折行,是從容器底部開(kāi)始的折行,但每行元素之間的排列仍保留正向。

3. 一個(gè)復(fù)合屬性

flex-flow= flex-drection + flex-wrap

flex-flow相當(dāng)于規(guī)定了flex布局的“工作流(flow)”

flex-flow: row nowrap;

三、元素如何彈性伸縮應(yīng)對(duì)

當(dāng)flex-wrap: nowrap;不折行時(shí),容器寬度有剩余/不夠分,彈性元素們?cè)撛趺础皬椥浴钡厣炜s應(yīng)對(duì)?

這里針對(duì)上面兩種場(chǎng)景,引入兩個(gè)屬性(需應(yīng)用在彈性元素上)

flex-shrink:縮小比例(容器寬度<元素總寬度時(shí)如何收縮)

flex-grow:放大比例(容器寬度>元素總寬度時(shí)如何伸展)

1. flex-shrink: 縮小比例

來(lái)看下以下場(chǎng)景,彈性容器#container寬度是200px,一共有三個(gè)彈性元素,寬度分別是50px、100px、120px。在不折行的情況下,此時(shí)容器寬度是明顯不夠分配的。

實(shí)際上,flex-shrink默認(rèn)為1,也就是當(dāng)不夠分配時(shí),元素都將等比例縮小,占滿整個(gè)寬度,如下圖。

#container {display: flex;? flex-wrap: nowrap;}

元素收縮的計(jì)算方法

真的是等比縮小(每個(gè)元素各減去70/3的寬度)嗎?這里稍微深究一下它的收縮計(jì)算方法。

彈性元素1:50px→37.03px

彈性元素2:100px→74.08px

彈性元素3:120px→88.89px

先拋結(jié)論:flex-shrink: 1并非嚴(yán)格等比縮小,它還會(huì)考慮彈性元素本身的大小。

容器剩余寬度:-70px

縮小因子的分母:1*50 + 1*100 + 1*120 = 270?(1為各元素flex-shrink的值)

元素1的縮小因子:1*50/270

元素1的縮小寬度為縮小因子乘于容器剩余寬度:1*50/270 * (-70)

元素1最后則縮小為:50px + (1*50/270 *(-70)) = 37.03px

加入彈性元素本身大小作為計(jì)算方法的考慮因素,主要是為了避免將一些本身寬度較小的元素在收縮之后寬度變?yōu)?的情況出現(xiàn)。

2. flex-grow: 放大比例

同樣,彈性容器#container寬度是200px,但此時(shí)只有兩個(gè)彈性元素,寬度分別是50px、100px。此時(shí)容器寬度是有剩余的。

那么剩余的寬度該怎樣分配?而flex-grow則決定了要不要分配以及各個(gè)分配多少。

(1)在flex布局中,容器剩余寬度默認(rèn)是不進(jìn)行分配的,也就是所有彈性元素的flex-grow都為0。

(2)通過(guò)指定flex-grow為大于零的值,實(shí)現(xiàn)容器剩余寬度的分配比例設(shè)置。

元素放大的計(jì)算方法

放大的計(jì)算方法并沒(méi)有與縮小一樣,將元素大小納入考慮。

僅僅按flex-grow聲明的份數(shù)算出每個(gè)需分配多少,疊加到原來(lái)的尺寸上。

容器剩余寬度:50px

分成每份:50px / (3+2) = 10px

元素1放大為:50px + 3 * 10 = 80px

無(wú)多余寬度時(shí),flex-grow無(wú)效

下圖中,彈性容器的寬度正好等于元素寬度總和,無(wú)多余寬度,此時(shí)無(wú)論flex-grow是什么值都不會(huì)生效。

同理,對(duì)于flex-shrink,在容器寬度有剩余時(shí)也是不會(huì)生效的。因此這兩個(gè)屬性是針對(duì)兩種不同場(chǎng)景的互斥屬性。

四、彈性處理與剛性尺寸

在進(jìn)行彈性處理之余,其實(shí)有些場(chǎng)景我們更希望元素尺寸固定,不需要進(jìn)行彈性調(diào)整。設(shè)置元素尺寸除了width和height以外,flex還提供了一個(gè)flex-basis屬性。

flex-basis設(shè)置的是元素在主軸上的初始尺寸,所謂的初始尺寸就是元素在flex-grow和flex-shrink生效前的尺寸。

1. 與width/height的區(qū)別

首先以width為例進(jìn)行比較??聪孪旅娴睦?。#container {display:flex;}。

11111
22222

</div>

(1) 兩者都為0

width: 0 —— 完全沒(méi)顯示

flex-basis: 0 —— 根據(jù)內(nèi)容撐開(kāi)寬度

(2) 兩者非0

width: 非0;

flex-basis: 非0

—— 數(shù)值相同時(shí)兩者等效

—— 同時(shí)設(shè)置,flex-basis優(yōu)先級(jí)高

(3) flex-basis為auto

flex-basis為auto時(shí),如設(shè)置了width則元素尺寸由width決定;沒(méi)有設(shè)置則由內(nèi)容決定

(4) flex-basis == 主軸上的尺寸 != width

將主軸方向改為:上→下

此時(shí)主軸上的尺寸是元素的height

flex-basis == height

2. 常用的復(fù)合屬性 flex

這個(gè)屬性應(yīng)該是最容易迷糊的一個(gè),下面揭開(kāi)它的真面目。

flex = flex-grow + flex-shrink + flex-basis

復(fù)合屬性,前面說(shuō)的三個(gè)屬性的簡(jiǎn)寫(xiě)。

一些簡(jiǎn)寫(xiě)

flex: 1?=?flex: 1 1 0%

flex: 2?=?flex: 2 1 0%

flex: auto?=?flex: 1 1 auto;

flex: none?=?flex: 0 0 auto;?// 常用于固定尺寸 不伸縮

flex:1 和 flex:auto 的區(qū)別

其實(shí)可以歸結(jié)于flex-basis:0和flex-basis:auto的區(qū)別。

flex-basis是指定初始尺寸,當(dāng)設(shè)置為0時(shí)(絕對(duì)彈性元素),此時(shí)相當(dāng)于告訴flex-grow和flex-shrink在伸縮的時(shí)候不需要考慮我的尺寸;相反當(dāng)設(shè)置為auto時(shí)(相對(duì)彈性元素),此時(shí)則需要在伸縮時(shí)將元素尺寸納入考慮。

因此從下圖(轉(zhuǎn)自W3C)可以看到絕對(duì)彈性元素如果flex-grow值是一樣的話,那么他們的尺寸一定是一樣的。

五、容器內(nèi)如何對(duì)齊

前面講完了元素大小關(guān)系之后,下面是另外一個(gè)重要議題——如何對(duì)齊??梢园l(fā)現(xiàn)上面的所有屬性都是圍繞主軸進(jìn)行設(shè)置的,但在對(duì)齊方面則不得不加入作用于交叉軸上。需要注意的是這些對(duì)齊屬性都是作用于容器上。

1. 主軸上的對(duì)齊方式

justify-content

2. 交叉軸上的對(duì)齊方式

主軸上比較好理解,重點(diǎn)是交叉軸上。因?yàn)榻徊孑S上存在單行和多行兩種情況。

交叉軸上的單行對(duì)齊

align-items

默認(rèn)值是stretch,當(dāng)元素沒(méi)有設(shè)置具體尺寸時(shí)會(huì)將容器在交叉軸方向撐滿。

當(dāng)align-items不為stretch時(shí),此時(shí)除了對(duì)齊方式會(huì)改變之外,元素在交叉軸方向上的尺寸將由內(nèi)容或自身尺寸(寬高)決定。

注意,交叉軸不一定是從上往下,這點(diǎn)再次強(qiáng)調(diào)也不為過(guò)。

交叉軸上的多行對(duì)齊

還記得可以通過(guò)flex-wrap: wrap使得元素在一行放不下時(shí)進(jìn)行換行。在這種場(chǎng)景下就會(huì)在交叉軸上出現(xiàn)多行,多行情況下,flex布局提供了align-content屬性設(shè)置對(duì)齊。

align-content與align-items比較類似,同時(shí)也比較容易迷糊。下面會(huì)將兩者對(duì)比著來(lái)看它們的異同。

首先明確一點(diǎn):align-content只對(duì)多行元素有效,會(huì)以多行作為整體進(jìn)行對(duì)齊,容器必須開(kāi)啟換行。

align-content: stretch | flex-start | flex-end | center | space-between | space-around

align-items: stretch | flex-start | flex-end | center | baseline

在屬性值上,align-content比align-items多了兩個(gè)值:space-between和space-around。

align-content與align-items異同對(duì)比

與align-items一樣,align-content:默認(rèn)值也是stretch。兩者同時(shí)都為stretch時(shí),毫無(wú)懸念所有元素都是撐滿交叉軸。

#container {

? align-items: stretch;

? align-content: stretch;

}

當(dāng)我們將align-items改為flex-start或者給彈性元素設(shè)置一個(gè)具體高度,此時(shí)效果是行與行之間形成了間距。

#container {? align-items: flex-start;? align-content: stretch;}/*或者*/#container {? align-content: stretch;}#container > div {height:30px;}

為什么?因?yàn)閍lign-content會(huì)以整行為單位,此時(shí)會(huì)將整行進(jìn)行拉伸占滿交叉軸;而align-items設(shè)置了高度或者頂對(duì)齊,在不能用高度進(jìn)行拉伸的情況下,選擇了用間距。

嘗試把a(bǔ)lign-content設(shè)置為頂對(duì)齊,此時(shí)以行為單位,整體高度通過(guò)內(nèi)容撐開(kāi)。

而align-items僅僅管一行,因此在只有第一個(gè)元素設(shè)置了高度的情況下,第一行的其他元素遵循align-items: stretch也被拉伸到了50px。而第二行則保持高度不變。

#container {? align-items: stretch;? align-content: flex-start;}#container > div:first-child {height:50px;}

兩者的區(qū)別還是不明顯?來(lái)看下面這個(gè)例子。

這里僅對(duì)第二個(gè)元素的高度進(jìn)行設(shè)置,其他元素高度則仍保持內(nèi)容撐開(kāi)。

以第一個(gè)圖為例,會(huì)發(fā)現(xiàn)align-content會(huì)將所有行進(jìn)行頂對(duì)齊,然后第一行由于第二個(gè)元素設(shè)置了較高的高度,因此體現(xiàn)出了底對(duì)齊。

兩者差異總結(jié):

兩者“作用域”不同

align-content管全局(所有行視為整體)

align-items管單行

能否更靈活地設(shè)置交叉軸對(duì)齊

除了在容器上設(shè)置交叉軸對(duì)齊,還可以通過(guò)align-self單獨(dú)對(duì)某個(gè)元素設(shè)置交叉軸對(duì)齊方式。

值與align-items相同

可覆蓋容器的align-items屬性

默認(rèn)值為auto,表示繼承父元素的align-items屬性

#container {display: flex;? align-items: flex-start;}#container > div:first-child {? align-self: stretch;}#container > div:nth-child(3) {? align-self: center;}#container > div:nth-child(4) {? align-self: flex-end;}

六、其他

order:更優(yōu)雅地調(diào)整元素順序

#container > div:first-child {order:2;}#container > div:nth-child(2) {order:4;}#container > div:nth-child(3) {order:1;}#container > div:nth-child(4) {order:3;}

order:可設(shè)置元素之間的排列順序

數(shù)值越小,越靠前,默認(rèn)為0

值相同時(shí),以dom中元素排列為準(zhǔn)

七、總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容