必要条件

この記事に必要な予備知識

HTMLとCSS、CSS3の新機能についてのある程度の知識

 

必要となるその他の製品

  • ChromeまたはOperaブラウザー
  • コードエディター

ユーザーレベル

すべて

原文 作成日: 2013/3/18

Working with flexbox: The new specification

柔軟なレイアウト。同じ高さの列。HTMLソースでの記述順序に依存しない表示。これらをCSSで実現するのは決して簡単ではありませんでした、これまでは。柔軟なボックスレイアウト、つまり新しいflexbox仕様には、ボックスレイアウトが容易になることに加えてさまざまなメリットがあります。

この記事では、最新のflexbox仕様について説明すると共に、柔軟なレイアウトを作成する方法を紹介します。flexboxを使ったレイアウトでは、すべての列の高さを揃え、HTMLソースでの記述順序にかかわらず任意の順序で要素を配置できます。

ブラウザーのサポートについて

flexboxに対するブラウザのサポートはまだ万全とはいえません。現在、ほとんどのブラウザーがflexboxをサポートしているものの、この仕様には複数のバージョンがあります。問題は、すべてのブラウザーが最新バージョンをサポートしているわけではないことです。最新のflexbox仕様をサポートしているブラウザーは次のとおりです。

  • Opera(12.1)- 最新のflexbox仕様をサポートしています。ベンダープレフィックスは不要です。
  • Chrome(23.0)- 最新のflexbox仕様をサポートしています。ただし、-webkitベンダープレフィックスが必要です。
  • Safari(5.1)- 以前のバージョンのflexbox仕様をサポートしています。-webkitベンダープレフィックスが必要です。
  • Internet Explorer(10)- 以前のバージョンのflexbox仕様をサポートしています。-msベンダープレフィックスが必要です。Internet Explorer 9およびこれより前のInternet Explorerはflexbox仕様をサポートしていません。
  • Firefox(16.0)- 以前のバージョンのflexbox仕様をサポートしています。-mozベンダープレフィックスが必要です。ただし、バージョン20.0からはベンダープレフィックスなしで最新のflexbox仕様をサポートしています。

最新のflexbox仕様をサポートしているモバイルデバイスは次のとおりです。

  • iOSおよびAndroid - 以前のバージョンのflexbox仕様をサポートしています。ただし、-webkitプレフィックスが必要です。
  • Blackberry(バージョン10)- 最新のflexbox仕様をサポートしています。ただし、–webkitプレフィックスが必要です。
  • Opera mini - サポートしていません。

つまり、最新仕様をサポートしているブラウザーは2つだけということになります。この記事ではこれらのブラウザーを使います。まもなく最新仕様をサポート予定のブラウザーが1つあり、他のほとんどのブラウザーとモバイルデバイスは古いバージョンの仕様をサポートしています。

注意:この記事の執筆時点で、最新仕様をサポートしているのはChromeとOperaの最新バージョンだけです。最新仕様をサポートしているブラウザーはこの2つだけなので、サンプルCSSには-webkit以外のベンダープレフィックスは含まれていません。

詳しくは、W3CのWebサイトをご覧ください。

柔軟なボックスレイアウトモデル

CSSは数種類のレイアウトモデルに対応しています。これまで、ブロック、インライン、テーブル、配置レイアウトモデルを使用して要素を操作してきました。

Flexboxはまた別のレイアウトモデルです。Flexboxには、主軸(横軸)と交差軸(縦軸)という2本の軸があります。主軸は水平方向の軸であり、主軸と垂直に交わる軸が交差軸です。それぞれの軸に寸法が割り当てられ、軸ごとに開始点と終了点があります。コンテナ内のアイテムおよびコンテナ自体のサイズは、関連付けられている幅と高さに基づいて決定されます。図1を参照してください。

Flexboxの作成方法

