CSS3 Flexbox屬性與彈性盒模型

2023-02-15 10:52 更新

簡(jiǎn)介

CSS3新增的Flexible Box Layout(彈性盒模型布局方式)是CSS3規(guī)范中提出的一種新的布局方案。該布局方案提供了一種更加高效簡(jiǎn)單的方式來(lái)處理容器中的元素布局、對(duì)齊、空間分配等操作,即使容器中的元素尺寸未知(或者尺寸大小是動(dòng)態(tài)的)也能工作得很好。目前CSS3提出的此種布局方式也被各大主流瀏覽器所支持,可以預(yù)見(jiàn)Flexbox Layout在未來(lái)將會(huì)被廣泛使用。

本文將詳細(xì)的介紹該布局模型,同時(shí)會(huì)輔以一定的示例來(lái)具體說(shuō)明如何在具體的web開(kāi)發(fā)中應(yīng)用該布局模型,達(dá)到傳統(tǒng)布局方案(塊級(jí)布局、內(nèi)聯(lián)布局、絕對(duì)定位局部等)的效果。

初識(shí)Flexbox

先讓我們來(lái)說(shuō)一說(shuō)Flexbox Layout(彈性盒模型布局)的基本原理。

在彈性盒模型布局中,需要事先指定一個(gè)容器,后續(xù)的所有布局操作都是基于此容器來(lái)定義的。其核心是容器會(huì)根據(jù)布局的需要(動(dòng)態(tài)的)調(diào)整其中所包含的子元素(即布局條目)的尺寸、順序來(lái)填充容器的所有可用空間。

當(dāng)容器的尺寸由于屏幕大?。ɑ蛘邽g覽器窗口尺寸)發(fā)生變化時(shí),其中包含的布局條目也會(huì)自動(dòng)地進(jìn)行調(diào)整。舉個(gè)例子,當(dāng)容器尺寸增大時(shí),包含的條目將會(huì)自動(dòng)拉伸以沾滿多余的空白空間;當(dāng)容器尺寸變小時(shí),條目會(huì)自動(dòng)收縮以適應(yīng)容器的尺寸防止移除容器的范圍。

額外提一點(diǎn),F(xiàn)lexbox布局是不存在內(nèi)置的布局方向的。這是什么意思呢?比如傳統(tǒng)的布局方案中,塊級(jí)布局(block)默認(rèn)是將各個(gè)塊級(jí)元素按照垂直方向自上向下依次堆放;內(nèi)聯(lián)布局(inline)默認(rèn)是將各個(gè)內(nèi)聯(lián)元素按照水平方向按照從左到右的順序依次堆放。而彈性盒布局不存在這種默認(rèn)的布局方向限制,它提供了獨(dú)立的布局方向?qū)傩?,開(kāi)發(fā)人員可以根據(jù)布局需要自行設(shè)置。

相關(guān)概念

彈性盒布局是一種新的布局方式。它涉及到一些新的概念,這里我們對(duì)其加以解釋。如下圖所示,


