CSS Grid を使ったレスポンシブ マルチカラム レイアウト

グリッドレイアウト(display: grid)を使ってレスポンシブな複数カラムのレイアウト(画面幅や親要素の幅に応じてカラム数が変化するレイアウト)を作成する覚書です。

Sass を使って複数のスタイルを動的に作成する方法やコンテナクエリを使う方法などについても。

作成日:2025年02月20日

画面サイズに合わせてカラム数を変更

以下は画面サイズに合わせてコンテナに収まる限り多くの同じ幅のカラムを作成する例です。画面サイズに応じて列幅とカラム数が変化します。

1
2
3
4
5
6

この例では、各カラムの幅の最小値は 200px、要素同士の間隔(ギャップ)は 10px としています。

<div class="column-w200">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
</div>
.column-w200 {
  display: grid; /* グリッドレイアウトを適用 */
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); /* 幅を自動調整 */
  gap: 10px; /* 要素同士の間隔 */
}

.column-w200 div  {
  min-height: 100px;
  background-color: #a2bcaa;
}

grid-template-columns プロパティは、グリッドの列を設定します。

repeat(auto-fit, minmax(200px, 1fr)) は repeat() で繰り返しを適用し、auto-fit は親要素の幅に応じてできるだけ多くの列を配置します。minmax() で最小幅 200px、最大幅 1fr(親要素の幅を均等に分割)の列を作成しています。

上記では子要素の div 要素に min-height: 100px; を設定していますが、代わりに親要素(コンテナー)に grid-auto-rows を使って以下のように記述することもできます(ほぼ同じ動作)。

.column-w200 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  grid-auto-rows: minmax(100px, auto);
  gap: 10px;
}

本題とは関係ありませんが、子要素の div 要素には以下を指定して水平・垂直方向に中央配置しています。

.column-w200 div  {
  min-height: 100px;
  background-color: #a2bcaa;
  color: #fff;
  /* 親要素をフレックスコンテナとする */
  display: flex;
  /* 交差軸方向の整列位置を中央に指定 */
  align-items: center;
  /* 主軸方向の整列位置を中央に指定 */
  justify-content: center;
}

gap の調整

以下は、gap を @media で調整できるようにする例です。

画面幅が 576px までは gap は 5px で、それ以上では 10px になります。

.column-w200 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 10px;
}

@media (max-width: 576px) {
  .column-w200 {
    gap: 5px;
  }
}

CSS ネスティングを使って以下のように記述することもできます。

.column-w200 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 10px;

  @media (max-width: 576px) {
    gap: 5px
  }
}
@container を利用

画面幅(ビューポート幅)によって gap を設定するのではなく、親要素や祖先要素(コンテナとなる要素)の幅によって gap を設定するには @container(コンテナクエリ)を使用します。

この例では基準となるコンテナ要素 .grid-container を作成してグリッドの親要素 .column-w200 をラップしていますが、幅の基準となる要素があればその要素をコンテナとして使用します。

<div class="grid-container">
  <div class="column-w200">
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
    <div>6</div>
  </div>
</div>

以下は .grid-container の幅が 576px までは gap は 5px で、それ以上では 10px になります。

.grid-container {
  container-type: inline-size;
  container-name: grid-container;
}

.column-w200 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 10px;

}

@container grid-container (max-width: 576px) {
  .column-w200 {
    gap: 5px
  }
} 
1
2
3
4
5
6

Sass で動的に生成

以下は Sass でカラムの最小幅を 200px から 300px の間で 20px ずつ異なるクラスを生成する例です。

@for $i from 0 through 5 {
  .column-w#{ 200 + $i * 20 } {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax((200 + $i * 20)px, 1fr));
    gap: 10px;
  }
}

@container grid-container (max-width: 576px) {
  [class^=column-w2] {
    gap: 5px;
  }
}

@for は指定された回数だけ繰り返し処理を実行します。@for $i from 0 through 5 で $i は 0 から 5 までの数字を1ずつ増やしながら処理を繰り返します。

.column-w#{ 200 + $i * 20 } は変数 $i の値をクラス名に埋め込むための書き方です。

#{ } は Sass の式の結果を CSS に埋め込むための構文で、セレクタやプロパティ名に変数を使って演算をする場合に使用します(インターポレーション)。

上記をコンパイルすると以下のような CSS が生成されます。

.column-w200 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 10px;
}

.column-w220 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 10px;
}

.column-w240 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 10px;
}

.column-w260 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 10px;
}

.column-w280 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 10px;
}