Flexboxの仕組みを理解するには、実際に試してみるのが一番です。そのために簡単なデモを用意しました。このデモでは、HTMLドキュメントのbody内に次のHTMLが記述されています。最大幅の画面上には、HTMLによって3つの列がレイアウトされます。最小幅の画面には列が1つだけ表示されます。それらの中間では2列のレイアウトになります。

 <div class="flex-container">     <div class="header"><p>Header</p></div>     <div class="content"><p>Main Content</p></div>     <div class="sidebar primary"><p>Primary Sidebar</p></div>     <div class="sidebar secondary"><p>Secondary Sidebar</p></div>     <div class="footer"><p>Footer</p></div> </div>

上記のように、ここではflex-container divタグを1つだけ使用しており、これがFlexコンテナとなります。そして、5つの内部divタグ(header、footer、main content、2つのsidebar)がflexアイテムとなります。

ここには示されていませんが、main contentとprimary sidebarのdivタグ内はダミーテキストが挿入されています。汎用的な基本スタイルを用いて各divタグに背景色、余白、テキスト色を設定し、すぐに見分けられるようにしました。ダウンロードしたサンプルZIPファイル(flexbox.zip)のbase.cssファイルを参照してください。

flexboxを作成するには、コンテナの表示プロパティとして、次の2つのうちいずれかの値を設定するだけです。

.flex-container {display: flex;} .flex-container {display: inline-flex;}

1番目はブロックレベルのflexboxを作成し、2番目はインラインレベルのflexboxを作成します。このデモでは、次のように、CSS内にブロックレベルのflexboxを作成します。

.flex-container {     display: -webkit-flex;     display: flex; }

次のように表示されます。

このコードを使ってflexboxを作成しましたが、デフォルトのままでは魅力が伝わらないかもしれません。flexbox内のすべての要素がflexアイテムになったので、左寄せが設定されているかのように、各flexアイテムが左端から順番に配置されます。ちょっとおもしろい光景です。配置方向はflex-directionプロパティで設定できます。

注意:新旧の仕様を取り入れ、多数のブラウザーで動作するflexboxを作成する方法について、Chris Coyierがすばらしい記事を書いています。ここで取り上げるのは最新仕様だけですが、上記のflex-container divコードを拡張し、より多くのブラウザーに対応できるように変更できます。

.flex-container {   display: -webkit-box;      /* OLD - iOS 6-, Safari 3.1-6 */   display: -moz-box;         /* OLD - Firefox 19- (buggy but mostly works) */   display: -ms-flexbox;     /* TWEENER - IE 10 */   display: -webkit-flex;     /* NEW - Chrome */   display: flex;                /* NEW, Spec - Opera 12.1, Firefox 20+ */ }

詳しくは、Chrisの投稿記事「Using Flexbox: Mixing Old and New for the Best Browser Support(flexboxの使用:新旧の仕様を組み合わせてより多くのブラウザーに対応)」をご覧ください。

順序と向き

現在、flexアイテムが順番に配置される理由はflex-directionプロパティに関係しています。このプロパティは、flexboxの主軸の方向を設定します。次の4つの値があります。

  • row(デフォルト値)
  • row-reverse
  • column
  • column-reverse

ここでは値を何も設定していないので、デフォルトのrowが適用されます。値row-reverseを設定した場合、すべてのアイテムが水平方向に配置されるのは同じですが、並び順が逆になります。この場合、ヘッダーが右端に配置され、(右寄せを指定したときと同じように)その他の各divが右から左へ順番に配置されます。

flex-directionをcolumnに設定すると、flexboxの開始位置が上端になり、各divが上から下に配置されます。値column-reverseを設定した場合、コンテナの下端がflexboxの開始位置となり、各flexアイテムが下から上へ配置されます。

flex-directionと共に設定するもう1つのプロパティとして、flex-wrapがあります。これは、コンテナにflexboxを単一行で配置するか、複数行で配置するかを設定します。次の値を指定できます。

  • nowrap
  • wrap
  • wrap-reverse

ショートカットプロパティflex-flowを使用すれば、これらのプロパティをまとめで設定できます。flex-flowを使用する場合、flex-directionを設定してからflex-wrapを設定します。このデモでは、flex-flowを次のように設定しています。

