カードUIはサービス一覧・ポートフォリオ・ブログ記事リストなど、現代のWebサイトで最も頻繁に使われるレイアウトパターンのひとつです。単純に並べるだけなら簡単ですが、「画面幅に応じて自動的に列数が変わる」「カードの高さを揃えてボタンを底に固定する」「ホバー時に浮き上がるアニメーション」といった実務水準の仕上がりを目指すには、CSS Gridの仕組みを深く理解する必要があります。このレッスンでは、CSS Gridの基礎からauto-fillとauto-fitの違い・カードコンポーネントの設計・レスポンシブグリッドの実装まで、実際のコードとともに徹底解説します。
CSS Grid カードレイアウト — 4つの核心概念
CSSグリッドは「グリッドコンテナ(親要素)」と「グリッドアイテム(子要素)」の2層構造で成り立ちます。親にdisplay: gridを指定するだけで、直接の子要素がグリッドアイテムになります。
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
| 記法 | 意味 | 例 |
|---|---|---|
repeat(3, 1fr) | 1fr幅の列を3本作る | 3等分のカラム |
repeat(3, 200px) | 200px固定の列を3本作る | 固定幅カラム |
1fr 2fr 1fr | 左右が1fr、中央が2frの3列 | センター強調レイアウト |
minmax(200px, 1fr) | 最小200px・最大1frの列 | auto-fillと組み合わせ |
fr(fraction)はグリッドの残り幅を分割する比率単位です。repeat(3, 1fr)はグリッドの幅からgapの合計を引いた残り幅を1:1:1に分割します。pxや%と組み合わせることもできます。
/* サイドバーレイアウト: 左240px固定, 右が残り全部 */
grid-template-columns: 240px 1fr;
💡
gapプロパティはrow-gapとcolumn-gapをまとめて指定できます。gap: 24pxは行・列ともに24px。gap: 32px 24pxなら行32px・列24pxになります。Flexboxのgapと同じ構文です。
メディアクエリなしでカードを自動折り返しするにはrepeat(auto-fill, minmax(240px, 1fr))またはrepeat(auto-fit, minmax(240px, 1fr))を使います。この2つは似ていますが動作が異なります。
/* auto-fill: カードが少なくても空列を確保する */
.grid-auto-fill {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 24px;
}
/* auto-fit: カードが少ない場合は空列を潰して拡張 */
.grid-auto-fit {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 24px;
}
| キーワード | カードが多い場合 | カードが少ない場合 | 推奨シーン |
|---|---|---|---|
auto-fill | 自動折り返し | 空の列が残る | グリッドの幅を固定したい場合 |
auto-fit | 自動折り返し | カードが幅いっぱいに広がる | カードが少ない時も見栄えを保ちたい場合 |
⚠️
minmax()の最小値にfrは使えません(frは他の列を配置した後の残り幅を分け合う単位で、最小サイズの基準にできないため、仕様上無効です)。minmax(240px, 1fr)のように、最小値にはpx・%・min-contentなどを指定し、最大値に1frを使うのが基本パターンです。
<article class="card">
<div class="card-thumbnail">
<img src="/images/work1.jpg" alt="プロジェクト名">
</div>
<div class="card-body">
<span class="card-tag">Web制作</span>
<h3 class="card-title">プロジェクト名</h3>
<p class="card-description">このプロジェクトの概要を2〜3文で説明します。</p>
<a href="/works/1" class="card-btn">詳しく見る</a>
</div>
</article>
すべてのカードの高さを揃えて、ボタンを常にカード下部に固定するにはflex-direction: columnとmargin-top: autoの組み合わせが鍵です。
.card {
background: #ffffff;
border-radius: 12px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
overflow: hidden;
display: flex;
flex-direction: column;
transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
.card-thumbnail {
aspect-ratio: 16 / 9;
overflow: hidden;
}
.card-thumbnail img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.4s ease;
}
.card:hover .card-thumbnail img {
transform: scale(1.05);
}
.card-body {
padding: 20px;
display: flex;
flex-direction: column;
flex: 1;
}
.card-description {
color: #64748b;
font-size: 0.875rem;
line-height: 1.7;
flex: 1;
}
.card-btn {
margin-top: auto;
display: inline-block;
padding: 10px 20px;
background: #2563eb;
color: #ffffff;
border-radius: 6px;
text-decoration: none;
font-size: 0.875rem;
font-weight: 600;
text-align: center;
transition: background-color 0.2s;
}
.card-btn:hover {
background-color: #1d4ed8;
}
💡
aspect-ratio: 16 / 9は画像コンテナの縦横比を固定します。縦横比を固定することで、縦長・横長・正方形など異なるサイズの画像を読み込んでもサムネイルの高さが均一になります。object-fit: coverと組み合わせると画像がトリミングされて均等に表示されます。
モバイルファーストで記述し、画面幅が広がるにつれて列数を増やすのが基本です。
/* モバイル: 1列 (デフォルト) */
.card-grid {
display: grid;
grid-template-columns: 1fr;
gap: 20px;
}
/* タブレット: 2列 */
@media (min-width: 640px) {
.card-grid {
grid-template-columns: repeat(2, 1fr);
gap: 24px;
}
}
/* PC: 3列 */
@media (min-width: 1024px) {
.card-grid {
grid-template-columns: repeat(3, 1fr);
gap: 28px;
}
}
メディアクエリを一切書かずに自動レスポンシブを実現する方法です。
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 24px;
}
| アプローチ | メリット | デメリット |
|---|---|---|
| メディアクエリで列数指定 | 列数を厳密にコントロールできる | コード量が増える |
| auto-fitで自動 | コードが少なく柔軟 | 1〜2枚時にカードが広がりすぎる場合がある |
| Tailwindのgrid-cols指定 | クラスだけで管理できる | Tailwind導入が前提 |
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
<article class="bg-white rounded-xl shadow-sm overflow-hidden">
...
</article>
</div>
💡 Tailwind CSSの
sm:・lg:などのプレフィックスはモバイルファーストのメディアクエリに対応しています。sm:grid-cols-2は「画面幅640px以上で2列」という意味です。クラス名を見るだけでレイアウトが把握できるため、チーム開発での可読性も高まります。
.card:first-child {
grid-column: span 2; /* 2列分の幅を占める */
}
| プロパティ | 値の例 | 効果 |
|---|---|---|
grid-column: span 2 | — | 横2マス分占める |
grid-row: span 2 | — | 縦2マス分占める |
grid-column: 1 / -1 | — | 行全体(全列)を占める |
align-self: stretch | — | そのアイテムの高さをグリッド行いっぱいに伸ばす |
<article class="card">のHTMLをサムネイル・タグ・タイトル・説明文・ボタンの構造で4枚作成してください。.card-gridにdisplay: gridとrepeat(auto-fit, minmax(280px, 1fr))を設定し、ブラウザ幅を変えながら自動折り返しを確認してください。.cardにdisplay: flex・flex-direction: columnを設定し、.card-btnにmargin-top: autoを追加して、カードの高さが異なるときもボタンが揃うことを確認してください。.card:hoverでtranslateY(-4px)とシャドウ変化のアニメーションを実装してください。CSS Gridはグリッドコンテナにdisplay: gridとgrid-template-columnsを指定することで列定義が完成します。fr単位で残り幅を比率分割し、gapで余白を管理します。auto-fitとminmax()の組み合わせはメディアクエリなしで自動レスポンシブを実現する強力なパターンです。カードコンポーネントはflex-direction: columnでボタンを底に固定し、aspect-ratioでサムネイルを均一化します。ホバーアニメーション・シャドウ・transformで高品質なインタラクションを加えることで、実務で使えるカードグリッドが完成します。次のレッスンでは、ここまで学んだヘッダー・グリッドを組み合わせた1ページサイトの完成と公開方法を学びます。
全問正解でこのレッスンが「完了」になり、コースの全レッスンを完了すると修了証が発行されます。解説つき・何度でも挑戦できます。
Q1.カードが2枚しかないときも、幅いっぱいに広げて見栄えを保ちたい。適した指定はどれですか。
Q2.カードごとに説明文の長さが違い、ボタンの位置が揃いません。本文に沿った解決策はどれですか。
Q3.grid-template-columns: 240px 1fr; はどのような列を作りますか。
完全無料・クレジットカード不要
デザイン基礎 - 視覚コミュニケーション入門
レイアウトはデザインの「骨格」です。
35分本文は無料で閲覧可
WordPress HP制作完全講座
ホームページ(HP)を作る前に最も重要なのが「なぜ作るのか」という目的の明確化です。
30分無料公開
WordPress HP制作完全講座
WordPressでHPを公開するには、サーバー(サイトのデータを保存・配信する場所) と ドメイン(サイトのアドレス) の2つが必要です。
30分無料公開
WordPress HP制作完全講座
サーバーとドメインの準備が整ったら、いよいよWordPressのインストールです。
30分無料公開
WordPress HP制作完全講座
WordPressのテーマはサイトの「外観と機能の土台」です。
30分本文は無料で閲覧可
WordPress HP制作完全講座
WordPressの「固定ページ(Pages)」は、投稿(ブログ記事)とは異なる、恒久的なコンテンツを掲載するためのページタイプです。
30分本文は無料で閲覧可
各レッスンの理解度チェックに合格すると ✓ がつきます