National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 80 24°C PM2.5 21
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 18

Flexbox(二):伸縮與常見版型

flex-grow、flex-shrink、flex-basis,導覽列、卡片列與置中
Interaction 25 minute(s)

Learning Objectives

  • 說明 flex-basis 是項目的基準尺寸,並用 flex-grow 的比例算出剩餘空間怎麼分
  • 說明空間不夠時 flex-shrink 依「flex-shrink × 基準尺寸」的比例縮小,以及 flex-shrink: 0 的用途
  • 寫出簡寫 flex: 1、flex: auto、flex: none 分別代表的三個值
  • 用 margin-left: auto 與 align-self 調整單一項目,並說明 order 只改變視覺順序、不改變閱讀與鍵盤順序
  • 用 Flexbox 做出導覽列、等高卡片列與頁尾貼底三種常見版型

項目怎麼分空間

上一課的設定都寫在容器上:排成一列、置中、換行。可是很多版面的問題是「每個項目該多寬」:

  • 搜尋列:輸入框要占滿剩下的寬度,旁邊的按鈕維持原本大小。
  • 三張卡片:不管內容多少,三張一樣寬。
  • 手機畫面變窄:logo 不能被壓扁,其他項目可以縮。

這些都靠寫在項目上的三個屬性:

屬性 問的問題 預設值
flex-basis 分配空間之前,這個項目原本想要多大? auto(看 width 或內容)
flex-grow 還有剩餘空間時,我要分幾份? 0(不長大)
flex-shrink 空間不夠時,我要讓出幾份? 1(會縮小)

預設值的意思是:項目照內容的大小排,不會自己長大去填滿空位,但空間不夠時會縮小。

用數字算:剩餘空間怎麼分

瀏覽器分配空間的步驟(以單行、橫向為例):

  1. 每個項目先拿到基準尺寸(flex-basis)。
  2. 算剩餘空間:容器寬度 − 所有基準尺寸 − 所有 gap。
  3. 剩餘空間是正的:依 flex-grow 的比例分給項目。
  4. 剩餘空間是負的(放不下):依 flex-shrink × 基準尺寸 的比例從項目身上扣掉。

例一:長大。 容器 600px,三個項目 flex-basis: 100px,flex-grow 分別是 1、2、0,沒有 gap。

項目 1 項目 2 項目 3
基準尺寸 100 100 100
剩餘空間 600 − 300 = 300,按 1:2:0 分 +100 +200 +0
最後寬度 200 300 100

例二:縮小。 容器 300px,兩個項目的基準尺寸是 300px 與 100px,flex-shrink 都是 1。 放不下的部分是 300 + 100 − 300 = 100px,依 1 × 300:1 × 100 = 3:1 扣掉,大的項目多讓一點:

項目 1 項目 2
基準尺寸 300 100
要扣掉的 100px,按 3:1 分 −75 −25
最後寬度 225 75

flex-shrink: 0 表示「我不縮」:logo、頭像這類不能變形的東西常這樣設。 另外,項目預設不會縮到比內容最窄的寬度還窄(例如一個長單字),這是 min-width: auto 的作用;需要時可以設 min-width: 0 解除。

下面的實驗會把這張表算給你看,並和瀏覽器實際排出來的寬度並列。

互動實驗:flex-grow、flex-shrink 與 flex-basis

三個項目的 flex-basis 都是 100px。點方塊或「選取項目」的按鈕選一個項目,再改它的屬性;下方的表格依上面的步驟算出每個項目分到多少,最右欄是瀏覽器實際量到的寬度。做完最後一個任務後,在方塊上按 Tab 鍵試試,鍵盤焦點的順序有沒有跟著畫面改變?

簡寫 flex

三個屬性通常用簡寫 flex 一次寫完,順序是 grow shrink basis:

寫法 等於 意思
不寫(初始值) 0 1 auto 照內容大小,不長大,會縮小
flex: 1 1 1 0% 基準尺寸當作 0,空間全部按比例分:幾個 flex: 1 就幾等分
flex: 2 2 1 0% 分到的是 flex: 1 的兩倍
flex: auto 1 1 auto 先照內容大小,剩下的再平均分(內容多的最後還是比較寬)
flex: none 0 0 auto 完全不伸縮,維持內容大小

flex: 1 和 flex: auto 的差別就在基準尺寸:三張卡片想要一樣寬,用 flex: 1; 想要「內容多的寬一點,但一起填滿」,用 flex: auto。

調整單一項目的兩個工具:

  • align-self:只改這一個項目在交叉軸上的對齊,覆寫容器的 align-items。
  • margin-left: auto:auto 外距會吃掉主軸上所有的剩餘空間,於是把這個項目(和它後面的項目)推到最右邊。導覽列「左邊 logo、右邊登入鈕」就是這樣做的。