它包含如下幾個(gè)概念,

  1. flex container,即所謂的容器(或者稱(chēng)之為彈性盒、flex容器)。注意這里說(shuō)的容器并不是單純的dom元素所指代的容器,而是特指設(shè)置了彈性盒布局的dom元素。
  2. flex item,即所謂的條目(或者稱(chēng)之為flex條目)。這里的條目其實(shí)就是容器的子元素。比如ul元素為一個(gè)flex容器,那么其內(nèi)部包含的li元素就是flex條目。大部分時(shí)候,不同的彈性盒布局真正產(chǎn)生變化的其實(shí)就是條目的布局行為發(fā)生了變化。
  3. main axiscross axis,即所謂的主軸交叉軸(有的翻譯文章也稱(chēng)之為側(cè)軸)。這兩個(gè)屬性定義flex布局方向。需要注意的是,雖然圖中主軸是水平方向,交叉軸是垂直方向,但是這并不是固定的,開(kāi)發(fā)人員完全自定義主軸和交叉軸的方向。
    1. 在使用flex布局時(shí),一般我們需要首先明確主軸的方向,然后交叉軸的方向也會(huì)隨之確定下來(lái)。因?yàn)?strong>交叉軸的方向始終是與主軸的方向是垂直的。
    2. flex容器中flex條目可以根據(jù)布局需要排列成單行或者多行。
    3. 主軸main axis的作用是確定每一行上flex條目的排列方向。
    4. (當(dāng)flex條目成多行排列時(shí))交叉軸cross axis的作用是確定行與行之間的排列方向。
  4. main startmain end,即所謂的主軸起點(diǎn)主軸終點(diǎn)。
    1. 明確主軸的方向后(如上所述,不管是主軸還是交叉軸其實(shí)只有兩種方向,即水平或者垂直),還需要確定他們各自的排列方向。
    2. 假如已經(jīng)明確主軸的方向是水平的,那么其排列方向仍然會(huì)有兩種可選,一種是從左到右的排列方向(flex條目從左到右依次堆放),另一種是從右到左排列方向(flex條目從右到左依次堆放)。
    3. 主軸起點(diǎn)在左主軸終點(diǎn)在右即為從左到右的排列方向。(如上圖所示)
    4. 主軸起點(diǎn)在右主軸終點(diǎn)在左即為從右到左的排列方向。
  5. cross startcross end,即所謂的交叉軸起點(diǎn)交叉軸終點(diǎn)。
    1. 跟主軸起點(diǎn)和主軸終點(diǎn)的含義類(lèi)似,交叉軸起點(diǎn)和交叉軸終點(diǎn)明確了行與行之間的排列順序。
    2. 假如已經(jīng)明確交叉軸的方向是垂直的,那么其排列方向仍然將會(huì)有兩種可選,一種是從上到下的排列方向(第二行在第一行的下方),另一種是從下到上的排列方向(第二行在第一行的上方)。
  6. 所以,在flex容器進(jìn)行布局時(shí),在每一行中會(huì)把其中的flex條目從主軸起始位置開(kāi)始,依次排列到主軸結(jié)束位置。當(dāng)flex容器中存在多行時(shí),會(huì)把每一行從交叉軸起始位置開(kāi)始,依次排列到交叉軸結(jié)束位置。
  7. main sizecross size,即所謂的主軸尺寸交叉軸尺寸。對(duì)應(yīng)dom元素在主軸和交叉軸上的大小。
    1. 如果主軸方向是水平的(那么交叉軸方向肯定是垂直的),此時(shí)主軸尺寸即是dom元素(flex容器)的寬度屬性,交叉軸尺寸即是dom元素(flex容器)的高度屬性。
    2. 如果主軸方向是垂直的,那么主軸尺寸和交叉軸尺寸對(duì)應(yīng)的dom元素寬高屬性與之前相反。

繼續(xù)學(xué)習(xí)flex布局之前,一定要弄明白這些概念,因?yàn)榫唧w的屬性設(shè)置會(huì)與這些概念息息相關(guān)。

新舊語(yǔ)法

在進(jìn)行flex布局相關(guān)屬性的詳細(xì)說(shuō)明之前,有必要提一點(diǎn)。就是flex布局先后有兩種語(yǔ)法,一種是W3C于2009年發(fā)布的舊語(yǔ)法,另一種是W3C最新發(fā)布的新語(yǔ)法。

這里我不對(duì)前后兩種語(yǔ)法的差異作解析,僅從語(yǔ)法層面說(shuō)明存在這個(gè)差異。

舊語(yǔ)法中,所有的flex屬性都以box打頭,flex設(shè)置為display: box。如下所示:

/*使用flex的屬性通常有多個(gè)值,以下以豎線劃分,具體每個(gè)值的作用請(qǐng)看下文*/        
.box{
     /*定義容器的display屬性*/
    display: -moz-box; /*Firefox*/
    display: -webkit-box; /*Safari,Opera,Chrome*/
    display: box;
   /*box-pack定義子元素主軸對(duì)齊方式*/
   box-pack: start | end | center | justify;
   /*box-align定義子元素交叉軸對(duì)齊方式*/
   box-align: start | end | center | baseline | stretch;
   /* box-direction定義子元素的顯示方向 */
   box-direction: normal | reverse | inherit;
   /* box-orient定義子元素是否應(yīng)水平或垂直排列 */
   box-orient: horizontal | vertical | inline-axis | block-axis | inherit;
   /* box-lines定義當(dāng)子元素超出了容器是否允許子元素?fù)Q行 */
   box-lines: single | multiple;
}

.item{
    /*定義子元素屬性*/
    /* box-flex定義是否允許當(dāng)前子元素伸縮 */
    -moz-box-flex: 1.0; /*Firefox*/
    -webkit-box-flex: 1.0; /*Safari,Opera,Chrome*/
    box-flex: <value>;
    /* box-ordinal-group定義子元素的顯示次序,數(shù)值越小越排前 */
    box-ordinal-group: <integer>;
}

