そこが知りたい、Flexbox 第1回 仕様を知る 1

この記事では、CSS Flexible Box Layout Moduleによるカラムレイアウトの仕様を解説します。フレックスコンテナと、フレックスアイテム、それぞれに設定できるプロパティを紹介します。

発行

著者 坂巻 翔大郎 フロントエンド・エンジニア
そこが知りたい、Flexbox シリーズの記事一覧

基本的な仕様は変わっていません。仕様策定が続いていますので、最新仕様については仕様書もご確認ください。(2019.05.16)

Flexible Box Layoutでカラムレイアウト

たとえば、左右にカラム分けされたレイアウトを作りたいとします。これをCSSで実現する方法は何通りも存在します。

過去にCodeGridで紹介したような*table-cellinline-blockを利用したカラムレイアウトであったり、単純にfloatを使用したものであったり、display: grid;であったり……。

*注:これまでに紹介した記事

方法は挙げればきりがないのですが、今回はCSS Flexible Box Layout Module(以下、Flexbox)に触れたいと思います。また、今回の記事では古いシンタックスには触れず、執筆時点での最新の仕様*を元に解説していきます。

*注:執筆時点での最新の仕様

執筆者が元にした執筆時点(2015年4月上旬)での最新の仕様は、次の通りです。

CSS Flexible Box Layoutは文字通りレイアウトのための仕様です。CSS 2.1での仕様には、みなさんがよく知っている、次のような仕様があります。

  • block layout
  • inline layout
  • table layout
  • positioned layout

flex layoutもこれらのレイアウトモードのひとつで、より複雑なWebアプリケーションやWebページのレイアウトためにデザインされたものです。

なお、紹介するサンプルは次のリポジトリからダウンロード、またはクローンできます。併せて参照してください。

Flexible Boxサンプルリポジトリ

Flexboxを使うとどういったことができるのか

では、そのFlexboxを使うと、どんな悩みが解決されるのかを、筆者なりに考えてみました。

  • 兄弟要素の高さを揃えたい
  • 子要素の高さを親要素の高さにしたい
  • table-cellで実装する際、position: relative;を指定したい
  • カラムの順番を入れ替えたい
  • 上下中央配置をしたい

これらはFlexboxを使わなくとも、実装が可能かもしれません。

たとえば、カラムの順番を入れ替えるといったことは、以前小山田が、「CSS再入門 display: tableの活用 3」で紹介した方法があります。

この方法では、display: tableを指定した要素に、directionプロパティを使用して文章の方向を逆にすることで、カラムを入れ替えるという方法がありました。とても有用ですが、筆者的には少しトリッキーな方法に思えました。

小山田も書いているように、このプロパティは本来はアラビア語やヘブライ語といった、右から読み進めるための言語のテキストの記述方向をコントロールするためのプロパティだからです。

その振る舞いを知っていれば、「なるほど。」と理解することができるのですが、知らない場合、そこで使われているdirectionプロパティの本来の使用目的から、文章を右から始まるようにしたいのかな? と思ってしまうからです。

上下中央配置についても、古くから試行錯誤され、とてもトリッキーな手法が多く存在します。コードだけを一見しても、何をしているかが不明瞭なものが多くあります。

一方、Flexboxはレイアウトをするための仕様です。いろいろな配置がやりやすくなるメリットが注目されがちですが、それに加えて、CSSを見たとき、どういったレイアウトを作るためのコードなのかが、わかりやすくなるのもメリットだと筆者は考えています。

対応ブラウザ

対応ブラウザに触れておきます。最新のブラウザではほとんど使うことができますが、Internet Exprolerは11以降、Android 4.4以降でないと使えません。また現在でもSafariとiOS Safariには-webkit-のベンダープリフィックスが必要です。

古いブラウザは対応しておらず、どんなサイトでも使えるとは言いがたいですが、限られた環境では優れた実装となりうることもあります。

しかしながら、正直理解しづらい仕様だと思いますので、この記事で学んでいきましょう。

フレックスコンテナとフレックスアイテム

Flexboxを攻略するには、まず2つの重要な用語を押さえる必要があります。

フレックスコンテナフレックスアイテムという用語は、Flexboxを理解する上で、一番大事な言葉です。

display: flex;(またはinline-flex)が指定された要素を「フレックスコンテナ(flex container)」と呼び、その子要素を「フレックスアイテム(flex item)」と呼びます。親要素がdisplay: flex;であれば、その子要素が自動的にフレックスアイテムとなります。

Flexboxに関連するプロパティは、名前がややこしく覚えづらいのですが、フレックスコンテナに指定できるプロパティと、フレックスアイテムに指定できるプロパティとで分けられるので、それぞれ解説していきます。

フレックスコンテナに指定できるプロパティ

まずは、フレックスコンテナとなる要素に指定できるプロパティです。

display

