響應式 CSS 與版面配置

最後更新: 2023-04-16 14:49:19 +0800 +0800
原文以英文撰寫。您正在閱讀AI翻譯版本。

響應式版面配置應該源自內容限制,而不是裝置型號清單。Intrinsic sizing、flexbox、grid、媒體查詢與容器查詢提供互補的控制方式。

建立響應式基礎 #

viewport 宣告會讓 CSS viewport 符合裝置寬度:

html
<meta name="viewport" content="width=device-width, initial-scale=1">

不要加入 user-scalable=no 或過低的 maximum-scale;頁面縮放是一種無障礙機制。在螢幕鍵盤周圍定位控制項的應用程式,可能也需要 visual viewport API,因為可見區域可能改變,而 layout viewport 不一定會改變。

使用 border-box sizing,並限制替換內容的尺寸:

css
html {
  box-sizing: border-box;
}

*,
*::before,
*::after {
  box-sizing: inherit;
}

img,
video,
svg {
  display: block;
  max-inline-size: 100%;
  block-size: auto;
}

沒有這些規則時,padding 可能意外增加元件寬度,而具有較寬 intrinsic 尺寸的媒體可能從狹窄的 viewport 溢出。

將閱讀內容置中並加以限制 #

可讀的欄位需要最大行長,以及適用於小螢幕的內側間距:

css
main {
  inline-size: min(100%, 72ch);
  margin-inline: auto;
  padding-inline: 1rem;
}

ch 會近似 0 字形的 advance width。它適合用於正文行長;對於尺寸不應依賴所選字型的控制項,rem 和像素能更適切地表達尺寸。在全域 border-box 政策下,padding-inline 會在受限寬度內建立符合書寫模式的內側間距;無須選擇實體左、右屬性,即可支援由左至右、由右至左與直排文字。

避免在頁面的主要內容上設定固定的 min-width。例如 min-width: 480px 的宣告,會在窄於 480 CSS 像素的 viewport 上強制水平捲動。min()、max() 與 clamp() 可以在不對 viewport 作出不受支援的假設下維持限制:

css
h1 {
  font-size: clamp(2rem, 1.25rem + 3vw, 4rem);
}

選擇 Flexbox 或 Grid #

Flexbox 沿著主軸排列一維序列。Grid 定義列與欄,並可跨兩個軸對齊項目。

css
.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
}

flex-direction 決定主軸。justify-* 屬性沿主軸分配空間;align-* 屬性控制交叉軸。align-items 為子項目設定預設值,而 align-self 會覆寫單一項目的設定。flex-flow 結合 flex-direction 與 flex-wrap。

Grid 適合用於欄位應自動形成的卡片:

css
.cards {
  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax(min(18rem, 100%), 1fr)
  );
  gap: 1rem;
}

內部的 min() 可避免 18 rem 的最小值溢出窄於 18 rem 的容器。auto-fit 會折疊空的軌道,讓有內容的卡片使用可用寬度。

當 Grid 內容必須允許縮小到其 intrinsic minimum 以下時,使用 minmax(0, 1fr):

css
.sidebar-layout {
  display: grid;
  grid-template-columns: minmax(12rem, 1fr) minmax(0, 3fr);
}

針對環境限制加入媒體查詢 #

媒體查詢應在內容不再適合時引入版面配置變更:

css
@media (width < 48rem) {
  .sidebar-layout {
    grid-template-columns: 1fr;
  }
}

Range syntax 可直接表達邊界。常見的媒體特性包括 width、height、orientation、aspect-ratio、resolution、prefers-color-scheme、prefers-reduced-motion、hover 與 pointer。

輸入特性很重要,因為狹窄的觸控螢幕與狹窄的桌面視窗並不提供相同的互動方式:

css
@media (hover: hover) and (pointer: fine) {
  .menu-item:hover {
    text-decoration: underline;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    scroll-behavior: auto;
    animation-duration: 1ms;
    animation-iteration-count: 1;
    transition-duration: 1ms;
  }
}

不要使用 hover: none 證明裝置是手機。混合式裝置可能具備多種輸入機制。

使用容器查詢實作可重複使用的元件 #

元件可能出現在寬的頁面欄位中,也可能出現在狹窄的側邊欄中。因此,相較於 viewport,元件自身可用的空間更有用:

css
.card-region {
  container-type: inline-size;
}

.card {
  display: grid;
  gap: 1rem;
}

@container (width >= 32rem) {
  .card {
    grid-template-columns: 10rem minmax(0, 1fr);
  }
}

Containment 應放在查詢元件的祖先元素上。避免查詢同一元素的尺寸,同時又讓查詢所改變的樣式作用於該元素,因為這會建立循環 sizing logic。

容器查詢會設定後代元素的樣式,而不是查詢容器本身。子項目仍可能因其 intrinsic minimum sizes 而溢出,因此在內容必須縮小的位置套用 min-inline-size: 0 或適當的 wrapping policy。

測試版面配置行為 #

應在內容開始換行、溢出或留下過多空間的寬度下測試,而不只是測試命名的裝置預設值。請包含:

  • 長單字、URL、翻譯文字與較大的字型設定。
  • 鍵盤焦點,以及至少放大至 200% 的縮放。
  • 減少動態效果與兩種色彩配置。
  • 粗略與精細指標。
  • 空、最小與最大資料集。

響應式版面配置會在連續的寬度範圍內保持有效,而不是在少數幾張螢幕擷取畫面之間切換。

評論

在 GitHub 上閱讀或評論(發表評論需要登入)