🌟

CSS flexとgridの使い分け

2022/12/07に公開

この記事は ミライトデザイン Advent Calendar 2022の5日目の記事です。
https://qiita.com/advent-calendar/2022/miraito-inc

実装するときにflexとgridの使い分けを把握していなかったので調べてみました!

本題に入る前に
html、cssレイアウトの時代別レイアウト手法を振り返った後に、flexとgridの使い分けについて話していこうかと思います。

テーブルレイアウト

自分はfloatの全盛期からこの業界に入ったため、使ったことがないです。
近年でもこのレイアウトを見ることはないため、詳細は割愛します。

気になる方はICS MEDIAさんの記事を読んでみてください。
若い世代が知らない2000年代のHTMLコーディングの地獄 - ICS MEDIA

float

flexが定着する前に横並びのレイアウトをする際によく使われていたCSSですね。
挙動を見る限り本来は画像に対して文章を回り込ませるようなレイアウトをしたい時に使われるCSSだったのかなと思ってます。

自分がfloatを使う時は次のようなレイアウトをしたい時ぐらいですかねぇ。

メリット

  • 古いブラウザにも対応している
    • flexやgridが各ブラウザで対応しているため、現在はそのメリットも薄くなった

デメリット

  • 配置の自由度が低い
    • 回りこむ特性上、横並びか画像に対して文章の回り込み以外に使い道がない
    • floatを使うとmarginの相殺が起きなくなるため、要素を使いまわしたい時に都度styleを上書きしないといけない

floatを適用している要素の後にfloatが適用されないようにするための対策が必要でした。

※これが無いとfloatを適用していないのに回り込みが適用されて意図しない挙動になります

clear:bothを設定する必要があったため、clearfixというclassにfloatを解除するためのプロパティを設定してfloatを使うときにはclearfixもセットでよく使われていたかと思います。

サンプルコード

floatを使った横並びの実装です。
久しぶりに書いてみましたが、記述量も多く相変わらず手間のかかる子ですねぇ。

<ul class="float-items clearfix">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  <li>item 4</li>
  <li>item 5</li>
  <li>item 6</li>
</ul>
// clear:bothが無いと、次の要素にもfloatが適用される
.clearfix:after {
    content:" ";
    display:block;
    clear:both;
}
.float-items {
  max-width: 600px;
  & > li {
    float: left;
    min-width: 180px;

    margin: 20px 0;
    background-color: rgba(180, 234, 88, 0.2);
    font-size: 1.5rem;
  }
  & li:not(:nth-child(3n)) {
    margin-right: 20px;
  }
}

デモはcodepenに書きましたので、気になる方は見て下さい。

flex先生が現れる前は重宝されていたfloat君ですが、flex先生が完全に対応してしまった昨今ではなかなか活躍する場が無くなって来たかなと言ったところですね。

flex

CSS3から登場した、縦横配置のレイアウトをするために作られたプロパティです。

大体のレイアウトはflexで出来てしまうため、とりあえずレイアウトする時はflexと言った感じで使われているのはでないでしょうか。

メリット

  • 様々なレイアウトに柔軟に対応できる
    • 要素の並び順指定(order
    • 要素間の幅(gap
  • 実装に必要な記述量が少ない

デメリット

  • 入れ子構造に複雑になる
    • flexを使いたい箇所にflexコンテナを用意する必要があるためdivがその分増えてしまう

自分がweb制作の業界に入った頃(2017年)にはflexもあったのですがIE対応がまだ不十分だった事もあり、当時はまだfloatが使われていました。

ただ自分はfloatが使い勝手が悪くてflexibility.jsでなんとか対応してflexを使ってました💪

IE8・9にもFlexboxを対応させる、flexibility.jsがとっても便利! | Webクリエイターボックス

登場した当初は不具合も多く、この記事は何度も助けられました。
flexboxのバグに立ち向かう(flexboxバグまとめ) - Qiita

サンプルコード

flexを使った横並びの実装です。

見て分かると思いますが、floatと比べると記述量も少なくて手軽に出来るのがいいところですね👍

<ul class="flex-items"> 
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  <li>item 4</li>
  <li>item 5</li>
  <li>item 6</li>
</ul>
.flex-items {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  max-width: 600px;

  & > li {
    min-width: 180px;
    background-color: rgba(88, 234, 222, 0.2);
    font-size: 1.5rem;
  }
}

flexの使い方はほげさんが解説しているので参考にしてみてください。
https://zenn.dev/suzuki_hoge/articles/2022-12-chrome-flexbox-5846a346663a67

grid

gridは格子状のマス目(Excelの表)があるとして、そのマス目に対してどのgrid要素を配置するかを決めることができるプロパティです。
↓格子状のマス目というのはこんなやつです

レイアウトを考える時ですが、flexとは違ってあらかじめどのマスにどの要素を割り当てるのかを考えるところから入ります。
具体的な話は使い分けの時にするので、ここでは簡単にイメージでだけ持ってもらえれたらと思います。

メリット

  • 2次元的なレイアウトができる
    • flexは縦か横の1次元レイアウト
  • htmlがシンプルになる
    • flexと違って親コンテナを必要としないため、divを追加する必要がない

デメリット

  • 古いブラウザだと対応していない
    • IE11のサポートが完全終了してくれるので、現在はあまり気にならない

サンプルコード

gridを使った横並びの実装です。
flexに比べると気持ち程度に記述量が少なくなりましたね。

横並び程度だったら、使い分けを気にしなくてもいいかなーと思います。

<ul class="grid-items">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  <li>item 4</li>
  <li>item 5</li>
  <li>item 6</li>
</ul>
.grid-items {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, auto));
  gap: 20px;

  max-width: 600px;
  & > li {
    background-color: rgba(234, 88, 88, 0.2);
    font-size: 1.5rem;
  }
}

