CSS Gridで、カードを幅に合わせて自動で並べる方法
カードを親の幅に合わせて自動で並べるには、CSS Grid で grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)) と書きます。メディアクエリを書かなくても、幅 220px 以上のカードが入るだけ横に並び、入りきらないカードは次の行に回ります。余った幅は、同じ行のカードに均等に配られます。
検証環境は Ubuntu 24.04、Node.js 22.23.4、Playwright 1.63.0、Chromium 153 です。HTML と CSS だけのページを Playwright で開き、親の要素の幅を変えながら、カードの幅や1行の枚数を getBoundingClientRect() と getComputedStyle() で読みました。Firefox と Safari では試していません。各ブラウザーの対応バージョンは、互換性データ(@mdn/browser-compat-data 8.1.8)の値です。

基本は grid-template-columns の1行
<div class="cards">
<div class="card">カード 1</div>
<div class="card">カード 2</div>
<!-- … -->
</div>
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 16px;
}
/* カードの見た目(後の flex-wrap の例のために border-box にしている) */
.card {
box-sizing: border-box;
padding: 16px;
border: 2px solid #00c8e8;
border-radius: 8px;
background: #eefafd;
}
grid-template-columns は、グリッドの列の幅を決めるプロパティです。ここに書いた値は、次の2つを組み合わせています。
minmax(220px, 1fr):1列の幅を「220px 以上、残りの幅を分け合った分(1fr)以下」にするrepeat(auto-fill, …):その列を、親の幅からあふれない範囲で、できるだけ多く繰り返す
検証環境で、カード 6 枚の親の幅を変えて測ると、次のようになりました。
| 親の幅 | 列の数 | カードの幅 |
|---|---|---|
| 455px | 1 | 455px |
| 456px | 2 | 220px |
| 691px | 2 | 337.5px |
| 692px | 3 | 220px |
| 927px | 3 | 約 298.3px |
| 928px | 4 | 220px |
| 960px | 4 | 228px |
| 1164px | 5 | 220px |
列が増えるのは、220px のカードと 16px の gap が、ちょうど入りきる幅になったときです。2列なら 220 × 2 + 16 = 456px、3列なら 220 × 3 + 16 × 2 = 692px で、表の境目と一致しました。列が増えた直後のカードは 220px ちょうどで、親が広がるにつれて余った幅を分け合って太くなり、次の列が入る幅になると、また 220px に戻ります。
列の数はこの最小の幅で決まるので、カードの中身が収まる幅を選びます。カードは列の幅いっぱいに広がり、padding と枠はその内側に収まります。カードの box-sizing を content-box(何も指定しないときの値)に戻しても、親の幅 960px でカードの幅は 228px のままでした。
同じ行のカードは、高さもそろいます。親の幅 960px で、1枚だけ文が長く4行に折り返されるカードを入れたところ、そのカードと同じ行の4枚がどれも高さ 132px になり、次の行の2枚は 60px のままでした。
カードが少ないときは、auto-fill と auto-fit で並び方が変わる
repeat() の1つ目には、auto-fill の代わりに auto-fit も書けます。MDN の repeat() の説明によると、auto-fit は auto-fill と同じように列を作り、カードを置いた後で、空の列をたたみます。
違いが出るのは、1行に入るカードの数より、カードの枚数が少ないときです。親の幅 960px にカードを 2 枚だけ置いて、列の幅を読みました。
| 書き方 | 列の幅 | カードの幅 |
|---|---|---|
auto-fill |
228px 228px 228px 228px | 228px |
auto-fit |
472px 472px 0px 0px | 472px |
auto-fill では、カードが入っていない2列が残り、カードは 228px のまま左に寄りました。auto-fit では、空の2列が 0px にたたまれ、2枚のカードが 472px ずつに広がって、横幅いっぱいになりました。

カードが 6 枚あって1行目が埋まるときは、どちらも列の幅が 228px × 4 で、違いはありませんでした。検索結果のように枚数が変わる一覧で、カードの幅をいつも同じにしておきたいなら auto-fill、少ないときは横に広げたいなら auto-fit を選びます。
狭い画面でカードがはみ出すときは、min() で最小幅を抑える
minmax(220px, 1fr) のままだと、親の幅が 220px より狭いときに、カードがはみ出します。親の幅を 200px にすると、列の幅は 220px のままで、カードの右端が親の外に 20px 出ました。MDN の repeat() の説明にも、どの回数でもあふれるときは、繰り返しの回数を 1 にすると書かれています。検証環境でも列は1つでしたが、その幅は 220px のままでした。
これを防ぐには、最小の幅を min() で「220px と、親の幅の小さいほう」にします。
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(220px, 100%), 1fr));
gap: 16px;
}
親の幅 200px で試すと、列の幅は 200px になり、カードは親の中に収まりました。親の幅 960px のときは、min() を付ける前と同じく 228px × 4 列で、広い画面での並び方は変わりませんでした。

flex-wrap で並べると、最後の行のカードが伸びる
同じような並びは、Flexbox の flex-wrap: wrap でも作れます。
.cards-flex {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.cards-flex > .card {
flex: 1 1 220px;
}
親の幅 960px にカードを 5 枚置くと、どちらも1行目に4枚、2行目に1枚が並びました。違いは2行目です。flex-wrap では、最後の1枚が行の残りを全部使って 960px に伸びました。Grid の auto-fill では、2行目のカードも1行目と同じ 228px で、1行目のカード 1 の真下に並びました。

flex-wrap の例では、カードの box-sizing: border-box が効いています。MDN の box-sizing の説明にあるとおり、content-box に戻すと、flex-basis の 220px は padding と枠を含まない幅になります。親の幅 960px で試すと、1行目に3枚(約 309.3px ずつ)、2行目に2枚が並び、4枚は入りませんでした。Grid の例では、上で書いたとおり幅は変わりませんでした。
カードの幅を行をまたいでそろえたい一覧には、Grid の auto-fill のほうが合います。
使えるブラウザーのバージョン
互換性データでは、grid-template-columns の repeat() は Chrome 57、Firefox 76、Safari 10.1 から使えます(Firefox は 52 から一部対応)。min() は Chrome 79、Firefox 75、Safari 11.1 からです。flex-wrap の例で使った Flexbox の gap は、Chrome 84、Firefox 63、Safari 14.1 からです。repeat() の対応状況は、MDN の repeat() のページにある互換性の表でも見られます。





