[CSS] Flexible Box Layout Module 解説レポート

使い始めたら手放せないフレキシブルボックスレイアウトモジュールについて熱く語ります。

注)
これは6年前に社内向けレポートか何かで書いたやつだと思います…(うろ覚え)
今でも通用する内容だったのでドライブにあった原稿を転載しました。
内容が古いところは加筆修正してます。

フレキシブルボックスレイアウト?とは?

5つめの新しいレイアウト方法です。
今は知ってないと恥ずかしいレベルにメジャーとなったレイアウト方法です。

CSSで何かの要素を配置しようとしたとき、選択可能な手段は4つありました。

  • ブロックレイアウト
    —— 文書をレイアウトする為に設計されたもの。
  • インラインレイアウト
    —— テキストをレイアウトする為に設計されたもの。
  • テーブルレイアウト
    —— 2Dデータを表形式でレイアウトする為に設計されたもの。
  • ポジショニングレイアウト
    —— 要素に授ける自由の翼。

Web制作経験がある人ならこの4つ全て使ったことがあると思いますが、同時にこの4つだけでは痒い所に手が届かない事例に遭遇した事があるんじゃないでしょうか。

Flexレイアウトはユーザー インターフェイス設計のために最適化されているので、上記4つ+ノウハウ+JSでやっつけていたようなレイアウトを驚くほど簡単に作ることができます。

なにができるの?

フレキシブルボックスレイアウトは子要素を任意の方向に並べる事が得意です。

並べた要素の順番を入れ替えることもプロパティの指定1つで行えます。

仕様の変遷と対応ブラウザ

とてつもなく便利なモジュールですが、残念な歴史が1つ。
それはブラウザによって対応する仕様とシンタックスが違っていたということです。

W3C Working Draft, 23 July 2009

http://www.w3.org/TR/2009/WD-css3-flexbox-20090723/

現状一番多くのブラウザがサポートしている仕様。
この仕様をサポートしたブラウザが登場するようになったことで、フレキシブルボックスというものが広く認知されるようになった。

古いPC版ブラウザとスマートフォン版ブラウザ相手ならこの仕様。
2019年現在この仕様の端末は販売されていません。

W3C Working Draft, 22 March 2012

http://www.w3.org/TR/2012/WD-css3-flexbox-20120322/

2011〜2012年春仕様。box-だったところがflex-になった。
丁度同時期に開発中だったのか、何故かIE10だけがこの仕様に準拠している。

_人人人人人人人人人人_
> IE10だけこの仕様 <
 ̄Y^YY^YYYY^YY^Y ̄

W3C Candidate Recommendation, 18 September 2012

http://www.w3.org/TR/css3-flexbox/

勧告候補。PC版ブラウザの最新版(IE10以外)は概ね対応してきている。

現在はこれ。あの頃夢見た世界がやっと…

シンタックスで見る仕様の違い

親要素(黒い枠)の中に3つの子要素を均等配置するケースについて、各仕様に準じた書き方をすると以下のようになります。
※ベンダープレフィックスは全て省略しています。

W3C Working Draft, 23 July 2009 の場合

div {
  display: box;
  box-pack: justify;
  box-align: center;
  box-orient: horizontal;
}

W3C Working Draft, 22 March 2012 の場合

div {
  display: flexbox;
  flex-pack: justify;
  flex-align: center;
  flex-direction: row;
}

W3C Candidate Recommendation, 18 September 2012の場合

div {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-flow: row;
}

これを書いている現時点(2013/9)ではW3C Working Draft, 23 July 2009の仕様で書いておけば対応するPC・スマートフォン両方のブラウザをカバーすることができます。
勧告版仕様を使いたい場合は、
PC→勧告仕様
IE10→2012仕様
スマホ・旧PC→2009仕様
を使い分けることになります。
2019年現在は勧告仕様で概ねオッケーですが、ベンダープレフィックスの有無などで脚を引っ張られる事があります。
サポート状況はブラウザによって異なるので、対応状況は随時Caniuse.com等で確認してください。

用語の図解