新語(yǔ)法中,所有的flex屬性都以flex打頭,flex設(shè)置為display: flex。如下所示:

/* 容器的display屬性 */
.box{
    display: -webkit-flex; /*webkit*/
    display: flex;
}
 
/*行內(nèi)flex*/
.box{
    display: -webkit-inline-flex; /*webkit*/
    display:inline-flex;
}
/* 容器樣式 */
.box{
    flex-direction: row | row-reverse | column | column-reverse;
    /*主軸方向:左到右(默認(rèn)) | 右到左 | 上到下 | 下到上*/
 
    flex-wrap: nowrap | wrap | wrap-reverse;
    /*換行:不換行(默認(rèn)) | 換行 | 換行并第一行在下方*/
 
    flex-flow: <flex-direction> || <flex-wrap>;
    /*主軸方向和換行簡(jiǎn)寫(xiě)*/
 
    justify-content: flex-start | flex-end | center | space-between | space-around;
    /*主軸對(duì)齊方式:左對(duì)齊(默認(rèn)) | 右對(duì)齊 | 居中對(duì)齊 | 兩端對(duì)齊 | 平均分布*/
 
    align-items: flex-start | flex-end | center | baseline | stretch;
    /*交叉軸對(duì)齊方式:頂部對(duì)齊(默認(rèn)) | 底部對(duì)齊 | 居中對(duì)齊 | 上下對(duì)齊并鋪滿 | 文本基線對(duì)齊*/
 
    align-content: flex-start | flex-end | center | space-between | space-around | stretch;
    /*多主軸對(duì)齊:頂部對(duì)齊(默認(rèn)) | 底部對(duì)齊 | 居中對(duì)齊 | 上下對(duì)齊并鋪滿 | 上下平均分布*/
}
/* 子元素屬性 */
.item{
    order: <integer>;
    /*排序:數(shù)值越小,越排前,默認(rèn)為0*/
 
    flex-grow: <number>; /* default 0 */
    /*放大:默認(rèn)0(即如果有剩余空間也不放大,值為1則放大,2是1的雙倍大小,以此類(lèi)推)*/
 
    flex-shrink: <number>; /* default 1 */
    /*縮?。耗J(rèn)1(如果空間不足則會(huì)縮小,值為0不縮?。?/
 
    flex-basis: <length> | auto; /* default auto */
    /*固定大小:默認(rèn)為0,可以設(shè)置px值,也可以設(shè)置百分比大小*/
 
    flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
    /*flex-grow, flex-shrink 和 flex-basis的簡(jiǎn)寫(xiě),默認(rèn)值為0 1 auto,*/
 
    align-self: auto | flex-start | flex-end | center | baseline | stretch;
    /*單獨(dú)對(duì)齊方式:自動(dòng)(默認(rèn)) | 頂部對(duì)齊 | 底部對(duì)齊 | 居中對(duì)齊 | 上下對(duì)齊并鋪滿 | 文本基線對(duì)齊*/
}

關(guān)于這兩種更多的差異請(qǐng)參閱官方文檔或者CSS參考手冊(cè)。

其中新舊語(yǔ)法中間還有存在一種非官方的過(guò)渡語(yǔ)法規(guī)范,flex設(shè)置為display: flexbox

順便提一句,關(guān)于新舊語(yǔ)法在實(shí)際使用時(shí),肯定是推薦使用新語(yǔ)法的,雖然新語(yǔ)法的瀏覽器支持性不如舊語(yǔ)法,但是畢竟是舊的語(yǔ)法,遲早是要淘汰的,而且新語(yǔ)法的表現(xiàn)也更加一致。

屬性詳解

注意,flex布局中的css樣式聲明與一般的css聲明不同,它會(huì)有兩個(gè)作用對(duì)象,分別是flex容器flex條目。即,有的flex屬性只能作用于flex容器,而有的flex屬性只能作用于flex條目。

下面我們針對(duì)flex布局的各個(gè)屬性分別作詳細(xì)說(shuō)明。

問(wèn)題引導(dǎo)

在詳細(xì)闡述各個(gè)屬性之前,我們先來(lái)拋出一個(gè)比較常見(jiàn)的布局問(wèn)題。問(wèn)題是這樣的,現(xiàn)在有一個(gè)無(wú)序列表(ul元素),其包含了6個(gè)列表項(xiàng)(li元素),如何做可以讓列表項(xiàng)(li元素)自適應(yīng)父容器的尺寸?換句話說(shuō),當(dāng)父容器尺寸足夠大時(shí),所有的li元素平鋪成一行;當(dāng)父容器的尺寸減小時(shí),li元素自動(dòng)換行。