displayプロパティにflexもしくはinline-flexを指定することで、フレックスコンテナなります。そして、フレックスコンテナの直下の子要素が、自動的にフレックスアイテムになります。注意したいのは、孫要素はフレックスアイテムにはならないことです。

.container {
  display: flex; /* or inline-flex */
}

flex-direction

フレックスアイテムを縦並び、もしくは横並びにするかどうかの配置を指定します。

.container {
  flex-direction: row | row-reverse | column | column-reverse;
}

*注:|

コード中の|は、「いずれか(or)」という意味です。仕様書にはよく出てくる記述なので、覚えておくとよいでしょう。

それぞれのプロパティ値の意味は、次のようになります。

意味
row 初期値。ltr*の中では左から右に、rtl*の中では右から左に並びます
row-reverse ltrの中では右から左に、rtlの中では左から右に並びます
column 上から下に並びます。
column-reverse 下から上に並んでいきます。

*注:ltrrtl

ltrrtlは、文字表記の方向のことです。ltrleft to rightrtlright to leftの意味で、dir属性やdirectionプロパティで使用されるキーワードです。

flex-wrap

通常、フレックスアイテムは1行にすべて収まろうとします。wrapwrap-reverseを指定することで、フレックスアイテムがその行に収まりきらないときは、次の行へ折り返させることができます。また、折り返す際にどちらから始まるかも指定できます。

.container{
  flex-wrap: nowrap | wrap | wrap-reverse;
}
意味
nowrap 初期値。折り返しは発生しない
wrap フレックスコンテナの行(または列)に、収まり切らなかった場合は、複数行(または複数列)になる。flex-direction: row;のときは、下に折り返す。flex-direction: column;のときは、文字の表記方向に従って折り返す
wrap-reverse フレックスコンテナの行(または列)に、収まり切らなかった場合は、複数行(または複数列)になる。flex-direction: row;のときは、上に折り返す。flex-direction: column;のときは、文字の表記方向とは逆に折り返す

flex-directionによるフレックスアイテムの並ぶ方向や、flex-directionと同様に、flex-wrapも文字の表記方向によって、フレックスアイテムの折り返す方向が変わります。それぞれの組み合わせによって、どうフレックスアイテムがどう並ぶかを図示してみました。

まずは、文字の表記方向が左から右(ltr)になっていて、flex-direction: row;のときと、flex-direction: column;のときの、flex-wrapの各値を指定をした場合の図です。

図の左のflex-direction: row;のときは、縦軸の向きを変化させ、右のflex-direction: column;のときは横軸の向き変化させます。

次に、文字の表記方向が右から左(rtl)の場合を見てみましょう。

フレックスアイテムは文字の表記方向にそって並びます。図の左のflex-direction: row;のときは、縦軸の向きが変化するだけなので、特に難しくはないのですが、右のflex-direction: column;のときは、横軸の向きが変化するため混乱しそうです。ですが、あくまで文字の表記方向にそって折り返すのか、文字の表記方向とは逆に折り返すのかの差でしかありません。

flex-flow

flex-flowプロパティはflex-directionflex-wrapのショートハンドプロパティです。初期値はrow nowrapです。

.container{
  flex-flow: <`flex-direction`> || <`flex-wrap`>;
}

justify-content

このプロパティでは、flex-directionで指定した配置を基準にして、フレックスアイテム全体の整列を指定します。

.container {
  justify-content: flex-start | flex-end | center | space-between | space-around;
}

プロパティ値の意味は、次のようになります。

意味
flex-start flex-direction: row;のときは左揃えになり、flex-direction: column;のときは上揃えになる
flex-end flex-direction: row;のときは右揃えになり、flex-direction: column;のときは下揃えになる
center 中央配置される。
space-between 均等に余白をあけるが、両端には余白を作らない
space-around 均等に余白をあけ、両端にも余白が作成される

align-items

このプロパティでは、フレックスアイテムごとの整列方向をまとめて指定できます。

.container {
  align-items: flex-start | flex-end | center | baseline | stretch;
}

それぞれのプロパティ値の意味は、次の通りです。

意味
flex-start flex-direction: row;のときは上揃えになり、flex-direction: column;のときは左揃えになる
flex-end flex-direction: row;のときは下揃えになり、flex-direction: column;のときは右揃えになる
center 中央に揃う
baseline 文字のベースラインに揃える
stretch 高さが指定されていない場合、フレックスコンテナの高さまで広がる。またflex-flow: row wrap;などのときに、折り返す場合は、同じ行にあるフレックスアイテムの高さが同じになる

align-content

flex-wrapプロパティの値に、wrapまたはwrap-reverseを指定した場合に、このプロパティは有効になります。複数行になったとき、フレックスアイテムをどのように揃えるかを指定できます。

.container {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}

それぞれのプロパティ値の意味は、次の通りです。

