今覚えたい!エンジニアのための CSS の基礎講座 〜Flexbox レイアウト編〜

大好評の「エンジニアのためのCSS基礎講座」シリーズの続編です。今回は前回の記事でも少しだけ触れた Flexbox レイアウトについて解説したいと思います。

Flexbox は CSS3 から導入され、ヌーラボのサービスでも一部 Flexbox を使用しています。また最近では React Native のコンポーネントのレイアウトにもこの Flexbox が使われており大変注目が集まっています。なので「今更聞けない!」というより「今覚えたい!」技術になりますので、是非マスターしておきましょう。

Flexbox とは

Flexbox は正確には CSS Flexible Box Layout Module といいます。その名の通り、柔軟なボックスレイアウトを可能にする CSS の新しいレイアウトモードです。横並びのレイアウトを組む際に従来の方法であれば float や inline-block、または table-cell を駆使してやっていましたが、最近ではこの便利な Flexbox を使う方法が主流となりつつあります。

レスポンシブデザインとの親和性も高く、今まで CSS だけで実現するのは難しかった複雑なレイアウトを Flexbox を使って簡単に組むことができるようになりました。

対応ブラウザ

Can I use… を見ると、現在では全てのモダンブラウザで Flexbox を使うことができます。

Can I use...各ブラウザの Flexbox 対応状況

IE も IE10 から Flexbox を使うことができますが、いくつかバグがあります。ですが、基本的なレイアウトでしたら問題なく使うことができます。IE のバグとその対策については flexbugs が参考になります。

また IE9 以下にも Flexbox に対応させたい場合は flexibility.js などのライブラリを使う手もありますが、Flexbox の全ての機能を使えるようになるわけではないので、個人的には IE9 以下用には float や inline-block で代替するやり方をおすすめします。inline-block を使ったフォールバックの書き方については以下の記事が参考になります。

Flexbox のいいところ

「Flexbox を使うと何が嬉しいの?」とよく聞かれることがありますが、ざっと思いつくだけでも以下のようなメリットがあります。

  • CSS に一行スタイルを足すだけで簡単に横並び
  • 上下左右の位置揃えが簡単
  • CSS だけで横並びしている要素の高さを自動で揃えれる
  • 要素の並び順を HTML の変更無しで CSS で変えられる
  • カラムの横幅の指定が簡単&柔軟

これだけでも Flexbox を使う価値があるのではないでしょうか。また Flexbox レイアウトは float レイアウトに比べてパフォーマンスが良いと言われています。Flexbox と float のパフォーマンス比較に関しては以下の記事が参考になります。

では、今挙げたメリットを元に、実際に Flexbox を使いながら、どれくらい便利なのかを見ていきましょう。

Flexbox の基本的な使い方

CSS に一行スタイルを足すだけで横並び

前回の float の解説で作ったサンプルを使って説明していきます。以下がそのサンプルです。

See the Pen Float Layout by johnykei (@johnykei) on CodePen.

まずは、このサンプルと同じレイアウトを float は使わずに Flexbox を使って作ってみましょう。

See the Pen Flexbox Layout by johnykei (@johnykei) on CodePen.

見た目はほぼ一緒ですが、コード量は float を使った時に比べて6行も削減できています。やったことは親要素 .post に以下のたった一行のスタイルを加えただけです。

display: flex;

flex コンテナと flex アイテム

display: flex; を指定した要素は「flex コンテナ」、flex コンテナの直下の子要素は「flex アイテム」と呼びます。flex アイテムは特別な指定をする必要はなく、 flex コンテナの直下の子要素であれば自動的に flex アイテムとなり、横並びになります。

Flexbox のイメージ図

よって先ほどのサンプルは display: flex; を入れるだけで float を使った時のように横並びになったわけです。これが Flexbox レイアウトの基本です。

上下左右の位置揃えが簡単

左右の位置揃え

左右の位置揃えには justify-content プロパティを使います。justify-content プロパティは flex コンテナに指定し、flex アイテムの水平方向の配置方法を設定します。このプロパティには以下の値があります。どのような効果があるかは以下のサンプルで実際に試してみてください。

See the Pen justify-content sample by johnykei (@johnykei) on CodePen.

