css 的 flex 彈性佈局,普遍應用在當今的頁面開發中,其彈性伸縮的的靈活性很是擅長於開發有響應式需求的網站。可是有不少時候,其靈活性也會讓人疑惑,特別是肯定尺寸時,基本上是靠不斷嘗試。爲了在開發時更加駕輕就熟,下面將以主軸方向上,也就是默認佈局方向上的成員寬度值計算爲例子進行研究。
css
flex 是彈性的伸縮佈局,具備伸和縮兩個特性,下面在研究時也以伸和縮兩種狀態來進行研究。 在開始以前,先說一下一些定義,類名 container 是 flex 容器, 類名 item 是 flex 的成員對象,每一個成員對象內嵌了自已的內容。每一個成員都設置了相應的外邊距、邊框、內邊距,爲了方便表述把每一個成員的外邊距寬度的左右寬度和表述爲 margin,相似的表述爲 border、padding,在下面的計算中會有說起。最後把每一個成員的內容區域寬度表述爲 content。在下面的例子中咱們會發現,成員的最終寬度大小是由成員的 width flex-basis 和 content 值共同決定,在不一樣狀態下也會分別受到 flex-grow 和 flex-shrink 的影響
git
下面的 flex 佈局中設置了 6 個成員,每一個成員都設置了不一樣的 width flex-basis content flex-grow 值github
<div class="wrapper">
<h1>test</h1>
<style>
.container { display: flex; background-color: #915151;}
.item { height: 80px; text-align: center; background-color: rgb(214, 120, 52);border-radius: 1em; border: 5px solid #000;text-align: left;margin: 15px; padding: 10px }
</style>
<div class="container">
<div class="item" style="flex-grow: 1;width: 100px; flex-basis: 0">
<div style="width: 40px"></div>
</div>
<div class="item" style="flex-grow: 0; width: 250px; flex-basis: 200px">
<div style="width: 300px"></div>
</div>
<div class="item" style="flex-grow: 2; flex-basis: 200px">
<div></div>
</div>
<div class="item" style="flex-grow: 2; width: 70px">
<div></div>
</div>
<div class="item" style="flex-grow: 2;">
<div style="font-family: monospace;">12345678910111213141516</div>
</div>
<div class="item" style="flex-grow: 3; width: 200px;">
<div style="width: 100px"></div>
</div>
</div>
</div>複製代碼
下面是生成佈局的截圖,包括了每一個成員的尺寸
瀏覽器
最內層的區域就是成員的大小區域,也就是成員的寬度和高度值,從寬度值能夠看出,有的元素的寬度值和成員的 content 大小同樣, 有的和成員的 width 值同樣,有的和二者都不一樣,下面將經過公式來計算各個成員的最終寬度值。bash
因爲不是每一個成員都設置了相應的 flex-basis、width 和 內容的 width 值,因此我先定下下面的規則來補充缺失的參數值,設置 t-flex-basis 爲轉化的 flex-basis 值, t-width 爲轉化的 width 值,t-content 爲轉化的 content 值
app
經過以上規則,就能夠把成員的參數值轉化爲下表的數據佈局
下面能夠開始計算最終寬度值測試
計算步驟字體
獲取剩餘空間flex
剩餘空間 = 容器可分配空間 - 每一個成員(margin + border + padding + t-flex-basis)的和
在我這裏的容器寬度是 1349px,這個也是這裏的容器可分配空間
剩餘空間 = 1349 - (30 + 10 + 20 + 0) - (30 + 10 + 20 + 200) - (30 + 10 + 20 + 200) - (30 + 10 + 20+ 70) - (30 + 10 + 20 + 149.5) - (30 + 10 + 20 + 200) = 169.5
分配剩餘空間
分配的剩餘空間 = 剩餘空間 * (當前成員的 flex-grow) / 待分配成員的 flex-grow 值之和
item1 分配的剩餘空間 = 169.5 * 1 / (1 + 0 + 2 + 2 + 2 + 3) = 16.95
item2 分配的剩餘空間 = 169.5 * 0 / (1 + 0 + 2 + 2 + 2 + 3) = 0
item3 分配的剩餘空間 = 169.5 * 2 / (1 + 0 + 2 + 2 + 2 + 3) = 33.9
item4 分配的剩餘空間 = 169.5 * 2 / (1 + 0 + 2 + 2 + 2 + 3) = 33.9
item5 分配的剩餘空間 = 169.5 * 2 / (1 + 0 + 2 + 2 + 2 + 3) = 33.9
item6 分配的剩餘空間 = 169.5 * 3 / (1 + 0 + 2 + 2 + 2 + 3) = 50.85
找出不符合分配的成員,從新計算分配空間
所謂不符合分配的成員指的是 (分配的剩餘空間 + t-flex-basis) < min(t-content, t-width)
當成員不符合分配時,那麼該成員的最終值就是 t-content 和 t-width 中的最小值
不然成員的最終值就是:分配的剩餘空間 + t-flex-basis
經過比較能夠獲得 item1 不符合分配
item1 (0 + 16.95) < min(t-content,t-width) = 40
因此 item1 的最終寬度是 40
因爲 item1 若是是按分配應該是 16.95,如今是 40,多佔據了 23.05
因此要從新分配空間,分配的空間中要減小相應比例的空間
item2 從新分配後的剩餘空間 = 0 - 23.05 * 0 / (0 + 2 + 2 + 2 + 3) = 0
item3 從新分配後的剩餘空間 = 33.9 - 23.05 * 2 / (0 + 2 + 2 + 2 + 3) = 28.78
item4 從新分配後的剩餘空間 = 33.9 - 23.05 * 2 / (0 + 2 + 2 + 2 + 3) = 28.78
item5 從新分配後的剩餘空間 = 33.9 - 23.05 * 2 / (0 + 2 + 2 + 2 + 3) = 28.78
item6 從新分配後的剩餘空間 = 50.85 - 23.05 * 3 / (0 + 2 + 2 + 2 + 3) = 43.17
經過比較能夠獲得 item2 不符合分配
item2 (0 + 200) < min(250, 300) = 250
因此 item2 的最終寬度是 250
因爲 item2 若是是按分配應該是 200,如今是 250,多佔據了 50
因此要從新分配空間,分配的空間中要減小相應比例的空間
item3 從新分配後的剩餘空間 = 28.78 - 50 * 2 / (2 + 2 + 2 + 3) = 17.67
item4 從新分配後的剩餘空間 = 28.78- 50 * 2 / (2 + 2 + 2 + 3) = 17.67
item5 從新分配後的剩餘空間 = 28.78- 50 * 2 / (2 + 2 + 2 + 3) = 17.67
item6 從新分配後的剩餘空間 = 43.17 - 50 * 3 / (2 + 2 + 2 + 3) = 26.5
經過比較能夠獲得以上的成員都符號分配
item3 的最終寬度是 17.67 + 200 = 217.67
item4 的最終寬度是 17.67 + 70= 87.67
item5 的最終寬度是 17.67 + 149.5= 167.17
item6 的最終寬度是 26.5 + 200 = 226.5
能夠看到計算結果和最終的結果是一致的
以上是關於在伸長狀態下成員的計算規則,那麼在收縮狀態下,上面的計算公式還能起做用嗎
下面的 flex 佈局中設置了 6 個成員,每一個成員都設置了不一樣的 width flex-basis content flex-shrink 值, 爲了讓元素處於收縮狀態,我修改了成員的大小
<div class="wrapper">
<h1>test</h1>
<style>
.container {display: flex; background-color: #915151;}
.item {height: 80px; text-align: center; background-color: rgb(214, 120, 52); border-radius: 1em;border: 5px solid #000;text-align: left;margin: 15px;padding: 10px}
</style>
<div class="container">
<div class="item" style="flex-shrink: 1;width: 100px; flex-basis: 500px">
<div style="width: 40px"></div>
</div>
<div class="item" style="flex-shrink: 0; width: 250px; flex-basis: 300px">
<div style="width: 300px"></div>
</div>
<div class="item" style="flex-shrink: 2; flex-basis: 500px">
<div></div>
</div>
<div class="item" style="flex-shrink: 2; width: 400px">
<div></div>
</div>
<div class="item" style="flex-shrink: 2;">
<div style="font-family: monospace;">12345678910111213141516</div>
</div>
<div class="item" style="flex-shrink: 3; width: 300px;">
<div style="width: 100px"></div>
</div>
</div>
</div>複製代碼
下面是生成佈局的截圖,包括了每一個成員的尺寸
下面將經過公式計算成員最終的寬度值
按照前面說起的轉化規則,獲得相似下面的表格
依據上面提到的計算步驟進行計算
獲取剩餘空間
剩餘空間 = 容器可分配空間 - 每一個成員(margin + border + padding + t-flex-basis)的和
在我這裏的容器寬度是 1349px,這個也是這裏的容器可分配空間
剩餘空間 = 1349 - (30 + 10 + 20 + 500) - (30 + 10 + 20 + 300) - (30 + 10 + 20 + 500) - (30 + 10 + 20+ 400) - (30 + 10 + 20 + 149.5) - (30 + 10 + 20 + 300) = -1160.5
分配剩餘空間
分配的剩餘空間 = 剩餘空間 * (當前成員的 flex-shrink) / 待分配成員的 flex-shrink值之和
item1 分配的剩餘空間 = -1160.5 * 1 / (1 + 0 + 2 + 2 + 2 + 3) = -116.05
item2 分配的剩餘空間 = -1160.5 * 0 / (1 + 0 + 2 + 2 + 2 + 3) = 0
item3 分配的剩餘空間 = -1160.5 * 2 / (1 + 0 + 2 + 2 + 2 + 3) = -232.1
item4 分配的剩餘空間 = -1160.5 * 2 / (1 + 0 + 2 + 2 + 2 + 3) = -232.1
item5 分配的剩餘空間 = -1160.5 * 2 / (1 + 0 + 2 + 2 + 2 + 3) = -232.1
item6 分配的剩餘空間 = -1160.5 * 3 / (1 + 0 + 2 + 2 + 2 + 3) = -348.15
找出不符合分配的成員,從新計算分配空間
所謂不符合分配的成員指的是 (分配的剩餘空間 + t-flex-basis) < min(t-content, t-width)
當成員不符合分配時,那麼該成員的最終值就是 t-content 和 t-width 中的最小值
不然成員的最終值就是:分配的剩餘空間 + t-flex-basis
經過比較能夠獲得 item5 不符合分配
item5 (-232.1 + 149.5) < min(t-content,t-width) = 149.5
因此 item5 的最終寬度是 149.5
因爲 item5 若是是按分配應該是 -82.6,如今是 149.5,多佔據了 232.1
因此要從新分配空間,分配的空間中要減小相應比例的空間
item1 從新分配後的剩餘空間 = -116.05 - 232.1 * 1 / (1 + 0 + 2 + 2 + 3) = -145.0625
item2 從新分配後的剩餘空間 = 0 - 232.1 * 0 / (1 + 0 + 2 + 2 + 3) = 0
item3 從新分配後的剩餘空間 = -232.1 - 232.1 * 2 / (1 + 0 + 2 + 2 + 3) = -290.125
item4 從新分配後的剩餘空間 = -232.1 - 232.1 * 2 / (1 + 0 + 2 + 2 + 3) = -290.125
item6 從新分配後的剩餘空間 = -348.15 - 232.1 * 3 / (1 + 0 + 2 + 2 + 3) = -435.1875
經過比較能夠獲得 item6 不符合分配
item6 (-435.1875 + 300) < min(300, 100) = 100
因此 item6 的最終寬度是 100
因爲 item6 若是是按分配應該是 -135.1875,如今是 100,多佔據了 235.1875
因此要從新分配空間,分配的空間中要減小相應比例的空間
item1 從新分配後的剩餘空間 = -145.0625 - 235.1875 * 1 / (1 + 0 + 2 + 2) = -192.1
item2 從新分配後的剩餘空間 = 0 - 235.1875 * 0 / (1 + 0 + 2 + 2) = 0
item3 從新分配後的剩餘空間 = -290.125- 235.1875 * 2 / (1 + 0 + 2 + 2) = -384.2
item4 從新分配後的剩餘空間 = -435.1875 - 235.1875 * 2 / (1 + 0 + 2 + 2) = -529.2625
經過比較能夠獲得 item4 不符合分配
item4 (-529.2625 + 400) < min(t-content,t-width) = 0
因此 item4 的最終寬度是 0
可是能夠看到 item4 實際的渲染結果不是 0,因此以上的計算公式在收縮狀態下是無效的,問題出如今計算剩餘空間的計算上,在收縮狀態下的計算公式是
分配的剩餘空間 = 剩餘空間 * (當前成員的 flex-shrink * t-flex-basis) / 待分配成員的(flex-shrink * t-flex-basis)之和
從新計算以上的步驟
分配剩餘空間
分配的剩餘空間 = 剩餘空間 * (當前成員的 flex-shrink * t-flex-basis) / 待分配成員的(flex-shrink * t-flex-basis)之和
item1 分配的剩餘空間 = -1160.5 * 1 * 500 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 2 * 149.5 + 3 * 300) = -165.83
item2 分配的剩餘空間 = -1160.5 * 0 * 300 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 2 * 149.5 + 3 * 300) = 0
item3 分配的剩餘空間 = -1160.5 * 2 * 500 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 2 * 149.5 + 3 * 300) = -331.666
item4 分配的剩餘空間 = -1160.5 * 2 * 400 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 2 * 149.5 + 3 * 300) = -265.33
item5 分配的剩餘空間 = -1160.5 * 2 * 149.5 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 2 * 149.5 + 3 * 300) = -99.168
item6 分配的剩餘空間 = -1160.5 * 3 * 300 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 2 * 149.5 + 3 * 300) = -298.5
找出不符合分配的成員,從新計算分配空間
所謂不符合分配的成員指的是 (分配的剩餘空間 + t-flex-basis) < min(t-content, t-width)
當成員不符合分配時,那麼該成員的最終值就是 t-content 和 t-width 中的最小值
不然成員的最終值就是:分配的剩餘空間 + t-flex-basis
經過比較能夠獲得 item5 不符合分配
item5 (-99.168 + 149.5) < min(t-content,t-width) = 149.5
因此 item5 的最終寬度是 149.5
因爲 item5 若是是按分配應該是 50.33,如今是 149.5,多佔據了 99.17
因此要從新分配空間,分配的空間中要減小相應比例的空間
item1 分配的剩餘空間 = -165.83 - 99.17 * 1 * 500 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 3 * 300) = -181.325
item2 分配的剩餘空間 = 0 - 99.17 * 0 * 300 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 3 * 300) = 0
item3 分配的剩餘空間 = -331.666 - 99.17* 2 * 500 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 3 * 300) = -362.65
item4 分配的剩餘空間 = -265.33 - 99.17 * 2 * 400 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 3 * 300) = -290.1225
item6 分配的剩餘空間 = -298.5 - 99.17 * 3 * 300 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400 + 3 * 300) = -326.39
經過比較能夠獲得 item6 不符合分配
item6 (-326.39 + 300) < min(300, 100) = 100
因此 item6 的最終寬度是 100
因爲 item6 若是是按分配應該是 -26.39,如今是 100,多佔據了 126.39
因此要從新分配空間,分配的空間中要減小相應比例的空間
item1 分配的剩餘空間 = -181.325 - 126.39 * 1 * 500 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400) = -208.8
item2 分配的剩餘空間 = 0 - 126.39 * 0 * 300 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400) = 0
item3 分配的剩餘空間 = -362.65 - 126.39* 2 * 500 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400) = -417.6
item4 分配的剩餘空間 = -290.1225 - 126.39 * 2 * 400 / (1 * 500 + 0 * 300 + 2 * 500 + 2 * 400) = -334.08
經過比較能夠獲得以上成員都符號要求
item1 的最終寬度是 500 - 208.8 = 291.2
item2 的最終寬度是 0 + 300= 300
item3 的最終寬度是 -417.6 + 500= 82.4
item4 的最終寬度是 -334.08 + 400 = 65.9
能夠看到計算結果和最終的結果是一致的
從以上的分析和計算中,能夠看到成員的寬度受多個參數所控制,主要屬性是 flex-basis, 其中在伸長和收縮狀態中,計算分配的剩餘空間的公式是不一樣的,並且在計算中還會受到成員內容大小和成員自身大小的影響,成員的最終值不得小於成員內容大小和成員自身大小中的最小值,不然就取這個最小值並從新分配剩餘空間。這裏能夠舉一個例子,不少時候咱們設置 flex: 1 並但願成員都是等分的,通常狀況下是沒有問題的。其中 flex: 1 其實是 flex-basis: 0%, flex-grow: 1, flex-shrink: 1,若是你不能控制成員的內容大小,當這個內容尺寸大於等分尺寸時,因爲沒有設置 width 值, width 值默認等於內容大小,按照以上的分析,該尺寸就會改變成員寬度,形成等分的效果失效,要避免這種狀況,能夠設置 width 的值爲 0,這樣成員內容大小和成員自身大小中的最小值就爲0,等分尺寸確定大於該值,成員尺寸便取等分尺寸,固然這個時候成員內容就會溢出。
經過以上的分析,咱們對計算成員寬度已經有初步的瞭解,基本上能應對大部分的狀況,可是 flex 佈局還不止以上的屬性,並且不一樣的屬性之間還能互相組合,甚至在有的時候可能在容器上設置了絕對定位(flex功能不會消失),或者成員上設置了 box-sizing(設置的 width 值可能不一樣於讀取的 width 值),或者 width 值是百分比(父元素寬度不肯定時,width 的表現像 auto,等父元素肯定後纔開始計算),flex-grow 或者 flex-shrink 是小數(知足特定狀況計算規則會改變)等,在以上這些狀況下計算時要考慮因素會更多。還有一點要注意的是,以上佈局是在默認父元素是 nowrap 狀況下,以上規則可能看上去有點複雜,可是在實際開發中,咱們只要記住影響成員寬度的參數就能夠了,實在不符合預期纔去調節對應的參數。
爲了研究 flex 佈局規則,我特地寫了一個測試頁面,你們有興趣也能夠去看一下
flex 佈局測試 changk99.github.io/flexbox/