大家都能想到的一種常規(guī)做法應(yīng)該就是給li元素設(shè)置浮動(dòng)。不過(guò)這里我們將使用flex布局來(lái)實(shí)現(xiàn)這種布局需求。html和css代碼如下,


<ul class="flex-container">
    <li class="flex-item">1</li>
    <li class="flex-item">2</li>
    <li class="flex-item">3</li>
    <li class="flex-item">4</li>
    <li class="flex-item">5</li>
    <li class="flex-item">6</li>
</ul>


.flex-container {
    list-style: none;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
}
.flex-item {
    margin: 5px;
    width: 300px;
    height: 300px;
    text-align: center;
    line-height: 300px;
    background-color: gold;
}

具體的效果可以看這個(gè)demo。各位看官可以自行縮放瀏覽器的窗口,觀察.flex-item塊的排列行為。注意,這里我并沒(méi)有使用浮動(dòng)的相關(guān)屬性。

display: flex

在之前說(shuō)過(guò),要想使用彈性盒布局必須事先指定一個(gè)容器,這個(gè)容器就是所謂的flex容器。那么如何指定flex容器呢?很簡(jiǎn)單,將其display屬性設(shè)置為flex即可。如下,

.flex-container {
    display: flex;
}

注意,如果需要在內(nèi)聯(lián)的場(chǎng)景下使用flex布局,則需要設(shè)置display: inline-flex。而且以下幾種屬性設(shè)置在彈性盒布局中是不起作用的,

  1. 浮動(dòng)元素(float
  2. 清除浮動(dòng)(clear
  3. css3多列布局(columns-*
  4. 垂直居中(vertical-align
  5. 首行/首字符選擇偽類(lèi)(::first-line::first-letter

flex-direction

flex-direction屬性的作用是設(shè)置主軸方向。我們之前有說(shuō)過(guò),一旦主軸方向確定,那么連帶的交叉軸的方向也會(huì)確定下來(lái)。這樣就確定了flex條目基本的排列方式。

下面我們來(lái)看一下flex-direction的具體用法,如下表,

可選值 含義 備注
row 橫向從左到右排列 左對(duì)齊。此為默認(rèn)值
row-reverse 反轉(zhuǎn)橫向排列(從右到左拍立) 右對(duì)齊
column 縱向排列(從上到下排列) 即設(shè)置主軸方向?yàn)榇怪狈较?/td>
column 反轉(zhuǎn)縱向排列(從下到上排列) 主軸方向?yàn)榇怪狈较?,但是越是后面的flex條目反而在上方

在這個(gè)demo中,可以肆意改變flex-direction的值,并改變?yōu)g覽器窗口大小,觀察頁(yè)面布局的變化。

flex-wrap

flex-wrap屬性用于設(shè)置當(dāng)所有的flex條目的尺寸之和超過(guò)flex容器的主軸尺寸時(shí)應(yīng)該采取的行為。這是什么意思呢?

在默認(rèn)情況下,flex容器中的flex條目會(huì)盡量的在一行上占滿flex容器的空間。當(dāng)主軸尺寸大于所有flex條目尺寸之和時(shí),這時(shí)并沒(méi)有什么問(wèn)題。但是,當(dāng)主軸尺寸小于所有flex條目尺寸之和時(shí),此時(shí)就會(huì)出現(xiàn)flex條目之間相互重疊或者換行的情況。所以flex-wrap屬性就是專(zhuān)門(mén)用來(lái)處理這種情況的。

下面讓我們來(lái)看一下flex-wrap的具體用法,如下表,

可選值 含義 備注
nowrap 容器中的條目只占滿容器在主軸方向上的一行,此時(shí)可能出現(xiàn)條目互相重疊或超出容器范圍的現(xiàn)象 此為默認(rèn)值
wrap 當(dāng)容器中的條目超出主軸方向上的一行時(shí),會(huì)把條目排列到下一行。而下一行的位置與交叉軸的方向一致 交叉軸的存在感就是在此
wrap-reverse wrap的含義類(lèi)似,不同的是下一行的位置與交叉軸的方向相反。 -

與之前類(lèi)似,我們可以在這個(gè)demo中實(shí)驗(yàn)不同flex-wrap取值的差異。

flex-flow

之前說(shuō)的兩個(gè)屬性flex-directionflex-wrap,從某種意義上來(lái)說(shuō)就是設(shè)置flex布局的主軸和交叉軸。一旦flex布局的主軸和交叉軸確定下來(lái),基本上整個(gè)布局中flex條目的排列方式我們就可以自行腦補(bǔ)出來(lái)了。

flex-flow屬性其實(shí)就是flex-directionflex-wrap的復(fù)合屬性。所以下面兩段代碼的效果是一致的。


.flex-container1 {
    flex-direction: row;
    flex-wrap: wrap;
}
.flex-container2 {
    flex-flow: row wrap;
}

order

前面說(shuō)的幾個(gè)屬性其實(shí)都是針對(duì)flex容器的設(shè)置。而order屬性是針對(duì)flex條目的。它的作用是自定義flex容器中條目的順序。其用法示例如下,


.flex-item:last-child {
    order: -1;
}

這段css代碼中使用了css3新出的一個(gè)結(jié)構(gòu)偽類(lèi)選擇器:last-child,其作用是匹配.flex-item元素且該元素是其父元素的最后一個(gè)子元素。關(guān)于css3選擇器的更多內(nèi)容歡迎閱讀博主的這篇文章初識(shí)CSS3選擇器。

言歸正傳,上面的css代碼,將導(dǎo)致最后一個(gè)li元素反而在第一個(gè)展示。效果如下,

注意,此時(shí)雖然最后一個(gè)子元素被置頂展示,但是并沒(méi)有改變其html文檔結(jié)構(gòu)。

order的用法如下,


order: <integer>

用整數(shù)值來(lái)定義排列順序,數(shù)值小的排在前面。默認(rèn)值為0,且可以設(shè)置為負(fù)值。

flex條目的彈性設(shè)置

彈性盒模型的真正牛逼的地方在于flex容器中的flex條目的尺寸是彈性的。這是啥意思呢?個(gè)人覺(jué)得它包含下面的幾層含義,

  • 主軸尺寸不夠大時(shí),使用flex-wrap可以讓flex條目自動(dòng)換行。
  • 主軸尺寸不夠大時(shí),還可以縮小條目的尺寸防止溢出容器范圍。
  • 主軸尺寸足夠大時(shí),可以適當(dāng)擴(kuò)展條目的尺寸來(lái)占用容器的額外空白空間。

這里我們把重心放在后兩點(diǎn)上,即flex容器可以根據(jù)本身尺寸的大小來(lái)動(dòng)態(tài)地調(diào)整flex條目的尺寸。

flex條目尺寸的彈性由3個(gè)css屬性來(lái)確定,分別是flex-basis、flex-growflex-shrink。他們的相關(guān)說(shuō)明如下,

屬性 可選值 默認(rèn)值 作用對(duì)象 含義 備注
flex-basis <length>, <percentage>, auto auto flex條目 設(shè)置彈性條目的初始主軸尺寸 這里的初始值表示flex容器調(diào)整之前flex條目尺寸的初始值。此屬性跟width等屬性的設(shè)置模式是一致的
flex-grow <integer> 1 flex條目 當(dāng)容器有多余的空間時(shí),這些空間在不同條目之間的分配比例 用于設(shè)置flex條目的擴(kuò)展因子,不能取負(fù)值
flex-shrink <integer> 1 flex條目 當(dāng)容器的空間不足時(shí),各個(gè)條目尺寸縮小的比例 此屬性的作用與flex-grow相反

關(guān)于上述三個(gè)屬性的一些額外說(shuō)明,

flex-basis

flex-basis用于設(shè)置flex條目的初始尺寸(未進(jìn)行任何調(diào)整之前)。當(dāng)設(shè)置為auto時(shí),則實(shí)際使用的值是主軸尺寸屬性的值。若主軸尺寸也是auto,那么使用的值由條目?jī)?nèi)容的尺寸來(lái)確定。

