Flexbox:那個靈活的盒子有多大?
已發表: 2022-03-10這是我關於 Flexbox 的系列文章的第三部分。 在過去的兩篇文章中,我們研究了創建 flex 容器時會發生什麼,並探索了它在 Flexbox 中的對齊方式。 這次我們來看看尺碼。 我們如何控制彈性項目的大小,瀏覽器在控制大小時會做出哪些選擇?
彈性項目的初始顯示
如果我有一組項目,其中包含可變長度的內容,並將其父項設置為display: flex
,則項目將顯示為一行並在該軸的開始處排列。 在下面的示例中,我的三個項目的內容很少,並且能夠將每個項目的內容顯示為一條完整的線。 由於flex-grow
的初始值為0
,因此項目不會增長到 flex 容器的末尾有空間,不要增長。

如果我向這些項目添加更多文本,它們最終會填滿容器,並且文本開始換行。 這些框被分配了容器中的一部分空間,該空間對應於每個框中的文本數量——文本字符串較長的項目被分配更多空間。 這意味著當隔壁的項目只包含一個單詞時,我們不會得到一個包含大量文本的又高又瘦的列。

如果您曾經使用過 Flexbox,那麼您可能對這種行為很熟悉,但也許您想知道瀏覽器是如何工作的,就像您查看多個現代瀏覽器一樣,您會發現它們都在做同樣的事情。 這歸結於規範中製定了諸如此類的細節,確保任何在新瀏覽器或其他用戶代理中實現 Flexbox 的人都知道該計算應該如何工作。 我們可以使用規範為自己找到這些信息。
CSS 內部和外部尺寸規範
在查看 Flexbox 規範中有關大小調整的任何內容時,您很快就會發現,您需要的很多信息都在另一個規範中——CSS Intrisnic 和 Extrinsic Sizing。 這是因為我們使用的尺寸概念並不是 Flexbox 獨有的,就像對齊屬性不是 Flexbox 獨有的一樣。 但是,對於這些尺寸結構如何在 Flexbox 中使用,您需要查看 Flexbox 規範。 感覺有點像來回跳躍,所以我將在這裡總結一些關鍵定義,我將在本文的其餘部分使用它們。
首選尺寸
框的首選大小是由width
或height
定義的大小,或者是inline-size
和block-size
這些屬性的邏輯別名。 通過使用:
.box { width: 500px; }
或邏輯別名inline-size
:
.box { inline-size: 500px; }
你說你希望你的盒子是 500 像素寬,或內聯方向 500 像素。
最小內容大小
min-content size 是一個盒子在不引起溢出的情況下可以達到的最小尺寸。 如果您的盒子包含文本,那麼將採取所有可能的軟包裝機會。
最大內容大小
最大內容大小是盒子可以容納內容的最大大小。 如果該框包含沒有格式的文本以將其拆分,則它將顯示為一個完整的長字符串。
彈性項目主要尺寸
彈性項目的主要尺寸是它在主要維度中的尺寸。 如果你連續工作——用英語——那麼主要的尺寸就是寬度。 在英文的列中,主要的尺寸是高度。
項目還具有最小和最大主尺寸,由它們在主尺寸上的min-width
或min-height
定義。
計算彈性項目的大小
現在我們已經定義了一些術語,我們可以看看我們的彈性項目是如何調整大小的。 flex
屬性的初始值如下:
-
flex-grow: 0
-
flex-shrink: 1
-
flex-basis: auto
flex-basis
是計算尺寸的東西。 如果我們將flex-basis
設置為0
並將flex-grow
設置為 1,那麼我們所有的盒子都沒有起始寬度,因此 flex 容器中的空間被平均分配,為每個項目分配相同數量的空間。
參見 Pen Smashing Flexbox 系列 3: flex: 1 1 0; 作者:Rachel Andrew (@rachelandrew) 在 CodePen 上。
而如果flex-basis
是auto
和flex-grow: 1
,則僅分配備用空間,同時考慮到內容的大小。
請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Smashing Flexbox Series 3:flex: 1 1 auto short text。
在沒有多餘空間的情況下,例如當我們的內容多於一行時,就沒有空間可以分發。
請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Smashing Flexbox 系列 3:flex: 1 1 auto long text。
這向我們表明,如果我們想知道 Flexbox 是如何計算出我們盒子的大小,那麼弄清楚auto
的含義是非常重要的。 auto
的值將是我們的起點。
定義自動
當auto被定義為 CSS 中的某個值時,它將在該上下文中具有非常具體的含義,值得一看。 正如規範編輯 Fantasai 的這篇演講所解釋的那樣,CSS 工作組花費了大量時間來弄清楚 auto 在任何情況下的含義。
我們可以在規範中找到有關auto
用作flex-basis
時的含義的信息。 上面定義的術語應該有助於我們剖析這個陳述。
“當在 flex 項目上指定時,auto 關鍵字檢索主要尺寸屬性的值作為使用的 `flex-basis`。 如果該值本身是 auto,那麼使用的值就是 `content`。”
因此,如果我們的flex-basis
是auto
,Flexbox 會查看定義的主要尺寸屬性。 如果我們給任何彈性項目一個width
,我們就會有一個主尺寸。 在下面的示例中,所有項目的寬度都是 110px,因此這被用作主要尺寸,因為 flex-basis 的初始值為 auto。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Smashing Flexbox Series 3: flex items with a width。
然而,我們最初的例子有沒有寬度的項目,這意味著它們的主要尺寸是auto
的,所以我們需要進入下一句,“如果該值本身是自動的,那麼使用的值就是content
。”
我們現在需要查看規範中關於content
關鍵字的內容。 這是您可以為您的flex-basis
使用(在支持瀏覽器中)的另一個值,例如:
.item { flex: 1 1 content; }
規範定義content
如下:
“指示基於彈性項目內容的自動大小。 (它通常相當於最大內容大小,但需要調整以處理縱橫比、固有大小約束和正交流”
在我們的示例中,對於包含文本的彈性項目,我們可以忽略一些更複雜的調整併將content
視為最大內容大小。
所以這就解釋了為什麼當我們在每個項目中有少量文本時,文本不會換行。 flex 項目是自動調整大小的,所以 Flexbox 正在查看它們的最大內容大小,項目以該大小適合它們的容器,然後工作就完成了!
故事並沒有到此結束,因為當我們添加更多內容時,框不會保持在最大內容大小。 如果他們這樣做了,他們會打破彈性容器並導致溢出。 一旦它們填滿容器,內容就會開始包裝,並且項目會根據其中的內容變得不同大小。
解決靈活的長度
正是在這一點上,規範變得相當複雜,但是,需要執行的步驟如下:
首先,將所有項目的主要尺寸相加,看看它是否大於或小於容器中的可用空間。
如果容器大小大於總大小,我們將關心flex-grow
因素,因為我們有增長空間。

如果容器大小小於總大小,那麼我們將關心flex-shrink
因子,因為我們需要收縮。

凍結任何不靈活的項目,這意味著我們已經可以決定某些項目的大小。 如果我們使用flex-grow
這將包括任何具有flex-grow: 0
項目。 這是我們的彈性項目在容器中剩餘空間時的場景。 flex-grow
的初始值為 0,因此它們會變得與它們的最大寬度一樣大,然後它們不再從它們的主要尺寸增長。
如果我們使用flex-shrink
,那麼這將包括任何帶有flex-shrink: 0
項目。 如果我們將flex-shrink
因子設置為 0,我們可以看到在這一步中會發生什麼。這些項目在它們的max-content
狀態下凍結,因此不會彎曲並安排自己以適應容器。
請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Smashing Flexbox Series 3: flex: 0 0 auto。
在我們的例子中——使用彈性項目的初始值——我們的項目可以縮小。 所以這些步驟繼續進行,算法進入一個循環,在這個循環中計算出分配或帶走多少空間。 在我們的例子中,我們使用flex-shrink
因為我們的項目的總大小比容器大,所以我們需要佔用空間。
flex-shrink
因子乘以項目內部的基本大小,在我們的例子中是max-content
大小。 這給出了一個減少空間的值。 如果項目僅根據flex-shrink
因子移除空間,那麼小項目可能基本上消失,已移除所有空間,而較大的項目仍有空間收縮。
在這個循環中還有一個額外的步驟來檢查會變得小於或大於其目標主尺寸的項目,在這種情況下,項目停止增長或縮小。 同樣,這是為了避免某些物品與其他物品相比變得很小或很大。
所有這一切都在規範方面進行了簡化,因為我沒有看過一些更邊緣的場景,你通常可以在你的腦海中更進一步,假設你很高興讓 Flexbox 做它的事情並且不是在像素之後完美。 在大多數情況下,記住以下兩個事實會起作用。
如果您是從auto
增長的,那麼flex-basis
將被視為項目上的任何寬度或高度或max-content
大小。 然後將根據flex-grow
因子使用該大小作為起點來分配空間。
如果您從auto
縮小,則flex-basis
將被視為項目上的任何寬度或高度或max-content
大小。 然後將根據flex-basis
大小乘以flex-shrink
因子來移除空間,因此與項目的最大內容大小成比例地移除空間。
控制增長和收縮
這篇文章的大部分時間我都在描述 Flexbox 在留給自己的設備時的作用。 當然,您可以通過使用flex
屬性來更好地控制您的 flex 項目。 通過了解幕後發生的事情,他們有望看起來更可預測。
通過設置你自己的flex-basis
,或者給項目本身一個尺寸,然後將其用作flex-basis
你從算法中收回控制權,告訴 Flexbox 你想從這個特定的尺寸增長或縮小。 您可以通過將flex-grow
或flex-shrink
設置為 0 來完全關閉增長或收縮。然而,在這一點上,值得使用控制彈性項目的願望來檢查您是否使用了正確的佈局方法。 如果您發現自己試圖在二維中排列彈性項目,那麼您可能會更好地選擇網格佈局。
調試大小相關問題
如果您的 flex 項目最終達到了意外的大小,那麼這通常是因為您的 flex-basis 是自動的,並且有一些東西給了該項目一個寬度,然後將其用作 flex-basis。 在 DevTools 中檢查項目可能有助於確定大小的來源。 您還可以嘗試將flex-basis
設置為0
,這將強制 Flexbox 將項目視為具有零寬度。 即使這不是您想要的結果,它也將有助於確定使用中的flex-basis
值是造成您的尺寸問題的罪魁禍首。
彈性間隙
Flexbox 的一個非常需要的特性是能夠指定彈性項目之間的間隙或間距,就像我們可以在網格佈局和多列佈局中指定間隙一樣。 這個特性是為 Flexbox 指定的,作為 Box Alignment 的一部分,並且第一個瀏覽器實現正在進行中。 Firefox 期望在 Firefox 63 中為 Flexbox 提供間隙屬性。可以在 Firefox Nightly 中查看以下示例。
請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Smashing Flexbox 系列 3:flex-gaps。

與網格佈局一樣,在將空間分配給彈性項目之前,會考慮間隙的長度。
包起來
在這篇文章中,我試圖解釋一些關於 Flexbox 如何計算 flex 項有多大的細節。 這似乎有點學術性,但是,花一些時間來理解它的工作方式可以為您在佈局中使用 Flexbox 節省大量時間。 我發現回到這樣一個事實真的很有幫助,默認情況下,Flexbox 試圖為您提供一堆不同大小的項目的最合理的佈局。 如果一個項目有更多的內容,它會被賦予更多的空間。 如果你和你的設計不同意 Flexbox 認為最好的,那麼你可以通過設置自己的flex-basis
來收回控制權。