1. 程式人生 > >CSS之深入理解 flex 佈局以及計算

CSS之深入理解 flex 佈局以及計算

起因:對於Flex佈局,閱讀了大漠老師和其他老師寫的文章後,我還是不太理解Flexbox是如何彈性的計運算元級專案的大小以及一些其他細節。在大漠老師的幫助下,我去查閱Flexbox 的 W3C 規範文件

1. 對於flex盒模型的設計期望:

- 在任何流動的方向上(包括上下左右)都能進行良好的佈局

- 可以以逆序 或者 以任意順序排列布局

- 可以線性的沿著主軸一字排開 或者 沿著側軸換行排列

- 可以彈性的在任意的容器中伸縮大小(今天重點研究的主題)

- 可以使子元素們在容器主軸方向上 或者 在容器側軸方向上 進行對齊

- 可以動態的 沿著主軸方向 伸縮子級的尺寸,與此同時保證父級側軸方向上的尺寸

2. 主軸和側軸

首先每一根軸都包括 三個東西:維度、方向、尺寸

- 所謂的維度實際上就是意思就是子元素 橫著排還是豎著排(x 軸 或 y 軸)

- 方向 即排列子元素的順序 順序還是逆序

- 尺寸 即width[height] : 每一個子元素在主軸方向所佔的位置的總和 如果主軸是水平的,那麼尺寸就是父元素內所有item的outerWidth總和,如果主軸是垂直的,那麼尺寸就是父元素的outerHeight

主軸是依靠 flex-direction 和 所有子元素在主軸方向上的item-size的總和確定的,flex-direction這個屬性可以控制子元素的排列方向和排列順序

側軸是依靠 flex-wrap 和 所有子元素在主軸方向上的item-size的總和確定的,flex-wrap 可以控制子元素 在側軸方向上的排列方式以及順序

而關於不同種類不同情況下的 item-size 我們會在下面討論,現在您可以簡單將它理解為width[height]

這裡寫圖片描述

為了方便 flex-direction + flex-wrap 合併成了一個屬性 flex-flow

通過這個簡單而複雜的屬性,我們就能夠控制所有子元素的水平和垂直方向,逆序排列和順序,換行和不換行

主側軸的切換十分簡單,當主軸設定的時候,它的垂直面,就預設被設定成了側軸

這裡寫圖片描述

這條CSS屬效能夠告訴我們那些資訊?

- 子元素是橫著排列的,主軸是水平的橫軸,側軸是豎直的縱軸

- 子元素是逆序並沿著主軸排列的,從右到左

- 子元素是換行的

- 子元素是逆序並沿著側軸排列的,從下到上

3. FFC (flex formatting context)

Flexbox 佈局新定義了格式化上下文,類似 BFC(block formatting context)。有多類似呢? 就是除了佈局和一些細節不同以外的一切規則都和 BFC 是相同的

例如,設定了 display: flex; 或 display: inline-flex的元素,和BFC一樣,不會被浮動的元素遮蓋,不會垂直外邊距坍塌等等

而對於設定了 display: inline-flex 的盒子來說,我們可以類比 display: inline-box;行理解。即 一個被行列化後的 Flexbox。它不會獨佔一行,但是可以設定寬和高

4. 與BFC的細微區別

- Flexbox 不支援 ::first-line 和 ::first-letter 這兩種偽元素

- vertical-align 對 Flexbox 中的子元素 是沒有效果的

- float 和 clear 屬性對 Flexbox 中的子元素是沒有效果的,也不會使子元素脫離文件流(但是對Flexbox本身是有效果的!)

- 多欄佈局(column-*) 在 Flexbox 中也是失效的,就是說我們不能使用多欄佈局在Flexbox 排列其下的子元素(魚和熊掌不可得兼嘛)

- Flexbox 下的子元素不會繼承父級容器的寬

5. flex item(flex 子元素)

CSS解析器會把定義了 display: flex 和 display: inline-flex 的 Flexbox 下的子元素整體裝進一個看不見的盒子(這個盒子也就是 flex item )裡,我們通過排列這些盒子來達到排序、佈局、 伸縮的目的

規範中把這種盒子稱為 flex item,而子元素中包括了標籤節點以及文字節點。標籤節點很容易理解,需要注意的是文字節點(Flexbox的所有子元素自動成為容器成員,稱為Flex專案(flex item),簡稱”專案”。 )

預設情況下,flex 會將連續的文字節點裝進 flex-item 之中,使文字可以和標籤節點一起排序和定位

值得注意的是,空格也是文字節點,所以 white-space 會影響Flexbox 中的佈局

這裡寫圖片描述

使用white-space屬性之後,flexbox會將空格也算成字元,包裹進flex item內

6. flex-item-size 如何計算的

item-size(尺寸)為主軸方向上item的content再加上自身的margin 、 border 和 padding 就是這個item的尺寸

6.1 flex-basis 的優先順序比 width[height]: 非auto; 高

如果子元素沒有內容和預設固定寬高,且設定了flex-basis。flex-item content以flex-basis來決定,無論width[height] 設定了多少,(可理解為 flex-basis 比 width[height]: 非auto 的優先順序高)

