CSS講座 / Gridの応用:repeat・auto-fit・auto-fill・エリア

Gridのrepeatは同じトラック定義を繰り返し、auto-fitとauto-fillは使える幅から繰り返し数を決めます。大きなページ領域には、grid-template-areasで名前を付けて配置を表す方法もあります。

固定回数と幅に応じた繰り返し

.cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

repeat(3, …)は三列を作ります。四番目の項目が増えても列数を四つにするのではなく、通常は次の行へ回ります。

.cards {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 192px), 1fr));
}

auto-fitとminmax(min(100%, 192px), 1fr)の組み合わせは、通常192pxを最低幅とし、それより狭い親では親の100%を最低値にできます。最低値を192pxだけにすると、親がそれ未満のとき列自体がはみ出す場合があります。

幅800px、最低192px、gap16pxなら三列には608px、四列には816pxが必要なので三列が入る条件です。その後の余りの配分で実際の列幅が決まります。最低幅と最終幅は区別します。

auto-fitとauto-fillの空列を比べる

auto-fillは入る数の繰り返し列を用意し、項目がなくても空の列を残します。auto-fitは配置後の空の繰り返し列を折りたたみ、残った列へ空きを配れます。十分な項目で列が埋まる場合や一列しか入らない幅では、差が見えないこともあります。

この違いは「常に何列になるか」ではなく、同じ幅と項目数で空の列をどう扱うかで判断します。MDNのrepeatに自動繰り返しの条件が説明されています。

denseとHTMLの順番を区別する

grid-auto-flow: rowは通常の行方向の自動配置です。denseを加えると後の小さな項目を前の空きへ戻して配置できます。ただしHTMLの順番が変わるわけではなく、Tab移動や読み上げの順と見た目がずれる場合があります。

手順、時系列、入力欄のように順番が意味を持つ内容では、隙間を埋める見た目だけで選ばないでください。MDNのgrid-auto-flowを参照してください。

自動列とdenseの完全例

次をgrid-auto-repeat.htmlとして保存します。幅800pxに二項目なら、auto-fitは二列で各392px、auto-fillは三列で各約256pxと空列になる条件です。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>grid-auto-repeat.html</title>
  <style>
* { box-sizing: border-box; }
body { margin: 16px; font: 16px/1.6 sans-serif; color: #243447; }
h1 { font-size: 24px; } h2 { font-size: 20px; margin-top: 32px; }
a { color: #145f8f; } a:focus-visible { outline: 3px solid #b4470b; outline-offset: 3px; }
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 192px), 1fr));
 gap: 16px; width: min(100%, 800px); }
 .cards > div { min-width: 0; padding: 16px; background: #dceefa; overflow-wrap: anywhere; }
 .flow { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px;
 grid-auto-flow: row; max-width: 600px; margin-top: 16px; }
 .flow > a { padding: 12px; background: #e8f5de; }
 .flow > .wide { grid-column: span 2; }
  </style>
</head>
<body>
<h1>Comparing empty repeated columns</h1><div class="cards"><div>First card</div><div>Second card</div></div>
<h2>Default auto-placement</h2><div class="flow"><a class="wide" href="#result">1: two spaces</a><a class="wide" href="#result">2: two spaces</a><a href="#result">3: One space</a><a href="#result">4: one space</a></div>
<p id="result">This is the destination of the automatic-layout link.</p>
</body>
</html>
  1. 二つの比較領域の実際の幅を測ります。項目を四つに増やすと三列が埋まり、差が小さくなることを確認して二つへ戻します。
  2. 親を192px未満まで狭め、min(100%, 192px)が収まるか見ます。最低値だけを192pxへ変えて比較し、元へ戻します。
  3. .flowのrowをrow denseへ変えます。二列分の大きな項目の前にできた空きへ、小さな三番目の項目が入るか確認します。
  4. リンクへTabで移動し、文書順が1・2・3・4であることを確認してrowへ戻します。

名前付きエリアでページの骨格を作る

grid-template-areasは、引用符一組で一行、各名前でセルの担当を表します。子のgrid-areaを同じ名前にすると、その領域へ配置されます。各行のセル数をそろえ、同じ名前は一つの長方形にします。L字や離れた島にはできません。ピリオドは空のセルです。MDNのgrid-template-areasで文法を確認できます。

次をgrid-areas.htmlとして保存します。広い画面ではheaderとfooterが二列分、本文と補足がその間です。640px以下では、HTMLと同じheader・main・aside・footerの順に一列で並びます。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>grid-areas.html</title>
  <style>
* { box-sizing: border-box; }
body { margin: 16px; font: 16px/1.6 sans-serif; color: #243447; }
h1 { font-size: 24px; } h2 { font-size: 20px; margin-top: 32px; }
a { color: #145f8f; } a:focus-visible { outline: 3px solid #b4470b; outline-offset: 3px; }
.page { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
 grid-template-areas: "header header" "main aside" "footer footer"; gap: 16px; max-width: 1000px; }
 .page > * { min-width: 0; padding: 20px; background: #dceefa; overflow-wrap: anywhere; }
 header { grid-area: header; } main { grid-area: main; } aside { grid-area: aside; } footer { grid-area: footer; }
 @media (max-width: 640px) {
 .page { grid-template-columns: minmax(0, 1fr); grid-template-areas: "header" "main" "aside" "footer"; }
 }
  </style>
</head>
<body>
<h1>Page area names</h1><div class="page"><header>Site title</header><main><h2>Main content</h2><p>This is the main content area. The HTML order keeps it first on mobile, too.</p></main><aside>Related information</aside><footer>Contact and site information</footer></div>
</body>
</html>

asideのgrid-areaだけを別名へ変えると、意図した領域との対応がなくなります。元へ戻してください。テンプレートを一時的に「header header」「header aside」「footer footer」へ変えるとheaderがL字となり、指定が無効になることも調べられます。確認後は正しい長方形に復元します。

カードの自動列と、ページの大きな領域の命名は役割が違います。まずラインとトラックの基礎を確認し、内容を読みやすい順に保ったうえで必要な仕組みを選びます。