伸縮自如的 CSS Flexbox

Joe Chang
Coding Hot Pot
Published in
9 min readJan 20, 2022
photo by @kikekiks

目前工作上切版大部分都是使用flex語法了,不過我發現我只對基礎的flex語法比較熟,如果要做進階的調整就會卡關了,像是flex: 1 2 200px這類的😭,因此決定寫一篇筆記來幫助自己理解flex

在學習flex之前一定要對flexbox模型有一定的認識,下圖就是flexbox的結構,主軸(main axis)和交錯軸(Cross Axis)為相對關係,主軸的方向可以做修改,當主軸變了交錯軸也會隨之改變,舉例來說,如果主軸改為垂直方向,那麼交錯軸就會變成水平方向

不管是主軸或是交錯軸都具有方向性,這會決定主軸的起始點和終點

圖片來源:https://www.freecodecamp.org/news/css-flexbox-tutorial-with-cheatsheet/
html結構

接下來開始實作flex! 先準備一個父容器container(200px * 200px ),裡面放了三個子元素item( 50px * 50px ),然後額外寫一個鄰居與父容器並行,在還沒做任何設定之前會如下圖

display : flex | inline-flex

我們在父容器身上設定display:flex,就會發現子元素可以水平排列了,假設父容器需要和「我是鄰居」這個span並排顯示的話,就需要設置成display:inline-flex,而flex和 inline-flex的差異就如同block 和inline-block,前者不可與其他元素並排,後者則是可以

將父容器設定為display:inline-flex

flex-direction : row | row-reverse | column | column-reverse

假如我們需要修改主軸的方向,可以透過flex-direction來修改主軸的方向,row(水平 — 由左至右) 、row-reverse(水平反轉 — 由右至左) 、column(垂直 — 由上至下) 、column-reverse(垂直反轉 — 由下至上),搭配箭頭來看會更清楚主軸的方向性為何

justify-content : flex-start | flex-end | center | space-between | space-around | space-evenly

justify-content控制子元素的水平對齊,正確來說是主軸對齊,預設值為flex-start,如上圖最左邊那個容器,子元素均向左對齊,假如我們需要將父容器裡面的子容器置中的話,只要將justify-content設定為center即可,如果需要子容器等距間隔開來,則可以使用 space-between、 space-evenly、space-around等等,這三者會有些許的不同,端看使用情境來做選擇

space-between、 space-evenly、space-around三者的差異

align-items : flex-start | flex-end | center | stretch | baseline

align-items控制子元素的垂直對齊,預設值為flex-start,個人最常使用的值為center和 flex-end

而stretch和 baseline只會在子元素高度不一致的時候有效果,下圖可以看到左邊兩個父容器分別設定了stretch和 baseline,但卻沒有任何的反應,是因為子元素都設定一樣的高度,因此stretch和 baseline的行為就像flex-start一樣,都是對齊上方,而右邊兩個父容器刻意將1號子元素height設定為80px , 2號不設定高度,3號設定height為50px,可以看到stretch的效果是將沒有設定高度的子元素稱滿整個父容器,而baseline是以子元素的基線做為對齊線

flex-wrap : nowrap | wrap | wrap-reverse

為了演示flex-wrap語法,我們多新增三個子元素,就會發現一件詭異的事情,一個子元素的寬為50px,6個就是300px,父容器的寬為200px,理當來說子元素應該要變兩行才對,怎麼會全部擠在同一行,那是因為flex-wrap預設為nowrap,全部的子元素都會被放在同一行,如果要斷行的話,只要設定wrap即可,另外如果要顛倒斷行的順序可以寫wrap-reverse

align-content : flex-start | flex-end | center | space-between | space-around | space-evenly

align-items負責單行的交錯軸對齊,而align-content負責多行的交錯軸對齊,基本上熟悉justify-content的邏輯,align-content就能快速上手

以上都是針對整體做設定,接下來會介紹針對單一元素做設定

order

針對子元素設定order的話,就可以改變排列的順序,不過設定的邏輯跟我預想的不太一樣,將3號子元素的order設定為1結果是排在最後一個,設定為-1則是排在第一個,假設每個子元素都有設定order的話,排列的順序就會是預期的,ex將1號子元素order設定為3,2號容器設定為5…

align-self: auto | stretch | flex-start | center | flex-end | baseline

針對單一元素設定交錯軸的對齊,假如父容器已經有設定align-items的話,align-self會沒作用,這點要特別注意

接下來就來到今天的重頭戲,也是我比較不熟的部分 — flex!

flex-grow

設定子元素的延伸,預設值為0不縮放,若父容器還有多餘的空間,則子元素會依照設定flex-grow的比例做延伸

flex-shrink

設定子元素的縮放,預設值為1,若設定為0則不縮放,當父容器的空間不足,則子元素會依照flex-shrink的比例做縮放

flex-basis

子元素的基礎寬度,預設為auto

flex

flex為flex-grow、flex-shirk 和 flex-basis的縮寫,如果只寫一個值代表設定flex-grow

搭配實作來看看flex-grow和flex-shirk是怎麼運作的吧!先將父容器寬度為400px,藍色的子元素設定為width: 200px,綠色的子元素設定為width: 100px ,畫面會如下,是沒被撐滿的,如果要讓子元素填滿父容器可以設定flex-grow

將藍色子元素設定為flex-grow:1,綠色子元素為flex-grow:2,flex-grow的計算步驟如下:

  1. 先計算父容器剩餘空間:400-(200+100) = 100
  2. 子容器的flex-grow分別為1, 2,剩餘空間除以3(1+2)
  3. 100 / 3 = 33.33…
  4. 藍色子元素的寬 = 200+(1*33.33) = 233.34
  5. 綠色子元素的寬 = 100+(2*33.33) = 166.65

接下來示範flex-shirk,父容器的寬度維持400px,藍色的子元素設定為width: 300px,綠色的子元素設定為width: 200px,這時的子元素是寬度總和是大於父容器的,因此我們可以透過flex-shrink來依照設定的比例做縮放

將藍色子元素設定為flex-shrink:2,綠色子元素為flex-shrink:1,flex-shrink的計算步驟如下:

  1. 先計算超出的部分:300+200–400 = 100
  2. 計算權重 : 2*300 + 1*200 = 800
  3. 計算藍色子元素縮放了多少:(100*2[flex-shirk]*300[width]) / 800 = 75
  4. 計算綠色子元素縮放了多少:(100*1[flex-shirk]*200[width]) / 800 = 25
  5. 藍色子元素縮放後的寬度為 300–75 = 225
  6. 綠色子元素縮放後的寬度為 200–25=175

想不到flex-shrink的計算方式居然跟flex-grow的方式不一樣,而且還複雜了許多,不過實務上應該是不會需要精算到這麼仔細啦,有個基本概念就可以了,經過這次實作對flex的熟悉度又更上一層樓了!💪

最後附上這張圖,算是快速的概覽flexbox語法

圖片來源:https://www.webtips.dev/flexbox-in-css

參考資料:

深入解析 CSS Flexbox

--

--

Joe Chang
Coding Hot Pot

前端工程師,唯有非常努力,才能看起來毫不費力