フレックスアイテムの折り返しのマスター

フレックスボックスは一次元のレイアウトとして設計されており、つまりアイテムを行または列として扱います。 — しかし、同時ではありません。しかし、フレックスアイテムを新しい行に折り返し、 flex-directionrow の場合は新しい行を、 flex-directioncolumn の場合は新しい列を生成します。このガイドでは、これがどのように動作するのか、何のために設計されているのか、どのような場合にフレックスボックスより CSS グリッドレイアウトが必要になるかを説明します。

折り返しを行う

flex-wrap プロパティの初期値は nowrap です。つまり、コンテナーに対して幅が広すぎるフレックスアイテムのセットがあると、コンテナーからはみ出してしまいます。幅が広くなりすぎたら折り返すようにしたい場合は、flex-wrap プロパティを追加して wrap の値を設定するか、一括指定の flex-flow を使用して row wrap または column wrap の値を設定する必要があります。

アイテムはコンテナーの中に収まります。次の例では、10 個のアイテムを配置しています。すべてのアイテムの flex-basis は 160px で、伸長と縮小が可能です。最初の列で 160 ピクセルのアイテムを配置する空間がなくなると、新しいフレックス行が作成され、すべてのアイテムが配置されるまで繰り返されます。アイテムが成長すると、各列を完全に埋めるために、160 ピクセルよりも大きく拡張されます。最終行にアイテムが 1 つしかない場合は、行全体を埋めるように伸縮します。

これと同じことが列でも起こります。アイテムが折り返して新しい列を作り始め、それぞれの列を完全に埋めるためにアイテムを伸長するようにするためには、コンテナーに高さを設定する必要があります。

折り返しと flex-direction

折り返しは、flex-direction と組み合わせることで、期待通りの効果を発揮します。flex-directionrow-reverse に設定されている場合、アイテムはコンテナーの端から始まり、逆順に並んでいきます。

なお、反転は行内方向にのみ行われます。右から開始して 2 行目に進み、再び右から開始します。下から開始してコンテナーを上がっていくという、両方の方向で反転しているわけではありません。

一次元レイアウトの説明

上の例で見たように、アイテムが伸縮することが許されていれば、最後の行や列のアイテムが少なくなると、それらのアイテムは空いた空間を埋めるように伸びていきます。

フレックスボックスには、ある行のアイテムとその上の行のアイテムの位置を揃える方法はありません。各フレックス行は新しいフレックスコンテナーのように機能します。これが主軸の空間分配を行います。アイテムが 1 つだけで、そのアイテムが成長することが許可されている場合、1 つのアイテムのフレックスコンテナーがある場合と同様に、その軸いっぱいに表示されます。

2 次元でのレイアウトが必要な場合は、おそらくグリッドレイアウトを使用します。上記の折り返し行の例を CSS グリッド版のレイアウトと比較すると、違いが分かります。次のライブサンプルでは、CSS グリッドレイアウトを使用して、160 ピクセル以上の列が収まるだけのレイアウトを作成し、余分な空間をすべての列に分配しています。ただし、この場合、アイテムはグリッド内に留まり、最終行のアイテム数が少なくなっても伸びることはありません。

これが一次元と二次元のレイアウトの違いです。フレックスボックスのような一次元方式では、行または列のみを制御します。グリッドのような二次元のレイアウトでは、両方を同時に制御します。行ごとに空間を分配したい場合は、フレックスボックスを使用してください。そうでない場合は、グリッドを使用してください。

フレックスボックスベースのグリッドシステムはどのように機能するか

通常、フレックスボックスベースのグリッドシステムは、フレックスボックスを馴染みのある float ベースのレイアウトの世界に戻すことで機能します。フレックスアイテムにパーセント値の幅を割り当てると、flex-basis として、または flex-basis の値を auto のままにしてアイテム自体に幅を追加することで、2 次元のレイアウトのような印象を与えることができます。以下の例では、この機能を確認できます。

ここでは、flex-growflex-shrink0 に設定して、柔軟性のないフレックスアイテムを作り、フロートレイアウトで行っていたように、パーセント値を使って柔軟性をコントロールしています。

