多數人以為,一個網站的排版一開始就得選邊站,這個專案要走 Grid 派,還是 Flexbox 派?不少新手教學也真的把兩者當成對立的兩派來比較,讓人誤以為開工前得先站好隊,才敢動手寫第一行 CSS。
但打開任何一個像樣的商業網站原始碼,幾乎找不到只靠單一種排版方法撐到底的頁面。外層的商品卡片牆、圖片畫廊,多半是 CSS Grid 搭出的二維骨架;牆內每一張卡片裡,標題、內文、按鈕怎麼上下排、按鈕又怎麼貼齊卡片底部,常常交給 Flexbox 做一維處理。兩者根本不是二選一的門派,而是同一個頁面裡各司其職的兩種工具。CSS Grid 和 Flexbox 的差異,不在誰比較新、誰比較強,而在解決的排版問題本來就不同維度,Grid 天生用來處理「橫也要對齊、直也要對齊」的二維版面,Flexbox 則專攻「只沿著一個方向排」的一維版面。
搞懂這個分界,你就不會在該用 Grid 的地方硬套 Flexbox、堆出一層層多餘的巢狀元素才勉強拼出對齊效果,也不會在只需要一列按鈕靠右的場合,大費周章畫一張根本用不到的網格。接下來先從兩者各自的定義講起,再攤開四個實際會影響切版決策的差異,最後再回頭解決最開頭那個提問——一個頁面裡,兩者究竟該怎麼分工。

CSS Grid 是什麼?
想像一個電商網站的商品卡片牆,你想要一次排出四欄、每欄等寬,而且不管商品出到第幾件,新增的一列卡片都得跟上一列乖乖對齊。CSS Grid 要處理的正是這種需求,它是一種「版面驅動」(layout-in)的二維排版模型,做法是先用 display: grid 搭配 grid-template-columns、grid-template-rows 畫出一張由行與列組成的網格骨架,再把內容放進格子裡,或是交給瀏覽器的自動放置規則排。
換句話說,Grid 的思考順序是先決定這裡要幾欄、每欄多寬,內容才對號入座填進格子,而不是先看內容多寬再回頭湊版面。分配格子寬度時常用到的 fr 單位,代表的是剩餘空間的等分比例,比如 grid-template-columns: 1fr 2fr 就是把可用寬度切成三份,第二欄拿走兩份。每個格子的位置也可以直接用格線編號指定,像是從第 2 條直線排到第 4 條直線,不必依賴自動排列規則。
Flexbox 是什麼?
換個情境,頁面頂端常見的導覽列,左邊放 Logo,右邊放選單,兩者不需要跟下面任何一列對齊,只要沿著同一條水平線排好就好。這種只需要控制單一方向的需求,正是 Flexbox 的拿手好戲,它是一種「內容驅動」(content-out)的一維排版模型,只沿著單一方向,一列或一欄,排列項目,做法是用 display: flex 搭配 flex-direction,寫成 row 就沿水平方向排、寫成 column 就沿垂直方向排,讓每個項目依自己內容的大小決定要占多少空間,空間不夠時再用 flex-wrap 讓項目換行。
Flexbox 的排列邏輯裡有兩條軸線,flex-direction 訂出來的那條叫主軸,垂直於它的那條叫交叉軸。想控制項目在主軸方向怎麼分布,像是靠左、置中還是左右對齊,用的是 justify-content;想控制項目在交叉軸方向怎麼對齊,像是頂部對齊還是垂直置中,用的是 align-items。這幾個屬性搭配起來,前面提到的「Logo 靠左、選單靠右」這種排法,幾乎兩三行就能寫完。
CSS Grid 和 Flexbox 有什麼差異?
「一個二維、一個一維」這句話幾乎每篇教學都會提一次,但講完就結束,對你實際切版沒有太大幫助。真正該弄清楚的,是這個差異在四個地方會怎麼影響你的決策,從換行後對不對得齊,到寫 CSS 時思考的順序,一路到卡片內容能不能跨卡片對齊在同一條線上。
排版維度:一維方向與二維網格
拿一個具體情境驗證最快。假設你要排五個項目,寬度不固定,排到第四個超出容器寬度時得自動換行。用 Flexbox 搭配 flex-wrap: wrap,換行後那一整批新出現的項目,會在新的一行裡重新分配空間,跟上一行的欄位沒有任何對齊關係,誰寬誰窄,兩行互不相干。換成 Grid,因為行列早在 grid-template-columns 裡就先定義好了,換行後的項目仍然乖乖對齊在同一欄,第一行第二欄跟第二行第二欄的左右邊界會是同一條線。

