flex-basis
是 Flexbox 布局模塊中 flex
屬性的另一個子屬性,在前面的課程中我們深度剖析了瀏覽器是如何計算 Flex 項目尺寸的,或者說 Flexbox 是如何工作的。對于眾多 Web 開發者而言,在 CSS 中都習慣于使用像 width
、height
、min-*
和 max-*
以及它們對應的 CSS 邏輯屬性(比如 inline-size
、block-size
等)給元素設置尺寸大小。
在使用 Flexbox 布局模塊時,同樣如此,使用這些屬性給 Flex 項目設置尺寸。只不過,這些屬性不一定就能決定 Flex 項目的尺寸大小,它除了受 Flex 容器的空間和 Flex 項目的擴展因子(flex-grow
),以及 Flex 項目的收縮因子(flex-shrink
)影響之外,還受 Flex 項目的基準值(或者說假設主尺寸 Main Size)的影響,即 flex-basis
屬性的影響。
在這節課程中,我們就一起來探討這方面的話題,在 Flexbox 布局中,Flex 項目的大小究竟是由誰來決定的 。
容器的尺寸由誰來決定
Web 上的每一個元素都被視為一個盒子,它相當于一個容器,就好比我們生活中的器皿,通過格式化(CSS 的 display
屬性的值)之后有著不同的形態:
不同的器皿都有著自己的大小。在 CSS 中,這些容器的大小可以是由容器的內容來決定,也可以顯式地通過屬性來控制。大家最為熟知的應該是 CSS 盒模型中的屬性來決定一個容器(元素)的大小 。
只不過在指定容器大小時,你可能是 明確地知道容器的確切尺寸 ,也有可能是由著容器的內容來決定尺寸大小 。簡單地說,就是一個是明確的尺寸 (Definite Size),一個是不確定的尺寸 (Indefinite Size)。
- 明確的尺寸 指的是不需要執行布局就可以確定盒子的大小。也就是說,顯式地給容器設置一個固定值,或內容所占區域的大小,或一個容器塊的初始大小,或通過其他計算方式得到的尺寸,比如 Flexbox 布局中的“拉伸和收縮”(Stretch-fit),即
flex-grow
和flex-shrink
。
- 不確定的尺寸 指的是一個未知的尺寸。也就是說,容器的大小具備無限空間,有可能很大,也有可能很小。
通俗來說,明確的尺寸是知道元素的 width
(或 inline-size
)和 height
(或 block-size
)屬性的確定值;不確定的尺寸是需要根據內容來計算的,所以要知道不確定的尺寸就需要先檢查內容,也就是自動計算尺寸。
但不管是明確的尺寸還是不確定的尺寸設置,在 CSS 中都是由下面這些屬性來控制:
物理屬性 | 邏輯屬性(horizontal-tab) | 邏輯屬性(vertical-lr) | 邏輯屬性(vertical-rl) |
---|---|---|---|
width | inline-size | block-size | block-size |
height | block-size | inline-size | inline-size |
min-width | min-inline-size | min-block-size | min-block-size |
min-height | min-block-size | min-inline-size | min-inline-size |
max-width | max-inline-size | max-block-size | max-block-size |
max-height | max-block-size | max-inline-size | max-inline-size |
這些屬性被稱為 尺寸屬性 ,它們可以接受 <length-percentage>
、auto
、none
、min-content
、max-content
和 fit-content
(CSS Grid 中還有一個 fit-content()
)等值。其中 <length-percentage>
分為 <length>
(就是使用長度單位的一些值,比如 100px
、100vw
等),<percentage>
指的是百分比單位的值,比如 50%
。
一般情況下,CSS 尺寸屬性的值是一個 <length-percentage>
的話,則表示這個容器有一個明確的尺寸;如果 CSS 尺寸屬性的值是像 auto
、min-content
、max-content
和 fit-content
的話,則表示這個容器的尺寸是不明確的,需要根據內容來計算。
注意,
fit-content
和fit-content(<length-percentage>)
所描述的不是同一個東西,它們的區別將放到 CSS Grid 相關的課程中介紹 。
換句話說,在 CSS 中,任何一個容器都有四種自動計算尺寸大小的方式:
auto
:會根據格式化上下文自動計算容器的尺寸;
min-content
:是在不導致溢出的情況下,容器的內容的最小尺寸;
max-content
:容器可以容納的最大尺寸,如果容器中包含未格式化的文本,那么它將顯示為一個完整的長字符串;
fit-content
:如果給定軸中的可用空間是確定的,則等于min(max-content, max(min-content, stretch-fit))
,反之則等于max-content
。
需要注意的是, CSS 中的寬高比屬性,即
aspect-ratio
也可以決定一個容器的尺寸。
在 Flexbox 布局中,Flex 項目同樣被視為一個容器,它的大小也可以由這些屬性(尺寸屬性)和尺寸屬性值來決定。只不過,對于 Flex 項目而言,除了這些尺寸屬性之外,它還有一個 flex-basis
屬性可用于控制尺寸大小 。
flex-basis 在 Flexbox 中的作用
flex-basis
屬性在 Flexbox 中對 Flex 項目尺寸起著決定性的作用。簡單地說,flex-basis
屬性在任何空間分配發生之前,會對 Flex 項目的尺寸大小進行初始化 。即,在任何 Flex 容器空間(剩余空間或不足空間)分配發生之前初始化 Flex 項目尺寸 。
Flexbox 中 Flex 容器的空間是由
flex-grow
、flex-shrink
和 Flex 容器的對齊方式來分配的。詳細請參閱前面的課程:《04 | Flexbox 布局中的對齊方式 》、 《06|Flexbox 中的計算:通過擴展因子比例來擴展 Flex 項目》和《07|Flexbox 中的計算:通過收縮因子比例收縮 Flex 項目》。
flex-basis
屬性的語法規則很簡單:
flex-basis: content | <width>
該屬性的默認值是 auto
,它可以接受 content
和 <width>
值。
<width>
值指的是 CSS 的width
屬性(尺寸屬性),可用于width
屬性的值都可以用于flex-basis
,比如我們熟悉的px
、%
、vw
等,以及需要根據內容自動計算的屬性值,比如min-content
、max-content
和fit-content
等。
content
是指 Flex 項目的內容的自動尺寸,它通常相當于 Flex 項目最大內容大小(max-content
)。
如果 flex-basis
的值設置為 auto
,瀏覽器將先檢查 Flex 項目的主尺寸(Main Size)是否設置了絕對值,再計算 Flex 項目的初始值。比如說,你給 Flex 項目顯式設置了 width: 200px
,那么 200px
就是 Flex 項目的 flex-basis
值,該值也被稱為是 Flex 項目的假設主尺寸,因為 Flex 項目的最終主尺寸(flex-basis
計算后的值)會受 Flex 容器剩余空間或不足空間的影響,除非 flex-grow
和 flex-shrink
兩屬性的值都顯式設置為 0
。
如果 Flex 項目可以自動調整大小,則 auto
會解析為其內容的大小,此時 min-content
和 max-content
就會起作用,并且 Flex 項目的 flex-basis
值將會是 max-content
。
有一點需要注意的是,如果在 flex-basis
屬性上設置了除 auto
和 content
之外的所有值,它和書寫模式以及閱讀模式是有關的,在水平書寫模式(ltr
或 rtl
),flex-basis
的解析方式與 width
相同。
不同的是,如果一個值對于 width
將解析為 auto
,那么該值對于 flex-basis
就會被解析為 content
。例如,flex-basis
的值是一個百分比值,那么它會相對于 Flex 容的主軸尺寸(Main Size)來計算;如果 Flex 容器的大小不確定時,則 flex-basis
使用的值會是 content
。
可用于 flex-basis 屬性的值
可用于 CSS 的尺寸屬性,比如
width
的值都可用于flex-basis
屬性上。
現在我們知道了,flex-basis
屬性可以取 <width>
值來對 Flex 項目的主尺寸進行初始化,而一般情況之下,這個 <width>
就好比 CSS 中的 width
屬性。為了更好地幫大家理解 flex-basis
取 <width>
中所起的作用,這里有必要花一點時間來重溫 width
屬性。
特別注意,這里的
<width>
是一個屬性值,即flex-basis
屬性的值;而width
卻是一個 CSS 的尺寸屬性,用于設置元素寬度的尺寸,它的值類型種類多樣 。
你可以給任何一個非內聯元素顯式設置一個 width
屬性,用來指定容器的寬度。只不過不同的屬性值渲染出來的結果有所差異。比如下面這樣的一個示例:
:root {--width: auto;
}.item {width: var(--width);
}
Demo 地址: https://codepen.io/airen/full/wvjqXrZ
正如上圖所示,當給一個容器的 width
屬性設置一個固定值時,有一個極大的缺陷,即 內容斷行 或 內容溢容器 ,尤其是內容溢出,它很有可能就會打破布局的美觀。
很多時候,Web 開發者并不知道容器的內容是什么,所占的寬度是多少,就會造成上圖的現象。哪怕是使用了 min-content
、max-content
和 fit-content
也會面臨類似現象 。
為此,為了盡可能避免這種缺陷的出現,在給容器設置尺寸的時候,更建議使用 min-width
來替代 width
屬性。首先能被運用于 width
屬性的值都可以用在 min-width
屬性上。不同的是,min-width
可以防止 width
值小于 min-width
指定的值所造成的布局缺陷。
注意,
min-width
的默認值是auto
,瀏覽器計算出來的值是0
。
在上面的示例中,我們知道容器 width
設置的值小于內容寬度的時候,會造成一定的缺陷(我們不希望看到的效果)。如果在上面的示例中,在 .item
上添加一個 min-width
就可以較好避免這種現象:
暫時無法在飛書文檔外展示此內容
Demo 地址: https://codepen.io/airen/full/ZEoJjEK
你可能會好奇,那么應該給容器的 min-width
屬性設置一個什么樣的值呢?一般情況之下,這是根據元素所在的環境來決定的。它是一個假想的理想值。
min-width
屬性在構建 Web 布局或 Web 組件時是很有用處的,尤其是在構建一個多語言 的 Web 頁面或 Web 應用中。在多語言版本網站中“表達同一個意思的文本內容所占寬度是不一致的 ”,比如一個“完成”按鈕,中文可能是“完成”,英文可能是“Done”,阿位伯文是“?????”,韓文是“??”,日文可能是“フィニッシュ”,蒙古語又是“Дуусга”,等等。
當你從中文切換到阿位伯文(或英文切換到阿位伯文)時,文本內容的所占寬度并不一致。如果未顯式給容器設置 width
或 min-width
屬性的值,就會造成按鈕大小不一致,這也有可能會影響 Web 布局或整體的視覺效果。如果顯式加上 width
就有可能會在某個語種下造成內容溢出或斷行,那么這個時候顯式設置一個 min-width
就會有一個較好的視覺效果:
Demo 地址: https://codepen.io/airen/full/dyezjZL
使用 min-width
的好處大家都看到了,在內容較長的按鈕上,min-width
可以擴展容器的寬度,在內容較少的按鈕上,具有統一的尺寸。
min-width
除了在一些多語言版本網站上可見之外,也適用于像“徽標”(Badge)這樣的組件:
在構建這樣的標簽列表時,建議限制一個標簽的最小寬度(即顯式設置 min-width
屬性的值),這樣就可以保證標簽列表項內容很短(少)時,它的外觀不會受到影響:
有了這種靈活性,無論標簽內容有多短,標簽在視覺上看起來都不錯。另外,除了考慮內容過短之外,我們還需要考慮內容過長時對 UI 的視覺影響,這時候我們可以考慮使用 max-width
屬性。
在容器(或元素)上顯式設置 max-width
屬性值時,可以防止 width
屬性值超過了 max-width
指定的值,造成內容溢出。max-width
的一個常見而簡單的用例是將它與圖像一起使用。考慮下面的例子:
比它的父容器更大。通常給 img 設置 max-width 的值為 100% ,圖像的寬度就不會超過容器的寬度。如果圖像比父容器小,則 max-width: 100% 不會對圖像產生實際影響,因為它比容器小。
也就是說,CSS 中的 width
、min-width
和 max-width
都可以用來設置元素的寬度。很多時候,在實際的使用過程中,可能會在同一個元素上使用多個屬性來設置容器的寬度。比如:
.item {width: 100px;min-width: 200px;
}/* 或 */
.item {width: 200px;max-width: 100px;
}/* 或 */
.item {min-width: 100px;max-width: 200px;
}/* 或 */
.item {width: 150px;min-width: 100px;max-width: 200px;
}
那么問題來了,它們都是用來指定容器寬度的,當同一個容器上使用它們時,究竟由誰來決定容器最終的尺寸。
雖然說 width
、 min-width
和 max-width
三個屬性都可以用來指定一個容器的寬度,但它們之間還是有一定的差異的,比如說:
.item {width: 150px;min-width: 100px;max-width: 200px;
}
上面這段代碼將會告訴瀏覽器,.item
元素的寬度是 150px
(由width
指定),但它不能小于 100px
(由 min-width
指定) ,且不能大于 200px
(由 max-width
指定)。不難發現,其中 min-width
和 max-width
屬性像是給容器的寬度做了一定的限制。也就是說,當符合某一條件時,其中就有一個屬性起作用。這個也有點類似于 CSS 選擇器權重一樣,看誰的權重大,誰就起作用。
為了搞清楚,它們之間權重是如何比較(誰決定誰),我們這里通過幾個簡單的示例來向大家闡述。先來看 width
和 min-width
兩者的關系。
button {width: 100px;
}/* width > min-width */
.case1 button:nth-child(2) {min-width: 80px;
}/* width = min-width */
.case2 button:nth-child(2) {min-width: 100px;
}/* width < min-width */
.case3 button:nth-child(2) {min-width: 140px;
}
Demo 地址: https://codepen.io/airen/full/qBYXJWq
從這個示例中我們可以得到一個簡單的結論:
當
width
屬性的值大于或等于min-width
屬性的值時,瀏覽器會取width
屬性的值;當width
屬性的值小于min-width
屬性的值時,瀏覽器會取min-width
屬性的值 。
if (width >= min-width) {瀏覽器取 width 屬性的值
} if (width < min-width) {瀏覽器取 min-width 屬性的值
}
把上面示例中的 min-width
換成 max-width
:
button {width: 100px;
}/* width > max-width */
.case1 button:nth-child(2) {max-width: 80px;
}/* width = max-width */
.case2 button:nth-child(2) {min-width: 100px;
}/* width < max-width */
.case3 button:nth-child(2) {max-width: 140px;
}
Demo 地址: https://codepen.io/airen/full/WNJEaOq
從這個示例中,我們可以得到這樣的一個結論:
當
width
屬性的值大于max-width
屬性的值時,瀏覽器會取max-width
屬性的值;當width
屬性的值小于或等于max-width
屬性的值時,瀏覽器會取width
屬性的值 。
if (width > max-width) {瀏覽器取 max-width 屬性的值
}if (width =< max-width) {瀏覽器取 width 屬性的值
}
也有時候,在同一個元素上顯式設置 width
、min-width
和 max-width
,或者只在元素上顯式設置 min-width
和 max-width
:
Demo 地址: https://codepen.io/airen/full/GRdvYdw
正如上面這個示例所示:
如果
min-width
屬性的值大于max-width
屬性的值,瀏覽器會將min-width
屬性的值作為容器(元素)的寬度;如果min-width
屬性的值小于max-width
屬性的值,則會取max-width
屬性的值 。
如果它們同時出現在一個容器上,可以按照下面的規則來決定元素的寬度:
- 元素的
width
大于或等于max-width
時,取max-width
,即max-width
能覆蓋width
;
- 元素的
width
小于或等于min-width
時,取min-width
,即min-width
能覆蓋width
;
- 當
min-width
大于max-width
時,取min-width
,即min-width
優先級將高于max-width
。
注意,上面這個規則同樣適用于 CSS 的
min-height
、height
和max-height
以及它們對應的 CSS 邏輯屬性,比如min-inline-size
、inline-size
和max-inline-size
;min-block-size
、block-size
和max-block-size
。
CSS 中給元素設置一個尺寸時,除了設置具體值之外,還可以通過一些數學表達式來給其設置值,比如 calc()
、min()
、max()
和 clamp()
等比較函數:
.calc {width: calc(100vw - var(--sideba-width) - var(--gap));
}.min {width: min(300px, 100%);
}.max {width: max(300px, 30vw);
}.clamp {width: clamp(300px, 300px + 15%, 400px);
}
其中 min()
、max()
可以傳入多個值,而且它們:
min()
可用來給元素設置一個最大值,相當于max-width
;
max()
可用來給元素設置一個最小值,相當于min-width
。
也就是說:
.item {width: 100%;max-width: 300px;/* 等同于 */width: min(300px, 100%);
}.item {width: 100%;min-width: 280px;/* 等同于 */width: max(280px, 100%);
}
這幾個函數是非常有用的,它們同樣也可以用于 flex-basis
屬性上。而且使用它們可以幫助 Web 開發者構建響應式 UI 。有關于這方面更詳細的介紹,將單獨放到后面的課程中,這里你只需要知道,我們可以在尺寸屬性上使用這些函數,做一些簡單的四則運算即可。
除了上面提到這些方式可以給一個容器設置寬度之外,你還可以給 width
屬性顯式設置 min-content
、max-content
和 fit-content
值。即能根據元素內容來決定元素大小,因此它們統稱為內部尺寸 。
<h1> CSS is Awesome</h1>
h1 {width: auto;
}
Demo 地址: https://codepen.io/airen/full/RwyLGmg
由于 <h1>
是一個塊元素,如果沒有顯式使用display
或它的父元素未改變上下文格式(比如父元素沒有顯式設置 display
屬性的值),那么 width
取值為 auto
時,它的寬度和其父元素的寬度等同(有點類似于 100%
的效果)。當其父容器寬度變小時,它也會跟著變小,小到 0
。其內容在沒有做其他樣式處理時(比如強制不斷行 white-space: nowrap
),內容會自動斷行。
如果你把 width
屬性的值設置為 min-content
時:
/* 外在尺寸 */
h1 {width: auto;
}/* 內在尺寸*/
h1 {width: min-content;
}
Demo 地址: https://codepen.io/airen/full/gOzGLYo
從上圖中不難發現,width
取值為 min-content
時,h1
的寬度始終是單詞“Awesome”長度(大約是 144.52px
)。它的寬度和容器寬度變化并無任何關系,但它受排版內相關的屬性影響,比如 font-size
、font-family
等。
注意,如果 h1
元素內有一個后代元素顯式指定了一個固定值,且該元素的寬度大于或等于 min-content
,那么 min-content
將會與這個元素寬度相等。
再來看 max-content
:
/* 外在尺寸 */
.item {width: auto;
}/* 內在尺寸 */
.item {width: min-content;
}.item {width: max-content;
}
Demo 地址: https://codepen.io/airen/full/jOxGVEd
當 h1
的 width
取值為 max-content
時,它的寬度是 h1
所在行所有內容的寬度(有點類似于元素加了 white-sapce: nowrap
,強制不斷行時的長度)。最后再來看 fit-content
:
/* 外在尺寸 */
.item {width: auto;
}/* 內在尺寸 */
.item {width: min-content;
}.item {width: max-content;
}.item {width: fit-content;
}
Demo 地址: https://codepen.io/airen/pen/zYZvGrY
相對而言,fit-content
要比 min-content
和 max-content
復雜得多:
h1 {width: fit-content;/* 等同于 */width: auto;min-width: min-content;max-width: max-content;
}
簡單地說,fit-content
相當于 min-content
和 max-content
,其取值:
- 如果元素的可用空間充足,
fit-content
將使用max-content
;
- 如果元素的可用空間不夠允足,比
max-content
小點(介于min-content
至max-content
之間),那就是用可用空間的值,不會導致內容溢出;
- 如果元素的可用空間很小,比
min-content
還小,那就使用min-content
。
使用下圖來描述它們之間的關系:
min-content
、max-content
和 fit-content
它們是屬性值,可以被運用于 CSS 的尺寸屬性上,比如 width
、 height
、inline-size
和 block-size
。同樣的,它們也可以用在 flex-basis
屬性上。
.item:has(img) {flex-basis: var(--flex-basis, auto)
}
Demo 地址: https://codepen.io/airen/full/VwxMPPq
簡單小結一下。flex-basis
可以因設置的值不同,所起的功效也將有差異,大致可以分為:
- 默認值:
auto
,根據內容來計算;
- 固定值:
<length>
,數值加上固定單位的長度值,比如100px
、100pt
;
- 相對值:
<length-percentage>
,數值加上相對單位的值,比如10rem
、10em
、10ch
、10ex
、10vw
、10vh
和10%
;
- 動態計算值:使用
calc()
、min()
、max()
和clamp()
,比如calc(100% - var(--sidebar-width))
、clamp(10rem, 10rem + 2vw, 30rem)
;
- 內在尺寸:
min-content
、max-content
和fit-content
。
Demo 地址: https://codepen.io/airen/full/JjvrEVx
flex-basis 的計算
現在你已經知道了,在 Flexbox 布局中,flex-basis
是用來初始化 Flex 項目尺寸的,即 初始化 Flex 項目的主尺寸(Main Size) ,也被稱為“假設主尺寸 ”。初始設置的 flex-basis
值并不是 Flex 項目的最終主尺寸,因為影響其最終尺寸的因素較多,比如,Flex 容器的剩余空間(或不足空間)、Flex 項目的擴展因子(flex-grow
屬性的值 )、Flex 項目的收縮因子(flex-shrink
)、Flex 項目的最小值(min-*
)和最大值(max-*
),以及 flex-basis
的初始值等等。
簡單地說,flex-basis
的計算分為兩個部分。
- 由 Flex 容器空間(剩余空間或不足空間),
flex-grow
、flex-shink
以及初始化flex-basis
相關參數計算后的flex-basis
值。這部分我們在前面的課程中介紹過了,可以閱讀《06|Flexbox 中的計算:通過擴展因子比例來擴展 Flex 項目》和《07|Flexbox 中的計算:通過收縮因子比例收縮 Flex 項目》。
- 指定 Flex 項目尺寸大小的相關屬性權重的計算。
我們這里要和大家一起探討的就是第二個部分,即 指定 Flex 項目尺寸大小的相關屬性權重的計算 。也就是說,當 Flex 項目上同時出現 flex-basis
、width
(或 inline-size
)、min-width
(或 min-inline-size
)和 max-width
(或 max-block-size
) 時,究竟是誰最有決定權。
需要特別聲明的是,這部分的計算是指 Flex 項目的假設主尺寸,就是在參與
flex-grow
、flex-shrink
計算之前,Flex 項目的初始化尺寸由誰來決定。
事實上,在 Flexbox 布局模塊 初始化 Flex 項目的尺寸時存在一個隱式的公式 ,即:
content
?width
?flex-basis
它的意思是,如果 Flex 項目未顯式指定 flex-basis
屬性的值,那么 flex-basis
將回退到 width
屬性;如果 Flex 項目同時都未顯式指定 flex-basis
和 width
屬性的值,那么 flex-basis
將回退到基于 Flex 項目的內容計算寬度 。
不過,最終決定 Flex 項目尺寸大小時,還會受 flex-grow
和 flex-shrink
以及 Flex 容器大小的影響,并且 Flex 項目的最終尺寸也會受 min-width
(或 min-inline-size
)和 max-width
(或 max-inline-size
)屬性值的限制。
接下來用一個簡單的示例來闡述 Flex 項目的內容(content
)、width
以及 flex-basis
對 Flex 項目尺寸的影響。
<div class="container"><div class="item"><span>A</span>longlonglongword</div><div class="item"><span>B</span>ook</div><div class="item"><span>C</span>ountries</div><div class="item"><span>D</span>iscuss</div><div class="item"><span>E</span>astern</div>
</div>
.container {display: flex;inline-size: 1000px;outline: 2px dashed #09f;color: #000;font-size: 1.5rem;min-block-size: 200px;
}
示例中的 .item
并沒有顯式設置任何與尺寸有關的屬性(比如 width
),也沒有顯式設置 flex-basis
屬性的值。此時,瀏覽器會將 Flex 項目的 flex-basis
屬性的值當作為 auto
,即:
.item {flex-basis: auto;
}
瀏覽器同時也會將 Flex 項目的 width
屬性的值視為 auto
,即:
.item {flex-basis: auto;width: auto;
}
此時,每個 Flex 項目的初始化尺寸由其自身的內容來決定:
- Flex 項目 A 的寬度約是
237.56px
;
- Flex 項目 B 的寬度約是
70.26px
;
- Flex 項目 C 的寬度約是
120.56px
;
- Flex 項目 D 的寬度約是
100.69px
;
- Flex 項目 E 的寬度約是
100.11px
。
Flex 容器 .container
有足夠多的空間來放置這些 Flex 項目:
Demo 地址: https://codepen.io/airen/full/BaxwRBx
注意,所有 Flex 項目的 flex-grow
和 flex-shrink
都采用的是默認值,即:
.item {flex-grow: 0;flex-shrink: 1;flex-basis: auto;width: auto;
}
此時,Flex 項目的初始化尺寸就是 Flex 項目自身內容(content
)來撐開 Flex 項目(瀏覽器計算值) 。它和 fit-content
的表現是極其相似的,Flex 容器有足夠空間時,它的表現和 max-content
相似,反則它的表現和 min-content
相似。
不過,要是在 Flex 項目上重置了 flex-shrink
屬性的值(顯式設置為 0
),Flex 項目不可收縮,那么 flex-basis
和 width
取值為 auto
時,它的表現和 flex-basis
或 width
設置為 max-content
是相同的。
Demo 地址: https://codepen.io/airen/full/NWMagjx
由此我們可以得到第一個結論:如果 Flex 項目的 flex-basis
和 width
取初始值 auto
時,Flex 項目的初始化尺寸是 fit-content
;但當 flex-shrink
顯式重置為 0
,Flex 項目不可收縮時,Flex 項目的初始化尺寸就是 max-content
。在這種條件之下,Flex 項目在根據 flex-grow
和 flex-shrink
比例重新計算 flex-basis
是最為復雜的,瀏覽器可能需要重復循環遍歷的計算 flex-basis
的值。
接下來,顯式地在 Flex 項目上給 width
指定一個值,比如 150px
:
.item {width: 150px;/* 等同于 */flex-grow: 0;flex-shrink: 1;flex-basis: auto;
}
將所有寬度為 150px
的 Flex 項目放到一個寬度為 1000px
的 Flex 容器中,Flex 容器有一定的剩余空間出現(即 250px
):
Demo 地址:https://codepen.io/airen/full/VwxMWVO
在該示例中,Flex 項目的 flex-basis
沒有顯式指定,所以會取其默認值 auto
,這個時候會回到 width
屬性的值,即 150px
。也就是說,Flex 項目的 flex-basis
初始化尺寸就等于 width
的值。這也印證了:
如果 Flex 項目未顯式設置
flex-basis
屬性的值,瀏覽器會采取 Flex 項目上的width
屬性的值 。
你可能已經發現了,由于在 Flex 項目上設置的 width
值小于 Flex 項目的內容最小尺寸(min-content
),將會造成 Flex 項目內容溢出,這和其他溢出容器的表現是一樣的。而且 flex-grow
屬性使用的也是其初始值 0
,所以 Flex 項目并不會去分配 Flex 容器的剩余空間,除非重置 Flex 項目的 flex-grow
值。
另外,當 Flex 容器有剩余空間時,即使 Flex 項目的 flex-shrink
值是 1
(可收縮),Flex項目的寬度也不會產生變窄的現象(因為只有 Flex 容器空間不足時,Flex 項目才會按照 flex-shink
的比例因子縮小)。
接著再看另一種情景,當 Flex 項目上同時顯式設置了 width
和 flex-basis
時,瀏覽器又會取哪個值作為 Flex 項目的初始化的寬度呢?比如下面這個示例:
.item {width: 150px;flex-basis: 100px;/* 等同于 */flex-grow: 0;flex-shrink: 1;flex-basis: 100px;
}
Demo 地址: https://codepen.io/airen/full/MWGOGwE
正如你所見,如果 Flex 項目上同時顯式設置了 width
和 flex-basis
值(非 auto
默認值)時,flex-basis
屬性的值將會替代 width
的值。但是:
- 當 Flex 項目的
flex-basis
值小于width
值,且width
值小于 Flex 項目的內容最小值(min-content
)時,Flex 項目的flex-basis
的值會等于width
屬性值;
- 當 Flex 項目的
flex-basis
值小于width
值,但width
值大于 Flex 項目的內容最小值(min-content
)時,Flex 項目的flex-basis
的值會等于 Flex 項目的內容最小值(min-content
);
- 當 Flex 項目的
flex-basis
值大于width
值,但小于 Flex 項目的內容最小值(min-content
)時,Flex 項目的flex-basis
的值會等于width
屬性值;
- 當 Flex 項目的
flex-basis
值大于width
值,且同時大于 Flex 項目的內容的最小值,Flex 項目的flex-basis
值不會被任何其他值所替代。
雖然如此,但是在 Flex 項目上只要同時顯式設置了 flex-basis
和 width
兩屬性的值,瀏覽器都將 Flex 項目的初始化尺寸(假想主尺寸)視為 flex-basis
的值。
.item {width: 150px;flex-basis: 100px;
}/* 等同于 */
.item {flex-basis: 100px;
}
上面代碼中,Flex 項目初始化的假想主尺寸都會是 100px
,也就是說,瀏覽器在根據 Flex 容器剩余空間(或不足空間)、Flex 項目的 flex-grow
或 flex-shrink
計算 flex-basis
最終值時,它(flex-basis
)的最初基礎都將是 100px
:
這也就是,Flex 項目的總寬度(width
屬性值總和)大于 Flex 容器空間(即 Flex 容器產生不足空間),但 Flex 項目的 flex-basis
顯式設置了 0
或 0%
時,即使 Flex 項目的 flex-shrink
(收縮因子)是非 0
的值,比如 1
或大于 1
的其他值,Flex 項目也不會按收縮比例分配 Flex 容器的不足空間。最終 Flex 項目的 flex-basis
值等于 Flex 項目的內容最小尺寸(min-content
) 。
Demo 地址: https://codepen.io/airen/full/YzLELvX
因此,如果你要給 Flex 項目設置一個初始化的尺寸(一個假設的主尺寸或者說一個理想的尺寸),應該盡可能地在 Flex 項目使用 flex-basis
來設置這個初始化尺寸 。這樣做可以更直接地告訴瀏覽器,Flex 項目的初始化主尺寸有多大。因為瀏覽器在計算 Flex 項目的 flex-basis
最終值都和 Flex 項目的初始化的 flex-basis
值有關聯。這里是不是有一種此 flex-basis
非彼 flex-basis
的感覺 (繞暈沒)!
在 Flexbox 布局中,只要給 Flex 項目顯式設置了 flex-basis
的值,就有可能會造成 Flex 容器有剩余空間或不足空間。不過在默認情況之下,Flex 容器有剩余空間時,Flex 項目不會自動擴展,這是因為 Flex 項目的 flex-grow
默認值為 0
,但 Flex 容器只要有不足空間,Flex 項目就會自動收縮,這是因為 Flex 項目的 flex-shrink
的默認值為 1
。
另外一點,Flexbox 布局中的 flex-basis
值,瀏覽器最終計算的 flex-basis
最終值也會像 width
屬性一樣,受 min-width
(或 min-inline-size
)、min-height
(或 min-block-size
)、max-width
(或 max-inline-size
)和 max-height
(或 max-block-size
)值的限制。
前面已經說過,在 CSS 中,如果元素同時出現 width
、min-width
和 max-width
屬性時,其權重計算遵循以下規則:
- 如果元素的
width
值大于max-width
值時,max-width
會覆蓋width
值,最終取max-width
值;
- 如果元素的
width
值小于min-width
值時,min-width
會覆蓋width
值,最終取min-width
值;
- 如果
min-width
值大于max-width
值時,min-width
的優先級將高于max-width
值,最終會取min-width
。
這些規則同樣適用于
height
、min-height
和max-height
以及它們對應的 CSS 邏輯屬性!
那么在 Flex 項目上,同時出現 width
、flex-basis
和 min-width
時,具體的運算過程如下:
- 根據“
content
?width
?flex-basis
”法則,先判斷出運用于 Flex 項目的初始化的值,即flex-basis
會運用于 Flex 項目;
- 再將計算出的
flex-basis
值和min-width
值作比較,如果flex-basis
值小于min-width
值,則 Flex 項目的最終值為min-width
值,即min-width
值會覆蓋flex-basis
的值作為 Flex 項目的最終值 。
比如:
.item {width: 150px;flex-basis: 100px;min-width: 180px;
}
最終所有 Flex 項目的初始化值(Base Size)是 100px
,最小值(Minimum Size)是 180px
,瀏覽器最終計算出來的 flex-basis
值也會是 min-width
值,即 180px
:
Demo 地址: https://codepen.io/airen/full/jOxaxjK
如果 Flex 項目同時出現 width
、flex-basis
和 max-width
時,具體的運算過程如下:
- 根據“
content
?width
?flex-basis
”法則,先判斷出運用于 Flex 項目的初始化的值,即flex-basis
會運用于 Flex 項目;
- 再將計算出的
flex-basis
值與max-width
比較,如果flex-basis
的值大于max-width
值,則flex-basis
的最終值是max-width
值,即max-width
值會覆蓋flex-basis
的值 。
比如:
.item {width: 150px;flex-basis: 300px;max-width: 100px;}
最終所有 Flex 項目的初始化值(Base Size)是 300px
,最大值(Maximum Size)是 100px
,瀏覽器最終計算出來的 flex-basis
值也會是 max-width
值,即 100px
:
Demo 地址: https://codepen.io/airen/full/XWqzBJj
如果 Flex 項目同時出現 width
、flex-basis
、min-width
和 max-width
時,會在上面的規則上增加新的一條規則來進行判斷:
當
min-width
大于max-width
時,min-width
優先級將高于max-width
。
然后再與 flex-basis
的值相比,flex-basis
會min-width
值 。反之,如果 min-width
小于 max-width
時,計算出來的 flex-basis
分別與 min-width
和 max-width
相比,如果小于 min-width
則取 min-width
,如果大于 max-width
則取max-width
。
比如:
.item {width: 150px;flex-basis: 300px;min-width: 120px;max-width: 100px;}
Demo 地址:https://codepen.io/airen/full/WNJXKGe
如果你理解了的話,可以使用更簡單的規則來決定 Flex 項目的尺寸。
首先根據
content
?width
?flex-basis
來決定用哪個值來初始化 Flex 項目的假設主尺寸。如果 Flex 項目顯式設置了flex-basis
屬性,則會忽略width
和content
。但最終瀏覽器計算出來的 Flex 項目主尺寸(計算后的flex-basis
屬性的值)會受到 CSS 的min-*
和max-*
屬性值的限制,其中min-*
用來設置 Flex 項目的下限值,max-*
用來設置 Flex 項目的上限值 。
我們可以用一個簡單的流程圖來描述:
Flex 項目的最小值(min-size)
在使用 Flexbox 布局的時候,很有可能其中某個 Flex 項目的文本內容很長,最終導致內容溢出:
你可能想到了在文本節點容器(它也是一個 Flex 項目)上設置:
/* ① 長單詞斷行,常用西文 */
.long-word {overflow-wrap: break-word;
}/* ② 文本截取,末尾添加 ... */
.text-overflow {white-space: nowrap;overflow: hidden;text-overflow: ellipsis;
}/* ③ 多行文本截取,末尾添加... */
.line-clamp {--line-clamp: 1;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: var(--line-clamp);-webkit-box-orient: vertical;
}
諸如此類的操作,我們只是希望防止內容(或長單詞破壞頁面布局)。如下圖所示:
設計師期望卡片標題在同一行,不能因為內容過長而讓設計效果失去一致性。為此,我們可以使用上面代碼 ② 來截取文本,并且在文本末尾出現三個點的省略號:
.text-overflow {white-space: nowrap;overflow: hidden;text-overflow: ellipsis;
}
或者輸入了惡意的內容,比如帶下劃線的URL或沒有空格的數字,字母等:
在這樣的布局中,即使我們的標題元素是一個 Flex 項目,并且已顯式設置了 flex
:
.card__title { flex: 1 1 0%; }
你會發現,卡片右側的 Icon 還是被長內容擠出容器(溢出):
你可能會想到,使用上面代碼 ① 讓長詞斷行顯示:
.long-word { overflow-wrap: break-word; }
你會發現,并未起效果:
即使你加了 hyphens
為 auto
也未生效。
你可能會認為它是一個 Flexbox 中的 Bug,事實上,W3C規范中也有相應的描述:
On a flex item whose overflow is visible in the main axis, when specified on the flex item’s main-axis min-size property, specifies an automatic minimum size.
大致意思上說:“主軸上 Flex 項目的 overflow
屬性是 visible
時,主軸上 Flex 項目的最小尺寸(min-size)將會指定一個自動的(automatic)最小尺寸 ”。前面我們也提到過:
默認情況下,Flex 項目(設置為
flex:1
的 Flex 項目)在收縮的時候,其寬度不會小于其最小內容尺寸(即min-content
)。要改變這一點,需要顯式設置min-width
或min-height
的值 。
因此,我們要解決這個問題,需要在使用 overflow-wrap
為 break-word
的地方重置 min-width
值,并且強制它變成0
:
.long-word { overflow-wrap: break-word; min-width: 0; }
另外,要提出的是,Flex 項目的 overflow
的值為 visible
以外的值時會導致 min-width
的值為 0
,這就是為什么在方法 ② 中做文本截取的時候,怎么沒有 min-width: 0
。
還有,Flex 項目的長文本(max-content
)或顯式設置 white-space: nowrap
在視覺上除了會打破布局之外,也會對相鄰的 Flex 項目進行擠壓,即使這些 Flex 項目顯式設置了尺寸。比如上面的示例:
.card__media { width: 4em; aspect-ratio: 1;
} .card__action { width: 3em; aspect-ratio: 1;
}
你會發現,后面三張卡片的左右兩側的 Flex 項目尺寸被擠壓,甚至還會造成視覺上的變形:
造成這個現象是由于標題(它也是一個 Flex 項目)內容過長(max-content
),Flexbox 容器無剩余空間來放置它,這個時候將會對同一軸上的其他 Flex 項目進行擠壓。大家知道,Flex項目的 flex
的默認值為:
.item {flex-grow: 0;flex-shrink: 1;flex-basis: auto;
}
flex-shrink
的值為 1
,表示 Flex 項目可以被收縮。解決這種現象,我們有兩種方法,最簡單的方法是在標題這個 Flex 項目元素上顯式設置 min-width
的值為 0
:
.card__title {min-width: 0;
}
另一種解法是在顯式設置了 width
或 height
的 Flex 項目上重置 flex-shrink
的值為 0
,告訴瀏覽器,即使 Flexbox 容器沒有足夠的剩余空間,你也不能來擠壓我的空間:
.card__media,
.card__action { flex-shrink: 0;
}
相對而言,或者一勞永逸的方案是 在顯式設置了flex: 1
的 Flex 項目的同時,也顯式設置min-width
的值為0
。
Demo 地址:https://codepen.io/airen/full/NWMwLmX
這里有一個小技巧,Flexbox 布局中要實現均分列(等分列)布局效果時,請在 Flex 項目上顯式設置 min-width
的值為 0
,避免因內容不等長,造成列不均等 。
小結
現在我們明白了,Flex 項目上的 width
只是 flex-basis
缺失時的備用值,在代碼中顯式設置的 flex-basis
也只是你假想的一個主尺寸,它的最終值會根據 Flex 容器剩余空間(或不足空間)以及 Flex 項目的擴展因子(或收縮因子)而有所不同。并且最終計算出來的 flex-basis
會受到 min-*
(Flex 項目的下限值)和 max-*
(Flex 項目的上限值)限制。
你可能也已經注意到了,flex-basis
其實就是 將 Flex 項目放入彈性容器之前的大小 。這個值僅僅是一個理想或假設的值(即,開發者根據設計稿給 Flex 項目定義的一個最理想化的值)。但這個時候的值絕對不是 flex-basis
的最終值。因為 Flex 項目一旦放入 Flex 容器之后,Flex 項目的 flex-basis
就會發生變化,瀏覽器會根據相應的環境給 Flex 項目計算出一個最終的 flex-basis
值,而這個最終計算出來的 flex-basis
值也是 Flex 項目的最終尺寸(大小)。
現在我們明白了,這width
只是flex-basis
缺失時的后備,并且min-width
和max-width
只是 flex-basis
的上限和下限。那么,flex-basis
究竟是什么?
在我們所有的插圖中,我們在將 Flex 項放入 Flex 容器之前將它們的大小可視化。 我們這樣做是因為flex-basis
就是:將彈性項目放入彈性容器之前的大小。這是物品的理想或假設尺寸。但flex-basis
不是保證尺寸!一旦瀏覽器將項目放入其 Flex 容器中,情況就會發生變化。
在我們上面的一些示例中,你看到彈性項目完全適合它們的彈性容器,因為所有項目的總和最終flex-basis
是我們容器的確切寬度(1000px)。flex-basis
發生這種情況時這很好,但通常彈性容器沒有足夠的空間,或者在其所有項目的值加起來之后會有額外的空間。
所以說,最終決定 Flex 項目大小的會由 Flex 容器的剩余空間(或不足空間) 、Flex 項目的理想主尺寸(Flex 項目的初始化值) 、Flex 項目的擴展因子 (flex-grow
值)或 Flex 項目的收縮因子 (flex-shrink
值)、 Flex 項目的最小內容(或最大內容)長度值 以及 Flex 項目的下限值(min-*
值)和(或)Flex 項目的上限值(max-*
值) 來決定。