Flexbox弹性盒模型
Flexbox叫彈性盒模型,它的使用場(chǎng)景主要是屏幕自適應(yīng)布局和取代浮動(dòng)布局。
細(xì)節(jié)性的知識(shí)需要大量實(shí)踐,系統(tǒng)性的知識(shí)則需要真正理解系統(tǒng)。我認(rèn)為Flexbox就屬于系統(tǒng)性的知識(shí)。所以這篇文章從概念入手,力求做到只要閱讀一遍,就可以讓開(kāi)發(fā)者心中有乾坤。
一維布局模型
你他媽可能是三體看多了吧,啥叫一維布局模型?
一維布局模型,簡(jiǎn)單講就是,在主軸方向確定的情況下,只有行,沒(méi)有列。
我們熟悉的二維布局模型有哪些呢?有display: table和display: grid。而我們今天要講的display: flex就是妥妥的一維布局模型了。
直接看圖。
可以看到,Flexbox有行的概念,卻沒(méi)有列的概念。這導(dǎo)致它的表達(dá)能力是受限的。
概念
我們?nèi)绾未_定一條短線(xiàn)是中文的一還是阿拉伯?dāng)?shù)字的1呢?
你可能覺(jué)得我在搞笑。一眼看過(guò)去,橫向的不就是中文的一,縱向的不就是阿拉伯?dāng)?shù)字的1么。
是的。那是因?yàn)槲覀冏裱恍┠J(rèn)的約定:兩眼連成的線(xiàn)確定了水平方向。
Flexbox也是這個(gè)道理。它是一個(gè)一維布局模型,我們就要找到確定僅有的維度的那根線(xiàn)。
這就引出了Flexbox的第一個(gè)概念:主軸(mian axis)與交叉軸(cross axis)。主軸就是那根僅有的維度線(xiàn)。兩眼連成的線(xiàn)與主軸方向保持平行,這就是肉眼看待Flexbox的正確方式。否則有時(shí)候它會(huì)顯得很別扭。
然后我們?cè)賮?lái)說(shuō)彈性盒子。既然它是一個(gè)盒子,那肯定得有容器,也得有內(nèi)容。
也就引出了Flexbox的第二個(gè)概念:彈性容器(flex container)與彈性項(xiàng)目(flex item)。
你可以將彈性容器理解為冷戰(zhàn)時(shí)期的柏林,各方國(guó)際政治勢(shì)力自然就是若干彈性項(xiàng)目了。幾個(gè)國(guó)際大流氓聚在一起開(kāi)會(huì)討論什么呢?當(dāng)然是開(kāi)會(huì)討論如何瓜分柏林咯。是的,彈性盒模型討論的就是彈性項(xiàng)目如何瓜分彈性容器這一溫馨的話(huà)題。
上一小節(jié)我們提到過(guò),Flexbox是一維布局模型。它帶來(lái)的結(jié)果就是Flexbox有行的概念,卻沒(méi)有列的概念。
所以引出Flexbox的第三個(gè)概念:行(line)。
直接看圖。
最小長(zhǎng)度
如果彈性容器有富余空間,那好說(shuō),大家分就是了。而如果彈性容器空間不夠,彈性項(xiàng)目不僅沒(méi)得分,大家還得擠一擠。那么問(wèn)題就來(lái)了,擠不是無(wú)限制的擠,咱們就來(lái)探討一下,擠到什么程度,是可忍孰不可忍?
舉個(gè)例子。
.container {display: flex;width: 850px;padding: 5px; } .container .item {width: 200px;height: 50px;margin: 5px; } .container .item:nth-child(2) {width: 1000px; }兩個(gè)彈性項(xiàng)目的長(zhǎng)度加起來(lái)的和已經(jīng)超過(guò)了彈性容器,所以不得不擠壓。擠壓的比率咱們先不考慮,咱們先觀(guān)察擠壓的方式。有沒(méi)有發(fā)現(xiàn)紅色部分都有不同程度的收縮,但是黃色部分卻巋然不動(dòng)?
黃色部分是什么?是彈性容器的padding和彈性項(xiàng)目的margin。盒子模型咱們都了解吧,除了padding、margin和border之外,是不是只剩content了?
咱們可以大膽猜測(cè),Flexbox只敢欺負(fù)盒子模型的content,其余都是大爺,惹不起。
別急,再來(lái)驗(yàn)證一下。
.container {display: flex;width: 850px;padding: 5px; } .container .item {width: 200px;height: 50px;margin: 5px; } .container .item:nth-child(2) {width: 1000px;padding: 0 450px; }這下是不是很清楚了?第一個(gè)彈性項(xiàng)目的content長(zhǎng)度已經(jīng)變成了0;第二個(gè)也好不到哪去,因?yàn)楹凶娱L(zhǎng)度都被padding占據(jù),它的content長(zhǎng)度實(shí)際上也是0。都把人家擠破產(chǎn)了,卻絲毫不敢動(dòng)其他的屬性,勢(shì)利眼無(wú)疑了。
我們?cè)賮?lái)看一個(gè)有意思的例子。
.container {display: flex;width: 850px;padding: 5px; } .container .item {width: 200px;height: 50px;margin: 5px; } .container .item:nth-child(2) {width: 1000px;padding: 0 300px; } .container .item .inner {width: 500px;height: 100%; }我在第二個(gè)彈性項(xiàng)目中放了一個(gè)長(zhǎng)500px的元素,結(jié)果你猜怎么著,彈性項(xiàng)目的padding竟然有一部分和元素重合了。連子元素都未能幸免。
一般來(lái)說(shuō)盒子模型的content都是被文字撐開(kāi)的,我們最后再來(lái)看看文字的情況。
在彈性項(xiàng)目顯式設(shè)置了寬度的情況下,彈性項(xiàng)目并不能完全包裹文字。也就是說(shuō)文字也幫不了它,既然它聲明了寬度,文字撐開(kāi)的長(zhǎng)度最多不能超過(guò)顯式聲明的寬度,超出的文字只能溢出。
而沒(méi)有顯式聲明寬度的情況,文字的寬度就是彈性項(xiàng)目盒子模型的content,Flexbox也拿它沒(méi)辦法。
總結(jié)一下:當(dāng)富余空間不夠時(shí),Flexbox只會(huì)擠壓彈性項(xiàng)目的content,其余如padding 、margin和border完全不受影響。同時(shí)彈性項(xiàng)目沒(méi)有顯式聲明寬度的情況下,Flexbox也不會(huì)擠壓文字。
display
從這里開(kāi)始,我們就要講具體的CSS屬性了。
display有兩個(gè)和Flexbox相關(guān)的屬性,分別是display: flex和display: inline-flex。
對(duì)于容器內(nèi)部的項(xiàng)目來(lái)說(shuō),效果是一樣的。它們的區(qū)別在于容器自身應(yīng)該以塊元素還是行內(nèi)元素的身份立命。包括table也有這樣的區(qū)分,就不多講了。
flex-direction
這個(gè)屬性聲明的是主軸的方位和方向。
首先,主軸可不一定是水平的,主軸切換了那可就什么都變了。
其次,主軸聲明的信息有兩個(gè),分別是:
- 它是水平的還是垂直的?
- 它在水平或垂直維度上是從左到右還是從右到左?
所以這里也涉及到四個(gè)屬性值。
.container {flex-direction: row(default) | row-reverse | column | column-reverse; }flex-wrap
這個(gè)屬性聲明的是當(dāng)容器中的項(xiàng)目一行放不下的時(shí)候,是讓大家擠一擠呢,還是換行。
其實(shí)這里也包含兩個(gè)信息:
- 要不要換行?
- 如果需要換行就會(huì)形成多行,多行是從上到下排列還是從下到上排列?
如果把flex-direction和flex-wrap結(jié)合起來(lái),大家會(huì)不會(huì)懵逼?上上下下左左右右。其實(shí)不管它怎么reverse,flex-direction反轉(zhuǎn)的是主軸的方向,flex-wrap反轉(zhuǎn)的交叉軸的方向。
抓住一些概念性的東西,就不會(huì)懵逼了。
flex-flow
這是一個(gè)集合屬性,可以同時(shí)定義flex-direction和flex-wrap。
也就是說(shuō),這一個(gè)屬性可以一站式聲明主軸和交叉軸的特性。
.container {flex-flow: row-reverse wrap-reverse; }justify-content
這個(gè)屬性聲明每行內(nèi)的項(xiàng)目如何水平對(duì)齊。
把彈性容器一行內(nèi)的項(xiàng)目想象成一行行內(nèi)元素,justify-content和text-align的食用方式是一樣的。
.container {justify-content: flex-start(default) | flex-end | center | space-between | space-around | space-evenly; }flex-start、flex-end和center非常表意,咱們按下不表。
解釋一下后面三個(gè)屬性值:
- space-between表示兩頭的項(xiàng)目對(duì)齊容器壁,項(xiàng)目與項(xiàng)目之間的空隙平均分配。所謂的between指的就是項(xiàng)目之間。
- space-around表示兩頭的項(xiàng)目與容器壁保留一個(gè)單位的空隙,項(xiàng)目與項(xiàng)目之間保持兩個(gè)單位的空隙。around翻譯成中文是周?chē)?#xff0c;指的就是每個(gè)項(xiàng)目左右兩邊的空隙平均分配。
- space-evenly表示兩頭的項(xiàng)目與容器壁之間的空隙和項(xiàng)目與項(xiàng)目之間的空隙都保持一個(gè)單位。evenly翻譯成中文是均勻,指的是所有空隙平均分配。
align-items
這個(gè)屬性聲明每行內(nèi)的項(xiàng)目如何垂直對(duì)齊。
.container {align-items: stretch(default) | flex-start | flex-end | center | baseline; }這里有一個(gè)問(wèn)題,如果彈性項(xiàng)目顯式的聲明了高度,那stretch將不再起作用。所以這里的例子,我往項(xiàng)目中加了一個(gè)子元素,把高度顯式的聲明在子元素上,這樣項(xiàng)目的高度就是被撐開(kāi)的。
<div class="container"><div class="item"><div class="inner">1</div></div><div class="item"><div class="inner">2</div></div><div class="item"><div class="inner">3</div></div> </div>可以看到,默認(rèn)情況下,行內(nèi)的彈性項(xiàng)目會(huì)拉伸,相當(dāng)于聲明了高度100%。一旦項(xiàng)目顯式的聲明了高度,拉伸就不再起作用了。
align-content
這個(gè)屬性將容器的一行視為最小單位。它聲明的是如果容器的交叉軸方向有富余空間,每行應(yīng)該如何垂直對(duì)齊。
.container {align-content: stretch(default) | flex-start | flex-end | center | space-between | space-around | space-evenly; }這里也一樣,如果彈性項(xiàng)目顯式的聲明了高度,那stretch將不再起作用。
同時(shí)有兩點(diǎn)需要注意:
- 彈性容器需要顯式的聲明高度,而且高度必須高于所有行的高度和,否則去哪來(lái)的富余空間呢?
- 如果容器內(nèi)只有一行,也就是說(shuō)不需要換行或者不允許換行,那align-content屬性將無(wú)法生效,因?yàn)樗亲饔糜谛械?#xff0c;只有一行也敢叫老子跑一趟?
為什么沒(méi)有justify-items
如果你同時(shí)了解display: flex和display: grid,也許你會(huì)發(fā)現(xiàn)它們都有xx-items和xx-content屬性。但是別急,再進(jìn)一步深究,發(fā)現(xiàn)Flexbox少了一個(gè)justify-items。
我們先來(lái)闡述一下xx-items和xx-content作用范圍有什么區(qū)別。
- xx-items作用于項(xiàng)目,這意思很明朗。
- xx-content又是作用于什么呢?肯定是比項(xiàng)目更大的單位,又聯(lián)想Flexbox的align-content是作用于行,我們可以大膽猜測(cè)xx-content作用于行或者列。
點(diǎn)破到這里,大家應(yīng)該有點(diǎn)眉目了吧?Flexbox是一維布局模型,它根本沒(méi)有列的概念。
你說(shuō)不對(duì)呀,既然Flexbox沒(méi)有列的概念,那不是應(yīng)該沒(méi)有justify-content屬性,而應(yīng)該有justify-items屬性么?
話(huà)是這么說(shuō),我當(dāng)初也是這么認(rèn)為的。
但后來(lái)仔細(xì)想一想,Flexbox的align-items聲明的是一行內(nèi)的項(xiàng)目如何垂直對(duì)齊,與之相對(duì),justify-items聲明的就應(yīng)該是一列內(nèi)的項(xiàng)目如何水平對(duì)齊。好像更離譜。而如果將彈性容器一行內(nèi)的每個(gè)項(xiàng)目都當(dāng)做一列,justify-content似乎就說(shuō)的通了。
這就好比討論螃蟹的螯到底是不是手一樣,怎么都覺(jué)得別扭。只能找一個(gè)相對(duì)更合理的說(shuō)法了。
提出這個(gè)問(wèn)題沒(méi)別的意思,只是想加深大家對(duì)Flexbox的理解。
order
從這里開(kāi)始,涉及到的屬性都是彈性項(xiàng)目自身的屬性。在大的格局確定的情況下,項(xiàng)目之間也是可以有一些騰挪空間的。
這個(gè)屬性聲明的是彈性項(xiàng)目自身的次序。只要顯式聲明了不是默認(rèn)值0的整數(shù),項(xiàng)目顯示的次序?qū)?huì)不同于源代碼定義的次序。
這個(gè)主要是留給JavaScript動(dòng)態(tài)控制項(xiàng)目的次序用的,非動(dòng)態(tài)直接修改源代碼的次序就好了。
.item {order: <integer>; /* default is 0 */ }flex-grow
這個(gè)屬性聲明的是彈性項(xiàng)目是否要瓜分行內(nèi)的富余空間,以及如何瓜分。
屬性值只允許正整數(shù)。
.item {flex-grow: <number>; /* default is 0 */ }首先解釋一下什么是富余空間:它是在彈性容器規(guī)則和彈性項(xiàng)目顯式寬度或者內(nèi)容的共同約束下,行內(nèi)剩余的水平空間。比如圖例中除去margin、padding的黃色部分。
行內(nèi)的富余空間是如何被瓜分的呢?
首先,彈性項(xiàng)目要提出申請(qǐng)。比如第一個(gè)項(xiàng)目提出flex-grow: 1,意思是說(shuō)它想要一份富余空間。至于一份富余空間是多少像素,目前還不能確定。
等所有項(xiàng)目都申請(qǐng)完畢,計(jì)算申請(qǐng)的總份數(shù)。已知富余空間長(zhǎng)度和申請(qǐng)總份數(shù),就能知道一份富余空間是多少像素。
最后根據(jù)每人提出申請(qǐng)的份數(shù),分配富余空間。
只有當(dāng)行內(nèi)有富余空間時(shí),flex-grow屬性才會(huì)生效。行內(nèi)空間已經(jīng)預(yù)先被瓜分完甚至不夠時(shí),該屬性就管不了了。
flex-shrink
這個(gè)屬性聲明的是彈性項(xiàng)目是否要瓜分行內(nèi)的負(fù)債空間,以及如何瓜分。
屬性值只允許正整數(shù)。
.item {flex-shrink: <number>; /* default is 1 */ }同樣,解釋一下什么是負(fù)債空間:它是在彈性容器規(guī)則和彈性項(xiàng)目顯式寬度或者內(nèi)容的共同約束下,行內(nèi)短缺的水平空間。此時(shí)如果不換行的話(huà),就要求擠壓彈性項(xiàng)目的長(zhǎng)度。
行內(nèi)的負(fù)債空間的瓜分規(guī)則與富余空間的瓜分規(guī)則大致相同。
首先,彈性項(xiàng)目要提出申請(qǐng)。只不過(guò)這時(shí)的份額就不再是我要多少,而是我還多少。
等所有項(xiàng)目都申請(qǐng)完畢,計(jì)算申請(qǐng)的總份數(shù)。
這里的問(wèn)題在于,計(jì)算負(fù)債空間的長(zhǎng)度稍微比較復(fù)雜。我們?cè)谖恼乱婚_(kāi)始探討過(guò)彈性項(xiàng)目最小長(zhǎng)度的話(huà)題,這里再次總結(jié)一下:
- 彈性容器只會(huì)擠壓彈性項(xiàng)目的content,其余如padding、margin和border不受影響。
- 如果彈性項(xiàng)目?jī)?nèi)有文本或者固定寬度的子元素,這又分兩種情況。第一種是項(xiàng)目本身沒(méi)有顯式聲明寬度,則最小長(zhǎng)度以子元素的長(zhǎng)度為準(zhǔn);第二種是項(xiàng)目本身顯式聲明了寬度,則最小長(zhǎng)度以子元素的長(zhǎng)度為準(zhǔn),但不能超過(guò)項(xiàng)目本身的寬度。結(jié)合上面圖例中最后兩個(gè)例子,更容易理解(我知道你已經(jīng)懵逼了)。
最后根據(jù)每人提出申請(qǐng)的份數(shù),分配負(fù)債空間。就是還債。
為什么flex-grow屬性的默認(rèn)值是0,而flex-shrink屬性的默認(rèn)值是1呢?
因?yàn)槟J(rèn)情況下,如果有富余空間我可以不要的,但是有負(fù)債空間又無(wú)法換行的話(huà),我不得不要。所以flex-shrink屬性的默認(rèn)值是1,意思就是默認(rèn)情況下,如果空間不夠則大家平均的被擠壓。
你可以將所有項(xiàng)目的flex-shrink屬性值設(shè)置為0,如此這般所有項(xiàng)目都鐵骨錚錚、不畏強(qiáng)權(quán)了。見(jiàn)上面圖例的第四個(gè)例子。
flex-basis
這個(gè)屬性聲明的是預(yù)先分配給彈性項(xiàng)目的長(zhǎng)度。它是width屬性的替代品,優(yōu)先級(jí)比width高。
.item {flex-basis: <length> | auto; /* default is auto */ }如果width和flex-basis都顯式的聲明了一個(gè)非auto的值,那么flex-basis的優(yōu)先級(jí)更高。否則,哪個(gè)顯式聲明了就以哪個(gè)為準(zhǔn)。
確實(shí)不太清楚制定flex-basis屬性標(biāo)準(zhǔn)的意義何在。
它們的區(qū)別好像僅限于屬性值為0的情況。width: 0我們都知道表示沒(méi)有寬度,見(jiàn)上面圖例的第二個(gè)例子;而flex-basis: 0表示以?xún)?nèi)容的寬度為寬度,見(jiàn)上面圖例中的第三個(gè)例子。
flex
這是一個(gè)集合屬性,可以同時(shí)定義flex-grow、flex-shrink和flex-basis。
你可以集合三個(gè)屬性的值,也可以只寫(xiě)flex-grow一個(gè)屬性的值。
.item {flex: <'flex-grow'> | <'flex-grow'> <'flex-shrink'> <'flex-basis'>; }align-self
這個(gè)屬性聲明的是彈性項(xiàng)目自身在行內(nèi)的垂直對(duì)齊方式。
“我就是我,是顏色不一樣的煙火”。
.item {align-self: auto(default) | stretch | flex-start | flex-end | center | baseline; }除了auto之外,align-self的屬性值和align-items的屬性值是一樣的,效果也一樣。
align-items: auto是說(shuō)我默認(rèn)服從集體,不自搞一套,所以才會(huì)多這么個(gè)屬性值。
為什么有align-self屬性而沒(méi)有justify-self屬性呢?
這個(gè)問(wèn)題我們討論過(guò)吧?因?yàn)闆](méi)有jusifty-items屬性,所以justify-self屬性也無(wú)從談起。
你看人家Grid就有justify-self屬性。
其他
有一個(gè)小游戲 Flexbox Froggy 可以幫助你輕松的實(shí)踐Flexbox的各項(xiàng)特性。
總結(jié)
以上是生活随笔為你收集整理的Flexbox弹性盒模型的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 京东到家怎么加盟
- 下一篇: 刺客信条奥德赛怎么召唤马