大好評の「エンジニアのための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 を使うことができます。
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 アイテムとなり、横並びになります。
よって先ほどのサンプルは 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 アイテムがある場合はそれよりも少ない値に指定する必要があります。
カラムの横幅の指定が簡単&柔軟
今作ったサンプルは幅をそれぞれ 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-basis
は flex アイテムの基準となる幅を指定します。width
と同じような動きをし、flex プロパティでは最後に記述します。以下のサンプルでは flex-basis
に 100px
を指定しています。
flex-basis: 100px;
See the Pen VjQXgX by johnykei (@johnykei) on CodePen.
flex アイテムの幅はきっちり 100px になっています。ただし後ほど説明する flex-grow
や flex-shrink
が指定されている場合は必ずしも flex-basis
で指定された幅で表示されるのではなく自動調整された上でレイアウトされます。
flex-basis
の値が auto
の場合は flex アイテムのコンテンツサイズに応じた幅を基準にレイアウトされます。
flex-basis: auto;
See the Pen bZLvyP by johnykei (@johnykei) on CodePen.
コンテンツ(文字)が多いアイテムの幅が広がっていることがわかります。
また先ほども説明しましたが、 flex-basis
に 0%
を指定すると flex アイテムは flex コンテナに収まるようにレイアウトされます。
See the Pen akqGby by johnykei (@johnykei) on CodePen.
先ほどお見せしたサンプルも同じく flex: 1 0 0%
を使っていました。flex-basis
の 0%
は flex-grow
と組み合わせて使うと、flex アイテムの幅を揃えつつ flex コンテナにきちんと収めてくれるのでとても便利です。
flex-basis
の初期値は auto
です。
flex-grow
flex-grow
は flex コンテナに余白がある場合の flex アイテムの伸びる比率を指定します。flex プロパティでは最初に記述します。先ほどのサンプルでは全て 1
を指定していたので幅が全てそろっていました。試しに真ん中のアイテムに flex-grow
の値を 2
にしてみましょう。
flex-grow: 2;
See the Pen GqQQEj by johnykei (@johnykei) on CodePen.
2
を指定したアイテムは他のアイテムに比べて2倍の横幅になりました。ここでは flex-basis
に 0%
を指定しているので2倍になっていますが、auto
や固定値(100px
など)を指定した場合は幅が2倍になるわけではありません。各 flex アイテムの flex-grow
の値の合計値に対する割合で flex コンテナの余白を幅としてそれぞれに足すとおぼえた方がわかりやすいかもしれません。以下の図を参考にしてください。
flex-grow
の初期値は 0
です。0
の場合は flex アイテムの幅に flex コンテナの余白は影響しません。またマイナスの値は無効です。
flex-shrink
flex-shrink
は flex アイテムの幅の合計が flex コンテナの幅より大きい場合に flex アイテムの縮む比率を指定します。flex プロパティでは2番目に記述します。以下のサンプルでは2番目の要素に flex-shrink
に 4
を指定しています。
flex-shrink: 4;
See the Pen jAkkvK by johnykei (@johnykei) on CodePen.
2番目のアイテムは他のアイテムに比べて縮まっていることがわかります。ちょっとわかりにくいかもしれませんが、要は flex-grow
の反対で各 flex アイテムの flex-shrink
の値の合計値に対する割合で flex コンテナからはみ出した幅をそれぞれの幅から引くとおぼえた方がわかりやすいです。こちらも解説の図を用意しましたので参考にしてください。
ただし、先ほど flex-basis
が 0%
の時には 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;
と margin
や transform
プロパティなどを組み合わせるのが主流でした。しかし 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-basis
が 0%
のままだと 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 アイテムの基準となる幅を設定flex
:flex-grow
,flex-shrink
,flex-basis
のショートハンド
今回紹介した Flexbox の機能は一部です。より詳しく知りたい方は CSS Flexible Box Layout Module Level 1 日本語訳 を読むのをおすすめします。是非他の機能も自分で実際に触ってみて、Flexbox の便利さを実感してみてくださいね。そしてもっと理解を深めて積極的に使っていきましょう!
ヌーラボでは現在フロントエンドエンジニアは募集しておりませんが、Flexbox もガンガン使いたい!というエンジニアも大歓迎です。是非こちらからご応募ください。
また、ヌーラボのフロントエンドエンジニアとお話がしてみたいという方も募集していますので、ご応募お待ちしています。
エンジニアのためのCSS基礎講座シリーズのバックナンバー