どちらの場合も基本的にレイアウトの方向が主軸となります。

  • Flexコンテナ
    flexアイテムを含む親要素のこと。
  • Flexアイテム
    flexコンテナの子要素。flexコンテナに直接テキストが入っている場合は、無名のflexアイテムに包まれる。
  • 主軸(main axis) ・交差軸(cross axis)
    レイアウト時に基準となる軸。
    交差軸は、横方向レイアウトの場合(上図)は縦軸だが、縦方向レイアウトの場合は横軸になる。
    レイアウトの方向によって主軸が変わるので、操作するプロパティも変わります。
  • main start/main end
    Flexアイテムは主軸を基準としてmain startからmain end方向へレイアウトされる。縦方向レイアウトの場合はmain startが上、main endが下になる。
  • cross start/cross end
    マルチラインレイアウトの場合、cross startからcross endに向けてFlexアイテムが配置される。

レイアウトの方向が横の場合

レイアウトの方向が縦の場合

プロパティの説明とサンプル

display:flex/inline-flex

flexコンテナの生成はdisplayプロパティの値にflexもしくはinline-flexを指定することです。
指定する要素はブロックレベル・インラインレベルを問いません。
display:flexのflexコンテナはブロックレベル、display:inline-flexのflexコンテナはインラインレベルになります。

元がブロックレベルの要素であっても、display:inline-flexを指定するとdisplay:inline-blockを指定したのと同じような挙動になります。
それとは逆に、要素にdisplay:inline-flexfloatあるいはposition:absoluteが指定してある場合、displayの算出値はflexになります。

See the Pen
Flexible Box Layout Module sample
by Tenderfeel (@Tenderfeel)
on CodePen.

Flexコンテナ内で適用されないプロパティ

ブロックレイアウト前提で設計されたプロパティのうち、いくつか使用できないものがあります。

flex-direction

指定したFlexコンテナー内にあるFlexアイテムのレイアウト方向を設定するプロパティ。
レイアウトの起点はmain startですが、reverseを付けると逆転してmain endになります。

  • row —— 横方向(デフォルト)用語にある図の1つ目
  • row-reverse —— 横方向(main endが起点)
  • column —— 縦方向。用語にある図の2つ目
  • column-reverse —— 縦方向(main endが起点)

See the Pen
CSS flex-direction sample
by Tenderfeel (@Tenderfeel)
on CodePen.

flex-wrap

FlexアイテムがFlexコンテナの末端に達したとき、自動で折り返すか否かを決める。レイアウトの基準になるのは交差軸で、プロパティの役割はwhite-spaceに近い。

  • nowrap —— Flexコンテナ内を1行でレイアウトする。FlexアイテムはFlexコンテナに収まるサイズに拡大・縮小する
  • wrap —— Flexコンテナ内を複数行にレイアウトする。Flexアイテムは末尾のものから順に新しい行へ配置される
  • wrap-reverse —— 挙動はwrapと同じだが、折り返しの向きが逆転する。

See the Pen
CSS flex-wrap sample
by Tenderfeel (@Tenderfeel)
on CodePen.

flex-flow

flex-directionflex-wrapを同時に指定するショートハンドプロパティ。
flex-directionの値の後、スペースで区切ってflex-wrapの値を記述する。

See the Pen
CSS flex-flow demo
by Tenderfeel (@Tenderfeel)
on CodePen.

order

Flexアイテムに対して並び順を指定するプロパティ。値は数値で初期値は0。
マイナスの値を指定した場合は前方に、0より大きい数値を指定した場合は後方に配置される。

See the Pen
CSS flexible box order demo
by Tenderfeel (@Tenderfeel)
on CodePen.

justify-content

FlexアイテムをFlexコンテナの主軸に沿って整列するプロパティ。space- 系が神過ぎる。
space-evenlyは登場が新しく、IE11やAndroid4系などが未対応です。

  • flex-start —— main startを起点に詰めて配置(初期値)
  • flex-end —— main end を起点に詰めて配置
  • center —— 中央に配置
  • space-between —— 最初と最後のflexアイテムをmain startとmain end寄りに配置。余ったスペースで残りのflexアイテムを均等に配置
  • space-around —— 全てのflexアイテムを均等に配置し、各アイテムの両側に半分の大きさの間隔を置く
  • space-evenly —— 全てのflexアイテムを均等に配置し、各アイテムの周りに同じ大きさの間隔を置く

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

align-items/align-self