意味
flex-start flex-direction: row;のときは左揃えになり、flex-direction: column;のときは上揃えになる
flex-end flex-direction: row;のときは右揃えになり、flex-direction: column;のときは下揃えになる
center 中央配置される
space-between 均等に余白をあけるが、両端には余白を作らない
space-around 均等に余白をあけるが、両端にも余白が作られる
stretch 余白が作られないようにフレックスアイテムの大きさを調整する

フレックスアイテムに指定できるプロパティ

フレックスアイテム自身の振る舞いを指定するプロパティがいくつかあります。

align-self

align-selfプロパティは、個々のフレックスアイテムの整列を指定することができます。基本的には上揃えで、一部の要素だけ中央揃えにしたり、下揃えにしたりといった整列をするために使用します。

.item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

それぞれのプロパティ値の意味は、次の通りです。

意味
auto フレックスコンテナのalign-itemsプロパティで指定された値になる。指定されていない場合はstretchとなる
flex-start flex-direction: row;のときは上揃えになり、flex-direction: column;のときは左揃えになる
flex-end flex-direction: row;のときは下揃えになり、flex-direction: column;のときは右揃えになる
center 中央に揃う
baseline 文字のベースラインに揃う
stretch 高さが指定されていない場合、フレックスコンテナの高さまで広がる。またflex-flow: row wrap;などのときに折り返す場合は、同じ行にあるフレックスアイテムの高さが同じになる

order

orderプロパティは、フレックスコンテナの中のフレックスアイテムの順序を指定します。orderプロパティの値(整数)の昇順で配置されます。値が同じ要素は、ソースコード内で現れる順に配置されます。

orderはHTMLの順序を入れ替えるわけではないので、文書の意味が変わってしまう心配はありません。

.item {
  order: <integer>;
}

flex-basis

フレックスアイテムの基本の長さを指定します。

そのほかのプロパティの指定値によって、設定された値の振る舞いが変わってきます。

後述するflexプロパティでflex-basisの指定を省略した場合、値は0が指定されます。

またautoと指定した場合、フレックスアイテムの中身のコンテンツの大きさに依存します。

flex-directionプロパティの値がrowrow-reverseのときは、widthプロパティのように振る舞い、columncolumn-reverseのときは、heightプロパティのように振る舞います。

.item {
  flex-basis: <length> | auto;
}

flex-grow

フレックスアイテムが、ほかのフレックスアイテムに比べて、どれだけ伸びるかの比率です。フレックスコンテナがすべてのフレックスアイテムを収め切っても、まだ余りのスペースがある場合、各フレックスアイテムのflex-growプロパティに従い、自動的に利用可能な領域いっぱいまで伸びます。初期値は0です。

.item {
  flex-grow: <number>;
}

指定を見ただけでは直感的にわかりにくいのですが、おおむね次のような挙動になります。

このプロパティの詳細については、次回さらに詳しく解説します。

flex-shrink

フレックスアイテムが、ほかのフレックスアイテムに比べて、どれだけ縮むかの比率です。フレックスコンテナがflex-wrap: nowrapで、しかも、すべてのフレックスアイテムを収めきれない場合、各フレックスアイテムのflex-shrinkプロパティに従い、ちょうど格納できるように、自動的に縮みます。初期値は1です。

.item {
  flex-shrink: <number>;
}

このプロパティも指定を見ただけでは直感的にわかりにくいのですが、おおむね次のような挙動になります。

flex-growと併せて、flex-shrinkも次回、さらに詳しく解説します。

flex

flexプロパティはflex-grow flex-shrink flex-basis のショートハンドプロパティです。

flexプロパティの初期値は0 1 autoです。

.item {
  flex: none | [ <flex-grow> <flex-shrink>? || <flex-basis> ]
}

*注:仕様の読み方

上記のコードに使われている記号は、次のような意味を持ちます。

  • []:括弧内はひとつのグループ
  • ??があるものは、省略が可能。その値がなくてもよい
  • ||||の前後にあるものは、順不同で、どちらが先にきてもよい

それぞれの値は省略可能です。また、キーワードでの指定も可能です。そのような省略した書き方をした際は、自動的に決められた値に設定されます。その指定は、次のようになっています。

省略した書き方 実際の値
flex: inherit; flex: inherit inherit inherit;
flex: initial; flex: 0 1 auto;
flex: auto; flex: 1 1 auto;
flex: none; flex: 0 0 auto;
flex: 1; flex: 1 1 0%;
flex: 100px; flex: 1 1 100px;
flex: 2 100px; flex: 2 1 100px;
flex: 100px 2; flex: 2 1 100px;
flex: 1 2; flex: 1 2 0%;

まとめ

今回はflexible boxの仕様にあるプロパティを一通り説明しました。まずは、それぞれのプロパティで何が設定できるのかを理解しないと、さらにそれらを組み合わせた実装は理解できません。

ですが、そのうちflex-growflex-shrinkは、1行に収まるように、伸びたり、縮んだりするという概要はわかったと思いますが、どのように計算されて収まるかの計算は、やや複雑です。

次回はその2つのプロパティと取り上げて解説します。