這裡寫圖片描述

這裡div的內容為空,則使用flex-basis設定的寬高

如果子元素沒有內容和預設固定寬高,那flex-basis的優先順序比width[height]高,無論width[height]設定多少,flex-item content都以flex-basis來決定

6.2 元素存在預設寬高

如果子元素有預設固定寬高(例如input標籤在頁面中會有一個預設的寬和高)、並且設定了flex-basis,那麼它的content以固定寬高為min-width/height,如果flex-basis 超過了固定寬高,那麼flex-basis則成為其 content,如果flex-basis比固定寬高小,那麼以固定寬高為 content

這裡寫圖片描述

6.3 元素存在 min-width[height] 或者 max-width[height]

如果flex-item有min-width[min-height]的限制,那麼flex-item content按照min-width值為下限,如果flex-basis的值大於min-width[min-height]那麼flex-item content以flex-basis計算

如果flex-basis的值小於min-width[min-height]那麼flex-item content以min-width[min-height]計算

這裡寫圖片描述

顯然,1號item設定的600px大於300px所以沿用了600px的寬,而2號的100px寬小於300px,所以使用的是300px的min-width

如果 min-width[min-height] 的值已經超出了容器的尺寸,那麼即使設定了 flex-shrink。 CSS解析器也不會進行將這個item的 content 縮放,而是堅持保留它的min-width[min-height]

這裡寫圖片描述

可見如果Flexbox設定的min-width超出了 flex container 的範圍,也不會對其進行壓縮

反之,如果設定了 max-width[height] 的值,那麼設定flex-basis無法超過這個值,對於 flex-grow 也僅僅只會增長到 max-width[height] 這個上限,而並不會超過它

7. width[height]: auto 優先順序等於 flex-basis

前面提到,如果給item同時設定了 width[height] 和 flex-basis 的話。flex-item content以flex-basis來決定。但是實際上預設的 width[height]: auto優先順序是等於 flex-basis 的

CSS解析器對比兩者的值,兩者誰大取誰作為item的基本尺寸,如果一個item沒有內容,那麼auto可能為空,所以flex-item content就會以flex-basis來決定

但是如果item有了內容,且內容撐開的尺寸比flex-basis大,那麼flex-item content就會根據width[height]: auto來決定,且無法被縮放。反之,如果比flex-basis小,flex-item content就會以flex-basis來決定

這裡寫圖片描述

width: auto時當內容長度比 flex-basis 大,則 flex-item content以內容長度來決定,且無法shrink

這裡寫圖片描述

如果 flex-basis 的長度大於文字內容長度,那麼flex-item content以 flex-basis 來決定

這裡寫圖片描述

同時設定了flex-basis: 800px; 和 width: 1px; flex-item content以 flex-basis 來決定,可以發生shrink

這裡寫圖片描述

注意2號盒子我設定了 flex-shrink: 1; 1號盒子和3號盒子我設定了 flex-shrink: 0; 意思就是我將所有的需要shrink的空間都壓到了2號盒子上,總共的需要 shrink的空間為 0 * 600 + 1 * 20 + 0 * 100 = -20;而2號盒子只有20的空間,理應被完全shrink變為0,但是值得注意的是2號盒子並沒有被完全 shrink,還保留了一個文字的距離

除此之外,overflow: hidden; 也會影響

這裡寫圖片描述

文字長度在 600px; 小於 flex-basis: 700px,所以flex-item content以flex-basis來決定,可以shrink

8. 隱藏屬性對 items-size 的影響

我針對了 display: none; visibility: hidden; visibility: collapse; transform: scale; 等屬性對 items 進行測試

結果如下:

- 如果設定了 visibility: hidden; | visibility: collapse; | transform: scale;的flex-item content 依然被算進主軸尺寸,CSS 解析器依然會根據他們的 flex-grow | flex-shrink 將可用空間 或者 負可用空間 分配給他們

- 如果設定了display: none; CSS解析器不會對該item的空間進行計算,也不會對其grow空間

9. 關於position: absolute 對item影響

position: absolute 也是適用 Flexbox 中的子元素的,並且設定了position: absolute屬性的子元素,也會受到 Flexbox 排列的影響

這裡寫圖片描述

設定了absolute 的子元素重疊在了一起,但是依然會受到 align-items: center; 的影響而居中。對於 Flexbox 本身來說,設定了position: absolute並不會對其下的子元素產生任何影響

我們重點看 Flexbox 下的子元素設定了 absolute 後有什麼結果

根據我做的實驗,我得到了如下的結論:

flexbox 下設定了absolute的子元素的位置受3個方面的影響:

- flexbox 流下面的 justify-content(主軸上對齊方式) 和 align-items(交叉軸上對齊方式)

- 單個子元素的 top、left、right、bottom

- 單個子元素的 margin

這裡寫圖片描述

設定了absolute 的 item 不會影響佈局,如圖其中1 2 3 4 5 號是設定了absolute的item,而 6 7 8 9號是沒有設定absolute的item Flexbox 我設定了 justify-content: center; 和 align-items: center; 每一個item我都給了 margin: 20px

#