交差軸に沿って指定するプロパティ。align-itemsはFlexコンテナに、align-selfはFlexアイテムに指定するプロパティです。

  • flex-start —— cross startを起点に詰めて配置
  • flex-end —— cross endを起点に詰めて配置
  • center —— 中央に配置
  • baseline —— ベースラインが一直線になるように配置
  • stretch —— 同じ列にあるFlexアイテムが全て同じ高さになるように配置(初期値)
  • auto —— align-selfのみ指定可能。親要素のalign-items値を計算する(初期値)

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

align-content

Flexコンテナがマルチラインである場合に、交差軸に沿って列の整列を指定するプロパティ。1行しか無い場合は影響しません。

  • flex-start —— cross startを起点に詰めて配置
  • flex-end —— cross endを起点に詰めて配置
  • center —— 中央に配置
  • space-between —— 最初と最後の列をcross startとcross end寄りに配置。余ったスペースで残りの列を均等に配置
  • space-around —— 全ての列を均等に配置
  • stretch —— 全ての列が同じ高さになるよう配置(初期値)

See the Pen
CSS align-content sample
by Tenderfeel (@Tenderfeel)
on CodePen.

flex

このプロパティは flex-growflex-shrinkflex-basisを一括指定するショートハンドで、Flexアイテムの幅をどのように扱うかを指定することが出来ます。
指定先はFlexアイテムです。

値の順番は次の通りです。

flex: <flex-grow> <flex-shrink> <flex-basis>;

flex-growとflex-shrinkは省略できます。省略された場合はどちらも1になります。
flex-basisを省略した場合は0pxが初期値になります。

初期値はこのようになっています。
flex: 1 1 0px;

flex-grow —— 親要素が大きすぎたときにFlexアイテムに振り分ける余白の割合
flex-shrink —— 親要素のサイズが不足しているときFlexアイテムをどれだけ縮小するか
flex-basis —— Flexアイテムのサイズを指定する

次のサンプルはflex-grow、flex-shrink、flex-basisの値をそれぞれ変えてみたものです。

See the Pen
flex-grow/flex-shrink demo
by Tenderfeel (@Tenderfeel)
on CodePen.

FlexItem1 → 拡大も縮小もしない。ウィンドウサイズを変えても150pxのまま変わらない。
FlexItem2 → 拡大時の割合を2、縮小時は1とする。ウィンドウサイズに比例して拡大縮小する。拡大するときはFlexItem3よりも割合が大きい。
FlexItem3 → 拡大はするが縮小はしない。幅150pxより小さくならないが、ウィンドウサイズが大きければ広がる。

flex-basisflex-shrinkの値が0である場合、調整無視して指定されたサイズで描画するため親要素のサイズが足りなくなった場合に他のFlexアイテムがはみ出します。
上のサンプルでは一番最後にあるFlexItem2用のflexプロパティの値を 2 0 300px に変更すれば確認できます。

次のサンプルはflex-basisでflexアイテムを操作してみたものです。

See the Pen
CSS flex-basis sample
by Tenderfeel (@Tenderfeel)
on CodePen.

.title → flexで100%指定。後続の.thumbと.descriptionを2列目に押しやる
.thumb → widthとheightだけ指定。
.description → flexで1を指定。thumb配置後に余った所を全部占領させる

Flexアイテムの挙動について

position:absoluteを指定した場合

Flexレイアウトはされず、いつも通りの挙動です。が、topbottomleftrightautoである場合staticと同じ挙動になるので、margin:autoでセンタリングする手法は使えません。

See the Pen
flexible box item absolute demo
by Tenderfeel (@Tenderfeel)
on CodePen.

visibility:collapseを指定した場合

Flexアイテムにvisibility:collapseを指定した場合、table-rowtable-cellと同じ効果になります。collapseに関してはブラウザの挙動がまちまちなので、その対応状況に引きずられてしまうようです。

See the Pen
Flexiblebox and visibility:collapse sample
by Tenderfeel (@Tenderfeel)
on CodePen.

おまけ

あるあるリストスタイル

左に配置したサムネイルにコンテンツの背景が回り込んだり回り込まなかったりするリストのサンプル。

See the Pen
Flexible box layout sample
by Tenderfeel (@Tenderfeel)
on CodePen.

参考文献

  • http://www.w3.org/TR/css3-flexbox/#flex
  • https://developer.mozilla.org/ja/docs/Web/Guide/CSS/Flexible_boxes
  • http://hyper-text.org/archives/2013/07/css_flexible_box.shtml

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください