前陣子在做公司的專案時,遇到一個用 flex 寫的 layout,明明已經用 flex-basis 限制寬度,但還是因為 layout 裡面的內容物的文字和圖片而把某一個區塊撐開。那時一直想不透是為什麼,所以就開始找資料,才發現跟 flex 本身的特性有關。
防止 flex item 因為特殊情況被撐開
實作情境
以下是模擬當初在實作的情境,主要是一個被分為三欄的 layout,每一欄都會被放入一個元件,其中中間的元件因為是放入類似文字編輯器的元件,所以這個元件內容並不是固定的,會動態的變動,也就有可能因為圖片過大,或出現無斷行文字而把中間這欄撐開。
=> container 裡面分別有三個 item,item2 的 flex-basis 設定成 300px,裡面放了一個含有 10 個 30px 的文字的 component。
<範例 HTML>
<範例 css>
<範例實際畫面>
當有比較大的圖片出現時,會出現以下狀況
<HTML (放入圖片後)>
<實際畫面(放入圖片後)>
中間這欄會被撐開,不只有原先我們希望的 300px 寬。
問題發生原因&解決方式
為什麼會發生這個問題?
這邊先來了解一下這個問題發生的原因!會出現這樣的狀況主要是因為設定flex之後,容器裡面的 item 的 min-width(flex-direction: row) 或 min-height(flex-direction: column) 的預設值為 auto,所以當內容物寬度或高度較大時,這一欄就會被撐開。到這裡,腦子動得比較快的人,可能還是會覺得哪裡怪怪的,這邊先暫時不延伸下去思考,先針對 flex item 被預設的特性下去做修改。
*被預設為 auto 的屬性是 min-width 還是 min-height 主要是看現在被設定的 flex 方向(主軸的方向),也就是 item 的排列方向是 x 軸還是 y 軸。
怎麼解決這個狀況?
前面提到跟 min-width 或 min-height 預設是 auto 有關,那這裡我們就只需要把它設定為 0 就可以了。在這個範例中,因為是主軸為 x 軸,所以要設定為 0 的是 min-width。
設定 min- 的目的是去讓 item 寬度不要隨著裡面的內容物撐大(ex: img),就可以讓 item 寬度維持在我們希望的 300px 以內。
這樣中間這一欄,就可以恢復成原本我們希望的 300px了。但在這個情境中,圖片會被蓋住,這時候可以依照實際的需求搭配 overflow 來呈現。
(當時我實務中的需求,scroll 的部分是設定在這一欄中的元件)
除了我這次的解法外,依照實際的確切情境,也可以透過 overflow 來解決這個狀況。
延伸思考
重新再回到剛剛前面提到的這個問題產生的原因,應該會有不少人覺得哪裡怪怪的,尤其是這個問題的重要部分-寬度的地方。明明每一欄的 flex-basis 都設定好了,而且合計是 container 的寬度,怎麼中間這欄可以被撐開呢?那其他欄位不就會被擠壓到嗎?
沒錯!這個部分也和 flex 的特性有關,也就是 flex-shrink。當 display 設定為 flex 時,flex item的flex-shrink 預設值會是 1,意思就是當空間不足時,item 就會被擠壓。這也就是讓中間欄位被撐開後,沒有導致其他 item 被擠倒 containe r外的原因。
在這個情況下,如果將另外兩個 item 的 flex-shrink 設定為 0,就會發生以下的狀況,也就是 item 超出 container。
其實 flex 是我在實做中很常使用到的排版方式,但有時會因為自己沒有真正認識它,而踩到一些雷。
不過仔細想想也就是因為 flex 有這樣能屈能伸(?)的特性,才會在非常好用的同時,偶爾出現這一些奇特的現象,但只要再多花一點時間了解它,就會越用越順手。
參考範例在這裡
貼心小提醒!!
因為是亂亂寫筆記,真的就是純紀錄之前實作時,如何解決曾經卡住過的問題,所以主要都是解決問題的方式為主,不會有太多詳細說明。