flex-grow

當(dāng)主軸尺寸足夠大時(shí),flex條目在容器內(nèi)一行就全部排列完了,此時(shí)容器的空間還有剩余,那么可用flex-grow擴(kuò)展flex條目。舉個(gè)例子,一個(gè)容器中有3個(gè)flex條目,其flex-grow屬性分別如下,


.flex-item:nth-child(1) {
    flex-grow: 1;
}
.flex-item:nth-child(2) {
    flex-grow: 2;
}
.flex-item:nth-child(3) {
    flex-grow: 3;
}

同時(shí),flex容器的寬度是800px,每個(gè)條目的寬度為200px,所以容器還將剩余200px。由于條目都設(shè)置了flex-grow屬性,那么此三個(gè)條目將按比例分配容器的剩余空間。第一個(gè)條目將得到200 1/6 = 33px左右,第二個(gè)條目將得到200 2/6 = 66px,第三個(gè)條目將得到200 * 3/6 = 99px左右。效果如下圖,

詳情可參考這個(gè)demo

flex-shrink

flex-shrink在使用上類(lèi)似flex-grow,不過(guò)它使用于設(shè)置當(dāng)主軸尺寸不夠大時(shí)縮小flex條目。同樣的,我們來(lái)舉個(gè)例子,一個(gè)容器中有3個(gè)flex條目,每個(gè)felx條目的尺寸為200px,容器的尺寸為500px。很明顯此時(shí)容器尺寸已經(jīng)放不下其中三個(gè)flex條目了。我們對(duì)每個(gè)flex條目設(shè)置flex-shrink屬性,


