【自學程式】那些年你沒搞懂的 Flexbox 及實務應用技巧

2022/04/28閱讀時間約 1 分鐘
在 Modern Web 的世界中,已經有非常多的套件、語法、框架,可以解決大部分網頁排版問題。
以我近期的觀察來說,在專案開發時,大部分公司會為了讓下一個接手、維護的開發者能更快上手專案架構,而採取原生的 CSS 寫法,而不是仰賴快速又方便的套件。
更進一步說,即便專案中使用了套件、框架,開發者好不好上手專案更多時候還是仰賴對 CSS 的熟悉度,如果對 CSS 掌握度不高,也會出現即便使用了套件,依然出現排版與自己預期不同的狀況。
今天我就要來分享過往自己曾常常踩雷的一個 CSS 概念:Flexbox掌握好 Flexbox 的概念,可以解決大部分你在網頁畫面切版上所需要解決的排版問題。

何謂 Flexbox ?為什麼我們需要這個語法?

Flexbox 是 CSS 中一種透過欄與列的方式進行排版的模型,這個模型可以讓元素伸縮、自適應容器,或是在有限空間下,自適應限制元件的寬高。
如果去觀察較早期的網頁,可能會發現有些原始碼還在使用 float 或是 position 的語法進行排版,但其實以上兩種排版方式有滿大的缺點:
  • 沒有辦法同時水平、垂直置中元素
  • 沒有辦法平均分配子元素在父元素中的佔比,及分配父元素的剩餘空間
  • 沒有辦法讓子元素彼此自動對齊彼此的高度
然而 Flexbox 可以很好地透過 flex 系列語法解決以上問題,這也讓開發者更快速、方便的進行網頁排版。

如何使用 Flexbox ?

在開始介紹如何使用 flexbox 之前,我們可以先來看看等等會使用到的程式碼範例:
在上方的範例中,我刻意建立了在實務上如果要建立列表會使用的 HTML 結構(當然我在其他文章中也有提到 ul>li 的使用方式,但為了免除一些不必要的調整,我統一使用 div 做示範)。
範例中也預填好一些簡單明瞭的樣式,接著我們要使用 flexbox 語法,來替列表進行排版:
我們可以在父元素 .list 上加上 display: flex 這個語法,此時就會按照 flexbox 模型進行網頁元素的排列,接著我們可以來看看加上 display: flex 後對範例產生的影響:
  1. 排列的方式改變了:預設的 div 元素,會帶有 display: block 的 CSS 預設屬性,照常理來說帶有 display: block 的元素,並不會與其他元素並列同一列才對,但是當父元素帶有 display: flex 時,會改變子元素 display 預設屬性所帶來的效果。
  2. 排列的方向變了:當父元素 .list 還沒有加上 display: flex 這個語法前,內層的子元素會按照原本的 display: block 特性進行排列,所以在一開始的範例中三個 div 元素是由上至下排列的。但加上 display: flex 這個語法後, 卻改變由左至右排列,且寬度也不再是 100% 了。
這究竟是為什麼呢?以下我們將針對 flexbox 的原理、語法、使用情境細細介紹:

Flex 基礎原理與 Flex container

就像上圖所呈現,flexbox 的組成會有 flex container 及 flex items 兩個要素。
通常帶有 display: flex 的元素,會稱為 flex container ,其包含的子元素,則會稱為 flex item ,初學 flex 時,可能會覺得這不是很重要而忽略,但其實 flex container 與 flex item 所能使用的語法是大大不同的,所以最好是將此概念銘記在心。
在文章的前半部,我們主要會專注在 flex container 的部分,flex item 的部分則會在後半部才會比較仔細的說明。
首先我們要先聊聊 flex container 是透過怎麼樣的機制來進行網頁排版的:
在 flex container 中,會使用主軸(main axis)與交錯軸(cross)的概念了來指定 flex items 排列的方向,通常我們會使用一個語法:flex-direction,來指定我們的主軸方向為何,讓我們直接來看範例:
在 flex-direction 中,我們可以帶入幾種值,分別為:row(由左至右)、row-reverse(由右至左)、column(由上至下)、column-reverse(由下至上),這個方向性就代表了主軸的方向性,交錯軸就會是相反的方向。
從上方的範例中可以看到,flex item 會根據 flex container 所指定的主軸方向進行排列。
在預設的狀況下,當 flex container 只要帶有 display: flex 的狀況下,就會有預設 flex-direction: row 的語法,所以即便我們額外設定,也不會有什麼差別,所以如果通常我們是要由左至右排列時,我們可以單純在 flex container 下 display: flex 這個語法即可。

