詳解flex布局的元素如何分配容器的剩余空間
文章主要介紹了詳解flex布局的元素如何分配容器的剩余空間,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)...
文章主要介紹了詳解flex布局的元素如何分配容器的剩余空間,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
自從開(kāi)始開(kāi)學(xué)習(xí) CSS 布局,想要比較靈活的把父元素的空間分配給各個(gè)子元一直是各個(gè)前端程序員的夢(mèng)想。
在 flex 之前,如果不是專門去搜索相關(guān)的解決方案,一般人幾乎想不出非常靈活的三(多)欄等高布局方案,而即使看了解決方案,很多人也會(huì)大呼奇技淫巧。
不得不感慨在 flex 之前 CSS 的布局功能之弱:基本只能使用一些并非為布局而設(shè)計(jì)的屬性來(lái)實(shí)現(xiàn)想要的布局——float、inline-block、position、甚至是 table 等。而使用這些屬性來(lái)實(shí)現(xiàn)各種布局效果,往往又會(huì)遇到相當(dāng)多另外的坑:比如浮動(dòng)的閉合、inline-block 的垂直對(duì)齊、position 的定位原點(diǎn)以及 table 的不夠靈活等。
直到出現(xiàn)了 flex
flex 可以說(shuō)是一次性解決了前端布局的所有的問(wèn)題(當(dāng)然,并沒(méi)有完全解決,要不然也不會(huì)有 grid layout 了),以前很難實(shí)現(xiàn)的布局效果在 flex 下簡(jiǎn)直不能更簡(jiǎn)單,以至于一些其它平臺(tái)也開(kāi)始吸納 flex 的布局思想,也有些開(kāi)源項(xiàng)目把 flex 的布局方式移植到其它平臺(tái)。
中文社區(qū)也有不少寫 flex 的文章,比如 ruanyifeng。然而個(gè)人覺(jué)得不少寫 flex 的文章都有個(gè)通病,就是一上來(lái)就整一堆 flex 相關(guān)的術(shù)語(yǔ),比如 flex container,flex item,main axis(主軸),cors axis(交叉軸),不禁讓人望而生畏,都還沒(méi)搞清楚怎么回事,就來(lái)一堆術(shù)語(yǔ)。
然而這還不是最大的問(wèn)題,最大的問(wèn)題是很多文章并沒(méi)有把 flex 布局的詳細(xì)計(jì)算方式講清楚,尤其是連 ruanyifeng 的文章也沒(méi)把這事說(shuō)清楚,但是在 Google 搜索 flex 相關(guān)的文章,他的文章卻會(huì)出現(xiàn)在第一頁(yè)。因?yàn)槲矣X(jué)得他寫的并不好,所以就不貼地址了,想看的同學(xué)可以自己搜一下,就在第一頁(yè)。
即使是 MDN 以及《The Book Of CSS3》里也沒(méi)把 flex-grow 和 flex-shrink 的計(jì)算方式說(shuō)清楚。
所以我決定寫這一篇文章,把 flex-grow 與 flex-shrink 的詳細(xì)計(jì)算方式講清楚。
flex 如何解決傳統(tǒng)常見(jiàn)布局問(wèn)題
在傳統(tǒng)布局中最常見(jiàn)也是急需的當(dāng)然就是在從左往右把父元素的空間分配給子元素以實(shí)現(xiàn)多欄布局了:按比例也好,定寬也好,更靈活的定寬加占用剩余空間也好。
那我們就從使用 flex 如何實(shí)現(xiàn)三欄布局開(kāi)始吧。
想要實(shí)現(xiàn)三欄等高布局,且兩邊的側(cè)欄寬度固定而中間一欄占用剩余的空間,如下代碼就足夠了:
<style>
section {display: flex;}
.left-side,
.right-side {width: 200px;}
.content {flex-grow: 1;}
</style>
<section>
<div class="left-side"></div>
<div class="content"></div>
<div class="right-side"></div>
</section>
其中 section 元素的寬度將會(huì)像 block 元素一樣盡量的寬,對(duì)外面的元素來(lái)說(shuō),它的行為很像一個(gè) block 塊。三個(gè)元素會(huì)從左往右占據(jù)父元素的空間(這很顯然)。左右側(cè)邊欄的寬度都是 200px,中間 .content 元素的寬度將會(huì)占據(jù) section 元素的剩余寬度。
另外,section 的高度會(huì)自動(dòng)被最高的一個(gè)子元素?fù)伍_(kāi),同時(shí)其它子元素的高度也會(huì)被拉到跟 section 元素一樣高,而如果給 section 元素設(shè)置了高度,而所有子元素的高度設(shè)置為 auto ,所有的子元素也都會(huì)自動(dòng)跟父元素一樣高,這簡(jiǎn)直就是在傳統(tǒng)布局中做夢(mèng)都想要的功能!
總之,在高度方面,flex 的表現(xiàn)是相當(dāng)符合直覺(jué)的。
另外,如果不給 flex 子元素設(shè)置寬度和 flex-grow,它會(huì)盡量的窄。
flex-grow 的計(jì)算方式
上面 demo 中最值得注意的是 .content 元素的 flex-grow 屬性,設(shè)置為 1 它就可以占滿水平剩余空間。這也是本文的重點(diǎn):講清 flex-grow 與 flex-shrink 屬性的詳細(xì)計(jì)算方式。
flex-grow 屬性決定了父元素在空間分配方向上還有剩余空間時(shí),如何分配這些剩余空間。其值為一個(gè)權(quán)重(也稱擴(kuò)張因子),默認(rèn)為 0(純數(shù)值,無(wú)單位),剩余空間將會(huì)按照這個(gè)權(quán)重來(lái)分配。
比如剩余空間為 x,三個(gè)元素的 flex-grow 分別為 a,b,c。設(shè) sum 為 a + b + c。那么三個(gè)元素將得到剩余空間分別是 x a / sum, x b / sum, x * c / sum,是為權(quán)重也。
舉個(gè)例子:
父元素寬度 500px,三個(gè)子元素的 width 分別為 100px,150px,100px。
于是剩余空間為 150px
三個(gè)元素的 flex-grow 分別是 1,2,3,于是 sum 為 6
則三個(gè)元素所得到的多余空間分別是:
150 * 1 / 6 = 25px
150 * 2 / 6 = 50px
150 * 3 / 6 = 75px
三個(gè)元素最終的寬度分別為 125px,200px,175px。
100px + 25px = 125px
150px + 50px = 200px
100px + 75px = 175px
可以打開(kāi)這個(gè) demo(下文中所有的 demo 都在這個(gè)頁(yè)面) 然后用開(kāi)發(fā)工具查看一下。注意不要用截圖工具量,可能量不準(zhǔn),因?yàn)楦叻制梁头糯蟮戎T多因素都會(huì)影響測(cè)量結(jié)果。
然而!不止這些,還有一種情況:
當(dāng)所有元素的 flex-grow 之和小于 1 的時(shí)候(注意是 1,也就是說(shuō)每個(gè)元素的 flex-grow 都是一個(gè)小數(shù)如 0.2 這樣的),上面式子中的 sum 將會(huì)使用 1 來(lái)參與計(jì)算,而不論它們的和是多少。也就是說(shuō),當(dāng)所有的元素的 flex-grow 之和小于 1 的時(shí)候,剩余空間不會(huì)全部分配給各個(gè)元素。
實(shí)際上用來(lái)分配的空間是 sum(flex-grow) / 1 * 剩余空間,這些用來(lái)分配的空間依然是按 flex-grow 的比例來(lái)分配。
還是上面一個(gè)例子,但是三個(gè)元素的 flex-grow 分別是 0.1,0.2,0.3,那么計(jì)算公式將變成下面這樣:
150 * 0.1 / 1 = 15px
150 * 0.2 / 1 = 30px
150 * 0.3 / 1 = 45px
150px - 15px - 30px - 45px = 60px,即還有 60px 沒(méi)有分配給任何子元素。
三個(gè)元素的最終寬度分別為:
100px + 15px = 115px
150px + 30px = 180px
100px + 45px = 145px
如上所述即是 flex-grow 的計(jì)算方式。
另外,flex-grow 還會(huì)受到 max-width 的影響。如果最終 grow 后的結(jié)果大于 max-width 指定的值,max-width 的值將會(huì)優(yōu)先使用。同樣會(huì)導(dǎo)致父元素有部分剩余空間沒(méi)有分配。
flex-shrink 的計(jì)算方式
前文已經(jīng)說(shuō)到,flex 幾乎一次性解決了前端布局的所有問(wèn)題。
那么既然可以在空間有多余時(shí)把多余空間分配給各個(gè)子元素,當(dāng)然也可以在空間不夠時(shí)讓各個(gè)子元素收縮以適應(yīng)有限的空間了。
這就是 flex-shrink 屬性的作用。
你可能會(huì)覺(jué)得 flex-shrink 的計(jì)算方式跟 flex-grow 很類似,然而事情并沒(méi)有這么簡(jiǎn)單。
flex-shrink 屬性定義空間不夠時(shí)各個(gè)元素如何收縮。其值默認(rèn)為 1。很多文章對(duì)此基本是一筆帶過(guò):“flex-shrink 屬性定義了元素的收縮系數(shù)”,根本就不說(shuō)它具體是怎么計(jì)算的。
flex-shrink 定義的僅僅只是元素寬度變小的一個(gè)權(quán)重分量。
每個(gè)元素具體收縮多少,還有另一個(gè)重要因素,即它本身的寬度。
舉個(gè)例子:
父元素 500px。三個(gè)子元素分別設(shè)置為 150px,200px,300px。
三個(gè)子元素的 flex-shrink 的值分別為 1,2,3。
首先,計(jì)算子元素溢出多少:150 + 200 + 300 - 500 = -150px。
那這 -150px 將由三個(gè)元素的分別收縮一定的量來(lái)彌補(bǔ)。
具體的計(jì)算方式為:每個(gè)元素收縮的權(quán)重為其 flex-shrink 乘以其寬度。
所以總權(quán)重為 1 150 + 2 200 + 3 * 300 = 1450
三個(gè)元素分別收縮:
150 1(flex-shrink) 150(width) / 1450 = -15.5
150 2(flex-shrink) 200(width) / 1450 = -41.4
150 3(flex-shrink) 300(width) / 1450 = -93.1
三個(gè)元素的最終寬度分別為:
150 - 15.5 = 134.5
200 - 41.4 = 158.6
300 - 93.1 = 206.9
同樣,當(dāng)所有元素的 flex-shrink 之和小于 1 時(shí),計(jì)算方式也會(huì)有所不同:
此時(shí),并不會(huì)收縮所有的空間,而只會(huì)收縮 flex-shrink 之和相對(duì)于 1 的比例的空間。
還是上面的例子,但是 flex-shrink 分別改為 0.1,0.2,0.3。
于是總權(quán)重為 145(正好縮小 10 倍,略去計(jì)算公式)。
三個(gè)元素收縮總和并不是 150px,而是只會(huì)收縮 150px 的 (0.1 + 0.2 + 0.3) / 1 即 60% 的空間:90px。
每個(gè)元素收縮的空間為:
90 0.1(flex-shrink) 150(width) / 145 = 9.31
90 0.2(flex-shrink) 200(width) / 145 = 24.83
90 0.3(flex-shrink) 300(width) / 145 = 55.86
三個(gè)元素的最終寬度分別為:
150 - 9.31 = 140.69
200 - 24.83 = 175.17
300 - 55.86 = 244.14
當(dāng)然,類似 flex-grow,flex-shrink 也會(huì)受到 min-width 的影響。
總結(jié)
雖然上面的公式看起來(lái)很復(fù)雜,其實(shí)計(jì)算過(guò)程還是比較簡(jiǎn)單的:如果所有元素的 flex-grow/shrink 之和大于等于 1,則所有子元素的尺寸一定會(huì)被調(diào)整到適應(yīng)父元素的尺寸(在不考慮 max/min-width/height 的前提下),而如果 flex-grow/shrink 之和小于 1,則只會(huì) grow 或 shrink 所有元素 flex-grow/shrink 之和相對(duì)于 1 的比例。grow 時(shí)的每個(gè)元素的權(quán)重即為元素的 flex-grow 的值;shrink 時(shí)每個(gè)元素的權(quán)重則為元素 flex-shrink 乘以 width 后的值。
- 關(guān)于CSS中@support實(shí)現(xiàn)漸進(jìn)式網(wǎng)頁(yè)設(shè)計(jì)實(shí)例代碼
- 詳解移動(dòng)端網(wǎng)頁(yè)設(shè)計(jì)實(shí)現(xiàn)內(nèi)滾動(dòng)的四種解決方案
- 網(wǎng)頁(yè)設(shè)計(jì)如何優(yōu)雅的實(shí)現(xiàn)垂直居中
- 網(wǎng)頁(yè)設(shè)計(jì):淺談網(wǎng)頁(yè)基本性能優(yōu)化規(guī)則小結(jié)
- 用戶需求導(dǎo)致?tīng)I(yíng)銷型網(wǎng)頁(yè)設(shè)計(jì)
- 網(wǎng)頁(yè)設(shè)計(jì)柵格就是你對(duì)頁(yè)面版式的規(guī)劃
- 網(wǎng)頁(yè)設(shè)計(jì)內(nèi)容網(wǎng)頁(yè)中關(guān)于圖片預(yù)覽的設(shè)計(jì)
- 網(wǎng)頁(yè)設(shè)計(jì):腳本素材重構(gòu)用戶體驗(yàn)
- 網(wǎng)頁(yè)設(shè)計(jì)實(shí)現(xiàn)復(fù)選框(checkbox)和單選框(radio)對(duì)齊的
- 2016年網(wǎng)頁(yè)設(shè)計(jì)趨勢(shì):卡片式設(shè)計(jì)如何在占盡優(yōu)勢(shì)?
關(guān)于CSS中@support實(shí)現(xiàn)漸進(jìn)式網(wǎng)頁(yè)設(shè)計(jì)實(shí)例代碼
文章主要給大家介紹了關(guān)于CSS中@support實(shí)現(xiàn)漸進(jìn)式網(wǎng)頁(yè)設(shè)計(jì)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用CSS具有一定的參考學(xué)習(xí)價(jià)值前言特性查詢賦予了我們...
詳解移動(dòng)端網(wǎng)頁(yè)設(shè)計(jì)實(shí)現(xiàn)內(nèi)滾動(dòng)的四種解決方案
這篇文章主要介紹了關(guān)于移動(dòng)端實(shí)現(xiàn)內(nèi)滾動(dòng)的四種解決方案,實(shí)現(xiàn)的效果就是在一個(gè)區(qū)域內(nèi)只允許部分區(qū)域產(chǎn)生滾動(dòng)的效果,而其余部分則不能移動(dòng),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。...
網(wǎng)頁(yè)設(shè)計(jì)如何優(yōu)雅的實(shí)現(xiàn)垂直居中
這篇文章主要給大家介紹了關(guān)于如何優(yōu)雅的實(shí)現(xiàn)垂直居中的相關(guān)資料,文中分別給大家介紹了已知寬高的元素、未知寬高的元素以及基于 Flexbox 的解決方案,都分別給出了示例代碼供大家參考學(xué)習(xí),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧...
網(wǎng)頁(yè)設(shè)計(jì):淺談網(wǎng)頁(yè)基本性能優(yōu)化規(guī)則小結(jié)
這篇文章主要介紹了淺談網(wǎng)頁(yè)基本性能優(yōu)化規(guī)則小結(jié)的相關(guān)資料,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧...
用戶需求導(dǎo)致?tīng)I(yíng)銷型網(wǎng)頁(yè)設(shè)計(jì)
我們的每期話題,團(tuán)隊(duì)在內(nèi)部都會(huì)通過(guò)郵件進(jìn)行一番討論,隨著討論的激烈,往往能碰撞出很多有意義的觀點(diǎn),因此,將討論內(nèi)容分享出來(lái),有興趣的朋友可以接著話題討論下去。Junchen:期望不是從石頭里面蹦出來(lái)的,所有期望都是受到外界影響、結(jié)合自身需求的一個(gè)外在表現(xiàn)...
網(wǎng)頁(yè)設(shè)計(jì)柵格就是你對(duì)頁(yè)面版式的規(guī)劃
英文原文:http://desktoppub.about.com/od/grids/l/aa_gridsorder.htm柵格就是你對(duì)頁(yè)面版式的規(guī)劃你日常所見(jiàn)的許多頁(yè)面都有柵格存在。你可能注意不到,但它確實(shí)存在,并且支撐著設(shè)計(jì)內(nèi)容,建立整體的架構(gòu),引導(dǎo)著頁(yè)面的元素。柵格是隱形的架構(gòu),用于指導(dǎo)你頁(yè)面...
網(wǎng)頁(yè)設(shè)計(jì)內(nèi)容網(wǎng)頁(yè)中關(guān)于圖片預(yù)覽的設(shè)計(jì)
之前有寫過(guò)《內(nèi)容頁(yè)頁(yè)碼的預(yù)覽導(dǎo)航》跟《照片預(yù)覽導(dǎo)航分析》兩個(gè)文章,想說(shuō)明的是預(yù)覽這一功能在用戶心理所占有的比重是很大的,如果僅僅只是給出一排順序數(shù)字做為鏈接的標(biāo)題,用戶的心理會(huì)產(chǎn)生不安全感。雖然給出一排順序數(shù)字做為鏈接幾乎是整個(gè)互聯(lián)網(wǎng)的默認(rèn)分頁(yè)鏈接模...
網(wǎng)頁(yè)設(shè)計(jì):腳本素材重構(gòu)用戶體驗(yàn)
設(shè)計(jì)網(wǎng)站的同志背景主要有兩種:學(xué)計(jì)算機(jī)、學(xué)藝術(shù)?;旧蠒?huì)寫代碼的不懂設(shè)計(jì),會(huì)設(shè)計(jì)的不懂代碼,這個(gè)格局似乎到今天還沒(méi)變。某些學(xué)計(jì)算機(jī)的同學(xué),有自己的審美品位,也能夠做出看起來(lái)不錯(cuò)的網(wǎng)站,但學(xué)藝術(shù)的同學(xué)普遍難搞懂代碼...
網(wǎng)頁(yè)設(shè)計(jì)實(shí)現(xiàn)復(fù)選框(checkbox)和單選框(radio)對(duì)齊的方法
本文主要介紹了實(shí)現(xiàn)checkbox&radio對(duì)齊的具體方法,對(duì)大家的頁(yè)面布局具有很好的參考價(jià)值,需要的朋友一起來(lái)看下吧...
2016年網(wǎng)頁(yè)設(shè)計(jì)趨勢(shì):卡片式設(shè)計(jì)如何在占盡優(yōu)勢(shì)?
有數(shù)據(jù)顯示2014年移動(dòng)端使用率遠(yuǎn)遠(yuǎn)高于桌面端,網(wǎng)頁(yè)設(shè)計(jì)都能很好的適應(yīng)小屏幕。這個(gè)結(jié)論就是:簡(jiǎn)單的界面風(fēng)格,比如:扁平化設(shè)計(jì),極簡(jiǎn)設(shè)計(jì),尤其是卡片設(shè)計(jì)比往年都要流...