どうも、くまだです。
CSSのGridレイアウトを使ったカード型UIの作り方メモ。
カード型レイアウト
コードは以下になります。
<ul class="card-list">
<li class="card">
<img src="thumbnail.jpg" alt="記事のサムネイル">
<div class="card__body">
<h2 class="card__title">カードのタイトル</h2>
<p class="card__text">カードの説明文が入ります。テキストの長さはカードによって変わることがあります。</p>
<a href="#" class="card__btn">もっと見る</a>
</div>
</li>
<li class="card">
<img src="thumbnail.jpg" alt="記事のサムネイル">
<div class="card__body">
<h2 class="card__title">2枚目のカード</h2>
<p class="card__text">短めのテキスト。</p>
<a href="#" class="card__btn">もっと見る</a>
</div>
</li>
<li class="card">
<img src="thumbnail.jpg" alt="記事のサムネイル">
<div class="card__body">
<h2 class="card__title">3枚目のカード</h2>
<p class="card__text">このカードはテキストが少し長めに入ります。カードの高さが変わると、ボタンの位置もバラつきます。高さを揃えるのがポイントです。</p>
<a href="#" class="card__btn">もっと見る</a>
</div>
</li>
</ul>.card-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 24px;
list-style: none;
padding: 40px;
margin: 0;
}
.card {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
display: flex; /* カード全体をflexコンテナに */
flex-direction: column; /* 縦方向に並べる */
}
.card img {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
.card__body {
padding: 16px;
display: flex; /* bodyもflexコンテナに */
flex-direction: column;
flex: 1; /* 残りの高さを全部使う */
}
.card__title {
font-size: 1.1rem;
margin: 0 0 8px;
}
.card__text {
font-size: 0.9rem;
color: #555;
margin: 0 0 16px;
}
.card__btn {
display: inline-block;
padding: 8px 16px;
background: #333;
color: #fff;
text-decoration: none;
border-radius: 4px;
font-size: 0.85rem;
align-self: flex-start; /* ボタンを左寄せにする */
margin-top: auto; /* ボタンを常に下に固定 */
}
grid + auto-fit/auto-fill + minmax() で自動折り返し
カードを横並びにして、画面幅に応じて自動で折り返すレイアウトです。メディアクエリを書かなくていいのがポイントです。
.card-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 24px;
list-style: none;
padding: 0;
margin: 0;
}
.card {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.card img {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
.card__body {
padding: 16px;
}
.card__title {
font-size: 1.1rem;
margin: 0 0 8px;
}
.card__text {
font-size: 0.9rem;
color: #555;
margin: 0 0 16px;
}
.card__btn {
display: inline-block;
padding: 8px 16px;
background: #333;
color: #fff;
text-decoration: none;
border-radius: 4px;
font-size: 0.85rem;
}- repeat():カラムを繰り返し生成する
- auto-fit:カードの数に合わせてカラム数を自動調整する
- minmax(280px, 1fr):最小幅280px、最大幅は余白を均等分割
画面幅が広ければカードが3列・4列に並び、狭くなると自動で2列・1列に折り返します。ブレークポイントを指定しなくてもレスポンシブになるのが、Gridレイアウトの強みです。
auto-fit と auto-fill の違い
auto-fit と auto-fill はよく混同されます。
〇 auto-fit
カードが少ない場合、空のカラムを折りたたんで、カードが横いっぱいに広がります。
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));カードが2枚しかないとき → 2枚が横いっぱいに広がる
〇 auto-fill
カードが少ない場合でも、空のカラムを保持したまま並べます。
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));カードが2枚しかないとき → 左から2枚が並び、右側に空のカラムが残る
- カードを均等に広げたい:auto-fit
- カードの幅を固定したい(空欄保持):auto-fill
カード内の要素の高さ・ボタン位置を揃える
.card {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
display: flex; /* カード全体をflexコンテナに */
flex-direction: column; /* 縦方向に並べる */
}
.card__body {
padding: 16px;
display: flex; /* bodyもflexコンテナに */
flex-direction: column;
flex: 1; /* 残りの高さを全部使う */
}
.card__text {
font-size: 0.9rem;
color: #555;
margin: 0 0 16px;
}
.card__btn {
display: inline-block;
padding: 8px 16px;
background: #333;
color: #fff;
text-decoration: none;
border-radius: 4px;
font-size: 0.85rem;
align-self: flex-start; /* ボタンを左寄せにする */
margin-top: auto; /* ボタンを常に下に固定 */
}これで、カード内のテキストが何行でも、ボタンの位置が常にカードの下部に揃います。
応用:Bento Grid風レイアウト
Bento Gridは、異なるサイズのカードを格子状に並べるレイアウトです。
grid-columnと grid-row`でカードのサイズを指定することで実現できます。
<div class="bento">
<div class="bento__item bento__item--wide">
<h2>メインカード(横幅2列分)</h2>
<p>大きなカードにはメインコンテンツを配置します。</p>
</div>
<div class="bento__item">
<h2>カードA</h2>
<p>標準サイズのカード。</p>
</div>
<div class="bento__item bento__item--tall">
<h2>縦長カードB</h2>
<p>縦方向に2行分使うカード。</p>
</div>
<div class="bento__item">
<h2>カードC</h2>
<p>標準サイズのカード。</p>
</div>
<div class="bento__item">
<h2>カードD</h2>
<p>標準サイズのカード。</p>
</div>
</div>.bento {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 200px;
gap: 16px;
}
.bento__item {
background: #f0f0f0;
border-radius: 12px;
padding: 24px;
display: flex;
flex-direction: column;
justify-content: flex-end;
}
/* 横幅2列分のカード */
.bento__item--wide {
grid-column: span 2;
}
/* 縦幅2行分のカード */
.bento__item--tall {
grid-row: span 2;
}
ここまで読んでくださりありがとうございました。