.flex-item:nth-child(1) {
    flex-shrink: 1;
}
.flex-item:nth-child(2) {
    flex-shrink: 2;
}
.flex-item:nth-child(3) {
    flex-shrink: 3;
}

如果我們希望flex容器能夠剛剛好將三個(gè)flex條目放下,我們需要縮小的尺寸為600-500 = 100px。接下來(lái)三個(gè)條目將根據(jù)flex-shrink屬性按比例的分?jǐn)傂枰s小的尺寸,即分別為100 1/6 = 16.6px,100 2/6 = 33.3px,100 * 3/6 = 50px。所以三個(gè)flex條目最終的尺寸為200 - 16.6 = 183.4px,200 - 33.3 = 166.7px,200 - 50 = 150px。效果如下,

詳情可參考這個(gè)demo。

多行彈性布局的注意事項(xiàng)

??注意,這里額外提一個(gè)非常重要的點(diǎn),就是在我們使用flex-growflex-shrink屬性對(duì)flex條目進(jìn)行擴(kuò)展或者縮小時(shí),這些操作其實(shí)是以為單位來(lái)操作的,容器先根據(jù)flex-wrap的屬性值來(lái)確定是單行布局或多行布局,然后把條目分配到對(duì)應(yīng)的行中,最后在每一行內(nèi)進(jìn)行空白空間的分配。

這什么意思呢?我們來(lái)舉個(gè)簡(jiǎn)單例子說(shuō)明一下。假如我有一份代碼如下,


<style>
.flex-container {
    width: 999px;
    flex-direction: row;
    flex-wrap: wrap;
    display: flex;
}
.flex-item {
    width: 300px;
    flex-grow: 1;
    flex-shrink: 1;
    flex-basis: auto;
}
</style>
<ul class="flex-container">
    <li class="flex-item">1</li>
    <li class="flex-item">2</li>
    <li class="flex-item">3</li>
    <li class="flex-item">4</li>
</ul>

這里容器中有4個(gè)flex條目,每個(gè)條目的寬度為300px,但是容器的尺寸只有999px,明顯是不足以放下所有的flex條目的。此時(shí)前三個(gè)條目將堆放在第一行,第4個(gè)條目將單獨(dú)的被堆放在第二行。此時(shí)第一行將會(huì)多出99px的空余空間,這99px的空余空間將會(huì)平均應(yīng)用到第一行的三個(gè)條目上;第二行因?yàn)橹挥幸粋€(gè)條目,此時(shí)這個(gè)條目將會(huì)直接占用剩余的699px。整個(gè)效果如下圖,

詳情可參考這個(gè)demo。

flex復(fù)合屬性

如你所見(jiàn),flex是一個(gè)復(fù)合屬性,它的語(yǔ)法如下,


flex: none | auto | [flex-grow] | [flex-shrink] | [flex-basis]

其中none的含義為:0 0 auto, 即flex-grow: 0,flex-shrink: 0, flex-basis: auto。
其中auto的含義為:1 1 auto, 即flex-grow: 1flex-shrink: 1, flex-basis: auto

當(dāng)flex-basis被省略時(shí),其值為0%。

flex條目的對(duì)齊

當(dāng)flex容器中flex條目的尺寸和排列都確定下來(lái)之后,我們還可以設(shè)置這些flex條目在容器中的對(duì)齊方式。

目前有三種對(duì)齊方式。

基于margin: auto對(duì)齊

第一種對(duì)齊方式是使用空白邊,即margin: auto。在使用自動(dòng)空白邊時(shí),flex容器中額外的空白空間將會(huì)由被聲明為auto的空白邊占據(jù)。

這種方式在W3C的官方文檔被稱(chēng)之為non-normative,更加像是一種奇淫巧計(jì)。

我們來(lái)看個(gè)具體的例子,



