【CSS】カード型レイアウトの作り方|auto-fitで自動折り返し+高さ揃え

どうも、くまだです。

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;
}

ここまで読んでくださりありがとうございました。

この記事を書いた人