.flex-container {     -webkit-flex-flow: row wrap;                flex-flow: row wrap; }

先ほど、「flexboxを使用すればソースの順序に束縛されずに配置できる」と説明しました。レスポンシブデザインを作成したことがあればおわかりかと思いますが、レイアウトが単一列の場合、HTMLと同じ順序でボックスが縦に配置されます。レイアウトが複数列に拡張されたときどのように対応するかによっては、これが制約となる場合があります。

flexboxでは、orderプロパティによってこの制約を取り除きます。このorderは、flexアイテムの表示順序を指定するためのプロパティです。このプロパティは整数値を取ります。flex-itemsの順序について、デモでは特に変わったことはしていませんが、ぜひいろいろ試してみてください。サンプルでは要素の順序を少し変更していますが、ここではソースと同じ順序で要素が配置されるようになっています。

.header                   {-webkit-order: 1;} .content                  {-webkit-order: 2;} .primary                  {-webkit-order: 3;} .secondary                {-webkit-order: 4;} .footer                   {-webkit-order: 5;}

この時点でデモページがどのように表示されるかには、こちらのスクリーンショットで確認してください。

flexboxがポイントレスであり、ポイントの有無にかかわらずレイアウトはまったく同じに見えることがおわかりいただけたと思います。flexboxを使用すればレイアウトを簡単に変更できます。実際に試してみましょう。

デフォルトのレイアウトでは、すべてのdivが1列に表示されます。このレイアウトはスマートフォンには適していますが、もう少し幅広の画面に表示するとしたらどうでしょうか。幅が48 em以上の画面で、Main ContentとPrimary Sidebarを2列に並べて表示したい場合はどうすればよいでしょう。アイテムの順序を変更し、Primary SidebarをMain Contentの前に表示するとしたら?そのようなときは次のように変更します。

@media screen and (min-width: 48em) {     .content {         width: 67%;         -webkit-order: 3;     }                         .primary {         width: 33%;         -webkit-order: 2;     } }

たったこれだけでレイアウトを変更できます。各divの幅を調整し、1行に収まるようにするだけです。さらに、順序を変更してPrimary Sidebarが最初に表示されるようにします。

この新しいレイアウトでデモページがどのように表示されるかは、こちらのスクリーンショットで確認してください。

非常にシンプルな変更ですが、何が変わったかおわかりでしょうか。Sidebar列の高さがMain Content列の高さと同じになっています。高さを揃えるためには何もしていません。Main Contentに段落を追加したり、いくつか削除したりしてみましょう。さらに、Sidebarにリスト項目も追加してみてください。どのように変更しても、これらの列の高さは常に等しくなります。これが、柔軟性に優れたflexboxの

メリットです。数行のシンプルなコードで、HTML構造が特定のソース順序に縛られていた制約を克服し、高さの等しい列がデフォルトでレンダリングされるようになりました。

もう1つのサイドバーも追加して、レイアウトを3列に拡張しましょう。その際、Primary Sidebarを右端へ移動し、Secondary Sidebarを中央に配置します。

@media screen and (min-width: 60em) {     .content {         width: 50%;         -webkit-order: 2;         order: 2;     }     .primary {         -webkit-order: 4;         order: 4;     }     .secondary {         -webkit-order: 3;         order: 3;     }     .sidebar {         width: 25%;     } }

この新しいレイアウトでデモページがどのように表示されるかは、こちらのスクリーンショットで確認してください。

先ほどと同様、変更はいたって簡単です。すべてが1行に配置されるように幅を調整し、flexアイテムの順序を変更しました。わずか数行のコードでレイアウトを変更できたことがおわかりいただけたと思います。ここでもやはり、何も設定しなくても、列の高さがすべて等しくなっています。

flexboxの特長はこれだけではありません。実際にデモを拡張してみましょう。

flexアイテムの柔軟性

