
CSSグリッド:推測なしで複雑なレイアウトを構築する
📷 Christina Morillo / PexelsCSSグリッド:推測なしで複雑なレイアウトを構築する
grid-template-columns、frユニット、auto-fillとauto-fitの違い — フォトギャラリーやダッシュボードなどの実際のレイアウトをゼロから構築。ビジュアルジェネレーター付き。
なぜグリッドの習得に時間がかかったのか
CSSグリッドを必要以上に避けていました。Flexboxがほとんどのニーズをカバーしていたし、グリッドのドキュメントを読み始めるたびに「暗黙のトラック」や「名前付きグリッドライン」などの用語に出くわして静かにタブを閉じていました。オーバーキルに感じられました。
考えが変わったのは、Flexboxでダッシュボードレイアウトを構築しようとしたときです。サイドバー、ヘッダー、メインコンテンツエリア、フッターがあり、それらを並べるためにフレックスコンテナを3レベル深くネストしていました。辛うじて動いたものの、デザインが変わるたびにHTMLを再構成しなければなりませんでした。そこで誰かがグリッドを教えてくれて、約1時間でCSS30行で全体を書き直しました。HTMLはほとんど変わらなかった。
それがFlexboxにはできないグリッドの強みです:コンテナから、アイテムのネストを気にせずに、二次元同時にレイアウトを定義できる。構造を定義すれば、アイテムがそこに収まります。
このガイドでは、グリッドを日常的に使うために実際に必要なことすべてをカバーします — コアプロパティ、変わっているが便利な関数、そして実際のプロジェクトで使用したパターン。読みながら視覚的に実験したい場合は、ToolBox HubsのCSSグリッドジェネレーターで列、行、ギャップをリアルタイムで設定し、生成されたCSSを確認できます。
メンタルモデル
コードの前に、まずメンタルモデルを理解しましょう:CSSグリッドは、グラフィックデザイナーがレイアウトグリッドについて考えるような思考を求めます。水平線と垂直線のシリーズを定義し、それらの線がセルを作成します。そしてコンテンツをそれらのセルに配置するか、ブラウザに自動配置させます。
これはFlexboxとは根本的に異なります。Flexboxはアイテム自体によってレイアウトが駆動されます — アイテムにプロパティを設定して、どのように伸縮または整列するかを指示します。グリッドはこれを反転させます。レイアウトはコンテナで定義され、アイテムがそれに従います。
グリッドの定義
1つのプロパティから始まります:
.container {
display: grid;
}
これだけでは多くのことはできません。アイテムはデフォルトで単一列にスタックされます。興味深いのはトラックの定義です。
grid-template-columnsとgrid-template-rows
これらは列と行のサイズを定義します。値はスペースで区切られたトラックサイズのリストです。
.container {
display: grid;
grid-template-columns: 200px 400px 200px;
grid-template-rows: 100px auto 60px;
}
これにより3列(200px、400px、200px)と3行(100px、コンテンツに必要な高さ、60px)が作成されます。アイテムは左から右、上から下にセルに配置されます。
px、em、rem、%、vwなど任意のCSSの長さの単位を使用できます。しかし、グリッドが導入した最も便利な単位は全く新しいものです。
frユニット
frユニットはフラクションの略です。グリッドコンテナ内の利用可能な空きスペースの一部を表します。パーセンテージよりもはるかに優れている理由はこちら:
/* パーセンテージのアプローチ — 計算が必要 */
.container {
display: grid;
grid-template-columns: 25% 50% 25%;
}
/* frのアプローチ — 比率を記述するだけ */
.container {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
}
どちらも同じレイアウトを作成しますが、frはギャップを正しく処理します。列間にgapを追加してパーセンテージを使用している場合、合計幅が100%を超えてオーバーフローが発生します。frでは、ブラウザはギャップを差し引いた後の空きスペースを計算し、それを配分します。計算がずっと少ない。
.container {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
gap: 24px;
/* ブラウザはまず2つの24pxギャップを差し引き、
残りを1:2:1の比率で分割します */
}
固定幅とfrユニットを混在させることもできます。これがほとんどの実際のレイアウトの仕組みです:
.layout {
display: grid;
grid-template-columns: 280px 1fr;
/* サイドバーは常に280px、コンテンツは残りすべてを取る */
}
そのパターン — 固定サイドバー、フレキシブルコンテンツ — は常に使っています。
repeat()関数
等しい幅の列が多い場合、手動で書き出すのは面倒です。repeat()はその省略形です:
/* repeat()なし */
.grid {
grid-template-columns: 1fr 1fr 1fr 1fr;
}
/* repeat()あり */
.grid {
grid-template-columns: repeat(4, 1fr);
}
repeat(4, 1fr)は「4つのトラック、各1fr幅」を意味します。複雑なパターンを繰り返すこともできます:
.grid {
grid-template-columns: repeat(3, 100px 1fr);
/* 作成される: 100px 1fr 100px 1fr 100px 1fr */
}
しかし、本当に強力なバージョンはrepeat()と2つの特別なキーワードを組み合わせます。
auto-fillとauto-fit
ここでグリッドが「便利」から「ほとんど魔法のよう」になります。正確な列数を指定する代わりに、収まるだけ多くの列を作成するようブラウザに指示できます:
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, 200px);
gap: 16px;
}
これにより、コンテナ幅に基づいて列数を自動的に調整するグリッドが作成されます。広い画面では5列、狭い画面では2列になるかもしれません。メディアクエリは不要です。
auto-fillとauto-fitの違いは微妙ですが意味があります:
auto-fillは収まるだけ多くのトラックを作成し、空のものも含みます。アイテムが3つしかなくても6列収まる場合、6列が作成されます — 最後の3つは空ですがスペースを占有します。
auto-fitも収まるだけ多くのトラックを作成しますが、空のトラックをゼロ幅に折りたたみます。6つ収まるグリッドに3つのアイテムがある場合、空のトラックが折りたたまれ、3つのアイテムが利用可能なスペースを埋めるために伸びます。
/* auto-fill: 空列はスペースを保持 */
.fill-grid {
grid-template-columns: repeat(auto-fill, 200px);
}
/* auto-fit: アイテムはコンテナを埋めるために拡張 */
.fit-grid {
grid-template-columns: repeat(auto-fit, 200px);
}
どちらを使うかはデザインによります。アイテムを一定のサイズに保ちたいフォトギャラリーにはauto-fillが通常より良いです。アイテムに行を埋めさせたいカードグリッドにはauto-fitが適切です。
minmax()
パズルの最後のピースはminmax()で、固定サイズではなくトラックのサイズ範囲を定義します。最小サイズと最大サイズの2つの引数を取ります。
.grid {
display: grid;
grid-template-columns: repeat(3, minmax(200px, 1fr));
}
これにより、少なくとも200px幅で最大で利用可能なスペースの1frである3列が作成されます。広い画面では拡張します。狭い画面では200px未満にはなりません。
repeat()、auto-fillまたはauto-fit、minmax()の組み合わせは非常に一般的で、標準的なレスポンシブグリッドパターンになっています:
.responsive-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 24px;
}
「収まるだけ多くの列を作成し、各々少なくとも240px幅で、利用可能なスペースを埋めるために均等に成長する」と読めます。アイテムは自動的に折り返します。メディアクエリなし。JavaScriptなし。急いでレスポンシブカードグリッドが必要な時に使うパターンです。
実世界の例:フォトギャラリー
これがどのように展開するかを示すために、フォトギャラリーをゼロから構築します。
<div class="gallery">
<img src="photo-1.jpg" alt="...">
<img src="photo-2.jpg" alt="...">
<!-- more photos -->
</div>
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 8px;
}
.gallery img {
width: 100%;
aspect-ratio: 1 / 1;
object-fit: cover;
display: block;
}
これだけです。グリッドはコンテナに収まる列数を自動的に計算します。画像はaspect-ratioを使って正方形のアスペクト比を維持し、object-fit: coverはトリミングを処理します。モバイルでは2列、広いデスクトップでは6列になるかもしれません。レイアウトはブレークポイントのリストではなく、本質的にレスポンシブです。
特定の写真を目立たせたい場合、複数のセルにまたがって配置できます:
.gallery img:first-child {
grid-column: span 2;
grid-row: span 2;
}
これにより最初の写真が2x2ブロックを占め、他のすべてがその周りに流れます。位置のトリック、フロートなし — グリッドの配置だけです。
実世界の例:ダッシュボードレイアウト
これがグリッドに納得させたユースケースです。サイドバー、ヘッダー、メインコンテンツ、フッターを持つダッシュボード。
<div class="dashboard">
<header class="dash-header">Header</header>
<nav class="dash-sidebar">Sidebar</nav>
<main class="dash-main">Main Content</main>
<footer class="dash-footer">Footer</footer>
</div>
.dashboard {
display: grid;
grid-template-columns: 260px 1fr;
grid-template-rows: 60px 1fr 40px;
grid-template-areas:
'header header'
'sidebar main'
'footer footer';
min-height: 100vh;
gap: 0;
}
.dash-header { grid-area: header; }
.dash-sidebar { grid-area: sidebar; }
.dash-main { grid-area: main; }
.dash-footer { grid-area: footer; }
grid-template-areasプロパティは特に読みやすくします。基本的にASCIIアートでレイアウトを描いています。ヘッダーとフッターは両方の列にまたがります。サイドバーは260px。メインコンテンツは残りすべてを埋めます。
これをレスポンシブにするのは簡単です:
@media (max-width: 768px) {
.dashboard {
grid-template-columns: 1fr;
grid-template-rows: 60px auto 1fr 40px;
grid-template-areas:
'header'
'sidebar'
'main'
'footer';
}
}
モバイルでは、すべてが単一列にスタックします。サイドバーはヘッダーの下に折りたたまれます。クリーン。
グリッドvsFlexbox:本当の答え
これをどちらか一方を選ばなければならないかのように扱う人がいます。そんなことはありません。異なる問題を解決します。
グリッドを使う場合:
- 行と列を互いに揃える必要がある
- ページレベルの構造(ヘッダー、サイドバー、メイン、フッター)を構築している
- 複数の行または列にまたがるアイテムが必要
- アイテムではなくコンテナからレイアウトを定義したい
- 各カード内に整列したコンテンツエリアを持つ一貫したカードのグリッドを構築している
Flexboxを使う場合:
- アイテムの単一行または列がある
- アイテムがコンテンツに基づいてサイズを決める必要がある
- ナビゲーションリンク、ボタン、フォーム入力をインラインで配置している
- アイテムを折り返す必要があるが、交差行の整列は気にしない
ほとんどのプロジェクトで両方を使います。グリッドはページのスケルトンを処理します。Flexboxはコンポーネントの内部 — ナビバー、カード内のボタングループ、フォームレイアウト — を処理します。競合ではなく、補完的です。
最も明確なルールとして聞いたのは:「グリッドはレイアウト用。Flexboxは整列用」。単純化ですが、ほとんどの場合正しい方向に導いてくれます。
CSSグリッドジェネレーターの使用
グリッドレイアウトを構築していて、コードにコミットする前に結果を見たい場合は、ToolBox HubsのCSSグリッドジェネレーターを開く価値があります。列と行の数を設定し、ギャップを調整し、列と行のサイズを視覚的に設定して、プロジェクトにペーストするための正確なCSS出力を取得できます。
grid-template-areasを扱う場合に特に便利です — どのエリアがどのセルにまたがるかを視覚化するのは、コードを眺めるよりも視覚ツールの方がずっと簡単です。レイアウトを一度設定してCSSをコピーし、ドロップするだけ。手動で書くより速く、構築前にレイアウトアイデアを素早くテストするのに良い方法です。
ブラウザサポートと実際の注意点
グリッドは強力なブラウザサポートを持っています — すべての最新ブラウザは2017年以降フルサポートしています。ベンダープレフィックスは不要です。ポリフィルも不要です。書いてリリースするだけです。
1つの本物の注意点:Internet Explorer 11。IE 11は最新のグリッド構文とほぼ互換性のない-ms-プレフィックスプロパティを使った古いグリッド実装を持っています。アナリティクスがIE 11トラフィックを示している場合、グリッドの使用には慎重な検討またはフォールバックが必要です。
IE 11をサポートしていない人 — 正直、今ではほとんどがそうですが — には、グリッドは注意点なしに本番環境対応です。
注意すべき1つのプロパティ:subgrid。子グリッドが親グリッドのトラック定義を継承して参加できるようになり、ネストされたコンテンツの整列に便利です。Safariは2023年にサポートを追加し、ChromeはそのThankfully、2026年初頭ではサポートは全体的に安定していますが、スコープ内に古いブラウザを持つプロジェクトを構築している場合は、特定のターゲットを確認してください。
実際に使うプロパティ
複数のプロジェクトでグリッドを使った後、最もよく使うプロパティ:
/* コア定義 */
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
grid-template-rows: auto;
/* 複雑なレイアウトのための名前付きエリア */
grid-template-areas: 'header' 'sidebar main' 'footer';
/* アイテムの配置 */
grid-column: span 2;
grid-row: span 2;
/* または明示的な配置 */
grid-column: 1 / 3; /* ライン1から始まり、ライン3で終わる */
grid-row: 2 / 4;
/* スペーシング */
gap: 24px;
column-gap: 24px;
row-gap: 16px;
暗黙のグリッドプロパティ(grid-auto-rows、grid-auto-columns)も知っておく価値があります。アイテムが明示的に定義されていない行に自動配置される場合、grid-auto-rowsがその高さを設定します:
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 200px; /* すべての自動配置行は200px高 */
}
そして自動配置アイテムを行ではなく列に埋めたい場合、grid-auto-flow: columnが配置方向を反転させます。
理解できた瞬間
グリッドが怖くなくなった瞬間は、すべてのプロパティを暗記しようとするのをやめて、3つのことを内面化したときです:
- 列と行はアイテムではなくコンテナで定義します。
frユニットは空きスペースを比例的に配分します。repeat(auto-fill, minmax(min, 1fr))はレスポンシブグリッドのパターンです。
他のすべて — 名前付きエリア、スパン、明示的な配置 — は必要に応じて調べられます。しかし、これら3つのコンセプトで実世界のグリッド使用の80%を乗り越えられます。
CSSグリッドは、一度理解すると仕事をしてくれているように感じるツールの1つです。2015年にはフロートや深くネストされたFlexboxで50行かかったレイアウトが、今ではグリッドで10行でできます。それは本当のクオリティオブライフの向上で、しばらくすると、それ以前のレイアウトがどうだったか思い出すのに苦労するでしょう。