Flex 容器寬度被內容撐開的問題

陟上晴明發表於2023-02-07

在彈性佈局中,一個 flex 子項的最終尺寸是基礎尺寸(或內容尺寸)、彈性增長或收縮、最大最小尺寸共同作用的結果。
最終尺寸計算的優先順序是:
最大最小尺寸限制 > 彈性增長或收縮 > 基礎尺寸

  • 基礎尺寸由 flex-base 屬性或 width 屬性,以及 box-sizing 盒模型共同決定;
  • 內容尺寸最指最大內容寬度,當沒有設定基礎尺寸是會頂替基礎尺寸的角色;
  • 彈性增長指的是 flex-grow 屬性,彈性收縮指的是 flex-shrink 屬性;
  • 最大尺寸主要受 max-width 屬性限制;最小尺寸則比較複雜,受最小內容寬度、width 屬性和 min-width 屬性共同影響。

image.png

很早之前就遇到過這個問題但沒有整理,當時處理完問題之後就沒有管了。昨天又遇到了同樣的問題,因為巢狀的層次很深折騰了有2個小時,所以還是需要記錄下來以免未來又忘了。

其實很簡單,容器使用 width:0;flex:1; 即可解決問題。

但是稍微有點沒有理解的是:為什麼設定寬度為 0 時,使用 flex-grow:1 可以使容器放大,但是設定寬度為 100% 時,使用 flex-shrink:1 並不會讓容器縮小。


先來看一下問題復現吧:

CodePen Demo

在正常內容的時候不會出現問題(可以點選 Demo 的 EDIT ON CODEPEN 最大化預覽正常情況),但當元素內部的文字內容增多時,或者視窗縮小時 flex 容器的寬度就會被內容撐開。

看起來是不是十分複雜?因為我巢狀了 2 層 flex 容器,最內部的容器 .list-item 因為內容太多被撐開了,並沒有如願按照剩餘空間縮小子元素 .text 的寬度,同時寬度變大的 .list-item 導致外部的 .container.wrap 也被撐開了。

被撐開的 flex 容器比較多,不好說明,那麼看一下簡略版的復現 Demo ?

CodePen Demo 簡略版

這個就很簡單明瞭了,因為 .text 的內容太多,致使 .container 容器被撐開了,並且 .container 的寬度變大使 .wrap 的寬度也增大了,並不是按照設想的 100vw。同時文字標題超出省略的樣式也沒有應用到。

其實解決問題很簡單,容器使用 width:0;flex:1; 即可解決問題。


但是我疑惑的是,為什麼寬度設定為 0,flex佈局可以使容器放大,設定為 100% 就不能實現縮小了。找了一圈也沒見原因,問了一下肉大,他說可能和內容寬度有關係,讓我看看張大佬的《CSS新世界》。

? 果然在 6.2.12 這一節找到了類似的例子,並在 6.3 這一節中找到了具體解釋。

那設定了 flex:1 屬性後,容器為什麼和預期表現不一致?簡寫的 flex:1 具體簡寫了些什麼?

因為設定了 flex-basis 屬性的元素的最小尺寸是最小內容的寬度(文字內容在所有換行點換行後的尺寸),而我設定了標題不換行導致最小尺寸比較大,最終尺寸大於 flex:1 給到的 flex-basis:0%。(如果我們把標題設定會換行容器就不會被撐開了)。
具體解釋為:

flex-basis 屬性下的最小尺寸是由內容決定的,而 width 屬性下的最小尺寸是由 width 屬性的計算值決定的。

這裡出現的 “最小尺寸” 表示最終尺寸的最小值,所以在標題不換行的時候如果不設定 width0 那麼,flex 容器的寬度就會被內容撐開。當設定 width:0 之後,最小尺寸就為設定的 width 值了,就可以被 flex-grow:1 放大。

ok,以上就是 flex 容器被內容撐開的全部內容了,有條件的小夥伴可以入手一本 《CSS新世界》 看看,裡邊的內容有很多講些CSS新特性的實用例子,確實可以節約不少時間。

文件

《CSS新世界》- 張鑫旭
flex - CSS(層疊樣式表) | MDN
flex-basis - CSS(層疊樣式表) | MDN

相關文章