We're looking for a user researcher to understand the needs of developers and designers. Is this you or someone you know? Check out the post: https://mzl.la/2IGzdXS

Flexbox と他のレイアウト方法の関係

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

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

Box Alignment モジュール

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

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

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

注: 配置のためのプロパティは 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 より引用)

このガイドの後の記事「Aligning items in a flex container」では、flex アイテムに適用できる Box Alignment プロパティについて詳細に見ていきます。

gap プロパティ

row-gap プロパティ と column-gap プロパティ、およびこれらの一括指定プロパティ gap が、あらたに Box Alignment 仕様に追加されています。これらのプロパティは、はじめは CSS Grid 仕様の中で、それぞれ grid-row-gapgrid-column-gapgrid-gapとして定義されていましたが、フレックスボックスを含めたすべてのレイアウト方法で使用できるように名前が変更され Box Alignment に移動されました。各ブラウザーがフレックスボックスの gap プロパティを実装するまでは、アイテム間にギャップを作るには margin プロパティを使うことになります。

書字方向

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

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

書字方向

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

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

 

sideways-rlsideways-lr のサポートは現時点では Firefox のみということに注意してください。また writing-mode とフレックスボックスに関しての既知の問題がいくつかあります。ブラウザーのサポート状況については MDN の writing-mode ドキュメント に情報があります。しかし、もしレイアウトのために writing mode を使う予定であれば、それがどのような結果になるか注意深くテストすることが推奨されます。Writing mode はたやすくコンテンツを読めない状態にしてしまう可能性があるので、特に注意が必要です。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

「要素自体はボックスを生成しませんが、その子要素や疑似要素については通常と変わらずボックスを生成します。ボックス生成とレイアウトにおいては、この要素はその子要素や疑似要素によって置き換えられたように扱わなければなりません」

(訳注: https://www.w3.org/TR/css-display-3/#box-generation より引用)

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

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

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

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

警告: display: contents を利用すると、要素がアクセシビリティツリーからも削除されます。 – 読み上げソフトは中身を見ず、 display: none を使用したのと同様になります。 contents は表示のためだけのものであり、コンテンツや要素ではありません。

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

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

ドキュメントのタグと貢献者

このページの貢献者: mfuji09, dynamis, reppets
最終更新者: mfuji09,