Flexbox叫彈性盒模型盖矫,它的使用場景主要是屏幕自適應布局和取代浮動布局樟澜。
細節(jié)性的知識需要大量實踐,系統性的知識則需要真正理解系統阿趁。我認為Flexbox就屬于系統性的知識稽莉。所以這篇文章從概念入手瀑志,力求做到只要閱讀一遍,就可以讓開發(fā)者心中有乾坤。
一維布局模型
你他媽可能是三體
看多了吧劈猪,啥叫一維布局模型昧甘?
一維布局模型,簡單講就是战得,在主軸
方向確定的情況下充边,只有行
,沒有列
常侦。
我們熟悉的二維布局模型有哪些呢浇冰?有display: table
和display: grid
。而我們今天要講的display: flex
就是妥妥的一維布局模型了聋亡。
直接看圖肘习。
[圖片上傳失敗...(image-395a3d-1578030195248)]
可以看到,Flexbox有行
的概念坡倔,卻沒有列
的概念漂佩。這導致它的表達能力是受限的。
概念
我們如何確定一條短線是中文的一
還是阿拉伯數字的1
呢罪塔?
你可能覺得我在搞笑投蝉。一眼看過去,橫向的不就是中文的一
征堪,縱向的不就是阿拉伯數字的1
么瘩缆。
是的。那是因為我們遵循著一些默認的約定:兩眼連成的線確定了水平方向请契。
Flexbox也是這個道理咳榜。它是一個一維布局模型,我們就要找到確定僅有的維度的那根線爽锥。
這就引出了Flexbox的第一個概念:主軸(mian axis)與交叉軸(cross axis)。主軸就是那根僅有的維度線畔柔。兩眼連成的線與主軸方向保持平行氯夷,這就是肉眼看待Flexbox的正確方式。否則有時候它會顯得很別扭靶擦。
然后我們再來說彈性盒子腮考。既然它是一個盒子,那肯定得有容器玄捕,也得有內容踩蔚。
也就引出了Flexbox的第二個概念:彈性容器(flex container)與彈性項目(flex item)。
你可以將彈性容器理解為冷戰(zhàn)時期的柏林枚粘,各方國際政治勢力自然就是若干彈性項目了馅闽。幾個國際大流氓聚在一起開會討論什么呢?當然是開會討論如何瓜分柏林咯。是的福也,彈性盒模型討論的就是彈性項目如何瓜分彈性容器這一溫馨的話題局骤。
上一小節(jié)我們提到過,Flexbox是一維布局模型暴凑。它帶來的結果就是Flexbox有行
的概念峦甩,卻沒有列
的概念。
所以引出Flexbox的第三個概念:行(line)现喳。
直接看圖凯傲。
[圖片上傳失敗...(image-c6e1d9-1578030195249)]
最小長度
如果彈性容器有富余空間,那好說嗦篱,大家分就是了冰单。而如果彈性容器空間不夠,彈性項目不僅沒得分默色,大家還得擠一擠球凰。那么問題就來了,擠不是無限制的擠腿宰,咱們就來探討一下呕诉,擠到什么程度,是可忍孰不可忍吃度?
舉個例子甩挫。
.container {
display: flex;
width: 850px;
padding: 5px;
}
.container .item {
width: 200px;
height: 50px;
margin: 5px;
}
.container .item:nth-child(2) {
width: 1000px;
}
[圖片上傳失敗...(image-dd981a-1578030195249)]
兩個彈性項目的長度加起來的和已經超過了彈性容器,所以不得不擠壓椿每。擠壓的比率咱們先不考慮伊者,咱們先觀察擠壓的方式。有沒有發(fā)現紅色部分都有不同程度的收縮间护,但是黃色部分卻巋然不動亦渗?
黃色部分是什么?是彈性容器的padding
和彈性項目的margin
汁尺。盒子模型咱們都了解吧法精,除了padding
、margin
和border
之外痴突,是不是只剩content
了搂蜓?
咱們可以大膽猜測,Flexbox只敢欺負盒子模型的content
辽装,其余都是大爺帮碰,惹不起。
別急拾积,再來驗證一下殉挽。
.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;
}
[圖片上傳失敗...(image-5d0592-1578030195249)]
這下是不是很清楚了丰涉?第一個彈性項目的content
長度已經變成了0;第二個也好不到哪去此再,因為盒子長度都被padding
占據昔搂,它的content
長度實際上也是0。都把人家擠破產了输拇,卻絲毫不敢動其他的屬性摘符,勢利眼無疑了。
我們再來看一個有意思的例子策吠。
.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%;
}
[圖片上傳失敗...(image-5bf43-1578030195249)]
我在第二個彈性項目中放了一個長500px
的元素逛裤,結果你猜怎么著,彈性項目的padding
竟然有一部分和元素重合了猴抹。連子元素都未能幸免带族。
一般來說盒子模型的content
都是被文字撐開的,我們最后再來看看文字的情況蟀给。
[圖片上傳失敗...(image-6084f4-1578030195249)]
在彈性項目顯式設置了寬度的情況下蝙砌,彈性項目并不能完全包裹文字。也就是說文字也幫不了它跋理,既然它聲明了寬度择克,文字撐開的長度最多不能超過顯式聲明的寬度,超出的文字只能溢出前普。
[圖片上傳失敗...(image-3e4e66-1578030195249)]
而沒有顯式聲明寬度的情況肚邢,文字的寬度就是彈性項目盒子模型的content
,Flexbox也拿它沒辦法拭卿。
總結一下:當富余空間不夠時骡湖,Flexbox只會擠壓彈性項目的
content
,其余如padding
峻厚、margin
和border
完全不受影響响蕴。同時彈性項目沒有顯式聲明寬度的情況下,Flexbox也不會擠壓文字惠桃。
display
從這里開始换途,我們就要講具體的CSS屬性了。
display
有兩個和Flexbox相關的屬性刽射,分別是display: flex
和display: inline-flex
。
對于容器內部的項目來說剃执,效果是一樣的誓禁。它們的區(qū)別在于容器自身應該以塊元素還是行內元素的身份立命。包括table
也有這樣的區(qū)分肾档,就不多講了摹恰。
flex-direction
這個屬性聲明的是主軸的方位和方向辫继。
首先,主軸可不一定是水平的俗慈,主軸切換了那可就什么都變了姑宽。
其次,主軸聲明的信息有兩個闺阱,分別是:
- 它是水平的還是垂直的炮车?
- 它在水平或垂直維度上是從左到右還是從右到左?
所以這里也涉及到四個屬性值酣溃。
.container {
flex-direction: row(default) | row-reverse | column | column-reverse;
}
[圖片上傳失敗...(image-192af0-1578030195249)]
flex-wrap
這個屬性聲明的是當容器中的項目一行放不下的時候瘦穆,是讓大家擠一擠呢,還是換行赊豌。
其實這里也包含兩個信息:
- 要不要換行扛或?
- 如果需要換行就會形成多行,多行是從上到下排列還是從下到上排列碘饼?
.container {
flex-wrap: nowrap(default) | wrap | wrap-reverse;
}
[圖片上傳失敗...(image-783856-1578030195249)]
如果把flex-direction
和flex-wrap
結合起來熙兔,大家會不會懵逼?上上下下左左右右艾恼。其實不管它怎么reverse住涉,flex-direction
反轉的是主軸的方向,flex-wrap
反轉的交叉軸的方向蒂萎。
抓住一些概念性的東西秆吵,就不會懵逼了。
flex-flow
這是一個集合屬性五慈,可以同時定義flex-direction
和flex-wrap
纳寂。
也就是說,這一個屬性可以一站式聲明主軸和交叉軸的特性泻拦。
.container {
flex-flow: row-reverse wrap-reverse;
}
justify-content
這個屬性聲明每行內的項目如何水平對齊毙芜。
把彈性容器一行內的項目想象成一行行內元素,justify-content
和text-align
的食用方式是一樣的争拐。
.container {
justify-content: flex-start(default) | flex-end | center | space-between | space-around | space-evenly;
}
[圖片上傳失敗...(image-96682b-1578030195249)]
flex-start
腋粥、flex-end
和center
非常表意,咱們按下不表架曹。
解釋一下后面三個屬性值:
-
space-between
表示兩頭的項目對齊容器壁隘冲,項目與項目之間的空隙平均分配。所謂的between
指的就是項目之間绑雄。 -
space-around
表示兩頭的項目與容器壁保留一個單位的空隙展辞,項目與項目之間保持兩個單位的空隙。around
翻譯成中文是周圍
万牺,指的就是每個項目左右兩邊的空隙平均分配罗珍。 -
space-evenly
表示兩頭的項目與容器壁之間的空隙和項目與項目之間的空隙都保持一個單位洽腺。evenly
翻譯成中文是均勻
,指的是所有空隙平均分配覆旱。
align-items
這個屬性聲明每行內的項目如何垂直對齊蘸朋。
.container {
align-items: stretch(default) | flex-start | flex-end | center | baseline;
}
[圖片上傳失敗...(image-f98076-1578030195249)]
這里有一個問題,如果彈性項目顯式的聲明了高度扣唱,那stretch
將不再起作用藕坯。所以這里的例子,我往項目中加了一個子元素画舌,把高度顯式的聲明在子元素上堕担,這樣項目的高度就是被撐開的。
<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>
可以看到曲聂,默認情況下霹购,行內的彈性項目會拉伸,相當于聲明了高度100%
朋腋。一旦項目顯式的聲明了高度齐疙,拉伸就不再起作用了。
align-content
這個屬性將容器的一行視為最小單位旭咽。它聲明的是如果容器的交叉軸方向有富余空間贞奋,每行應該如何垂直對齊。
.container {
align-content: stretch(default) | flex-start | flex-end | center | space-between | space-around | space-evenly;
}
[圖片上傳失敗...(image-f5dc67-1578030195249)]
這里也一樣穷绵,如果彈性項目顯式的聲明了高度轿塔,那stretch
將不再起作用。
同時有兩點需要注意:
- 彈性容器需要顯式的聲明高度仲墨,而且高度必須高于所有行的高度和勾缭,否則去哪來的富余空間呢?
- 如果容器內只有一行目养,也就是說不需要換行或者不允許換行俩由,那
align-content
屬性將無法生效,因為它是作用于行的癌蚁,只有一行也敢叫老子跑一趟幻梯?
為什么沒有justify-items
如果你同時了解display: flex
和display: grid
,也許你會發(fā)現它們都有xx-items
和xx-content
屬性努释。但是別急碘梢,再進一步深究,發(fā)現Flexbox少了一個justify-items
伐蒂。
我們先來闡述一下xx-items
和xx-content
作用范圍有什么區(qū)別痘系。
-
xx-items
作用于項目,這意思很明朗饿自。 -
xx-content
又是作用于什么呢汰翠?肯定是比項目更大的單位,又聯想Flexbox的align-content
是作用于行昭雌,我們可以大膽猜測xx-content
作用于行或者列复唤。
點破到這里,大家應該有點眉目了吧烛卧?Flexbox是一維布局模型佛纫,它根本沒有列的概念。
你說不對呀总放,既然Flexbox沒有列的概念呈宇,那不是應該沒有justify-content
屬性,而應該有justify-items
屬性么局雄?
話是這么說甥啄,我當初也是這么認為的。
但后來仔細想一想炬搭,Flexbox的align-items
聲明的是一行內的項目如何垂直對齊蜈漓,與之相對,justify-items
聲明的就應該是一列內的項目如何水平對齊宫盔。好像更離譜融虽。而如果將彈性容器一行內的每個項目都當做一列,justify-content
似乎就說的通了灼芭。
這就好比討論螃蟹的螯到底是不是手一樣有额,怎么都覺得別扭。只能找一個相對更合理的說法了彼绷。
提出這個問題沒別的意思巍佑,只是想加深大家對Flexbox的理解。
order
從這里開始苛预,涉及到的屬性都是彈性項目自身的屬性句狼。在大的格局確定的情況下,項目之間也是可以有一些騰挪空間的热某。
這個屬性聲明的是彈性項目自身的次序腻菇。只要顯式聲明了不是默認值0的整數,項目顯示的次序將會不同于源代碼定義的次序昔馋。
這個主要是留給JavaScript動態(tài)控制項目的次序用的筹吐,非動態(tài)直接修改源代碼的次序就好了。
.item {
order: <integer>; /* default is 0 */
}
[圖片上傳失敗...(image-4b42a8-1578030195249)]
flex-grow
這個屬性聲明的是彈性項目是否要瓜分行內的富余空間秘遏,以及如何瓜分丘薛。
屬性值只允許正整數。
.item {
flex-grow: <number>; /* default is 0 */
}
[圖片上傳失敗...(image-e0dcce-1578030195249)]
首先解釋一下什么是富余空間:它是在彈性容器規(guī)則和彈性項目顯式寬度或者內容的共同約束下邦危,行內剩余的水平空間洋侨。比如圖例中除去margin
舍扰、padding
的黃色部分。
行內的富余空間是如何被瓜分的呢希坚?
首先边苹,彈性項目要提出申請。比如第一個項目提出flex-grow: 1
裁僧,意思是說它想要一份富余空間个束。至于一份富余空間是多少像素,目前還不能確定聊疲。
等所有項目都申請完畢茬底,計算申請的總份數。已知富余空間長度和申請總份數获洲,就能知道一份富余空間是多少像素阱表。
最后根據每人提出申請的份數,分配富余空間。
只有當行內有富余空間時,
flex-grow
屬性才會生效啸澡。行內空間已經預先被瓜分完甚至不夠時,該屬性就管不了了烂叔。
flex-shrink
這個屬性聲明的是彈性項目是否要瓜分行內的負債空間,以及如何瓜分固歪。
屬性值只允許正整數蒜鸡。
.item {
flex-shrink: <number>; /* default is 1 */
}
[圖片上傳失敗...(image-fe9fba-1578030195249)]
同樣,解釋一下什么是負債空間:它是在彈性容器規(guī)則和彈性項目顯式寬度或者內容的共同約束下牢裳,行內短缺的水平空間逢防。此時如果不換行的話,就要求擠壓彈性項目的長度蒲讯。
行內的負債空間的瓜分規(guī)則與富余空間的瓜分規(guī)則大致相同忘朝。
首先,彈性項目要提出申請判帮。只不過這時的份額就不再是我要多少局嘁,而是我還多少。
等所有項目都申請完畢晦墙,計算申請的總份數悦昵。
這里的問題在于,計算負債空間的長度稍微比較復雜晌畅。我們在文章一開始探討過彈性項目最小長度的話題但指,這里再次總結一下:
- 彈性容器只會擠壓彈性項目的
content
,其余如padding
、margin
和border
不受影響棋凳。 - 如果彈性項目內有文本或者固定寬度的子元素拦坠,這又分兩種情況。第一種是項目本身沒有顯式聲明寬度贫橙,則最小長度以子元素的長度為準贪婉;第二種是項目本身顯式聲明了寬度,則最小長度以子元素的長度為準卢肃,但不能超過項目本身的寬度。結合上面圖例中最后兩個例子才顿,更容易理解(我知道你已經懵逼了)莫湘。
最后根據每人提出申請的份數,分配負債空間郑气。就是還債幅垮。
為什么
flex-grow
屬性的默認值是0,而flex-shrink
屬性的默認值是1呢尾组?因為默認情況下忙芒,如果有富余空間我可以不要的,但是有負債空間又無法換行的話讳侨,我不得不要呵萨。所以
flex-shrink
屬性的默認值是1,意思就是默認情況下跨跨,如果空間不夠則大家平均的被擠壓潮峦。你可以將所有項目的
flex-shrink
屬性值設置為0,如此這般所有項目都鐵骨錚錚勇婴、不畏強權了忱嘹。見上面圖例的第四個例子。
flex-basis
這個屬性聲明的是預先分配給彈性項目的長度耕渴。它是width
屬性的替代品拘悦,優(yōu)先級比width
高。
.item {
flex-basis: <length> | auto; /* default is auto */
}
[圖片上傳失敗...(image-b97b99-1578030195249)]
如果width
和flex-basis
都顯式的聲明了一個非auto
的值橱脸,那么flex-basis
的優(yōu)先級更高础米。否則,哪個顯式聲明了就以哪個為準慰技。
確實不太清楚制定flex-basis
屬性標準的意義何在椭盏。
它們的區(qū)別好像僅限于屬性值為0的情況。width: 0
我們都知道表示沒有寬度吻商,見上面圖例的第二個例子掏颊;而flex-basis: 0
表示以內容的寬度為寬度,見上面圖例中的第三個例子。
flex
這是一個集合屬性乌叶,可以同時定義flex-grow
盆偿、flex-shrink
和flex-basis
。
你可以集合三個屬性的值准浴,也可以只寫flex-grow
一個屬性的值事扭。
.item {
flex: <'flex-grow'> | <'flex-grow'> <'flex-shrink'> <'flex-basis'>;
}
align-self
這個屬性聲明的是彈性項目自身在行內的垂直對齊方式。
“我就是我乐横,是顏色不一樣的煙火”求橄。
.item {
align-self: auto(default) | stretch | flex-start | flex-end | center | baseline;
}
[圖片上傳失敗...(image-5e2c96-1578030195249)]
除了auto
之外,align-self
的屬性值和align-items
的屬性值是一樣的葡公,效果也一樣罐农。
align-items: auto
是說我默認服從集體,不自搞一套催什,所以才會多這么個屬性值涵亏。
為什么有
align-self
屬性而沒有justify-self
屬性呢?這個問題我們討論過吧蒲凶?因為沒有
jusifty-items
屬性气筋,所以justify-self
屬性也無從談起。你看人家Grid就有
justify-self
屬性旋圆。
其他
有一個小游戲 Flexbox Froggy 可以幫助你輕松的實踐Flexbox的各項特性宠默。
轉自github