CSS flexboxのレイアウトで困った時に使えるスタイルシートのテクニックまとめ
Post on:2017年6月6日
flexboxを使ってレイアウトを実装するのは、何年もの間floatやclearfixを使っていた人に新しい驚きと喜びを与えます。主要なブラウザすべてにサポートされ、採用するプロジェクトも増えてきました。
しかし、以前のテクニックはflexboxに通用しません。
flexboxの仕様に基づいた、レイアウトで困った時に使えるスタイルシートのテクニックを紹介します。
11 things I learned reading the flexbox spec
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
- 01. flexboxにおけるmarginの特別な効果
- 02. min-widthでよくある問題
- 03. flexのデフォルト値に注意
- 04. flexboxはインラインにも使える
- 05. vertical-alignはflexアイテムには影響を与えない
- 06. %指定のmarginやpaddingは使わない
- 07. 隣接するflexアイテムのマージンは相殺しない
- 08.「position: static;」の場合でもz-indexは機能する
- 09. flex-basisは意外と重要
- 10 .align-itemsで垂直に整列させる
- 11. おわりに
01. flexboxにおけるmarginの特別な効果
下記のように、ロゴとタイトルのテキストとボタンを横並びに配置したいと考えました。
ヘッダのレイアウト(実際には点線は無しで)
これをflexboxで実装するためには、.titleに「flex: 1;」を指定して、残りの要素を押して配置する必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 |
.header { display: flex; } .header .logo { /* 何も必要ありません! */ } .header .title { flex: 1; } .header .sign-in { /* 何も必要ありません! */ } |
このシンプルさが、flexboxの非常に素晴らしいポイントです。
しかし、何らかの理由で、他の要素を押したくないことがあるかもしれません。画像だったり、下線だったり、あるいは別の理由かもしれません。
その場合は、「margin-left: auto;」をその他の要素に指定することで、右に押しだす状態をつくりだすことができます。「float: right;」のような感じです。
例えば、左の要素が画像であるなら、下記のようになります。
左の要素が画像
画像に指定する必要はありません。flexコンテナにspace-betweenを指定する必要もありません。ボタンのclassに「margin-left: auto;」を指定するだけです。
1 2 3 4 5 6 7 8 9 |
.header { display: flex; } .header .logo { /* 何も必要ありません! */ } .header .sign-in { margin-left: auto; } |
このテクニックをハックだと思われるかもしれませんが、違います。flexアイテムをflexボックスの最後まで押しやるという仕様で、自動的にマージンを合わせます。
参考: CSS Flexible Box Layout Module Level 1
このページで紹介しているすべてのテクニックは「flex-direction: row;」を想定したものですが、row-reverse, column, column-reverse でも問題ありません。
02. min-widthでよくある問題
コンテナ内にすべてのflexアイテムが収まるように収縮させることは簡単だと考えるかもしれません。flexアイテムに「flex-shrink: 1;」を指定すれば、確かに実現します。
例えば、下記のように書名のテキストとボタンを横並びにしたいと考えます。
書名と購入ボタン
これをflexboxで実装してみます。
1 2 3 4 5 6 7 8 9 10 11 12 |
.book { display: flex; } .book .description { font-size: 30px; } .book .buy { margin-left: auto; width: 80px; text-align: center; align-self: center; } |
書名のテキストが短い場合でも、購入ボタンは右端に配置したいため、01で使ったテクニック「margin-left: auto;」を指定しました。
しかし、書名が長い場合はそのテキストは可能な限り多くのスペースを使い、折り返されて表示されます。
あなたはこの結果に、不快な驚きを得るかもしれません。
書名が長い場合
レイアウトが崩れています!
もしレッドの境界線がスクリーンのサイズだったら、購入ボタンは表示されていません。
【メモ】わたしの勤務先ではこういったテストしてくれるQAチームが存在します。
この原因は、.descriptionの「min-width」がデフォルトで「auto」に設定されているためです。flexアイテムは文字通り、その言葉よりも狭くすることはできません。
原因が分かれば、解決方法も簡単です。
デフォルトで「min-width: auto;」になってしまっているので「min-width: 0;」を上書きし、このアイテムがその内容よりも狭いことを明示します。
また、アイテム内のテキストをどのように処理するかは自由です。私はword-wrapを指定することをお勧めします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.book { display: flex; } .book .description { font-size: 30px; min-width: 0; word-wrap: break-word; } .book .buy { margin-left: auto; width: 80px; text-align: center; align-self: center; } |
結果は、下記のようになります。
実装の結果
繰り返しになりますが、「min-width: 0;」はうまく処理するためのハックではなく、仕様から推奨されるテクニックです。
次のセクションでは、購入ボタンの幅が80pxになっていないことについて解説します。
03. flexのデフォルト値に注意
あなたが知っているように、「flex」は「flex-grow」「flex-shrink」「flex-basis」の3つのショートハンドです。
この3つを組み合わせて使う時に一般的なのは、下記でしょうか。
- コンテナに十分な広さがなく、アイテムをちょっと詰めておきたい時: 「flex: 0 1 auto;」
- コンテナに十分な広さがなく、アイテムで空きスペースを埋めるために伸ばす必要がある場合: 「flex: 1 1 auto;」
- アイテムがフレキシブルでない場合: 「flex: 0 0 auto;」
1つ目の指定はデフォルト値で、2つ目は「flex: auto;」で適用でき、3つ目は「flex: none;」で適用できます。なぜこの値がデフォルトなのかというと、その値が有用であると考えられているためです。
購入ボタンの実装に戻りましょう。
購入ボタンの幅を80pxに
購入ボタンを首尾一貫して同じ幅にするには、「flex: none;」を加えるだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
.book { display: flex; } .book .description { font-size: 30px; min-width: 0; word-wrap: break-word; } .book .buy { margin-left: auto; flex: none; width: 80px; text-align: center; align-self: center; } |
もちろん、「flex: 0 0 80px;」とすることもできました。しかし、「flex: none;」と指定することで、意図を明確に表しているという点で素晴らしいコードだと思います。また、こう指定することで、未来の自分がどのような目的で指定したか忘れてしまっても問題ありません。
プロパティの使い方
- flexboxアイテム: flex: 各プロパティの使い方をヴィジュアルで詳しく解説
04. flexboxはインラインにも使える
正直に言うと、わたしは数ヵ月前に「display: inline-flex;」の存在を知りました。これはflexコンテナをブロックではなく、インラインにすることができます。
このプロパティの存在は、意外と知られていない思います。
プロパティの使い方
- flexboxの使い方: 各プロパティの使い方をヴィジュアルで詳しく解説
05. vertical-alignはflexアイテムに影響を与えない
これはおそらく半分以上の人が知っていると思いますが、中央に配置するために「vertical-align: middle;」を指定しても機能しません。
これはflexboxの仕様によるもので、「vertical-alignはflexアイテムに影響を与えない」と記載されています(floatと同じですね)。
参考: CSS Flexible Box Layout Module Level 1
06. %指定のmarginやpaddingは使わない
これは単なるベストプラクティスではなく、おばあちゃんの知恵のようなものです。
marginやpaddingに%指定は避けるべきである -flexboxの仕様に愛を込めて
このことは、CSSWGの中でコンセンサスがとれているものではありませんが、用心してください。
07. 隣接するflexアイテムのマージンは相殺しない
マージンが隣接した場合に、相殺されることを知っているかもしれません。そして、相殺されないことがあることも知っているかもしれません。
そして今、わたし達は隣接するflexアイテムのマージンが相殺しないことを知っています。
08.「position: static;」の場合でもz-indexは機能する
わたしはこのことに気がついていない人がいると思います。これに気がつくと、非常に役立ちます。
flexアイテムにz-indexを指定したい場合、positionを指定する必要がありますか? いいえ、flexアイテムには必要ありません。
09. flex-basisは意外と重要
もしあなたが、3,3,4の値でflexアイテムがあるなら、flex-basisが0の場合、コンテンツにかかわらず利用可能なスペースの30%、30%、40%を割り当てます。そう、0である限り。
しかし、予測しにくい方法で動作させたい場合は「flex-basis: auto;」を使用します。これはflexの値を考慮するだけでなく、他の要因も考慮し、機能すると思う幅を考え出してください。
flex-basisの仕様を確認してみましょう。
flex-basisの仕様
わたしはこの仕様について言及しているブログの記事があると確認していますが、理由はどうあれ、仕様を画像で見るまで実際にクリックしませんでした。
プロパティの使い方
- flexboxアイテム: flex-basis: 各プロパティの使い方をヴィジュアルで詳しく解説
10. align-itemsで垂直に整列させる
わたしはflexアイテムを垂直に整列させたい場合は、常に「align-items: center」を使用しています。しかし、 「vertical-align」のように、値をベースラインに設定できるオプションもあります。これはアイテムのフォントサイズが異なり、ベースラインを整列させたい場合に適しています。
「align-self: baseline;」でも機能します。
プロパティの使い方
- flexboxコンテナ: align-items: 各プロパティの使い方をヴィジュアルで詳しく解説
- flexboxアイテム: align-self: 各プロパティの使い方をヴィジュアルで詳しく解説
11. おわりに
わたしは次の仕様を何度も読み返しましたが、理解するのが困難です。
The content size is the min-content size in the main axis, clamped, if it has an aspect ratio, by any definite min and max cross size properties converted through the aspect ratio, and then further clamped by the max main size property if that is definite.
コンテンツのサイズは主軸の最小コンテンツのサイズです、固定され、アスペクト比の場合は、アスペクト比を通じて変換された最小および最大のクロスサイズのプロパティによって決定され、さらに最大メインサイズのプロパティで固定されます。
仕様を読んで分かったことは、比較的簡単なことでも実は正しく理解していなかったことでした。経験は何年もの間、同じことをしているだけではないということが分かります。
わたしは前に書いたコードを読み返し、自動マージンを設定し、flexの値にautoやnoneのショートハンドを指定し、必要に応じてmin-widthを0に指定しました。
これらがうまく機能すると知っているので、非常に気分よく感じます。
sponsors