<nav>
    <ul>
        <li><a href=/about>About</a>
        <li><a href=/projects>Projects</a>
        <li><a href=/interact>Interact</a>
        <li id="login"><a href=/login>Login</a>
    </ul>
</nav>


ul {
    list-style: none;
    display: flex;
}
li {
    min-width: min-content;
}
#login {
   margin-left: auto;
}

其效果如下,

示例中的#login元素通過(guò)簡(jiǎn)單的margin-left設(shè)置,將其置于最右側(cè)展示。詳情可參考這個(gè)demo

基于主軸對(duì)齊

第二種對(duì)齊方式是基于主軸方向上的對(duì)齊策略??梢酝ㄟ^(guò)justify-content屬性來(lái)進(jìn)行設(shè)置。借助此屬性,我們可以調(diào)整flex條目在主軸方向上的對(duì)齊策略。

這種對(duì)齊方式的調(diào)整發(fā)生在修改條目的彈性尺寸和處理自動(dòng)空白邊之后。當(dāng)容器中的一行中的條目沒(méi)有彈性尺寸或是已經(jīng)達(dá)到了它們的最大尺寸時(shí),如果此時(shí)在這一行上還有額外的空白空間,我們可以使用justify-content來(lái)分配這些空白空間。該屬性還可以控制當(dāng)條目超出行的范圍時(shí)的對(duì)齊方式。

我們來(lái)看下justify-content屬性的基本用法,(注意justify-content用于設(shè)置flex容器)

可選值 含義
flex-start 條目集中于該行的起始位置。第一個(gè)條目與其所在行在主軸起始方向上的邊界保持對(duì)齊,其余的條目按照順序依次排列。
flex-end 條目集中于該行的結(jié)束方向。最后一個(gè)條目與其所在行在主軸結(jié)束方向上的邊界保持對(duì)齊,其余的條目按照順序依次排列。
center 條目集中于該行的中央。條目都往該行的中央排列,在主軸起始方向和結(jié)束方向上留有同樣大小的空白空間。如果空白空間不足,則條目會(huì)在兩個(gè)方向上超出同樣的空間。
space-between 第一個(gè)條目與其所在行在主軸起始方向上的邊界保持對(duì)齊,最后一個(gè)條目與其所在行在主軸結(jié)束方向上的邊界保持對(duì)齊??瞻卓臻g在條目之間平均分配,使得相鄰條目之間的空白尺寸相同。
space-around 類(lèi)似于space-between,不同的是第一個(gè)條目和最后一個(gè)條目與該行的邊界之間同樣存在空白空間,該空白空間的尺寸是條目之間的空白空間的尺寸的一半。

各屬性值的效果如下圖,

基于交叉軸對(duì)齊

第三種對(duì)齊方式是基于交叉軸方向上的對(duì)齊策略。此種方式中,我們有兩個(gè)屬性可以做相關(guān)設(shè)置,它們分別是align-itemsalign-self。其中前者是用來(lái)設(shè)置flex容器的,后者是用來(lái)設(shè)置flex條目的,這兩個(gè)屬性的作用對(duì)象是不同的。在某些場(chǎng)景下,我們可以對(duì)flex條目設(shè)置align-self來(lái)復(fù)寫(xiě)flex容器指定的對(duì)齊方式。

我們來(lái)看看align-items的基本用法,

可選值 含義
flex-start 條目與其所在行在交叉軸起始方向上的邊界保持對(duì)齊。
flex-end 條目與其所在行在交叉軸結(jié)束方向上的邊界保持對(duì)齊。
center 條目的空白邊盒子(margin box)在交叉軸上居中。如果交叉軸尺寸小于條目的尺寸,則條目會(huì)在兩個(gè)方向上超出相同大小的空間。
baseline 條目在基準(zhǔn)線上保持對(duì)齊。在所有條目中,基準(zhǔn)線與交叉軸起始方向上的邊界距離最大的條目,它與所在行在交叉軸方向上的邊界保持對(duì)齊。
stretch 如果條目的交叉軸尺寸的計(jì)算值是auto,則其實(shí)際使用的值會(huì)使得條目在交叉軸方向上盡可能地占滿。

各屬性值的效果如下圖,

align-self的屬性基本與align-items一致(用法和含義基本都一樣)。不過(guò)align-self除了align-items屬性可選值之外,還可以設(shè)置為auto。當(dāng)設(shè)置為auto時(shí),其值是父節(jié)點(diǎn)的屬性align-items的值,如果該節(jié)點(diǎn)沒(méi)有父節(jié)點(diǎn),則為stretch。