flexとgridの使い分け

さて、長くなりましたが本題です。

まず最初に先程のリストを使って、テキスト量を要素ごとに違うものを用意しました。
それが次の画像です。

画像から次の事がわかります。

  • flexは幅がバラバラになる
    • 内容に応じて幅が変わるパンくずのようなものに適している
  • gridは幅が同じになる
    • 決まった幅の要素が並ぶ時に適している

flexやgridを使い分ける点で意識したい事はデザインで幅や高さを一定にしたいのかというのが1つの使い分けるポイントになるかと思います。

gridが得意とするレイアウト

gridは固定レイアウトを得意とするため次のようなレイアウトにはgridが適しています。
こちらの内容をflexとgridでそれぞれ実装してみます。

grid

grid-templateを使って配置の配分を設定できるため、簡単な記述だけで出来ちゃいますね!

<div class="layout">
  <div class="layout__header">header</div>
  <div class="layout__sideNavi">sideNavi</div>
  <div class="layout__mainContent">mainContent</div>
  <div class="layout__footer">footer</div>
</div>
.layout {
  display: grid;
  gap: 10px;
  grid-template:
    "header header" 200px
    "nav    main" 1fr
    "footer    footer" 150px
    /200px 1fr;
  &__header {
    grid-area: header;
    background-color: rgba(180, 234, 88, 0.2);
  }
  &__sideNavi {
    grid-area: nav;
    background-color: rgba(88, 234, 222, 0.2);
  }
  &__mainContent {
    grid-area: main;
    background-color: rgba(88, 234, 222, 0.7);
  }
  &__footer {
    grid-area: footer;
    background-color: rgba(234, 88, 88, 0.2);
  }
}

flex

gridは親要素に設定を出来るのですが、flexは子要素に対して設定しないといけないため可読性はあまり良くないですね。

flexでも出来ないことはないですが、決まりきったレイアウトの場合はgridの方が良さそうです。

  <div class="flex">
    <div class="layout">
      <div class="layout__header">header</div>
      <div class="layout__body">
        <div class="layout__sideNavi">sideNavi</div>
        <div class="layout__mainContent">mainContent</div>
      </div>
      <div class="layout__footer">footer</div>
    </div>
  </div>
.flex {
  .layout {
    display: flex;
    flex-direction: column;
    height: 100%;
    gap: 10px;
    &__header {
      flex: 0 0 auto;
      width: 100%;
      height: 200px;
      background-color: rgba(180, 234, 88, 0.2);
    }
    &__body {
      flex: 1 1 auto;
      display: flex;
    }
    &__sideNavi {
      flex: 0 0 auto;
      width: 200px;
      background-color: rgba(88, 234, 222, 0.2);
    }
    &__mainContent {
      flex: 1 1 auto;
      display: flex;
      flex-direction: column;
      margin-left: 10px;
      background-color: rgba(88, 234, 222, 0.7);
    }
    &__footer {
      flex: 0 0 auto;
      height: 150px;
      background-color: rgba(234, 88, 88, 0.2);
    }
  }
}

終わり

特徴を把握する事で、flexやgridの使い分けがより明確になるかと思います!

自分はgridの使い方はここ1ヶ月ぐらいで使い始めました。
flexで出来てしまうが故に後回しにしていましたが特徴を捉えることで使い分けが出来る様になりました!

皆さんもflexとgridを使い分けて効率よくコーディングをしちゃいましょう!

僕の記事ではflexの使い方については触れていないですがほげさんがflexの解説をしてくれています。
良かったら一緒に目を通してみてください👀
https://zenn.dev/suzuki_hoge/articles/2022-12-chrome-flexbox-5846a346663a67

Discussion