瀑布流網格布局系統(Masonry Grid Layout System)
目的
瀑布流網格布局系統提供一個標準化、響應式的設計框架,用於展示高度不一的非均勻內容卡片(例如攝影作品集、使用者生成內容動態牆、混合媒體卡片或編輯式視覺探索看板)。標準的 CSS Grid 布局會強制行高對齊,當項目具有不同的長寬比或文字長度時,會在垂直方向產生不美觀的空白間隙。
設計一個有效的瀑布流網格需要解決將項目動態填入並行垂直欄位的空間挑戰,防止媒體資產載入時造成累計布局位移 (Cumulative Layout Shift, CLS),確保在行動裝置上優雅地減少欄位,並阻止視覺布局破壞邏輯 DOM 閱讀順序與鍵盤焦點導航順序 (WCAG 2.1 SC 1.3.2 與 SC 2.1.1)。
使用案例
- 攝影與視覺媒體作品集: 以緊密無縫的網格展示具有不同原生長寬比(直向、橫向、方形、全景)的圖片畫廊。
- 社交與 UGC 活動動態牆: 組織包含短文更新、完整文章、嵌入式圖片與影片預告的混合社交卡片。
- 電子商務 UGC 與評論牆: 以動態探索展示方式呈現顧客評論照片、標記的 Instagram 貼文與產品重點摘要。
- 編輯式探索與釘板: 建構靈感看板、書籤管理工具與靈感動態牆,其中的卡片包含具有可變垂直占地空間的多樣化內容元素。
何時不應使用
- 統一的長寬比網格: 如果所有項目都共用相同的長寬比(例如標準的 16:9 影片卡片或 1:1 產品目錄),請使用
responsive-grid-system或card-ui-system。 - 結構化的 2D 不對稱重點區: 對於精心策劃的英雄區塊,具有明確的 2D 矩形跨欄規則(例如一個 2x2 的主要特色區塊旁邊搭配 1x1 的統計區塊),請使用
bento-grid-layout-system。 - 嚴格的表格或對齊資料: 當使用者需要在水平列之間比較數值時(例如定價表或財務指標),請使用
data-table-ui-system或comparison-matrix-system。 - 連續的敘事與文章: 對於線性敘事,閱讀順序必須嚴格遵循單一垂直流程,請使用
article-layout-system或section-composition-system。
輸入
- 內容清單與長寬比: 媒體與文字內容的類型(圖片、影片、文字摘要、操作卡片)及其長寬比範圍(從 3:4 直式到 16:9 橫式)。
- 欄位架構需求: 目標跨螢幕尺寸的欄位數量(例如,寬螢幕桌上型電腦 4 欄,一般桌上型電腦 3 欄,平板 2 欄,手機 1 欄)。
- 互動性與焦點需求: 卡片內需要鍵盤無障礙功能的互動元素(按鈕、燈箱、內聯切換開關、連結)。
- 空間與主題 Token: 流體欄位間距與行間距 (
gap: clamp(12px, 2vw, 24px))、卡片背景填充、邊框圓角與焦點環 Token(來自fluid-spacing-system與focus-indicator-design-system)。
輸出
- 瀑布流布局架構規格書: 在純 CSS 多欄流程、CSS Grid 跨行 (
grid-auto-rows) 與 JavaScript 最短欄位填充之間進行策略選擇與技術藍圖規劃。 - 響應式欄位縮放矩陣: 定義斷點以實現平滑的欄位數量轉換與間距縮放。
- DOM 閱讀順序與鍵盤焦點地圖: 確保鍵盤導航 (
Tab/Shift+Tab) 遵循自然的視覺閱讀順序,不會出現混亂的欄位跳躍。 - 布局穩定性與長寬比保留規則: CSS 架構用於防止圖片與媒體載入期間的累計布局位移 (CLS)。
工作流程
1. 選擇架構策略
根據互動性與閱讀順序需求選擇合適的布局技術:
- 選項 A:純 CSS 多欄布局 (
column-count)- 最適合: 靜態畫廊、圖片為主的動態牆,或無互動的卡片,其中流程順序可以垂直向下依序填入第 1 欄、第 2 欄等。
- 實作:
column-count: 4; column-gap: var(--space-m);在子卡片上設定break-inside: avoid; margin-bottom: var(--space-m);。 - 取捨: 垂直的來源順序(欄位內從上到下)可能會使包含互動控制項的卡片造成鍵盤使用者的混淆。
- 選項 B:CSS Grid 搭配行跨欄 (
grid-auto-rows與grid-row: span X)- 最適合: 半靜態網格,其中卡片高度步階可以量化為固定的行軌道單位(例如
10px基底軌道)。 - 實作:
display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); grid-auto-rows: 10px; gap: 16px;。JavaScript 計算內容高度並套用grid-row: span Math.ceil(height / trackHeight)。 - 取捨: 保留原生的水平 DOM 順序,但需要輕量的 JS 高度計算或容器查詢。
- 最適合: 半靜態網格,其中卡片高度步階可以量化為固定的行軌道單位(例如
- 選項 C:JavaScript 最短欄容器分配
- 最適合: 高度互動的混合媒體動態牆,其中從左到右的閱讀順序至關重要,且卡片包含連結、按鈕和表單控制項。
- 實作: 建立 $N$ 個 flex 欄容器 (
display: flex; flex-direction: column; gap: var(--space-m);)。將傳入的卡片附加到當前總渲染高度最短的欄位中。 - 取捨: 需要用戶端 DOM 容器管理,但能保證完美的從左到右 DOM 焦點流程,且視覺上完全沒有垂直間隙。
2. 定義空間節奏與欄間距
在跨所有欄位與卡片內部邊距之間建立一致的間距 Token:
- 欄間距: 使用流體間距(例如
gap: clamp(16px, 2.5vw, 28px))。確保堆疊卡片之間的垂直間距等於水平欄間距,以維持均勻的空間密度。 - 卡片邊距與內部對齊: 使用流體 Token (
padding: var(--space-m)) 標準化內部卡片邊距。對於純媒體卡片(例如燈箱觸發器),允許圖片邊對邊顯示 (padding: 0; overflow: hidden;)。 - 圓角同步: 在外部卡片容器上套用一致的 border-radius(例如
12px至16px)。確保內部元素(例如頂部圖片)繼承同心圓角 (border-top-left-radius: calc(var(--card-radius) - 1px))。
3. 防止布局位移 (CLS) 與圖片失真
瀑布流網格在圖片載入期間非常容易受到累計布局位移的影響:
- 長寬比容器: 在圖片容器上明確宣告
aspect-ratio(aspect-ratio: 4 / 5; object-fit: cover; width: 100%; display: block;),或在媒體解析之前計算內聯 padding 比例。 - 骨架佔位符: 在遠端資產載入期間,渲染與預期卡片長寬比相符的樣式化骨架背景脈衝 (
background: var(--surface-subtle); animation: pulse 1.5s infinite;)。 - 圖片載入監聽器: 如果使用 JS 高度計算,請綁定
ResizeObserver或圖片load事件監聽器,以便在圖片完成渲染後重新計算欄位高度分配。
4. 調和 DOM 閱讀順序與焦點管理
確保符合 WCAG 1.3.2(有意義的順序)與 2.1.1(鍵盤):
- 避免視覺-DOM 脫節: 如果使用 CSS Columns,視覺布局會垂直向下流向欄位,請確保鍵盤焦點指示器保持清晰且合乎邏輯。如果卡片包含互動控制項,請優先使用 JavaScript 最短欄分配或 CSS Grid 行跨欄,以維持自然的從左到右、從上到下的頁籤順序(
Tab鍵順序)。 - 焦點指示器可見性: 標準化高對比、不被裁切的焦點指示器 (
outline: 3px solid var(--focus-ring-color); outline-offset: 3px;)。避免在未在剪裁邊界內增加足夠焦點指示器邊距的情況下對卡片使用overflow: hidden。 - 燈箱/模態視窗的鍵盤快捷鍵: 如果點擊瀑布流卡片會開啟模態覆蓋層或燈箱,請將鍵盤焦點限制在覆蓋層內 (
focus-trap),並在關閉時(Escape鍵)將焦點返回至原始發起卡片的觸發器。
5. 實作響應式欄位縮放
設計斷點以優雅地縮放欄位數量,同時不破壞內容平衡:
- 寬螢幕桌上型電腦 (≥ 1440px): 4 欄 (
column-count: 4或 4 個 flex 欄位軌道)。 - 一般桌上型電腦 (1024px – 1439px): 3 欄 (
column-count: 3或 3 個 flex 欄位軌道)。 - 平板 / 小螢幕 (640px – 1023px): 2 欄 (
column-count: 2或 2 個 flex 欄位軌道)。 - 手機 (< 640px): 1 欄 (
column-count: 1或單一垂直堆疊)。所有項目自然地以標準垂直間距堆疊。
決策規則
架構選擇矩陣
| 內容與互動類型 | 推薦的架構策略 | 理由 |
|---|---|---|
| 純圖片畫廊(燈箱觸發器) | CSS 多欄 (column-count) | 零 JS 足跡,原生瀏覽器多欄效能,乾淨的垂直圖片瀑布流。 |
| 互動卡片(按鈕、輸入框、連結) | JS 最短欄 Flex 分配 | 保留嚴格的從左到右 DOM 頁籤順序,防止螢幕閱讀器與鍵盤焦點跳躍。 |
| 動態載入動態牆(無限捲動) | CSS Grid 行跨欄 或 JS 欄分配 | 允許將新卡片順暢地附加到最短的欄位,無需重新排列整個頁面布局。 |
| 文字為主的編輯式釘板 | CSS Grid 行跨欄 (grid-auto-rows: 10px) | 維持水平閱讀順序,同時精確容納可變的文字長度。 |
限制條件
- 無障礙 (WCAG 2.1 AA 合規):
- SC 1.3.2 有意義的順序: 互動卡片的視覺排列必須與鍵盤頁籤導航順序 (
tabindex="0"焦點流程) 邏輯對齊。 - SC 1.4.3 對比度(最低): 呈現在卡片表面或圖片覆蓋層上的文字必須滿足最低 4.5:1 的對比度比例。對於直接放置在圖片上的文字,必須使用深色遮罩覆蓋層 (
background: linear-gradient(to top, rgba(0,0,0,0.8), transparent))。 - SC 2.1.1 鍵盤: 所有互動卡片元素(如按鈕、書籤觸發器、外部連結)必須完全可透過
Space和Enter鍵操作。 - SC 2.4.7 焦點可見: 互動卡片與觸發器必須顯示清晰的焦點環,且不被父層卡片的
overflow: hidden屬性裁切。 - SC 2.5.8 目標尺寸: 瀑布流卡片內的所有觸碰目標必須維持最低 24x24px 的互動區域(在觸控/行動裝置視埠上最低為 44x44px)。
- SC 1.3.2 有意義的順序: 互動卡片的視覺排列必須與鍵盤頁籤導航順序 (
- 布局位移效能: 瀑布流卡片內的圖片必須具有明確定義的內在長寬比或尺寸保留,以保證 CLS 保持在 0.1 以下。
常見失敗模式
- 鍵盤頁籤混亂: 對互動卡片使用 CSS
column-count,導致鍵盤Tab鍵先垂直移動穿過整個第一欄(從項目 1 到項目 10),然後才跳回第二欄的頂部。 - 累計布局位移 (CLS) 混亂: 在未設定長寬比樣式或載入骨架的情況下插入圖片,導致瀑布流欄位在每張圖片載入時反覆重新排列與跳動。
- 焦點環被裁切: 在瀑布流卡片上設定
overflow: hidden以強制圖片圓角,卻因此切斷了內部互動元素的標準外輪廓焦點環。 - 行動裝置上未限制的欄高: 未能將瀑布流網格在行動裝置上摺疊為單一欄位,導致卡片在超窄的多欄中擠壓,文字換行難以閱讀。
- 不均勻的欄位計數: 在動態動態牆中,新項目依序跨欄追加(1、2、3、1、2、3)而非檢查欄位高度,在較短欄位的底部產生大量垂直空白空間。
驗證標準
- 架構對齊: 選擇的策略(CSS Columns 對比 CSS Grid Row-Span 對比 JS Shortest-Column)符合卡片互動需求。
- 無非預期的垂直間隙: 卡片緊密排列,無橫向行對齊產生的空白間隙。
- 鍵盤頁籤導航: 互動卡片遵循邏輯的視覺頁籤順序(從左到右,從上到下)。
- 防止布局位移: 長寬比或骨架容器可防止遠端媒體載入時的 CLS (<0.1)。
- 響應式斷點適應: 網格從寬螢幕的 4 欄平滑縮放到手機 (<640px) 的單一垂直欄。
- WCAG AA 合規: 所有文字滿足 ≥4.5:1 對比度,觸碰目標滿足 ≥24x24px(行動裝置 ≥44x44px),且焦點環未被裁切且清晰可見。