flexboxの利点の1つは、コンテナを拡大縮小したとき、内部のアイテムも同じ比率のまま大きくなったり、小さくなったりすることです。しかも、サイズを一切指定する必要がありません。flexアイテムは、ボックスに合わせて自動的にサイズ調整されます。次のプロパティとショートハンドを使って設定できます。

  • flex-grow – 他のflexアイテムを基準にした、flexアイテムの拡大比率(正数値)を指定します。
  • flex-shrink – 他のflexアイテムを基準にした、flexアイテムの縮小比率(整数値)を指定します。
  • flex-basis – 余白を配置する前の、flexアイテムの初期メインサイズを指定します(widthまたはautoを指定できます)。
  • flex shorthand - none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]

flexboxの機能を確かめるため、Content divからテキストを削除し、新しいdiv(Box 1、Box 2、Box 3)に置き換えました。下図は、Main Content内のダミーテキストが削除された新しいHTMLを示しています。

<div class="flex-container">   <div class="header"><p>Header</p></div>   <div class="content flex-content">     <div class="box box1"><p>Box 1</p></div>     <div class="box box2"><p>Box 2</p></div>     <div class="box box3"><p>Box 3</p></div>   </div>   <div class="sidebar primary"><p>Primary Sidebar</p></div>   <div class="sidebar secondary"><p>Secondary Sidebar</p></div>   <div class="footer"><p>Footer</p></div> </div>

content div自体をflexboxに設定したので、flexbox内にさらに別のflexboxが配置された状態になりました。ここでは列の方向を設定します。このコンテナの高さを設定する必要があるので、30 emに設定します。

.content {     display: -webkit-flex;     display: flex;     -webkit-flex-flow: column wrap;             flex-flow: column wrap;     height: 30em; }

次のように、3つのボックスにそれぞれ背景色とflex-growプロパティを割り当てます。

