HTMLのレイアウト方法で最も新しいフレキシブルボックスをまめわざでも利用しています。
手軽に並列レイアウトができるスタイルですが、他の並列レイアウトとの使い分けはどうすべきか、flexにしかできない表現はあるのかを、実例を挙げながら解説します。
ある要素に定義するだけで、その直下の要素が並列になる便利なスタイルです。
シンプルな導入であれば、CSSで「display:flex」というスタイルを指定するだけです。
<ul>
<li>1番目の要素</li>
<li>2番目の要素</li>
<li>3番目の要素</li>
</ul>
ul {
display: -webkit-flex;
display: flex;
}
<style type="text/css" scoped>
ul {
display: -webkit-flex;
display: flex;
}
</style>
<style type="text/css" scoped>
ul {
display: -webkit-flex;
display: flex;
-webkit-justify-content: center;
justify-content: center;
-webkit-align-items: center;
align-items: center;
height: 200px;
}
中央寄せは、並列の場合の左右方向は
justify-content: center;
で、上下方向は
align-items: center;
で指定します。
ul {
display: -webkit-flex;
display: flex;
-webkit-justify-content: flex-end;
justify-content: flex-end;
-webkit-align-items: flex-end;
align-items: flex-end;
height: 200px;
}
上の例と同じプロパティを利用します。
left/topはflex-start、right/bottomはflex-endを使う点に注意しましょう。
このような右下寄せは、他の方法では容易ではないので、利用シーンがあればflexの出番と言えます。
使い方 | 解説 | |
float:left法 | 並列させたい要素のスタイルにfloat:left | 要素を回り込みさせることで並列レイアウトを実現 |
display:inline-block法 | 並列させたい要素のスタイルにdisplay:inline-block | 要素をインライン化(左寄せの場合に左詰め)することで並列レイアウトを実現 |
table法 | tableタグを利用するか CSSのdisplay:tableを使って要素をテーブル化 | 要素をテーブル化することで、並列・縦列を操る |
このように、並列レイアウトにはいくつか選択肢があり、必ずしもflexを採用する必要がありません。
しかし、flexにしかできない(あるいは別の方法ではコードが極めて冗長的になる)ケースがあります。これまでに利用した例から、flexの出番といえる使い方を以下に挙げてみました。
flex-directionプロパティを使うと、HTMLはそのままで、要素の順番逆転が可能です。更にrow/columnを指定して縦列でも利用が可能です。
また、orderプロパティで順番を明示できます。以下に、並列・縦列の順番入替えの例を挙げます。
ul {
display: -webkit-flex;
display: flex;
-webkit-justify-content: flex-end;
justify-content: flex-end;
-webkit-flex-direction: row-reverse;
flex-direction: row-reverse;
}
左右中央揃えを決める
justify-content
プロパティは、デフォルトではflex-startで、要素は先頭から配置されます。
flex-direction: row-reverse
として順番を入れ替えた場合は、先頭が右側と認識されるため、左寄せにするためには明示的に
justify-content: flex-end
として末尾から配置する必要があります。
ul {
display: -webkit-flex;
display: flex;
-webkit-align-items: flex-start;
align-items: flex-start;
-webkit-flex-direction: column-reverse;
flex-direction: column-reverse;
}
並び順と垂直の方向(並列の場合は縦方向、縦列の場合は横方向)の左右中央揃えを決める
align-items
は、デフォルトでstretch(引延し)のため、display:blockのように隙間なく要素が伸長します。明示的に
align-items: flex-start
とすると、stretchが解除されます。
ul.flx13 {
display: -webkit-flex;
display: flex;
}
ul.flx13 li:nth-of-type(3) {
-webkit-order: -1;
order: -1;
}
3番めの子要素にorderプロパティで順番を指定しています。
orderのデフォルト値は0のため、負数を指定することで1番目に設置できます。
3番めに1、1番目に2、2番めに3と全要素に順番を明示することも可能です。
左右中央揃えを設定する
justify-content
は、より正確に言えば「要素の展開方向(並列の場合は横方向、縦列の場合は縦方向)の要素の配置方法」を設定するプロパティです。
text-align: left/center/right(または縦列ならばvertical-align: top/center/bottom)
に対応した
justify-content: flex-start/center/flex-end
としての利用のほか、
justify-content: space-between/space-around
として均等配置を指定できます。これらの違いは、先頭の末尾の要素の前後にスペースが含まれるかどうかです。以下の実例を見れば一目瞭然です。
ul {
display: -webkit-flex;
display: flex;
-webkit-justify-content: space-between;
justify-content: space-between;
}
ul {
display: -webkit-flex;
display: flex;
-webkit-justify-content: space-around;
justify-content: space-around;
}
ul {
display: -webkit-flex;
display: flex;
-webkit-justify-content: space-between;
justify-content: space-between;
-webkit-align-items: flex-start;
align-items: flex-start;
-webkit-flex-direction: column;
flex-direction: column;
height: 200px;
}
ul {
display: -webkit-flex;
display: flex;
-webkit-justify-content: space-around;
justify-content: space-around;
-webkit-align-items: flex-start;
align-items: flex-start;
-webkit-flex-direction: column;
flex-direction: column;
height: 200px;
}
フレックスボックスの子要素にmargin: autoを設定することで、一部の要素だけを左右または上下に寄せることが可能です。以下、実例をご覧ください。
ul {
display: -webkit-flex;
display: flex;
-webkit-justify-content: flex-start;
justify-content: flex-start;
}
ul li:last-of-type {
margin-left: auto;
}
最後の要素にmargin-left:autoを設定し、左マージンを最大にしています。
ul {
display: -webkit-flex;
display: flex;
-webkit-justify-content: flex-start;
justify-content: flex-start;
}
ul li:nth-of-type(2) {
margin-left: auto;
background-color: #ffc;
}
2番めの要素にmargin-left:autoを設定し、右寄せをして、その右側にある要素も影響を受けています。
ul {
display: -webkit-flex;
display: flex;
-webkit-justify-content: flex-start;
justify-content: flex-start;
-webkit-align-items: flex-start;
align-items: flex-start;
-webkit-flex-direction: column;
flex-direction: column;
height: 200px;
}
ul li:last-of-type(3) {
margin-top: auto;
}
ul {
display: -webkit-flex;
display: flex;
-webkit-justify-content: flex-start;
justify-content: flex-start;
-webkit-align-items: flex-start;
align-items: flex-start;
-webkit-flex-direction: column;
flex-direction: column;
height: 200px;
}
ul li:nth-of-type(1) {
margin: 0 auto auto 0;
}
ul li:nth-of-type(2) {
margin: auto;
}
ul li:nth-of-type(3) {
margin: auto 0 0 auto;
}
このようにmargin:autoの組み合わせによって、かなり自在な配置が可能です。
子要素に、下記のようなプロパティを設定することで、大きさを微調整できます。
flex-grow | 伸長率 (ただし%ではなく数字) |
flex-shrink | 縮小率 (ただし%ではなく数字) |
flex-basis | 固定サイズ (ただし要素が指定サイズを超えてもはみ出さない) |
子要素の大きさを微調整できるのは、flexの最大の特徴の1つと言えます。
多くの場合、この仕様こそが「css flexを採用せざるを得ない」一番の理由になると思われます。
ul {
display: -webkit-flex;
display: flex;
-webkit-justify-content: flex-start;
justify-content: flex-start;
}
ul li {
-webkit-flex-grow: 1;
flex-grow: 1;
}
全ての要素にflex-grow:1を指定することで、1:1:1の比率で要素が伸長し、隙間が埋まります。
ul {
display: -webkit-flex;
display: flex;
-webkit-justify-content: flex-start;
justify-content: flex-start;
}
ul li:nth-of-type(2) {
-webkit-flex-grow: 1;
flex-grow: 1;
}
2番めの要素だけにflex-grow:1を指定することで、2番めだけが伸長し、隙間が埋まります。
1番目と3番めにflex-shrink:1を指定した場合も同様です。
ul {
display: -webkit-flex;
display: flex;
-webkit-justify-content: flex-start;
justify-content: flex-start;
}
ul li:nth-of-type(1) {
-webkit-flex-basis: 50px;
flex-basis: 50px;
}
ul li:nth-of-type(2) {
-webkit-flex-grow: 1;
flex-grow: 1;
}
ul li:nth-of-type(3) {
-webkit-flex-grow: 1;
flex-grow: 1;
}
1番めの要素にflex-basis:50pxを指定してサイズを固定し、2・3番目にflex-growを指定することで隙間を埋めています。
2・3番目のflex-growを指定しない場合は、1番目のサイズが固定されるだけで、隙間が埋まりません。
このflex-basisは、指定したサイズにできない場合は、それ以下のサイズに調整される「緩いサイズ指定」とも呼べる大きな特徴があります。これについては、下記のフォームの例で説明します。
ネット上の解説などを見ると、隙間を埋める魔法の言葉としてflex:1が多く紹介されていますが、やりたいことはflex-grow:1であることが分かります。
flex:1は、flex-grow:1、flex-shrink:1と解釈され、flex-grow:1だけの場合とは異なる挙動を表す場合があります。
例えばIE11では、flex:1とした要素の下に、サイズを指定した要素がある場合にはみ出してしまう現象が見られます(flex-wrap:wrapを無視してnowrapになります)ので、利用しないほうが無難です。
flexの改行可否を指定するプロパティ
flex-wrap
は、デフォルトではnowrapで改行を禁止しています。
これをwrap(改行可)にした場合に、flexの個性が光ります。以下に例を挙げます。
子要素を50%とサイズ指定しました。
これにより、1番目と2番めは均等に配置されます。
一方で、3番めは改行され、flex-growを優先して(サイズ指定は無視して)伸長します。これにより、最小サイズを保ちながら隙間を埋めることが可能になります。
ul {
display: -webkit-flex;
display: flex;
-webkit-justify-content: flex-start;
justify-content: flex-start;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
}
ul li {
-webkit-flex-grow: 1;
flex-grow: 1;
width: 50%;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
上の実例を組み合わせて、次のような条件を満たすフォームを作成してみます。
liにflexを設定し、その子要素のspanを並列配置しています。
flex-wrap: wrapとして並列と縦列を混合し、flex-basisで「はみ出さないサイズ指定」をしています。
サイズ指定は全てflex-basisに譲り、inputとtextareaのサイズは100%としています。
<style type="text/css" scoped>
ul li {
display: -webkit-flex;
display: flex;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-align-items: center;
align-items: center;
}
ul span:first-of-type {
-webkit-flex-basis: 120px;
flex-basis: 120px;
}
ul span:nth-of-type(2) {
-webkit-flex-basis: 210px;
flex-basis: 210px;
-webkit-flex-grow: 1;
flex-grow: 1;
}
ul input[type="text"], ul textarea {
width: 100%;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
</style>
<ul style="width:○○px">
<li><span>お名前</span>
<span><input type="text" name="name" size="20" /></span></li>
<li><span>電話番号</span>
<span><input type="text" name="tel" size="20" /></span></li>
<li><span>お問合せ内容</span>
<span><textarea name="content" cols="30" rows="5"></textarea></span></li>
<li><span>送信</span>
<span><input type="submit" value="送信" /></span></li>
</ul>
上から順に800px、500px、300px、200px、100pxとしています。
800pxと500pxでは全ての入力欄と見出しの組み合わせが並列になり、入力欄のサイズ幅だけが変動しています。
300pxでは、見出しと入力欄の推奨サイズである120+210=330pxを下回るため縦列化し、かつinputは横いっぱいに配置されます。
200px、100pxでは、それぞれ入力欄と見出しの推奨サイズを下回っているものの、はみ出すことなく表示されます。
このフォームは、テーブルレイアウトとRWDの組み合わせでも実現が可能ですが、並列と縦列を切り替えるためにメディアクエリを使って複数種類のCSSを定義する必要があります。
このコードではメディアクエリを使わずにRWDを実現しており、ディスプレイサイズではなく実際のフォームのサイズによってレイアウトが変わる点でメディアクエリより優れています。コーディングを減らせるメリットも有ります。
上記のフレックスボックスが対応していないブラウザについて、今回取り上げた実例で使ったプロパティの対応表を用意しました。
主に古いAndroid、iOS、OSXのSafariが対象です。
プロパティの効果 | モダンブラウザ | 旧webkit系ブラウザ | |
css flexの宣言 | display: -webkit-flex; display: flex; | display: -webkit-box; | |
揃え | 並列時の左右中央揃え、 縦列時の上下中央揃え | -webkit-justify-content: flex-start (center/flex-end); justify-content: flex-start (center/flex-end); | -webkit-box-pack: start (/center/end); |
並列時の上下中央揃え、 縦列時の左右中央揃え | -webkit-align-items: flex-start (/center/flex-end); align-items: flex-start (/center/flex-end); | -webkit-box-align: start (/center/end); | |
順番入替 | 順番逆転(並列) | -webkit-flex-direction: row-reverse; flex-direction: row-reverse; | -webkit-box-direction: reverse; |
順番逆転(縦列) | -webkit-flex-direction: column-reverse; flex-direction: column-reverse; | -webkit-box-direction: reverse; -webkit-box-orient: vertical; | |
順番指定 | ある子要素に -webkit-order: -1; order: -1; | それぞれの子要素に -webkit-box-ordinal-group: 1; -webkit-box-ordinal-group: 2; -webkit-box-ordinal-group: 3; | |
均等配置 | 左右隙間あり | -webkit-justify-content: space-between; justify-content: space-between; | -webkit-box-pack: justify; |
左右隙間なし | -webkit-justify-content: space-around; justify-content: space-around; | -- | |
自在に配置 | margin-○○: auto | -- | |
並列幅の指定 | 均等または一部 (一部の場合は1つの要素に適用) | 子要素に -webkit-flex-grow: 1; flex-grow: 1; | 子要素に -webkit-box-flex: 1; |
固定サイズ | ある子要素に -webkit-flex-basis: 50px; flex-basis: 50px; | -- | |
並列・縦列混合 | -webkit-flex-wrap: wrap; flex-wrap: wrap; | -- |
並列・縦列の混合ができず、display:-webkit-boxを指定した時点で、テーブルレイアウトの如く全ての並列化します。よって、フレックスボックスの最大の利点が活かせません。残念なことに、対象の多くが古いスマートフォンのため、主にスマホ向けに利用したい「並列・縦列混合レイアウト」を利用する際にネックになります。
この場合は「display:-webkit-boxを利用しない」という選択肢を考慮しましょう。上のフォームの例では、全てが縦列になり、ユーザー体験を損ないません。全てが並列になるぐらいなら縦列の方が良い場合が多いと思われます。
また「自在に配置」ができないので、配置が極めて重要な表現を担う場合は、専用のフォローが必要です。
プロパティの効果 | モダンブラウザ | 旧webkit系ブラウザ | |
css flexの宣言 | display: -webkit-flex; display: flex; | display: -ms-flexbox; | |
揃え | 並列時の左右中央揃え、 縦列時の上下中央揃え | -webkit-justify-content: flex-start (center/flex-end); justify-content: flex-start (center/flex-end); | -ms-flex-pack: start (/center/end); |
並列時の上下中央揃え、 縦列時の左右中央揃え | -webkit-align-items: flex-start (/center/flex-end); align-items: flex-start (/center/flex-end); | -ms-flex-align: start (/center/end); | |
順番入替 | 順番逆転(並列) | -webkit-flex-direction: row-reverse; flex-direction: row-reverse; | -ms-flex-direction: row-reverse; |
順番逆転(縦列) | -webkit-flex-direction: column-reverse; flex-direction: column-reverse; | -ms-flex-direction: column-reverse; | |
順番指定 | ある子要素に -webkit-order: -1; order: -1; | ある子要素に -ms-flex-order: -1; | |
均等配置 | 左右隙間あり | -webkit-justify-content: space-between; justify-content: space-between; | -ms-flex-pack: justify; |
左右隙間なし | -webkit-justify-content: space-around; justify-content: space-around; | -ms-flex-pack: distribute; | |
自在に配置 | margin-○○: auto | margin-○○: auto | |
並列幅の指定 | 均等または一部 (一部の場合は1つの要素に適用) | 子要素に -webkit-flex-grow: 1; flex-grow: 1; | 子要素に -ms-flex: 1 0 auto; |
固定サイズ | ある子要素に -webkit-flex-basis: 50px; flex-basis: 50px; | ある子要素に -ms-flex: 0 0 50px; | |
並列・縦列混合 | -webkit-flex-wrap: wrap; flex-wrap: wrap; | -ms-flex-wrap: wrap; |
-ms-flex-wrap:wrap;があるものの、サイズ指定より並列が優先されるため、意図した並列・縦列混合ができません。上の旧webkitの例と同じく「全てが並列になるぐらいなら全てが縦列の方が良い」場合はdisplay:-ms-flexbox;の利用を止めましょう。ただしIE10が対象であることを考えると、常に並列でも問題がないケースが多いと思われますので、旧webkitの場合と異なり利用する機会が増えそうです。
並列幅の指定時に-ms-flexを設定する際は、必ず-ms-flex:1 0 auto;と3つの値を設定しましょう。-ms-flex:1;とした場合、IE11は2番めの値であるflex-shrinkに1が省略されていると勝手に判定し、思い通りの幅にならない場合があります。IE10対策がIE11に悪影響を及ぼすケースなので注意が必要です。
これ以外は、ほぼ全てが対応しているので、コーディングの手間以外に追記するデメリットはありません。
並列表示にflexを利用する場合は、子要素にdisplay:inline-blockやfloat:leftを指定することで、未対応のブラウザでもある程度並列表現を再現できます。
順番入替・配置は対処のしようがないため、未対応ブラウザを無視するか、Javascriptなどで別途対応が必要です。
隙間を埋めるため、または幅を指定するために利用する場合は、他ブラウザと見た目が異なりますが、内容が表示されれば最低限のクロスブラウザは実現できます。