フレックスアイテムを横軸に並べる必要がある場合は、この方法で幅を制御することで実現できます。しかし、ほとんどの場合、この方法でフレックスアイテムに幅を追加する場合は、その部分をグリッドレイアウトに変更した方がよいことがわかります。

アイテム間の間隔の生成

フレックスアイテムを折り返すする際に、余白を空ける必要がある場合があります。現時点では、Box Alignment モジュール の gap プロパティをフレックスボックス用に実装したものはありません。将来的には、CSS グリッドと同様に、フレックスボックスでも row-gapcolumn-gap を使用できるようになる予定です。現時点では、これを実現するためには、margin を使用する必要があります。

下の実例を見ると、コンテナーの端に隙間ができないように隙間を作るためには、フレックスコンテナー自体に負のマージンを使用する必要があることがわかります。フレックスコンテナーの境界は 2 番目のラッパーに移動し、負のマージンによってアイテムをラッパー要素に引き上げることができます。

これが gap プロパティが必要な理由で、実装されれば問題の解決になります。gap は適切にアイテムの内側の辺にのみ置かれます。

アイテムの折り畳み

フレックスボックスの仕様では、アイテムに visibility: collapse を設定することで、フレックスアイテムが折り畳まれた場合の動作が詳細に規定されています。visibility プロパティの MDN ドキュメントを参照してください。仕様では、以下のように動作を説明しています。

「フレックスアイテムに visibility:collapse を指定すると、折り畳まれたフレックスアイテムになり、table-row や table-column の visibility:collapse と同様の効果が得られます。折り畳まれたフレックス アイテムはレンダリングから完全に削除されますが、フレックス行の交差軸の寸法を安定させる「支柱」が残ります。したがって、フレックスコンテナーにフレックス行が 1 つしかない場合、アイテムの折り畳み状態を動的に変化させると、フレックスコンテナーの主軸の寸法が変更されることがありますが、交差軸の寸法には影響しないことが保証されているため、ページの残りのレイアウトが「ぐらつく」ことはありません。ただし、フレックスの行の折り返しは折り畳み後に再実行されるため、複数の行を持つフレックスコンテナーの交差軸の寸法は変更される場合もあれば、変更されない場合もあります。" - Collapsed items

この動作は、JavaScript を使用してフレックスアイテムを対象にし、コンテンツの表示・非表示を行う場合などに便利です。仕様書の例では、そのようなパターンの一つを示しています。

次のライブ例では、折り返されていないフレックスコンテナーを使用しています。3 番目のアイテムは他のアイテムよりもコンテンツが多いのですが、visibility: collapse に設定されているため、フレックスコンテナーはこのアイテムを表示するために必要な高さの支柱を保持しています。CSS から visibility: collapse を削除するか、値を visible に変更すると、アイテムが消えて、折り畳まれていないアイテムの間にスペースが再分配されますが、フレックスコンテナの高さは変わりません。

Note: Chrome や Safari では折りたたまれている部分は非表示として扱われるため、以下の 2 つの例は Firefox を使用してください。

しかし、複数行のフレックスコンテナーを扱う場合は、折り返しが折り返しの後に再実行されることを理解する必要があります。つまり、ブラウザーは折り畳まれたアイテムがインライン方向に残した新しい空間を考慮して、折り返しの動作を再実行する必要があります。

つまり、アイテムが最初の行とは別の行になってしまう可能性があるのです。アイテムを表示したり隠したりすると、アイテムが別の行になってしまうこともあります。

次のライブ例では、この動作を作成しました。折り畳まれたアイテムの位置に基づいて、引き伸ばされている行が変化している様子がわかります。2 番目のアイテムにさらにコンテンツを追加すると、十分な長さになった時点で行が変更されます。その結果、一番上の行は、テキストの 1 行分の高さにしかなりません。

これによりレイアウトに問題が生じる場合は、構造を見直す必要があるかもしれません。たとえば、各行を別々のフレックスコンテナーに入れて、行がずれないようにするなどです。

visibility: hiddendisplay: none の違い

アイテムを display: none に設定して非表示にすると、そのアイテムはページの整形構造から削除されます。すなわち、カウンターはそれを無視し、トランジションも実行されません。visibility: hidden を使用すると、ボックスは整形構造の中に維持され、ユーザーには見えなくても、レイアウトの一部であるかのように動作することができるので便利です。