.box1 {     background: #933;     -webkit-flex-grow: 8;             flex-grow: 8; } .box2 {     background: #393;     -webkit-flex-grow: 1;             flex-grow: 1; } .box3 {     background: #339;     -webkit-flex-grow: 3;             flex-grow: 3; }

このように変更すると、寸法を何も指定しなくても、上記で設定した相対比率に基づき、3つのボックスのサイズがスペースに合わせて自動的に調整されます。Box 1のサイズはBox 2の8倍、Box 3のサイズはBox 2の3倍です。

この時点で、デモページがどのように表示されるかをこちらのスクリーンショットでご確認ください。

次に、2列レイアウトに切り替えるため、ボックスのサイズと順序を変更します。

@media screen and (min-width: 48em) {     .box1 {         -webkit-flex-grow: 6;                 flex-grow: 6;         -webkit-order: 1;                 order: 1;     }     .box2 {         -webkit-order: 3;                 order: 3;     }     .box3 {         -webkit-flex-grow: 1;                 flex-grow: 1;         -webkit-order: 2;                 order: 2;     } }

この時点でのデモをこちらのスクリーンショットでご確認ください。

3つの列を配置する余裕があるので、ボックスを再び変更しましょう。今度は、1行全体にBox 1を配置し、その下の行にBox 2とBox 3を配置します。まず、行としてレンダリングされるようにcontentflex-flowプロパティを変更し、box1の幅を100 %に設定します。

@media screen and (min-width: 60em) {     .content {         -webkit-flex-flow: row wrap;                 flex-flow: row wrap;     }     .box1{         width: 100%;     }     .box3 {         -webkit-flex-grow: 2;                 flex-grow: 2;         -webkit-order: 3;                 order: 3;     } }

この時点で、デモページがどのように表示されるかをこちらのスクリーンショットで確認してください。

ここでもやはり、わずか数行のCSSでレイアウトを大きく変えることができます。一見、それほどすごいことだと思えないかもしれません。でも、flexboxを使わずに、JavaScriptやjQueryで同様の変更をコーディングするとしたらどれほどの手間がかかるか考えてみてください。

flexアイテムの整列

寸法を指定しなくても、コンテナの大きさに合わせてflexアイテムを配置できることがわかりました。場合によっては、flexコンテナ内のアイテムに幅寸法と高さ寸法を指定する必要があります。例えば、決められたサイズの画像をグリッドに表示する場合などです。

では、デモをさらに調整してみましょう。3つのボックスからflex-grow値を削除し、次のように、3つのすべてのボックスに同じ幅と高さを設定します。

.box {     width: 25%;     height: 5em; }

この変更を行うと、コンテナに合わせてボックスのサイズが調整されなくなります。代わりに上端から順番に配置されます。これは、flexコンテナの方向が列に設定されているためです。これらのボックスを別の方法でコンテナ内に配置しましょう。そのために設定できるプロパティがいくつかあります。

justify-contentプロパティを使用すれば、コンテナの主軸に沿って要素を配置できます。この場合、flexコンテナに割り当てる値は次のとおりです。

  • flex-start - 上揃えまたは左揃え。
  • flex-end - 下揃えまたは右揃え。
  • center - 中央揃え
  • space-between - 均等に間隔をあけて配置します。
  • space-around - 均等に間隔をあけて配置し、左端と右端にも半分ずつ間隔をあけます。

交差軸(垂直方向)についても、同様の2つのプロパティがあります。

  • align-items - コンテナに設定。すべてのflexアイテムのデフォルト設定となります。
  • align-self - アイテムに設定。このプロパティが設定されているflexアイテムでは、align-itemsよりこちらが優先されます。

いずれのプロパティでもflex-startflex-endcenterを使用し、対象が交差軸であること以外はjustify-contentのときと同じように機能します。ただし、space-aroundspace-betweenは使用せず、代わりに次の値を設定します。どのように機能するかは状況によって異なります。

  • baseline - flexアイテムの縦位置をベースラインに揃えます。
  • stretch - 他のflexアイテムやベースラインに合わせてアイテムの高さを拡張します。

これらの値がどのように機能するかは状況によって異なります。ここでも少し紹介しますが、実際にいろいろ試してみてください。

最後のデモを使ってこれらのプロパティを設定しました。justify-contentspace-between値を設定し、align-itemscenter値を指定しています。これらの値をcontent divに追加しました。

.content {   -webkit-justify-content: space-between;               justify-content: space-between;   -webkit-align-items: center;               align-items: center;

2つのボックスのalign-items値をalign-itemプロパティで上書きします。

.box1 {   -webkit-align-self: baseline;               align-self: baseline; } .box3 {   -webkit-align-self: flex-end;               align-self: flex-end; }

この最後のデモがどのように表示されるかをこちらのスクリーンショットで確認してください。

このほかにもさまざまな値を設定し、どのような結果になるか試してください。

次のステップ

ここでは、flexboxの操作が非常に簡単であり、その動作が本当に「柔軟」であることを説明しました。1時間ほどflexboxを試していただければ、最新仕様をサポートしているブラウザーで実際にデザインしてみたくなるのではないでしょうか。

現在一般に普及している5種類のデスクトップブラウザーのうち、2つのブラウザーでflexboxの最新仕様がサポートされています。さらに、もう1つのブラウザー(Safari)も、まもなくflexboxの最新仕様を取り入れる予定です(既にwebkitに実装)。Internet Explorerのサポートについては、古いバージョンの操作に慣れているユーザーも多いことと思います。flexbox用のpolyfill(Flexieなど)を使用することで対応できます。

残念ながら、flexboxのサポート環境はまだ万全ではありませんが、今後改善されていく予定です。flexboxの古い仕様と新しい仕様が混在してかまわなければ、ほとんどのブラウザーを使用できます。

仕様がひととおり固まったことで、今後まもなく、どの最新ブラウザーも(ベンダープレフィックスなど)何らかの方法で最新仕様をサポートするようになるでしょう。Internet Explorerに関しては、旧バージョンまで遡ってサポートするか、polyfillを使用するかを検討する必要があります。