這就是判斷這個排版需不需要跨行列對齊的第一個提問。答案是需要,像是後台管理介面的表格式排版,Grid 幾乎是唯一選項;答案是不需要,像是標籤雲、按鈕群這種各行各自獨立的內容,Flexbox 反而比較輕巧。
佈局邏輯:內容決定尺寸,還是版面決定內容位置
這個差異再往下拆一層,會落到你寫 CSS 時思考的順序不一樣。用 Flexbox 排版,常常得靠 flex-grow、flex-shrink 這兩個屬性去說服瀏覽器該怎麼分配剩下的空間,一邊寫一邊在心裡盤算這個項目該多占一點、那個該讓一點。用 Grid 排版時,順序反過來,你是先把行列骨架訂死,內容進場後自己去對號入座,不太需要逐一協調每個項目要拿多少空間。
這裡有一個好用的判斷口訣,如果你發現自己在 Flexbox 裡一直靠 calc() 手動計算寬度,湊出某幾欄要對齊、某幾欄要固定比例的效果,通常代表這個排版一開始就該換成 Grid 來寫,而不是繼續在 Flexbox 裡疊加計算。
間距與對齊:gap 屬性現在兩邊都能使用
不少現有教學,包括一些看起來還算新的文章,仍然在講 Flexbox 沒有原生的間距控制,要在每個項目外側加 margin、再用負邊界去抵消最外圈多出來的空白才能對齊。這個說法現在已經過時,gap 屬性其實是 Flexbox 和 Grid 共用的標準寫法,兩邊都可以直接用 gap 設定項目之間的間距,不需要再靠 margin 湊。
主流瀏覽器桌面版與行動版目前都已經支援 Flexbox 的 gap,不論選 Grid 還是 Flexbox,間距這件事都已經是解決掉的問題,不必再因為擔心相容性而繞去用舊的 margin 寫法。
巢狀組合:subgrid 解決卡片內容無法對齊的老問題
過去 Grid 遇到巢狀結構,像是一排卡片,每張卡片裡再放一層自己的 grid,內層網格沒辦法跟外層網格的欄寬對齊,這是舊版教學普遍沒解決的痛點,卡片高矮不一時,標題、內文、按鈕的位置就會各卡片各自為政,對不上同一條線。
subgrid 解決的正是這個問題。把內層網格的 grid-template-columns 或 grid-template-rows 設成 subgrid,內層就會直接繼承外層網格的欄或列軌道,不用重新定義一次寬度。實務上最常見的場景是一排高矮不一的卡片,卡片內部的標題、內文、按鈕就算內容長短不同,也能跨卡片對齊在同一條線上,這件事目前只有 Grid 的 subgrid 能做到,Flexbox 天生只處理一維,沒有對應的機制。這項技術已被主流瀏覽器列為廣泛可用的標準功能,Chrome、Safari、Firefox、Edge 的現行版本都已支援,不再是只能挑一兩個瀏覽器用的實驗特性。