justify-content 決定 flex items 依主軸的排列方式

在前面有提到,在還沒有 flexbox 的網頁開發時期,要將子元素置中在父元素裡,是一件不輕鬆的事,但透過在 flex container 上使用 justify-content 語法,我們可以很輕鬆的做到這件事。
justify-content 提供了以下幾種值來針對 flex items 做排列:
  • flex-start:將 flex items 集中在主軸的起始位置(起始及結束位置可參考上圖)
  • flex-end:將 flex items 集中在主軸的結束位置
  • center:以主軸方向將 flex items 置中
  • space-around:以主軸方向將 flex items 的兩側,各自空出以間距為單位、二分之一的距離
  • space-between:以主軸方向將 flex items 貼緊 flex containers 兩側且平均分配間距
  • space-evenly:以主軸方向將剩餘空間平均分配在間距及 flex containers 兩側的空間,也就是平均分配 flex items 的距離
我們可以透過下方範例看懂這幾個語法的差異:
在有些狀況底下 justify-content 並不會生效:
  1. 你並不是在 flex container 使用這個語法
  2. 主軸的方向與你預期的不同
  3. 打錯字
  4. 使用到並非能在 flex container 與 flex items 能生效的語法(justify-content 語法有部分的值並非給 flexbox 做使用)

align-items 決定 flex items 依交錯軸的排列方式

除了水平的排列,很多時候我們也會需要針對網頁元素來做垂直的排版,這時我們就可以在 flex container 上使用 align-items 語法依照交錯軸的方向,對 flex items 進行群體的垂直排列(本文中所提到的水平與垂直,是基於 flex-direction: row 的設定,但在 flexbox 中主要還是以主軸、交錯軸為主)。
flex 提供了以下幾種跟 align-items 有關的語法:
  • stretch:如果不在 flex container 上特別設定 align-items 語法, 則會以 stretch 為預設值,帶有 stretch 特性的 flex container,其底下之 flex items 會依照當前 flex items 之最高的元素高度(cross size)做拉伸,或是依照 flex container 之高度直接填滿容器,若在 flex items 上設有高度(當主軸為 row 時)或是寬度(當主軸為 column 時),高度及寬度的權重會大於 align-items: stretch
  • normal(因為 normal 這個屬性,在其他非 flexbox 中也會生效,但在 flexbox 中,等同於 stretch,故不加以說明)
  • flex-start:將 flex items 集中在交錯軸的起始位置(起始及結束位置可參考上圖)
  • flex-end:將 flex items 集中在交錯軸的結束位置
  • center:以交錯軸方向將 flex items 置中
讓我們直接看範例:
這裡補幾個在使用此語法時可能會誤踩的雷點:
  1. 直接把 justify-content 有的語法代換進 align-items 中使用,但實際上他們有些語法是不共用的,例如:justity-content 在 flexbox 無法使用 stretch 這個屬性。
  2. 忘記給 flex container 設高度,導致垂直排版的效果出不來
  3. align-items 必須在 flex container 中使用才會生效

flex items 特性介紹

前文大致上將我們平常會在 flex container 上使用的語法介紹到一個段落,接著我們要來聊聊 flex items 的一些特性。
首先,怕大家忘記再重複說明一下, flexbox 的基本要素會包含:flex container 及 flex items,我們可以透過在父元素上加上 display: flex 讓子元素成為 flex items 。
而 flexbox 是具有方向性的,分為主軸(main axis)與交錯軸(cross axis),flexbox 的語法在不同的軸上有不同的應用。
根據上方概念, flex items 可以使用以下幾個屬性,但要注意以下語法是只作用在主軸上
  • flex-grow:若有剩餘空間時,flex items  會分配到多少比例的剩餘空間,通常預設值為 0
  • flex-shrink:當 flex item 超過 flex container 時,是否會依比例縮小,通常預設值為 1
  • flex-basis:設定 flex item 在主軸方向上的最小大小,預設值為 auto ,也就是會自適應主軸方向的大小(main size)
以上三個語法,還可以更濃縮為 flex 語法,以預設值作為範例: flex: 0 1 auto ,裡面的值依序為:flex-grow、flex-shrink 及 flex-basis。
讓我們來看看上述幾個語法的範例:
關於在 flex items 上使用 flex 語法,通常我們都只會在 flex-grow 與 flex-shrink 上以 0 與 1 的差異去區分是否要自動分配剩餘空間或是自適應容器。
前面有提到 flex-grow 與 flex-shrink 實際上是以**無單位之係數,**來計算分配比例的權重,然而這部分牽涉到 CSS 底層的演算機制,這裡就不多去研究實際分配權重是怎麼分配的,因為實務上我們也因為官方文件的標示不明確,而較少去使用。
由於權重的計算,也會因為整體容器的大小、flex items 的大小,而有所不同,建議可以直接使用響應式的單位來進行 flex items 大小的調整,例如:百分比。
那什麼狀況底下 flex-grow、flex-shrink 會無法生效呢?
  1. 在錯誤的軸上使用
  2. 搞錯 0 與 1 的使用方式