.column-w300 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 10px;
}

@container grid-container (max-width: 576px) {
  [class^=column-w2] {
    gap: 5px;
  }
}

以下は上記で生成したクラス column-w240(最小幅 240px)を使って画像とタイトルのコンテンツを表示する例です。

Photo 1

Photo 2

Photo 3

Photo 4

Photo 5

Photo 6

以下は上記の HTML です。

<div class="grid-container">
  <div class="column-w240">
    <div class="item">
      <div class="image-wrapper">
        <img src="../images/sample-01.jpg" alt="">
      </div>
      <h3 class="title">Photo 1</h3>
    </div>

    ・・・中略・・・

    <div class="item">
      <div class="image-wrapper">
        <img src="../images/sample-06.jpg" alt="">
      </div>
      <h3 class="title">Photo 6</h3>
    </div>
  </div>
</div>

CSS では画像の高さを揃えるため、追加で img 要素に aspect-ratioobject-fit を指定し、タイトルのスタイルを適当に指定しています。

[class^=column-w2] .item {
  .image-wrapper img {
    object-fit: cover;
    aspect-ratio: 16/10;
    width: 100%;
  }

  .title {
    font-size: 14px;
    padding: .75rem 0;
    text-align: center;
    font-weight: normal;
  }
}

カラム数とブレークポイントを指定

カラム数とブレークポイントを指定して、画面幅に応じてカラム数を変化させる例です。

  • 992px以上 :4カラム
  • 768px〜 992px :3カラム
  • 576px〜 767px :2カラム
  • 575px以下 :1カラム
1
2
3
4
5
6

この例では最大4列で表示するので、columns-4 というクラスを作成して指定しています。

また、@container(コンテナクエリ)を使用するのでグリッドを .multi-columns-container でラップしていますが、幅の基準となる要素があれば、その要素をコンテナとして使用(設定)します。

<div class="multi-columns-container">
  <div class="columns-4">
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
    <div>6</div>
  </div>
</div>

以下が CSS です。

.columns-4 の基本的な設定として、display: grid、gap: 1rem を指定し、grid-template-columns: repeat(1, 1fr) で1カラムとしています(画面幅が 576px 未満の場合)。

そして @media を使って画面幅が 576px 以上の場合は画面幅に応じて、repeat(2, 1fr)、repeat(3, 1fr)、repeat(4, 1fr) のようにカラム数を変化させます。

gap は基準となる .multi-columns-container の幅が 767px 以下の場合は 0.5rem としています。

.columns-4 {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(1, 1fr);
}

