TECH · CSS GridとFlexbox
GridとFlexboxの使い分け
CSS GridとFlexboxでレイアウトを組むサンプル集。管理画面の骨格、メディアクエリを書かないカードグリッド、中央寄せの4パターン、高さの揃わない敷き詰めを、そのまま貼れるコードで収録します。
サンプルとコード
ヘッダー・サイドバー・本文・フッターを grid-template-areas で名前を付けて配置します。HTMLの並び順とレイアウトが切り離されるので、狭い画面では領域名の並びを書き換えるだけで縦積みになります。
HTML
<div class="shell">
<header>
<span class="logo">Console</span>
<span style="margin-left:auto; color:#5a6478; font-size:0.86rem">田中 さん</span>
</header>
<nav aria-label="メインメニュー">
<ul class="nav-list">
<li><a href="#" aria-current="page">ダッシュボード</a></li>
<li><a href="#">注文</a></li>
<li><a href="#">商品</a></li>
<li><a href="#">お客様</a></li>
<li><a href="#">設定</a></li>
</ul>
</nav>
<main>
<div class="panel">
<h1>ダッシュボード</h1>
<p>ヘッダー・サイドバー・本文・フッターの4領域を、grid-template-areas で名前を付けて配置しています。HTML の並び順とレイアウトが切り離されているので、狭い画面では領域名の並びを書き換えるだけで縦積みになります。</p>
</div>
</main>
<footer>© 2026 Console — 管理画面の骨格サンプル</footer>
</div> CSS
/* 画面の骨格は「面」なので Grid。名前を付けた領域に置くと、
HTML の並び順とレイアウトを切り離せる。 */
.shell {
display: grid;
min-height: 100dvh;
grid-template-columns: 220px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"head head"
"side main"
"side foot";
}
.shell > header { grid-area: head; }
.shell > nav { grid-area: side; }
.shell > main { grid-area: main; }
.shell > footer { grid-area: foot; }
/* 狭い画面では1列に畳む。領域名で書いてあるので、
並べ替えは grid-template-areas を書き換えるだけで済む。 */
@media (max-width: 720px) {
.shell {
grid-template-columns: 1fr;
grid-template-areas:
"head"
"main"
"side"
"foot";
}
}
.shell > header {
display: flex; align-items: center; gap: 0.75rem;
padding: 0.9rem 1.2rem;
background: #fff; border-bottom: 1px solid var(--line);
}
.shell > nav {
padding: 1rem 0.8rem;
background: #fff; border-right: 1px solid var(--line);
}
.shell > main { padding: 1.4rem 1.2rem; }
.shell > footer {
padding: 0.8rem 1.2rem;
border-top: 1px solid var(--line);
color: var(--muted); font-size: 0.82rem; line-height: 1.7;
}
@media (max-width: 720px) {
.shell > nav { border-right: 0; border-top: 1px solid var(--line); }
} AIへの指示文
CSS Grid で管理画面の骨格を作ってください。
要件:
- grid-template-areas で head / side / main / foot の4領域に名前を付ける。
- 列は 220px と 1fr、行は auto / 1fr / auto。min-height: 100dvh で全高を取る。
- 各要素は grid-area で領域名を指定し、HTML の並び順に依存させない。
- 720px 未満では1列にし、grid-template-areas を head / main / side / foot へ
書き換えるだけで縦積みにする。位置指定を個別に上書きしない。
- サイドバーの現在地は aria-current="page" で示し、CSS はそれを見て塗る。
- 日本語の本文なので line-height は 1.85、letter-spacing は 0 にする。
メディアクエリを1行も書かずに列数が変わります。auto-fit と minmax の組み合わせで、幅に入るだけ列を作り、余ったトラックは畳みます。
HTML
<div class="cards">
<article class="card">
<h3>受注管理</h3>
<p>注文の一覧、絞り込み、CSV書き出しまで。</p>
<span class="foot">詳しく見る →</span>
</article>
<article class="card">
<h3>在庫連携</h3>
<p>倉庫システムと1時間ごとに同期します。差分だけを送るので回線に優しい構成です。</p>
<span class="foot">詳しく見る →</span>
</article>
<article class="card">
<h3>請求書の発行</h3>
<p>月末締めで自動生成。</p>
<span class="foot">詳しく見る →</span>
</article>
<article class="card">
<h3>権限管理</h3>
<p>編集者と閲覧者の2段階。招待はリンク発行だけで完了します。</p>
<span class="foot">詳しく見る →</span>
</article>
<article class="card">
<h3>監査ログ</h3>
<p>誰がいつ何を変えたかを90日間保持します。</p>
<span class="foot">詳しく見る →</span>
</article>
<article class="card">
<h3>通知</h3>
<p>メールとWebhookに対応。</p>
<span class="foot">詳しく見る →</span>
</article>
</div> CSS
/* 画面幅ごとの分岐を1行も書かずに列数が変わる。
auto-fit は「入るだけ列を作り、余ったトラックは畳む」。
min() を挟むのは、狭い画面で 240px が画面幅を超えて溢れるのを防ぐため。 */
.cards {
display: grid;
gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
}
/* auto-fill との違い:
auto-fit … 中身が少ないとき、残りのトラックを畳んでカードが伸びる
auto-fill … 空のトラックを残すので、カードは伸びず左に寄る
「1枚のときに全幅へ伸ばしたい」なら auto-fit を選ぶ。 */
.card {
background: #fff;
border: 1px solid var(--line);
border-radius: 12px;
padding: 1rem 1.1rem;
display: flex;
flex-direction: column;
gap: 0.35rem;
}
.card h3 { margin: 0; font-size: 1rem; line-height: 1.6; }
.card p { margin: 0; color: var(--muted); font-size: 0.88rem; line-height: 1.85; }
/* 最後の行を下端に押し付ける。高さが揃わないカードでも脚が揃う。 */
.card .foot {
margin-top: auto; padding-top: 0.6rem;
color: var(--accent); font-size: 0.82rem; line-height: 1.7;
} AIへの指示文
メディアクエリを使わないカードグリッドを作ってください。
要件:
- grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)) を使う。
- min(100%, 240px) にするのは、画面幅が 240px を下回ったときに
トラックが溢れるのを防ぐため。理由をコメントで書く。
- auto-fit と auto-fill の違いをコメントで説明する
(auto-fit は空トラックを畳んでカードが伸びる。auto-fill は空トラックを残す)。
- カードは flex-direction: column にし、最後の行に margin-top: auto を当てて
高さが揃わなくても脚が揃うようにする。
- gap で間隔を取り、margin では取らない。
place-items、Flexbox、min-height付き、絶対配置。どれを使うかは「子が複数か」「重ねる必要があるか」で決まります。4つを並べて違いが見えるようにしました。
HTML
<div class="grid2">
<div class="demo">
<h3>1. place-items: center(最短)</h3>
<div class="stage center-grid"><span class="chip">中央</span></div>
</div>
<div class="demo">
<h3>2. Flexbox(横並びのまま中央)</h3>
<div class="stage center-flex">
<span class="chip">左</span><span class="chip">右</span>
</div>
</div>
<div class="demo">
<h3>3. 高さのない親に min-height</h3>
<div class="center-minh" style="background:#f2f4f9"><span class="chip">中央</span></div>
</div>
<div class="demo">
<h3>4. 絶対配置(重ねるとき用)</h3>
<div class="stage center-abs"><span class="chip">中央</span></div>
</div>
</div> CSS
/* 1) いちばん短い。子が1つでも複数でも効く */
.center-grid {
display: grid;
place-items: center;
}
/* 2) Flexbox。横並びのまま中央に置きたいときはこちら。
gap も同時に効かせられる */
.center-flex {
display: flex;
align-items: center; /* 交差軸(縦) */
justify-content: center; /* 主軸(横) */
gap: 0.5rem;
}
/* 3) 高さを持たない親を中央にしたいとき。
親に min-height を与えるのを忘れない */
.center-minh {
display: grid;
place-items: center;
min-height: 150px;
}
/* 4) 絶対配置。ほかの要素の上に重ねたいときだけ使う。
translate(-50%, -50%) が要素自身の半分を戻す役割 */
.center-abs { position: relative; }
.center-abs > * {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
} AIへの指示文
要素を中央に置く方法を4パターン並べて比較できるサンプルを作ってください。
要件:
- 1つ目: display: grid と place-items: center。最短の書き方として紹介する。
- 2つ目: Flexbox の align-items: center と justify-content: center。
子を横並びのまま中央に置きたい場合で、gap も同時に効かせられる点を書く。
- 3つ目: 高さを持たない親に min-height を与えてから中央に置く。
- 4つ目: position: absolute と top/left 50% と translate(-50%, -50%)。
ほかの要素に重ねたいときだけ使う、と用途を限定して書く。
- 各パターンに見出しを付け、同じ見た目の要素を中央に置いて違いを比べられるようにする。
CSSのmasonryはまだ全ブラウザに来ていないため、いま確実に動く multi-column で組みます。読み順が「縦に流れて折り返す」形になる点だけ注意が要ります。
HTML
<div class="masonry">
<div class="tile"><div class="bar"></div><h3>短いメモ</h3><p>一行だけ。</p></div>
<div class="tile"><div class="bar"></div><h3>設計の覚え書き</h3><p>余白は4pxの倍数で刻む。行間は日本語なら1.8前後。この2つを最初に決めておくと、あとから全体を作り直さずに済みます。</p></div>
<div class="tile"><div class="bar"></div><h3>色の決め方</h3><p>まず1色だけ決めて、残りは明度で作る。</p></div>
<div class="tile"><div class="bar"></div><h3>読み込みの体感</h3><p>実際の速さより、待っていることが分かるかどうかが効きます。スケルトンを置くだけで印象が変わります。</p></div>
<div class="tile"><div class="bar"></div><h3>命名</h3><p>見た目ではなく役割で名付ける。</p></div>
<div class="tile"><div class="bar"></div><h3>フォーム</h3><p>ラベルは必ず上に置き、入力欄と for と id で結ぶ。プレースホルダーをラベル代わりにしない。入力を始めた瞬間に何の欄か分からなくなります。</p></div>
<div class="tile"><div class="bar"></div><h3>アイコン</h3><p>装飾なら aria-hidden を付ける。</p></div>
<div class="tile"><div class="bar"></div><h3>影</h3><p>距離を長く、不透明度を低く。近い影は安っぽく見えます。</p></div>
</div> CSS
/* CSS の masonry はまだ全ブラウザには来ていない。
いま確実に動くのは multi-column を使う方法。
段組みなので「縦に流れて折り返す」順序になる点だけ注意する。 */
.masonry {
column-count: 3;
column-gap: 1rem;
}
@media (max-width: 860px) { .masonry { column-count: 2; } }
@media (max-width: 560px) { .masonry { column-count: 1; } }
.masonry > * {
/* これが無いとカードが段の境目で分断される */
break-inside: avoid;
margin-bottom: 1rem;
}
.tile {
background: #fff;
border: 1px solid var(--line);
border-radius: 12px;
padding: 1rem 1.1rem;
}
.tile h3 { margin: 0 0 0.35rem; font-size: 0.98rem; line-height: 1.6; }
.tile p { margin: 0; color: var(--muted); font-size: 0.88rem; line-height: 1.85; }
.tile .bar {
height: 8px; border-radius: 999px; margin-bottom: 0.7rem;
background: linear-gradient(90deg, var(--accent), #22d3ee);
} AIへの指示文
高さの違うカードを隙間なく敷き詰めるレイアウトを作ってください。
要件:
- column-count と column-gap を使う。3列 → 860px 未満で2列 → 560px 未満で1列。
- 子要素には break-inside: avoid を必ず当てる。無いと段の境目で分断される。
- 間隔は margin-bottom で取る(multi-column では gap が縦方向に効かない)。
- 読み順が「縦に流れて折り返す」順序になるため、順序に意味がある一覧には
向かないことをコメントで明記する。
- カードの高さはばらつかせて、敷き詰めの効果が分かるようにする。
この技術について
GridとFlexboxは、どちらを覚えるべきか競う関係ではありません。扱う対象が違います。Gridは「面」を、Flexboxは「列」を扱う道具です。ページ全体の骨格のように縦横を同時に決めたいならGrid、ボタンとアイコンを一列に並べるように片方向へ流したいならFlexbox。この一点さえ掴めば、レイアウトで迷う時間はかなり減ります。
名前を付けると、HTMLの順序から自由になる
Gridでいちばん効くのは grid-template-areas です。領域に名前を付けて配置すると、HTMLの並び順とレイアウトが切り離されます。サイドバーをHTML上どこに書いても、画面のどこにでも置ける。
これが効くのは、画面幅で並びを変えるときです。狭い画面ではサイドバーを本文の下へ回したい、という要求は珍しくありませんが、位置指定を要素ごとに上書きしていくと、指定が増えるほど何がどこに出るのか読めなくなります。領域名で書いてあれば、grid-template-areas の文字列を書き換えるだけで並びが変わります。この記事の管理画面のサンプルは、まさにその形で組んであります。
メディアクエリを書かずに列数を変える
カード一覧の列数を画面幅で切り替えるのに、もうメディアクエリは要りません。repeat(auto-fit, minmax(min(100%, 240px), 1fr)) の一行で、幅に入るだけ列を作り、余ったトラックを畳んでくれます。
ここで min(100%, 240px) と書いているのには理由があります。単に minmax(240px, 1fr) と書くと、画面幅が240pxを下回ったときにトラックが画面から溢れて横スクロールが出ます。min() を挟むと、狭いときは自動的に100%まで縮むので溢れません。この一手間を忘れると、狭い端末でだけ壊れるという見つけにくい不具合になります。
中央寄せは4通りあり、使い分けがある
「中央に置く」だけで方法が複数あるのは、中央に置きたい状況が複数あるからです。子が1つなら place-items: center が最短。横並びのまま中央に置きたいならFlexboxで、gap も同時に効かせられます。親が高さを持っていないなら min-height を先に与える必要があり、ほかの要素に重ねたいときだけ絶対配置を使う。
絶対配置を最後に置いているのは、これがいちばん壊れやすいからです。親のサイズが変わっても追従はしますが、周囲の要素と場所を取り合わないため、内容が増えたときに重なります。重ねる意図があるときだけに限ってください。
敷き詰めだけは、まだ妥協が要る
高さの揃わないカードを隙間なく並べる、いわゆる石積み配置。CSSに専用の仕組みが入りつつありますが、全ブラウザで安定して使える段階ではありません。いま確実に動かすなら段組みを使うことになります。
ただし段組みは「縦に流れて折り返す」順序になるため、読み順が左上から右へ進みません。新着順の一覧のように順序が意味を持つ画面では使わないでください。写真ギャラリーのように順序が重要でない場面に限る、というのが現実的な線引きです。
使いどころとつまずきどころ
向いている場面
- 管理画面やダッシュボードの全体骨格
- 画面幅に応じて列数が変わるカード一覧
- ボタン・アイコン・ラベルの横並び
- 高さの揃わない画像やカードの敷き詰め
つまずきやすい点
- GridとFlexboxのどちらでもできる場面で迷い続ける
- auto-fit と auto-fill の違いを取り違える
- gap を margin で代用して端に余白が残る
- minmax の下限を固定値にして狭い画面で溢れる
よくある質問
GridとFlexboxはどちらを使えばいいですか。
縦横を同時に決めたいならGrid、片方向へ流したいならFlexboxです。ページ全体の骨格や表のような配置はGrid、ボタンとアイコンの横並びやツールバーはFlexbox。迷ったら「行と列の両方を指定したいか」を自問すると、たいてい答えが出ます。
auto-fit と auto-fill はどう違いますか。
中身が少ないときの挙動が違います。auto-fit は余ったトラックを畳むのでカードが伸びて全幅を埋め、auto-fill は空のトラックを残すのでカードは伸びず左に寄ります。「1枚しかないときに全幅へ広げたい」なら auto-fit を選んでください。
minmax の下限を固定値にしてはいけませんか。
画面幅がその値を下回ると溢れます。minmax(240px, 1fr) は 240px 未満の画面で横スクロールを生みます。min(100%, 240px) と書けば、狭いときは自動的に 100% まで縮むので安全です。
CSSのmasonryはまだ使えませんか。
仕様策定と実装が進んでいる段階で、全ブラウザで安定して使える状況ではありません。いま本番で敷き詰めが必要なら multi-column が確実です。ただし読み順が縦方向になるので、順序に意味がある一覧では避けてください。