CSS Flexible Box Layout Moduleで均等幅にレイアウトする

f:id:kudakurage:20130506225921j:plain

最近ではベンダープレフィックスも無くす方向に向かっているようですね。
数年前に比べればCSS3プロパティも使えるような状況になってきているような気がします。いや気がしているだけかもしれません。
まぁ、現状webkitが支配しているモバイルブラウザ環境ではCSS3だって使えますしね。

display: box

横幅を均等に分けてレイアウトしたいみたいなときにFlex boxは便利なプロパティですが、どんな感じにするのがいいのかを書いてみようと思います。
Flexible Boxの仕様はころころ変わってて、最初は「display: box」最新は「display: flex」だったりしますが、まずは「display: box」でやってみます。

<div class="flex-box">
  <div>short text</div>
  <div>long text long text</div>
  <div>more long text more long text</div>
</div>

まずはCSSを単純に書くと

.flex-box {
  display: -webkit-box;
  display: box;
}
.flex-box div {
  -webkit-box-flex: 1;
  box-flex: 1;
}

この場合すべての子要素が同じ横幅にはなりません。box-flexプロパティは子要素を並べた時に余った領域を分配する比率を指定するものです。
上記のHTMLの子要素は「width: auto」で、この場合はそれぞれのコンテンツ幅にあった横幅になると考えます。そして余ったスペースを均等に分けるので次のようなイメージですね。

f:id:kudakurage:20130506190203j:plain

これをきちんと均等幅にするにはwidthを指定すると良いです。
例えば「width: 100%」とするとすべての子要素が同じ100%の横幅になろうとしますが、入りきらないぶんを均等に縮めるように配置されます。

.flex-box {
  display: -webkit-box;
  display: box;
}
.flex-box div {
  -webkit-box-flex: 1;
  box-flex: 1;
  width: 100%;
}

f:id:kudakurage:20130506212147j:plain

ここで指定する横幅はすべての子要素で同じであればどんな値でもよく、例えば「width: 1px」のような場合でも、余った領域を均等に分配するのでこのような表示になります。

ちなみにFirefoxだと「100%」や「1px」だと意図したレイアウトにならないです。「1000px」といった大きな値を指定すると上手くレイアウトされるのですが。。

display: flex

最新仕様の「display: flex」ではFlexibilityを「flex」プロパティで指定するようになっています。

flexプロパティは「flex-grow」「flex-shrink」「flex-basis」という3つの値が指定できるようになっています。それぞれ子要素の「拡大の比率」「縮小の比率」「基本の幅(width)」を表します。
最初の仕様「box」のときは「flex-basis」に当たる値はwidthに該当していたわけですが、最新の「flex」ではその値を指定できるようになっているのですね。
つまり子要素にwidthが指定してあったとしても「flex-basis」の値をベースにして伸縮の計算がされることになります。
(ちなみにflex-basisにautoを指定することでwidthをベースにすることもできます)

flexプロパティは3つの値をそれぞれスペース区切りで指定するか「initial」「auto」「none」あとpositive-numberを指定できます。これらの指定は以下のように解釈されます。

Value Equivalent
initial flex: 0 1 auto
auto flex: 1 1 auto
none flex: 0 0 auto
positive-number flex: [positive-number] 1 0px


少し遠回りになりましたが、今回は子要素をすべて均等幅にレイアウトしたいので「flex-basis」にauto以外の値を指定する必要があります。
つまり1つか2つか3つ数字を並べれば良いということですね。

.flex-box {
  display: -webkit-flex;
  display: flex;
}
.flex-box div {
  -webkit-flex: 1;/* = 1 1 0 */
  flex: 1;

/* or ... */
  -webkit-flex: 1 1;/* = 1 1 0 */
  flex: 1 1;

/* or ... */
  -webkit-flex: 1 1 0;
  flex: 1 1 0;
}

ということで、以上を試してみたサンプルページを用意しました。initialとnoneは一見同じように見えますが、windowを縮めていくと違いがわかります。

Browser support

結局どちらを使えばいいのかという話です。現状のブラウザサポート状況は以下のような感じのようです(間違っていたら教えてください)。
今回の冒頭のように「モバイルブラウザ環境で」ということであれば、古い「box」の方で実装するのがいいのですかね。。。
今年のWWDCではiOSの新バージョンが発表されるようですが、それと同時に今後のSafari, Mobile Safariの動向も気になるところです。

- Chrome Safari Firefox Opera IE10 Mobile Safari Android Browser
box
flex × × × ×

※ ブラウザはそれぞれ最新バージョンです
SafariとIE10は古い仕様で実装されているようです

Firefoxは現状の最新版だとdefaultで無効にされているようです。Firefox 22からはまた有効化されるようです

Android Browserは新しいのと古いバージョンで差があるのできちんと実機で検証できてないです。ざっくり▲としています