內容自己決定尺寸的時候,交給 Flexbox
把前面四個差異放進實際情境,判斷要用哪一種其實沒有想像中複雜。只要這個排版符合以下情況,通常就是把它交給 Flexbox 的訊號。
導覽列是最典型的例子,Logo 靠左、選單項目靠右或置中,彼此只需要沿著同一條水平線排好,不需要跟頁面其他區塊對齊。按鈕群組也一樣,一排送出、取消、返回的按鈕,只要控制它們之間的間距與靠左或靠右對齊即可,不涉及跨行列的版面規劃。
單一方向的卡片列是另一種常見場景,一排產品卡片沿著同一列排開,允許換行,但換行後的每一行不需要跟上一行對齊寬度,這種只管這一行、不管別行的需求正是 Flexbox 的強項。置中單一區塊的內容,比如一個彈出視窗裡的圖示加文字說明要垂直水平都置中,靠 justify-content 加 align-items 兩三行就能解決,不必為了置中這麼單純的需求動用整套網格系統。
這幾個場景的共同點很清楚,它們都只需要控制一個方向,而且每個項目要占多少空間,交給內容自己決定就好,不必事先規劃出一張二維的網格骨架。
版面需要同時控制兩個維度時,換成 Grid
反過來,當一個排版需求同時牽涉橫向要對齊與縱向也要對齊兩個維度,通常就是該換成 Grid 出場的時候。
整頁版面骨架是最常見的場景,頁首、側邊欄、主要內容、頁尾這幾大區塊要怎麼分配位置與比例,一次用 grid-template-areas 或格線編號定義好,比逐一疊 Flexbox 容器再手動對齊清楚得多。卡片牆與圖片畫廊也是典型例子,不管是電商的商品格,還是作品集的圖片牆,只要牆內有好幾欄又有好幾列,而且列與列之間要對齊,Grid 一層就能搞定。儀表板這類需要精準排版的介面,像是一個畫面裡同時塞進圖表、數據卡片、篩選面板,各區塊的大小比例又不盡相同,也是 Grid 的主場,因為它一開始就是設計來處理先有格子、再放東西的需求。
另外有一個反面訊號值得注意,如果你發現自己想用 Flexbox 硬做出這種二維效果,通常得巢狀好幾層容器,外層一個 flex、裡面再包一個 flex,還要靠寬度計算去湊出對齊的假象,做起來又慢又脆弱,稍微調整內容就容易跑版。遇到這種情況,回頭改用 Grid,往往幾行程式碼就能把巢狀好幾層才勉強湊出來的效果做對。
CSS Grid 和 Flexbox 不是二選一,是分工合作
回到最開頭那個提問,一個頁面裡兩者到底該怎麼分工,答案其實很單純,大多數專案本來就是兩者並存,不是選了 Grid 就得放棄 Flexbox,反過來也一樣。
具體示範開頭提過的那個情境,商品卡片牆的外層容器用 display: grid 排出響應式的多欄網格,決定要幾欄、每欄多寬;每一張卡片內部再用 display: flex,讓標題、內文、按鈕做垂直方向的排列,並且讓按鈕不管內文長短都貼齊卡片底部。外層負責二維的版面骨架,內層負責一維的內容排列,兩層各自處理自己最擅長的維度,不互相搶工作。

不少人第一次接觸 Grid 之後會有個疑惑,Grid 出來了,是不是代表 Flexbox 快要被淘汰。實際情況並非如此,兩者從一開始解決的就不是同一種問題,Grid 擅長的二維對齊,取代不了 Flexbox 在一維排列上的靈活;Flexbox 讓內容自己決定尺寸的彈性,也做不到 Grid 那種先訂骨架再對號入座的精準。共存才是常態,不是退而求其次的妥協。判斷口訣同樣可以套用在這裡,只要控制一個方向就找 Flexbox,同時要控制兩個方向就找 Grid,多數頁面兩者都用得到,而且往往就在同一個容器的內外兩層,各自做好各自的事。
下次打開編輯器準備寫版面之前,先別急著問這次要用 Grid 還是 Flexbox。先問這個排版是一維還是二維,答案自然會告訴你該伸手拿哪一個工具,而且多數時候,你會發現自己需要的不是二選一,而是兩個一起上。排版從來不是選邊站的問題,而是分工合作的問題。