注:剩餘空間指的是無法填滿 container 時,所剩下來的空間。

align-self 決定 flex item 自身交錯軸的排列方式

講完 flex items 的特性後,再來聊聊另外一個屬於 flex items 的語法:align-self。
這個語法使用起來跟前面所提到的 align-items 差不多,唯一差別在於 align-self 是針對單一 flex item 進行交錯軸上的排列,而 align-items 語法是針對所有交錯軸上的 flex items 進行排列。
實際上,align-items 雖然是 flex container 的語法,但其實是群體性在 flex items 加上 align-self 語法罷了(這邊說的狀況是指最後結果的狀況,並不是使用 align-items 就真的會群體性產生 align-self 的語法)。
由於這兩者使用起來差不多,就不多額外介紹了,但有一個需要再三注意的地雷要提醒大家:並不是所有的 flex 語法都是對稱的,有 align-self 不代表 justify-self 也是作用在 flexbox 上,justify-self 就跟 justify-content: stretch 並不會在 flexbox 的結構中生效一樣,千萬不要搞混了!

flex-wrap 讓 flex items 自適應換行

另外一個 flexbox 非常好用的語法就是 flex-wrap ,這個語法可以判斷當前 flex items 是否會超出 flex container,flex-wrap 語法有以下幾種屬性:
  • wrap:當 flex items 超過 flex container 即依交錯軸起始到結束位置的方向換行(通常是向下)
  • nowrap:當 flex items 超過 flex container 時,隱藏超出去的部分
  • wrap-reverse:當 flex items 超過 flex container 即依交錯軸結束到起始位置的方向換行(通常是向上)
在預設的狀況下,會是 nowrap,讓我們來看看範例:
通常網頁在建立卡片或是列表時,如果是使用 flexbox 作為 layout 的方式,通常會使用此語法來進行列表的自適應。
那什麼樣的狀況下使用 flex-wrap 會不如預期呢?
  • 容器沒有設定寬度,所以容器可以無限延伸
  • flex items 沒有設定寬度,所以會無限被壓縮
而 flex-wrap 還有一個相關的延伸用法,就是當 flexbox 的交錯軸有剩餘空間時,我們可以使用 align-content 來進行行內的空間排列,但通常這樣的狀況不多見,不多見的原因在於:
通常會使用到 flex-wrap 這個語法,就是因為無法預期列表所需要的資料會有多少筆、內容會有多少,所以通常列表的高度我們會保持自適應,而不會寫死一個高度,也不會進而產生剩餘空間。
個人覺得以應用層面來說,align-content 這個語法有點雞肋,我們這邊就不多提這個語法了。

Flexbox 實務應用

最後來做個總結,以不同種的網頁排版來說,flexbox 算是相對彈性、好上手的語法,基本上可以處理掉大部分的網頁排版需求,舉凡:
  • 帶有規律性的列表
  • 可自適應、換行多筆資料所產生的元件
  • 同時做到水平、垂直方向的
  • 置中效果統一,不需要再用古老的置中方法
搞懂 flexbox 的運作模式,算是前端工程師基本中的基本,打好基礎在網頁切版上可以省去不少除錯的時間。
由於今天有提到 display 及 position 相關的用法,不熟悉的朋友可以參考下方文章:
希望透過這篇文章的分享,可以讓大家更了解 flex box 的特性,關於 flexbox 你有什麼想要跟我分享的嗎?歡迎下方留言與我分享!
希望今天的文章有幫助到正在閱讀的你,如果你喜歡我的文章的話,可以留下你的愛心或是收藏我的文章,也或者可以點選「贊助」,你的一杯咖啡絕對是我持續寫下去的動力!或是透過拍拍手,用你小小的行動支持我的創作!
我是Vivian,我們下次見。
關於我:
一名從英文系畢業的前端工程師,喜歡閱讀、寫東西及自我成長。
|聯絡我:[email protected]
參考資料:
為了追求可以窩在座位上、可以心無旁騖思考問題、座位可以亂七八糟沒關係、不需要到處哈腰點頭跑客戶,不用腳踩十公分、連妝都可以不用化的職場人生,文組少女毅然決然踏上RD的養成日常。
留言0
查看全部
發表第一個留言支持創作者!