@media (min-width: 576px) {
  .columns-4 {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 768px) {
  .columns-4 {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 992px) {
  .columns-4 {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* コンテナ要素の宣言(幅の基準となる要素を宣言) */
.multi-columns-container {
  container-type: inline-size;
  container-name: multi-columns-container;
}

@container multi-columns-container (max-width: 768px) {
  .columns-4 {
    gap: 0.5rem;
  }
}

Sass で動的に生成

4列以外にも、2列、3列、5列を最大列数とするクラスのスタイルを Sass を使って動的に生成する例です。

.columns-1〜.columns-5 の5つのクラスを作成し、メディアクエリでカラム数を変更します。

  • .columns-1 は常に1カラム
  • 576px 以上 : .columns-2 以上は 2カラム
  • 768px 以上 : .columns-3 以上は 3カラム
  • 992px 以上 : .columns-4 以上は 4カラム
  • 1200px 以上 : .columns-5 は 5カラム

1カラム表示の場合は、.columns-1 を指定してもしなくても同じですが、プログラム的にクラスを生成する場合を考慮して .columns-1 も作成しています。

$grid-breakpoints は Sass のマップ(Maps)です。Sass のマップは各要素をカンマ区切りで、キーと値をコロン区切りのペアで括弧の中に記述したものです。

$grid-breakpoints は、ブレークポイントがキーで、そのサイズで適用するカラム数が値になっています。

18-22行目は @for で .columns-2 から .columns-5 のデフォルトを1カラムとしています。

25行目の @each はリストやマップから要素を1つずつ取り出して処理するときに使います。$bp には $grid-breakpoints のキー(576px, 768px, …)が、$cols には値(2, 3, 4, 5)が入ります。

@media (min-width: $bp) で各ブレークポイントごとに @media (min-width: 576px) や @media (min-width: 768px) などのスタイルを作成し、@for $i from $cols through 5 で現在のカラム数 ($cols) から 5 まで繰り返して、.columns-2 から .columns-5 を生成しています。

.multi-columns {
  display: grid;
  gap: 1rem;
  // columns-1 は常に 1 カラム
  &.columns-1 {
    grid-template-columns: repeat(1, 1fr);
  }

  // ブレークポイント設定
  $grid-breakpoints: (
    576px: 2,
    768px: 3,
    992px: 4,
    1200px: 5,
  );

  // 2〜5カラムのデフォルトを 1カラムに
  @for $i from 2 through 5 {
    &.columns-#{$i} {
      grid-template-columns: repeat(1, 1fr);
    }
  }

  // メディアクエリでカラム数を調整
  @each $bp, $cols in $grid-breakpoints {
    @media (min-width: $bp) {
      @for $i from $cols through 5 {
        &.columns-#{$i} {
          grid-template-columns: repeat($cols, 1fr);
        }
      }
    }
  }
}

/* コンテナコンテキストの宣言 */
.multi-columns-container {
  container-type: inline-size;
  container-name: multi-columns-container;
}

@container multi-columns-container (max-width: 768px) {
  .multi-columns {
    gap: 0.5rem;
  }
}

Sass を使って定義しておくと、新しいブレークポイントやカラム数を追加するのも簡単です。

例えば、$grid-breakpoints に 1400px: 6 を追加して、$i の through の値を 6 に変更すれば 1400px 以上で 6 カラムのクラスが追加されます。

上記をコンパイルすると、以下の CSS が生成されます。

.multi-columns {
  display: grid;
  gap: 1rem;
}
.multi-columns.columns-1 {
  grid-template-columns: repeat(1, 1fr);
}
.multi-columns.columns-2 {
  grid-template-columns: repeat(1, 1fr);
}
.multi-columns.columns-3 {
  grid-template-columns: repeat(1, 1fr);
}
.multi-columns.columns-4 {
  grid-template-columns: repeat(1, 1fr);
}
.multi-columns.columns-5 {
  grid-template-columns: repeat(1, 1fr);
}
@media (min-width: 576px) {
  .multi-columns.columns-2 {
    grid-template-columns: repeat(2, 1fr);
  }
  .multi-columns.columns-3 {
    grid-template-columns: repeat(2, 1fr);
  }
  .multi-columns.columns-4 {
    grid-template-columns: repeat(2, 1fr);
  }
  .multi-columns.columns-5 {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 768px) {
  .multi-columns.columns-3 {
    grid-template-columns: repeat(3, 1fr);
  }
  .multi-columns.columns-4 {
    grid-template-columns: repeat(3, 1fr);
  }
  .multi-columns.columns-5 {
    grid-template-columns: repeat(3, 1fr);
  }
}
@media (min-width: 992px) {
  .multi-columns.columns-4 {
    grid-template-columns: repeat(4, 1fr);
  }
  .multi-columns.columns-5 {
    grid-template-columns: repeat(4, 1fr);
  }
}
@media (min-width: 1200px) {
  .multi-columns.columns-5 {
    grid-template-columns: repeat(5, 1fr);
  }
}

.multi-columns-container {
  container-type: inline-size;
  container-name: multi-columns-container;
}

@container multi-columns-container (max-width: 768px) {
  .multi-columns {
    gap: 0.5rem;
  }
}

@container

以下は @media の代わりに @container を使う例です。※内容を変更(修正)しました。2025/02/21

前述の @media のコードとの違いは、@media を @container コンテナ名(multi-columns-container)に置き換え、min-width: の値を #{$bp} のように、インターポレーション #{ } を使っています。

また、この例では、ブレークポイントの値は @container 用に変更しています。

.multi-columns {
  display: grid;
  gap: 1rem;
  // columns-1 は常に 1 カラム
  &.columns-1 {
    grid-template-columns: repeat(1, 1fr);
  }

  // ブレークポイント設定(変更)
  $grid-breakpoints: (
    480px: 2,
    640px: 3,
    780px: 4,
    840px: 5,
  );

  // 2〜5カラムのデフォルトを 1カラムに
  @for $i from 2 through 5 {
    &.columns-#{$i} {
      grid-template-columns: repeat(1, 1fr);
    }
  }

  // コンテナエリでカラム数を調整
  @each $bp, $cols in $grid-breakpoints {
    // ※ $bp を #{} で囲まないとエラーにる
    @container multi-columns-container  (min-width: #{$bp}) {
      @for $i from $cols through 5 {
        &.columns-#{$i} {
          grid-template-columns: repeat($cols, 1fr);
        }
      }
    }
  }
}

/* コンテナコンテキストの宣言 */
.multi-columns-container {
  container-type: inline-size;
  container-name: multi-columns-container;
}

@container multi-columns-container (max-width: 768px) {
  .multi-columns {
    gap: 0.5rem;
  }
}

以下は上記 Sass をコンパイルして生成される CSS です。

.multi-columns {
  display: grid;
  gap: 1rem;
}
.multi-columns.columns-1 {
  grid-template-columns: repeat(1, 1fr);
}
.multi-columns.columns-2 {
  grid-template-columns: repeat(1, 1fr);
}
.multi-columns.columns-3 {
  grid-template-columns: repeat(1, 1fr);
}
.multi-columns.columns-4 {
  grid-template-columns: repeat(1, 1fr);
}
.multi-columns.columns-5 {
  grid-template-columns: repeat(1, 1fr);
}
@container multi-columns-container (min-width: 480px) {
  .multi-columns.columns-2 {
    grid-template-columns: repeat(2, 1fr);
  }
  .multi-columns.columns-3 {
    grid-template-columns: repeat(2, 1fr);
  }
  .multi-columns.columns-4 {
    grid-template-columns: repeat(2, 1fr);
  }
  .multi-columns.columns-5 {
    grid-template-columns: repeat(2, 1fr);
  }
}
@container multi-columns-container (min-width: 640px) {
  .multi-columns.columns-3 {
    grid-template-columns: repeat(3, 1fr);
  }
  .multi-columns.columns-4 {
    grid-template-columns: repeat(3, 1fr);
  }
  .multi-columns.columns-5 {
    grid-template-columns: repeat(3, 1fr);
  }
}
@container multi-columns-container (min-width: 780px) {
  .multi-columns.columns-4 {
    grid-template-columns: repeat(4, 1fr);
  }
  .multi-columns.columns-5 {
    grid-template-columns: repeat(4, 1fr);
  }
}
@container multi-columns-container (min-width: 840px) {
  .multi-columns.columns-5 {
    grid-template-columns: repeat(5, 1fr);
  }
}

/* コンテナコンテキストの宣言 */
.multi-columns-container {
  container-type: inline-size;
  container-name: multi-columns-container;
}

@container multi-columns-container (max-width: 768px) {
  .multi-columns {
    gap: 0.5rem;
  }
}

以下の HTML は、

<div class="multi-columns-container">
  <div class="multi-columns columns-5">
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
    <div>6</div>
  </div>
</div>

.columns-5 を指定しているので、以下のように親要素の幅により最大5列で表示されます。

1
2
3
4
5
6

以下は上記のグリッドレイアウトの CSS を使ってグリッドの親要素に multi-columns と columns-4 クラスを指定し、最大4カラムでカード型のコンテンツを表示する例です。

<div class="multi-columns-container">
  <div class="multi-columns columns-4">
    <div class="item">
      <div class="image-wrapper">
        <img src="../images/sample-01.jpg" alt="">
      </div>
      <h3 class="title">Title 1</h3>
      <div class="content">Lorem, ipsum dolor sit amet consectetur adipisicing elit.</div>
    </div>

    ・・・中略・・・

    <div class="item">
      <div class="image-wrapper">
        <img src="../images/sample-06.jpg" alt="">
      </div>
      <h3 class="title">Title 6</h3>
      <div class="content">Quis dicta sunt nobis doloribus, modi omnis eius unde corporis provident fugit.</div>
    </div>
  </div>
</div>

この例では、コンテナクエリ(@container)を使って、2カラム(親要素が 480px )以上の場合は、画像の高さを揃えるため、aspect-ratio と object-fit を指定しています。1カラムの場合は、画像はオリジナルの縦横比で表示されます。

 @container multi-columns-container (min-width: 480px) {
  .image-wrapper img {
    object-fit: cover;
    aspect-ratio: 16/10;
    width: 100%;
  }
}

Title 1

Lorem, ipsum dolor sit amet consectetur adipisicing elit.

Title 2

Tempore ut nobis illo quis ratione.

Title 3

Deserunt, ipsa. Exercitationem perspiciatis quod cupiditate, sunt et distinctio ab pariatur, est quas nesciunt quae vitae numquam?

Title 4

Molestias, aliquam minima illo soluta consequuntur laborum fuga

Title 5

Consectetur soluta impedit excepturi dolor saepe pariatur dicta corrupti.

Title 6

Quis dicta sunt nobis doloribus, modi omnis eius unde corporis provident fugit.