互動練習:社團網站的導覽列

左邊是社團名稱與選單,右邊要放「加入社團」按鈕。現在每個連結各自排在文字流裡,高低也不一致。只改 CSS 完成任務。

小測驗:分配空間

1.

容器寬 600px、沒有 gap,三個項目都是 flex-basis: 100px,flex-grow 依序是 1、1、2。第三個項目最後多寬?

2.

flex: 1 等於下面哪一個寫法?

3.

容器寬 300px,兩個項目的基準尺寸是 300px 和 100px,flex-shrink 都是 1(內容都很短)。最後的寬度是?

第 1 次作答

order:畫面順序和閱讀順序

order 讓項目在畫面上換位置:所有項目預設 order: 0,數字小的排前面,相同的照 HTML 的順序。

但它只改變視覺順序。下面這些都仍然照 HTML 原始碼的順序:

  • 按 Tab 鍵時,鍵盤焦點移動的順序
  • 螢幕閱讀器唸出內容的順序
  • 選取、複製文字的順序

如果畫面上「看起來的順序」和「唸出來、Tab 過去的順序」不一樣,用鍵盤或螢幕閱讀器的人會覺得頁面跳來跳去。 無障礙規範 WCAG 的成功準則 1.3.2「有意義的順序」(Meaningful Sequence)就要求:內容的先後順序會影響意思時,程式能判斷出正確的閱讀順序。

所以實務上:

  • 內容的真實順序,直接在 HTML 裡排對。
  • order 只用在不影響意思的小調整(例如手機版把裝飾用的圖片移到文字後面)。
  • row-reverse、column-reverse 也有同樣的問題。

兩個常見版型:等高卡片與頁尾貼底

等高卡片列:容器 display: flex 之後,項目預設 align-items: stretch,三張卡片本來就一樣高。 麻煩的是卡片裡面:內容短的卡片,「報名」按鈕會停在中間。解法是讓卡片本身也變成直向的 flex 容器,按鈕用 margin-top: auto 推到底部:

.cards { display: flex; gap: 12px; }
.card  { flex: 1; display: flex; flex-direction: column; }   /* 卡片:等寬、內部直向排列 */
.card a { margin-top: auto; align-self: flex-start; }       /* 按鈕:推到底部、不要被拉滿整個寬度 */

一個元素可以同時是 flex 項目(對外)和 flex 容器(對內),這是 Flexbox 版面的常見寫法。

頁尾貼底(sticky footer):內容很少時,頁尾不要浮在畫面中間,而是貼在視窗底部:

body { min-height: 100vh; display: flex; flex-direction: column; margin: 0; }
main { flex: 1; }   /* 主內容吃掉剩下的高度,把頁尾推到底 */

100vh 是視窗高度的 100%。內容多到超過一個畫面時,頁尾就自然排在內容後面,不會蓋住內容。

互動練習:三張一樣寬的活動卡片

三張活動卡片現在由上往下疊。把它們排成一列:一樣寬、一樣高,而且「報名」按鈕都對齊在卡片底部。

小測驗:調整單一項目與常見版型

1.

一列三個連結,第三個設定 order: -1 之後顯示在最前面。這時按 Tab 鍵,焦點的順序是?

2.

導覽列裡有 logo、三個連結和一個「登入」按鈕。想讓「登入」貼到最右邊、其他維持在左邊,最直接的做法是?

3.

容器設定 align-items: center,但其中一張卡片想貼齊上緣。這張卡片要設定什麼?

第 1 次作答

重點整理

  • flex-basis 是基準尺寸;剩餘空間 = 容器 − 基準尺寸總和 − gap。
  • 有剩:依 flex-grow 的比例分;不夠:依 flex-shrink × 基準尺寸 的比例扣,flex-shrink: 0 表示不縮。
  • flex: 1 = 1 1 0%(幾個就幾等分);flex: auto = 1 1 auto;flex: none = 0 0 auto。
  • margin-left: auto 把項目推到最右邊;align-self 調整單一項目的交叉軸對齊。
  • order 只改視覺順序,鍵盤與螢幕閱讀器仍照 HTML 順序;真實順序直接在 HTML 排好。
  • 常見版型:導覽列(flex+margin-left: auto)、等高卡片(flex: 1+卡片內直向 flex)、頁尾貼底(body 直向 flex+main flex: 1)。

下一課換另一種版面工具 Grid:Flexbox 一次管一個方向,Grid 同時管欄與列,適合排成格子的版面。

這一課完成了!
Next lesson:Grid(一):欄、列與格線
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。