justify-content プロパティの値 効果
flex-start flex アイテムを左揃え (初期値)
flex-end flex アイテムを右揃え
center flex アイテムを左右中央揃え
space-between flex アイテムを等間隔に配置(最初と最後の要素は flex コンテナの端にくっつく)
space-around flex アイテムを等間隔に配置 (space-between とは違い、flex コンテナの端との間にもそれぞれ間隔が空く)

試しに、先ほど作ったサンプルに space-betweenを使ってみましょう。親要素 .post に以下のコードを加えてみます。

justify-content: space-between;

See the Pen Flexbox Layout horizontal left and right by johnykei (@johnykei) on CodePen.

(※ 右上の「EDIT ON CODEPEN」をクリックして広い画面でご覧ください。)

float: left:, float: right; を使わずに要素をそれぞれコンテナの左右に寄せることが簡単にできました。

さらに、float だけでは難しかった要素の左右中央揃えも justify-content を使えば一発です。

justify-content: center;

See the Pen Flexbox Layout horizontal center by johnykei (@johnykei) on CodePen.

(※ 右上の「EDIT ON CODEPEN」をクリックして広い画面でご覧ください。)

上下の位置揃え

前回 display: table-cell; を使ってテキストを画像の上下中央に配置したサンプルをお見せしました。Flexbox を使えばこれもたった一行で実現できます。親要素 .post に以下のコードを加えてみます。

align-items: center;

See the Pen Flexbox Layout Center Vertical by johnykei (@johnykei) on CodePen.

このように、 align-items プロパティを使うと今まで悩ましかった要素の上下中央揃えも簡単です。align-items プロパティについては次の章で詳しく説明します。

横並びしている要素の高さが自動で揃う

今まで横並びした要素の高さを揃えたい際には、js を使って高さを合わせたり、高さを固定したりしていました。Flexbox を使えば何もしなくても自動的に高さが揃います。

See the Pen YWpBwK by johnykei (@johnykei) on CodePen.

なぜ自動で高さが揃うかというと、先ほど上下中央揃えに使った align-items プロパティに stretch が初期値に指定されているからです。align-items プロパティは flex コンテナに指定し、flex アイテムの垂直方向の配置方法を設定します。そして、align-items: stretch は flex アイテムを flex コンテナの高さいっぱいに配置します。

このプロパティには以下の値があります。どのような効果があるかは以下のサンプルで実際に試してみてください。

See the Pen align-items sample by johnykei (@johnykei) on CodePen.

align-items プロパティの値 効果
stretch flex コンテナの高さいっぱいに flex アイテムを配置 (初期値)
flex-start flex アイテムを上揃え
flex-end flex アイテムを下揃え
center flex アイテムを上下中央揃え
baseline flex アイテム内の文字のベースラインを揃えて配置

試しに、先ほどのサンプルにも flex-end を使ってみましょう。

align-items: flex-end;

See the Pen RRgrkN by johnykei (@johnykei) on CodePen.

要素が下揃えになりました。プラン表などのレイアウトで使えそうですね。

要素の並び順を HTML の変更無しで CSS で変えられる

デザイン変更などで要素の並び順を変えないといけない場合が多々あります。そのような場合 HTML 要素を入れ替えるのが普通ですが、Flexbox レイアウトだと CSS のみで並び順を変えることができます。

試しに先ほどのサンプルの Cacoo を一番左に配置してみます。flex アイテムの並び順の変更には order プロパティを順番を変えたい flex アイテムに指定します。

order: -1;

See the Pen qNjovW by johnykei (@johnykei) on CodePen.

HTML の変更無しで並び順を変えることができました。

order プロパティの初期値は 0 なので、0 よりも少ない値(この場合 -1)を指定してやると一番前に配置されます。ただし既に同一  flex コンテナ内に order プロパティを指定している flex アイテムがある場合はそれよりも少ない値に指定する必要があります。

order プロパティの解説図

カラムの横幅の指定が簡単&柔軟

今作ったサンプルは幅をそれぞれ 300px で指定しています。なのでウィンドウ幅を狭めるとはみだしてしまうため、レスポンシブデザインにはなってません。ここで flex アイテムに指定する flex プロパティを使います。flex プロパティは flex-grow, flex-shrink, flex-basis プロパティの順のショートハンドです。

flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;

/* 上記の記述を flex プロパティでまとめて書くことができます。 */
flex: 1 1 auto; /* flex: (flex-grow の値) (flex-shrink の値) (flex-basis の値) */

試しに、幅の記述は削除して flex アイテムに以下のコードを指定してみます。

flex: 1 0 0%;

See the Pen jAwzRz by johnykei (@johnykei) on CodePen.

(※右上の「EDIT ON CODEPEN」をクリックして広い画面でご覧ください。)

幅が全て揃い、親要素いっぱいに配置されました。ウィンドウを狭めてもきちんとレスポンシブしています。このように flex アイテムに指定する flex プロパティはレスポンシブデザインにする際には非常に重要ですのでしっかり理解しておきましょう。

では、それぞれのプロパティがどのような役割を持っているのかを詳しく見ていきます。まず最初に flex-basis について説明します。

flex-basis

flex-basisflex アイテムの基準となる幅を指定します。width と同じような動きをし、flex プロパティでは最後に記述します。以下のサンプルでは flex-basis100px を指定しています。

flex-basis: 100px;

See the Pen VjQXgX by johnykei (@johnykei) on CodePen.

flex アイテムの幅はきっちり 100px になっています。ただし後ほど説明する flex-growflex-shrink が指定されている場合は必ずしも flex-basis で指定された幅で表示されるのではなく自動調整された上でレイアウトされます。

flex-basis の値が auto の場合は flex アイテムのコンテンツサイズに応じた幅を基準にレイアウトされます。

flex-basis: auto;

See the Pen bZLvyP by johnykei (@johnykei) on CodePen.

コンテンツ(文字)が多いアイテムの幅が広がっていることがわかります。

また先ほども説明しましたが、 flex-basis0% を指定すると flex アイテムは flex コンテナに収まるようにレイアウトされます。

See the Pen akqGby by johnykei (@johnykei) on CodePen.

先ほどお見せしたサンプルも同じく flex: 1 0 0% を使っていました。flex-basis0%flex-grow と組み合わせて使うと、flex アイテムの幅を揃えつつ flex コンテナにきちんと収めてくれるのでとても便利です。

flex-basis の初期値は auto です。

flex-grow

flex-growflex コンテナに余白がある場合の flex アイテムの伸びる比率を指定します。flex プロパティでは最初に記述します。先ほどのサンプルでは全て 1 を指定していたので幅が全てそろっていました。試しに真ん中のアイテムに flex-grow の値を 2 にしてみましょう。

flex-grow: 2;

See the Pen GqQQEj by johnykei (@johnykei) on CodePen.

2 を指定したアイテムは他のアイテムに比べて2倍の横幅になりました。ここでは flex-basis0% を指定しているので2倍になっていますが、auto や固定値(100px など)を指定した場合は幅が2倍になるわけではありません。各 flex アイテムの flex-grow の値の合計値に対する割合で flex コンテナの余白を幅としてそれぞれに足すとおぼえた方がわかりやすいかもしれません。以下の図を参考にしてください。

flex-grow プロパティの解説図

flex-grow の初期値は 0 です。0 の場合は flex アイテムの幅に flex コンテナの余白は影響しません。またマイナスの値は無効です。

flex-shrink

flex-shrinkflex アイテムの幅の合計が flex コンテナの幅より大きい場合に flex アイテムの縮む比率を指定します。flex プロパティでは2番目に記述します。以下のサンプルでは2番目の要素に flex-shrink4 を指定しています。

flex-shrink: 4;

See the Pen jAkkvK by johnykei (@johnykei) on CodePen.

2番目のアイテムは他のアイテムに比べて縮まっていることがわかります。ちょっとわかりにくいかもしれませんが、要は flex-grow の反対で各 flex アイテムの flex-shrink の値の合計値に対する割合で flex コンテナからはみ出した幅をそれぞれの幅から引くとおぼえた方がわかりやすいです。こちらも解説の図を用意しましたので参考にしてください。

flex-shrink プロパティの解説図

ただし、先ほど flex-basis0% の時には flex コンテナに収まるようにレイアウトされると説明しました。そのため flex コンテナからはみ出すことがないので flex-shrink はどんな値を入れても意味を持ちません。

flex-shrink の初期値は 1 です。flex-shrink の値が 0 の場合は縮まずにオリジナルサイズを維持します。またマイナスの値は無効です。

便利な Flexbox の使い方

アイコン付きボタンを Flexbox で作る

アイコン付きのボタンやリンクのテキストとアイコンの縦位置調整は地味に面倒でしたが、このような場合でも Flexbox が便利です。ただし、ボタンはインラインボックスとして使いたい場合が多いので、その際は display: inline-flex; を使います。display: flex; を指定した場合 flex コンテナはブロックボックスとなりますが、display: inline-flex; を使うとインラインボックスとして使うことができます。

display: inline-flex;
align-items: center;

See the Pen wWyVWV by johnykei (@johnykei) on CodePen.

vertical-align や margin-top 等の微調整はもう必要ありません。

flex アイテムを上下左右中央に配置する

先ほど「上下左右の位置揃えが簡単」の項目で説明した分の応用です。ダイアログなどを画面の上下左右中央に配置する場合に今までは position: absolute;margintransform プロパティなどを組み合わせるのが主流でした。しかし Flexbox を使えばとても短い記述量で組むことができます。また子要素の幅、高さに影響されないのもメリットです。flex コンテナに以下のスタイルを追加します。

display: flex;
justify-content: center;
align-items: center;

See the Pen ZOAgQB by johnykei (@johnykei) on CodePen.

flex アイテムの折り返し

今までで作ったサンプルは全て1行に flex アイテムを収めるものでしたが、複数行に配置したい場合もよくあると思います。例えば以下のサンプルは1行に4つのアイテムが配置されていますが、それぞれの幅が狭くて見難いですよね。では Flexbox を使って1行に2つのアイテムだけを配置して複数行にしたい場合はどうすればよいでしょうか?

See the Pen akqgAJ by johnykei (@johnykei) on CodePen.

このような場合 flex-wrap というプロパティを使います。flex-wrap で flex アイテムの折り返しを設定をすることができます。初期値は nowrap (折り返さない)になっていますので、flex コンテナに以下のスタイルを追加します。

flex-wrap: wrap;

また flex-basis0% のままだと flex コンテナに収まってしまうので、 flex-basis にコンテナの幅を2等分した幅から各マージンを引いた値を指定しましょう。flex-basis の値には calc も使用できます。

flex: 1 1 calc(50% - 30px); /* flex-basis: calc(50% - 30px); */

See the Pen grvNNQ by johnykei (@johnykei) on CodePen.

これで複数行にも対応できました。これをさらに応用すれば簡単に複数行に対応したグリッドシステムも作れます。

まとめ

いかがでしたでしょうか?Flexbox を使い出すと今までのやり方に戻れないくらい便利ですね。最後に今回使った Flexbox のプロパティをまとめておきます。

flex コンテナに設定可能なプロパティ

  • justify-content:flex アイテムの水平方向の配置設定
  • align-items:flex アイテムの垂直方向の配置設定
  • flex-wrap:flex アイテムの折り返し設定

flex アイテムに設定可能なプロパティ

  • order:flex アイテムの並び順を設定
  • flex-grow:flex アイテムの伸びる比率
  • flex-shrink:flex アイテムの縮む比率
  • flex-basis:flex アイテムの基準となる幅を設定
  • flexflex-growflex-shrinkflex-basis のショートハンド

今回紹介した Flexbox の機能は一部です。より詳しく知りたい方は CSS Flexible Box Layout Module Level 1 日本語訳 を読むのをおすすめします。是非他の機能も自分で実際に触ってみて、Flexbox の便利さを実感してみてくださいね。そしてもっと理解を深めて積極的に使っていきましょう!


ヌーラボでは現在フロントエンドエンジニアは募集しておりませんが、Flexbox もガンガン使いたい!というエンジニアも大歓迎です。是非こちらからご応募ください。

また、ヌーラボのフロントエンドエンジニアとお話がしてみたいという方も募集していますので、ご応募お待ちしています。

より良いチームワークを生み出す

チームの創造力を高めるコラボレーションツール

製品をみる