フレックスボックスと他のレイアウト方法の関係

この記事ではフレックスボックスが他の CSS モジュールとどのように組み合わせられるかを見ていきます。フレックスボックスについて学びたいときに気をつけておくべき仕様を明らかにし、またなぜフレックスボックスが他のモジュールと異なったものであるかという点についても明確にします。

メモ: CSS のバージョン 1 と 2 は、すべての CSS を長大な一つの文書に定義している単一の仕様でした。 CSS が機能の豊富な言語になるに従って、 CSS の各機能がそれぞれ異なるスピードで変化するため、一つの巨大な仕様をメンテナンスしていくことが問題になってきました。そこで CSS はモジュール化され、現在では個別の CSS 仕様が異なるモジュールとして CSS 全体を構成しています。これらのモジュールは互いに関係し合っていますが、それぞれ異なる開発ステージにあります。

ボックス配置モジュール

多くの人にとってフレックスボックスに着目し始めた最初の理由は、フレックスコンテナー内でフレックスアイテムを適正に配置する機能があるためです。フレックスボックスはアイテムの交差軸上での位置合わせを行ったり、主軸上での端揃えを行うためのプロパティを提供しています。

これらのプロパティは、フレックスボックスの仕様として生まれましたが、現在では Box Alignment 仕様書の一部でもあります。この仕様はフレックスボックスに限らない、すべてのレイアウトにおいて配置がどのように動作するかについての詳細を記しています。ボックス配置は位置合わせや端揃えについて扱い、また軸に沿った余白の分配についても扱っています。

ボックス配置に含まれているプロパティがフレックスボックス仕様においても詳細に記述され残っているのは、すべてのレイアウトタイプにおける配置方法の詳細を記さなければいけないボックス配置によって、フレックスボックス仕様の完成が遅れることのないようにするためです。フレックスボックス仕様には、将来 Box Alignment Level 3 が完成した際には、フレックスボックス仕様の定義はボックス配置の定義に取って代わられるというメモがあります。

