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

閱讀時間約 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,我們下次見。
關於我:
一名從英文系畢業的前端工程師,喜歡閱讀、寫東西及自我成長。
|聯絡我:vivian.enlife@gmail.com
參考資料:
為了追求可以窩在座位上、可以心無旁騖思考問題、座位可以亂七八糟沒關係、不需要到處哈腰點頭跑客戶,不用腳踩十公分、連妝都可以不用化的職場人生,文組少女毅然決然踏上RD的養成日常。
留言0
查看全部
發表第一個留言支持創作者!
相信透過之前的介紹,大家對於 CSS 選擇器(CSS selector)已經不陌生了,今天我們要來聊聊兩個在實務上非常好用的偽類(pseudo class )語法,他們分別是 :nth-child() 與 :nth-of-type(),在了解這兩個語法之前,我們首先要先來聊聊什麼是「偽類」呢?
不論是在基礎或是進階的版面排列,幾乎離開不了 position 系列的 CSS 語法,如果對於這些語法不熟悉,要快速完成畫面需求幾乎是不可能的,甚至會延宕整個團隊的開發速度(對,position 語法就是這麽重要)。
相信大家在一開始接觸 CSS 時,一定會很疑惑為什麼除了 width 外,還會有 max-width 及 min-width 語法呢? 當要開發響應式網頁時,到底要使用什麼語法來控制「斷點」?
對於前端初學者來說,在切版時會出現很多規則、不規則的網頁區塊,這時候我們會嘗試用各種相對定位、絕對定位、margin 或是 padding 的方式來進行網頁區塊的推擠。
明明想要某個欄位的寬高為 200px,卻發現自己不知道為什麼怎麼更改都會改不動,又或者寬高更改了,卻沒有辦法與其他元素並列。 上述的狀況,通常都是在不熟悉 HTML display 特性而產生的狀況下才會出現⋯⋯
在一個網頁上,會需要使用到圖片的地方有非常多處,像是品牌主視覺、橫幅廣告、側邊廣告、主要內容的預覽圖片、縮圖、背景圖片等。
相信透過之前的介紹,大家對於 CSS 選擇器(CSS selector)已經不陌生了,今天我們要來聊聊兩個在實務上非常好用的偽類(pseudo class )語法,他們分別是 :nth-child() 與 :nth-of-type(),在了解這兩個語法之前,我們首先要先來聊聊什麼是「偽類」呢?
不論是在基礎或是進階的版面排列,幾乎離開不了 position 系列的 CSS 語法,如果對於這些語法不熟悉,要快速完成畫面需求幾乎是不可能的,甚至會延宕整個團隊的開發速度(對,position 語法就是這麽重要)。
相信大家在一開始接觸 CSS 時,一定會很疑惑為什麼除了 width 外,還會有 max-width 及 min-width 語法呢? 當要開發響應式網頁時,到底要使用什麼語法來控制「斷點」?
對於前端初學者來說,在切版時會出現很多規則、不規則的網頁區塊,這時候我們會嘗試用各種相對定位、絕對定位、margin 或是 padding 的方式來進行網頁區塊的推擠。
明明想要某個欄位的寬高為 200px,卻發現自己不知道為什麼怎麼更改都會改不動,又或者寬高更改了,卻沒有辦法與其他元素並列。 上述的狀況,通常都是在不熟悉 HTML display 特性而產生的狀況下才會出現⋯⋯
在一個網頁上,會需要使用到圖片的地方有非常多處,像是品牌主視覺、橫幅廣告、側邊廣告、主要內容的預覽圖片、縮圖、背景圖片等。
你可能也想看
Google News 追蹤
Thumbnail
接下來第二部分我們持續討論美國總統大選如何佈局, 以及選前一週到年底的操作策略建議 分析兩位候選人政策利多/ 利空的板塊和股票
Thumbnail
🤔為什麼團長的能力是死亡筆記本? 🤔為什麼像是死亡筆記本呢? 🤨作者巧思-讓妮翁死亡合理的幾個伏筆
Thumbnail
上華蒙特梭利小學、中學和高中的教學理念以蒙特梭利教育為基礎,是台南地區一所特別的實驗學校。小學部分經營已經有七年,從一開始僅有八位學生到如今成長至七十多名學生,這樣的發展過程中,需要家長們慢慢了解並認同蒙特梭利的教育理念。 在這幾年的疫情風波中,學校經歷了許多挑戰,但已逐漸趨於穩定。上華蒙特梭利小
整理幾個自學網站,或許未來用得上。
Thumbnail
第二題練習題~應用的內容跟判斷質數差不多,甚至再更少一點(因為沒有要用到迴圈),所以這次寫起來就快很多,除了題目難度比較低之外,經過上次的洗禮之後,對於解題應該有再抓到更多感覺,所以寫這題比較有成就感一點XD 主題:宣告變數和判斷式的的綜合小應用 題目:每個人都有心目中夢想的身高,像小鳴就夢想著
Thumbnail
從跟著教學影片把老師的程式抄過一遍,變成看到題目能把題目轉為程式,對於初學者來說蠻困難的。所以我想以初學者的角度來分享自己怎麼適應這段轉換的過程,以及我解題的方法是什麼。(也順便紀錄一下自己的思路) ※主題:流程控制為主的綜合小應用 ※題目:讓使用者輸入一個數字,並用程式判斷該數字是否為質數
Thumbnail
網路上提到自學程式的文章,都會說自學程式非常地辛苦,而且要很自律,決心夠強;而當自己踏上這條路後,才發現何止是辛苦,根本是佈滿荊棘,常常寸步難行,且被刺地遍體鱗傷(喂~是不是有點太浮誇了),但在每個寫出程式豁然開朗的當下,卻又成就感滿滿,所以想藉著寫部落格紀錄一下自己的學習過程!
Thumbnail
程式語言只是工具,更重要的是程式邏輯 【運算思維】 1.拆解: 將一個任務或問題拆解成數個步驟或部分。 2.找出規律: 預測問題的規律,並找出模式做測試。 3.歸納與抽象化: 找出最主要導致此模式的原則或因素。 4.設計演算法: 設計出能夠解決類似問題並且能夠被重複執行的指令流程。
Thumbnail
最近很多人私訊我他們自學遇到的瓶頸,有些人會覺得學不會程式,是自己太笨沒天分,或從小數理能力就差,才學不起來。但以我自己這些年自學程式並創業的經驗,我認為可能原因是自己操之過急了,因為想要快速達到像是轉職或是創業等等目標,所以覺得得學得越快越好。但這個領域需要的是長時間的磨練,慢慢一點點累積
Thumbnail
設定好你的目標,做好目標分解,接下來就是學習與實作,在過程中,肯定會遇到各種問題需要debug,這應該是剛入門自學程式的人最痛苦的部分,可能看到bug不知道google要下甚麼關鍵字,也可能搜出一堆文章看得頭昏腦脹,所以想跟大家分享我在自學製作封鎖電商黑名單chrome插件過程,是怎麼面對這種狀況的
Thumbnail
之前跟大家分享【表現目標】和【學習目標】,有助於設定自學的終點,但是在執行目標的過程中是否遇過有目標也難以下手的問題呢?今天想跟大家說說【拆解目標】,這也是我在自學製作封鎖電商黑名單chrome插件賺取被動收入過程中運用的方法,希望對剛入門自學程式的朋友有幫助
Thumbnail
除了增進程式技術和技巧以外,我覺得建立起正確的【自學心態】更重要,保持正確的態度能讓你持續不斷的精進學習,不會半途而廢,也更能享受進步帶來的成就感,我從自己過去零基礎開始自學程式然後做出線上服務的經驗,整理出一些入門自學的朋友應該抱持的心態,相信會很有幫助
Thumbnail
接下來第二部分我們持續討論美國總統大選如何佈局, 以及選前一週到年底的操作策略建議 分析兩位候選人政策利多/ 利空的板塊和股票
Thumbnail
🤔為什麼團長的能力是死亡筆記本? 🤔為什麼像是死亡筆記本呢? 🤨作者巧思-讓妮翁死亡合理的幾個伏筆
Thumbnail
上華蒙特梭利小學、中學和高中的教學理念以蒙特梭利教育為基礎,是台南地區一所特別的實驗學校。小學部分經營已經有七年,從一開始僅有八位學生到如今成長至七十多名學生,這樣的發展過程中,需要家長們慢慢了解並認同蒙特梭利的教育理念。 在這幾年的疫情風波中,學校經歷了許多挑戰,但已逐漸趨於穩定。上華蒙特梭利小
整理幾個自學網站,或許未來用得上。
Thumbnail
第二題練習題~應用的內容跟判斷質數差不多,甚至再更少一點(因為沒有要用到迴圈),所以這次寫起來就快很多,除了題目難度比較低之外,經過上次的洗禮之後,對於解題應該有再抓到更多感覺,所以寫這題比較有成就感一點XD 主題:宣告變數和判斷式的的綜合小應用 題目:每個人都有心目中夢想的身高,像小鳴就夢想著
Thumbnail
從跟著教學影片把老師的程式抄過一遍,變成看到題目能把題目轉為程式,對於初學者來說蠻困難的。所以我想以初學者的角度來分享自己怎麼適應這段轉換的過程,以及我解題的方法是什麼。(也順便紀錄一下自己的思路) ※主題:流程控制為主的綜合小應用 ※題目:讓使用者輸入一個數字,並用程式判斷該數字是否為質數
Thumbnail
網路上提到自學程式的文章,都會說自學程式非常地辛苦,而且要很自律,決心夠強;而當自己踏上這條路後,才發現何止是辛苦,根本是佈滿荊棘,常常寸步難行,且被刺地遍體鱗傷(喂~是不是有點太浮誇了),但在每個寫出程式豁然開朗的當下,卻又成就感滿滿,所以想藉著寫部落格紀錄一下自己的學習過程!
Thumbnail
程式語言只是工具,更重要的是程式邏輯 【運算思維】 1.拆解: 將一個任務或問題拆解成數個步驟或部分。 2.找出規律: 預測問題的規律,並找出模式做測試。 3.歸納與抽象化: 找出最主要導致此模式的原則或因素。 4.設計演算法: 設計出能夠解決類似問題並且能夠被重複執行的指令流程。
Thumbnail
最近很多人私訊我他們自學遇到的瓶頸,有些人會覺得學不會程式,是自己太笨沒天分,或從小數理能力就差,才學不起來。但以我自己這些年自學程式並創業的經驗,我認為可能原因是自己操之過急了,因為想要快速達到像是轉職或是創業等等目標,所以覺得得學得越快越好。但這個領域需要的是長時間的磨練,慢慢一點點累積
Thumbnail
設定好你的目標,做好目標分解,接下來就是學習與實作,在過程中,肯定會遇到各種問題需要debug,這應該是剛入門自學程式的人最痛苦的部分,可能看到bug不知道google要下甚麼關鍵字,也可能搜出一堆文章看得頭昏腦脹,所以想跟大家分享我在自學製作封鎖電商黑名單chrome插件過程,是怎麼面對這種狀況的
Thumbnail
之前跟大家分享【表現目標】和【學習目標】,有助於設定自學的終點,但是在執行目標的過程中是否遇過有目標也難以下手的問題呢?今天想跟大家說說【拆解目標】,這也是我在自學製作封鎖電商黑名單chrome插件賺取被動收入過程中運用的方法,希望對剛入門自學程式的朋友有幫助
Thumbnail
除了增進程式技術和技巧以外,我覺得建立起正確的【自學心態】更重要,保持正確的態度能讓你持續不斷的精進學習,不會半途而廢,也更能享受進步帶來的成就感,我從自己過去零基礎開始自學程式然後做出線上服務的經驗,整理出一些入門自學的朋友應該抱持的心態,相信會很有幫助