flex行的對(duì)齊

前面說(shuō)完了flex容器中flex條目的對(duì)齊方式。這里我們?cè)賮?lái)說(shuō)一下flex行的對(duì)齊。什么叫flex行?W3C官方文檔中提到了一個(gè)名詞,叫做Flex Lines。

那么什么叫Flex Lines呢?說(shuō)的直白點(diǎn)就是多行flex布局時(shí),主軸方向上的每一行就是Flex Lines。

舉個(gè)例子,


<div id="flex">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
    <div class="item">4</div>
</div>


#flex {
    display: flex;
    flex-flow: row wrap;
    width: 300px;
}
.item {
    width: 80px;
}

很明顯,上述代碼生成的flex容器一行肯定堆放不下所有flex條目的。又因?yàn)樵O(shè)置了flex-wrap: wrap,所以其在主軸方向上會(huì)發(fā)生換行。如下圖,

如圖所示,此flex布局將分為兩行,每一行就是所謂的Flex Lines

如果一個(gè)flex布局容器中不止一行,我們同樣可以對(duì)行與行之間的對(duì)齊方式進(jìn)行設(shè)置。為這一設(shè)置提供支持的屬性就是align-content。其實(shí)此屬性的作用和justify-content屬性很相似,只不過(guò)justify-content是用于在主軸方向上對(duì)齊行內(nèi)的flex條目,而align-content是用于設(shè)置行與行之間的對(duì)齊策略。

align-content詳細(xì)的用法如下表,

可選值 含義
flex-start 行集中于容器的交叉軸起始位置。第一行與容器在交叉軸起始方向上的邊界保持對(duì)齊,其余行按照順序依次排列。
flex-end 行集中于容器的交叉軸結(jié)束位置。第一行與容器在交叉軸結(jié)束方向上的邊界保持對(duì)齊,其余行按照順序依次排列。
center 行集中于容器的中央。行都往容器的中央排列,在交叉軸起始方向和結(jié)束方向上留有同樣大小的空白空間。如果空白空間不足,則行會(huì)在兩個(gè)方向上超出同樣的空間。
space-between 行在容器中均勻分布。第一行與容器在交叉軸起始方向上的邊界保持對(duì)齊,最后一行與容器在交叉軸結(jié)束方向上的邊界保持對(duì)齊??瞻卓臻g在行之間平均分配,使得相鄰行之間的空白尺寸相同。
space-around 類(lèi)似于space-between,不同的是第一行條目和最后一個(gè)行目與容器行的邊界之間同樣存在空白空間,而該空白空間的尺寸是行目之間的空白空間的尺寸的一半。
stretch 伸展行來(lái)占滿剩余的空間。多余的空間在行之間平均分配,使得每一行的交叉軸尺寸變大。

各屬性值的效果如下,

瀏覽器兼容性

本文的新舊語(yǔ)法中曾經(jīng)提到,彈性盒模型官方有好幾個(gè)版本的語(yǔ)法,這是因?yàn)槠湟?guī)范本身有過(guò)多個(gè)不同版本,因?yàn)闉g覽器對(duì)于該規(guī)范的支持也存在一些不一致。大致來(lái)說(shuō)總共有三個(gè)不同版本的語(yǔ)法,

  • 最新規(guī)范:最新版本規(guī)范的語(yǔ)法,即display: flex。
  • 中間版本:2011年的非官方規(guī)范語(yǔ)法,即display: flexbox
  • 老規(guī)范:2009年的規(guī)范的語(yǔ)法,即display: box。

瀏覽器的支持情況如下,

Chrome Safari Firefox Opera IE Android iOS
21+(新規(guī)范) 6.1+(新規(guī)范) 22+(新規(guī)范) 12.1+(新規(guī)范) 11+(新規(guī)范) 4.4+(新規(guī)范) 7.1+(新規(guī)范)
20-(老規(guī)范) 3.1+(老規(guī)范) 2-21(老規(guī)范) - 10(中間版本) 2.1+(老規(guī)范) 3.2+(老規(guī)范)

從上面看來(lái),彈性盒布局模型基本已經(jīng)被主流的現(xiàn)代瀏覽器所支持。除了IE系的瀏覽器拖了后腿之外,基本可以無(wú)障礙的使用。不過(guò)雖然如此,我們?yōu)榱思嫒菪?,在?shí)際使用的時(shí)候除了規(guī)范中定義的屬性之外,最好添加不同瀏覽器內(nèi)核的私有前綴。

參考列表


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)