"メモ: 配置のためのプロパティは CSS Box Alignment [CSS-ALIGN-3] 中で定義されていますが、仕様策定を遅らせうるような依存関係を持たせないために、Flexible Box Layout にも同様のプロパティの定義が重複して掲載されています。これらのプロパティは CSS Box Alignment Level 3 が完成し、他のレイアウトモードへの効果を定義するまでは、flex レイアウトのみに適用されます。さらに、Box Alignment モジュールにて定義されるすべての新しい値は Flexible Box Layout にも適用されます。言い換えると、Box Alignment モジュールの完成後には、Box Alignment モジュールでの定義がここでの定義に取って代わるということです。" (訳注: https://www.w3.org/TR/css-flexbox-1/#alignment より引用)

このガイドの後の記事「フレックスコンテナー内のアイテムの配置」では、フレックスアイテムに適用できるボックス配置プロパティについて詳細に見ていきます。

書字方向

フレックスボックスの基本概念」の記事で、フレックスボックスが書字方向対応であることに触れました。書字方向については CSS の Writing Modes 仕様書で詳細に記されており、国によって異なる様々な書字方向にどのように CSS が対応しているか明らかにしています。書字方向によって文書中にレイアウトされるブロックの方向が変わることが、フレックスレイアウトにどのような影響を及ぼすかについて気を配らなければなりません。ブロック方向とインライン方向について理解することが、新しいレイアウト方法の鍵となります。

コンテンツが異なる書字方向の言語で書かれてるからという理由以外でも、文書の書字方向を変更したい場合があると知っておくことも大切です。各書字方向についての詳細な説明と、他言語のコンテンツのためあるいはクリエイティブな理由のために書字方向を使う方法については、この記事を参照してください。

書字方向

Writing mode 仕様では writing-mode プロパティのために以下の値を定義しており、特定の書字方向においてコンテンツがブロック内にレイアウトされる方向と、ブロックがページ内で配置される方向が適合するよう変更するために使えます。フレックスレイアウトに何が起こるかを理解するために、以下の例を変更してみてください。

  • horizontal-tb
  • vertical-rl
  • vertical-lr
  • sideways-rl
  • sideways-lr

sideways-rlsideways-lr の対応は現時点では Firefox のみということに注意してください。また writing-mode とフレックスボックスに関しての既知の問題がいくつかあります。ブラウザーの対応状況については MDN の書字方向のドキュメントに情報があります。しかし、もしレイアウトのために書字方向を設定する予定であれば、それがどのような結果になるか注意深くテストすることが推奨されます。比較的簡単に、文字が読みにくくなってしまうからです。

CSS の writing-mode プロパティを文書全体の書字方向を変更するために使うことはあまりないでしょう。通常は HTML 上で html 要素に dir 属性と lang 属性を指定することで、文書の言語とテキスト方向を指定します。それによって CSS が読み込まれなかったとしても文書を正しく表示することができます。

フレックスボックスと他のレイアウト方法

フレックスボックス仕様には、他のレイアウト方法を使用していて、それからフレックスアイテムになった場合に起こることの定義が含まれています。例えば float 設定されている要素がありその親要素がフレックスコンテナーとなった場合について、またあるいは、フレックスコンテナーがレイアウトの一部としてどのように振る舞うかについて記載されています。

display: flex に設定された要素は、他の包含ブロックを構成するブロックレベルコンテナーとほとんど同じように振る舞います。浮動要素が侵入せず、コンテナーのマージンは相殺されません。

フレックスアイテムについては、ある要素は浮動 (float) や解除 (clear) が設定されていて、その上で親要素に display: flex が設定されたためにフレックスアイテムとなった場合、浮動と解除のいずれも無効になり、浮動が配置される通常のフローからは外れます。inline-block やテーブルレイアウトでの位置合わせのために vertical-align プロパティを使用している場合、このプロパティは作用しなくなります。代わりにフレックスボックスの配置用プロパティを使うことができます。

次の例では、子要素は浮動設定されており、コンテナーには display: flex が設定されています。display: flex を削除すると、解除が適用されていないため .box が折りたたまれます。再度 display: flex を適用すると折りたたみは起こりません。これは子要素がフレックスアイテムに変換されたために、浮動が適用されなくなったためです。

フレックスボックスとグリッドレイアウト

CSS グリッドレイアウトとフレックスボックスは、ほかのレイアウト方法を上書きするという観点ではおおむね同じように振る舞います。しかし、フレックスボックスの方が古いブラウザーでも比較的サポートされているため、フレックスボックスをグリッドレイアウトのフォールバックとして使いたいときがあるかもしれません。このやり方はうまく動きます。フレックスアイテムがグリッドアイテムになるとき、そのアイテムに設定されている flex プロパティは無視されるようになります。

ボックス配置プロパティは、両レイアウト方法をまたいで使用することができ、グリッドレイアウトのフォールバックとしてフレックスボックスを使う場合にもうまくいきます。

フレックスとグリッドの違いは?

フレックスボックスと CSS グリッドレイアウトの違いは何か?なぜところどころ同じことをしているように見える 2 つの仕様がわざわざあるのか?というのはよくある疑問です。

この疑問に対する最も素直な答えは、仕様自体で定義されています。一方のフレックスボックスは一次元のレイアウト方法で、他方のグリッドレイアウトは二次元のレイアウト方法だということです。以下の例はフレックスレイアウトを使っており、基本コンセプトの記事で述べたようにフレックスアイテムは折り返すことができますが、折り返された場合にはそれぞれの行が別のフレックスコンテナーとなります。余白の分配の際にほかの行のアイテム配置については考慮されず、ほかの行との間でのアイテムの位置を揃えようともしません。

同様のレイアウトをグリッドで作成すると、行と列の両方を制御することができます。

これらの例はフレックスボックスとグリッドの主要な差異を示しています。グリッドレイアウトではサイズの指定の大部分はコンテナーに対して行い、トラックを組み上げてそこにアイテムを配置していきます。フレックスボックスではフレックスコンテナーを作りその方向を決めますが、アイテムのサイズに関する制御はアイテム自体に行っていくことになります。

場合によってはいずれのレイアウト方法でも適切に使えるかもしれませんが、この両方を自信を持って使えるようになるにつれて、それぞれのレイアウト方法が得意とするレイアウトの要求が異なっていることがわかってくるでしょう。そして最終的には両方のレイアウト方法を使うことになるでしょう。ひとつの正解や不正解があることはほとんどありません。

基本的なルールとして、折り返しされたフレックスコンテナーの一行の中のアイテムを、上の行のアイテムの位置と揃えるためにフレックスアイテムに幅を設定しようとするときには、二次元レイアウトがどうしても欲しくなることがあります。そのような場合には CSS グリッドレイアウトを使ったほうがよいでしょう。小さなコンポーネントにはフレックスボックスを使い、大きいコンポーネントにはグリッドレイアウトを使うべきというのは事実ではありません。とても小さいコンポーネントであっても二次元になることもあれば、大きなレイアウトを一次元のレイアウトで表現することが適している場合もあります。今はレイアウト方法を選べるようになったので、その利点を生かすためにいろいろと試してみてください。

グリッドとフレックスボックスのさらに詳しい比較については「グリッドレイアウトと他のレイアウト方法との関係」の記事を参照してください。この記事ではグリッドレイアウトがフレックスレイアウトと異なっている多くの点について詳述し、またグリッドレイアウトの持つグリッド上のアイテムのレイヤー機能などの追加機能について実例を示しています。また、どちらのレイアウト方法を選ぶべきかを決める手助けにもなるでしょう。

フレックスボックスと display: contents

display プロパティの値 contents は、仕様書の中で以下のように述べられている新しい値です。

「要素自体はボックスを生成しませんが、その子要素や擬似要素については通常と変わらずボックスを生成します。ボックス生成とレイアウトにおいては、この要素はその子要素や擬似要素によって置き換えられたように扱わなければなりません」 (訳注: https://www.w3.org/TR/css-display-3/#box-generation より引用)

display のこの値はボックス生成を制御し、ページ上に表示されスタイリングすることができるボックスをその要素が生成すべきか、または通常生成されるボックスは削除して子要素を親要素が元々加わっていたレイアウト方法に引き上げて参加させるべきかを制御します。これについては例を見たほうがわかりやすいでしょう。

以下の例では、フレックスコンテナーに 3 つの子要素があります。そのうちの 1 つにはさらに 2 つのネストした子要素があります。ネストした子要素は通常、フレックスレイアウトの構成に含まれません。フレックスレイアウトはフレックスコンテナーの直下の子要素のみに適用されます。

ここで display: contents をネストした要素のラッパーに追加することで、このラッパー要素がレイアウトから消え、2 つのネストした子要素がフレックスコンテナーの直下の要素であった時のようにレイアウトされます。display: contents を削除してみると元に戻ることを確認できます。

レイアウト上からボックスが削除されるだけで、レイアウト以外の観点ではこのネストした子要素が直下の子要素にならない点には注意が必要です。例では直下の子セレクターを使ってフレックスアイテムに背景色とボーダーを設定しているのですが、ネストした子要素には適用されないことが以下の例でわかります。フレックスアイテムとしてレイアウトはされますが、直下の子要素ではないため他のスタイリングまでは適用されません。

警告: 現在のほとんどのブラウザーの実装では、display: contents を持つ要素をアクセシビリティツリーから削除します(ただし、子孫は残ります)。これにより、要素自体がスクリーンリーダー技術でアナウンスされなくなります。これは仕様書によれば正しくない動作です。 display: contents を参照してください。

また、ボックスを削除した場合には、それを例えば背景色をネストした子要素に適用するために使用することはできません。今回の例において display: contents を削除すると、削除されていた直下の子要素がオレンジの背景色になっていることがわかります。この背景色はボックスが消えると同時に消えます。

display: contents のブラウザーの対応は限られていますが、このデモを動かすために必要です。 Firefox はすでに display: contents に対応しており、Chrome も実装しています。ブラウザーの対応が進めば、意味上の理由でマークアップが必要だが生成されてしまうボックスを表示したくないという場合において、この機能は大変有用なものになるでしょう。