個人的にいつもフレックスコンテナの justify-content
や align-items
や align-content
を試行錯誤的に記述してしまっていて、ほしい見た目にストレートフォワードに記述することができていなかったので、これらのプロパティを学んで自分なりに解釈しました。
私のようにフレックスボックスを何となく使っている人に参考になればという記事です。
この記事は、こう解釈すると CSS が書きやすいのではという記事であり、実際の描画処理の解説記事ではないです。解釈としても不正確な記述もあるかもしれません。取り上げているフレックスボックスのプロパティや値も網羅的ではありません。
[2025/02/25] 一部不正確な記述がありました ( 交差軸方向に余白がない状態だと align-content で交差軸方向に重力をかけてもアイテムは動けないと書いていますが、アイテムにちぢむ余地があれば重力をかけるとちぢみます)。後で修正します。
[2025/02/25] どのプロパティをどうするとどうなるかのツールを作成しました。
https://cookiebox26.github.io/games/misc/sample-flex-interactive.html
具体例に沿った説明
フレックスボックスは下図の 6 ステップの処理をしていると解釈できると思います。
上図の説明
- 主軸方向が 4 パターンあるので 4 列描いています。主軸方向を「水色→ピンク色」、折り返して改行する方向を「明→暗」で表現しています (折り返しが逆の wrap-reverse は略)。
- 上図で、アイテム 006 だけはサイズを指定していて (
height: 30px; width: 30px;
)、アイテム 012 だけは主軸方向へ可能な限りふくらむよう指定しています (flex: auto;
)。 - このとき、フレックスボックスは基本的には以下の処理をします (するようにみえます)。
- STEP1. で、とりあえずアイテムを主軸方向 & 折り返し方向に自然に並べます。
- STEP2. で、各アイテムの主軸方向へのふくらませを行います (ただし、実際にふくらむのは、ふくらむよう指定されているアイテム 012 のみです)。
- STEP3. で、各アイテムの交差軸方向へのふくらませを行います (ただ、サイズ指定がある アイテム 006 はふくらませた後にやっぱり元に戻します)。
- さらに、フレックスコンテナに
justify-content
やalign-items
やalign-content
プロパティが指定されているときは、以下の処理をします (するようにみえます)。-
STEP4. で、
justify-content
の値にしたがって、主軸方向に重力を発生させます (ただ上図では値がspace-between
なので、重力というよりアイテム間斥力を発生させています)。なお、もしすべての行 (列) で主軸方向に余白がなかったら、この重力を発生させても意味がありません。 -
STEP5. で、
align-items
の値にしたがって、STEP3. での交差軸方向へのふくらませを解除し1、行 (列) 内に交差軸方向の重力を発生させます 2 (上図では値がcenter
なのでアイテムが行 (列) の中央のラインに寄っています)。なお、もしすべてのアイテムがふくらませを解除しても行 (列) 内で交差軸方向に余白ができなかったら、この重力を発生させても意味がありません。 -
STEP6. で、
align-content
の値にしたがって、交差軸方向の重力を発生させます (上図では値がend
なのでアイテムが暗い方に寄っています)。なお、もし交差軸方向に余白がなかったら、この重力を発生させても意味がありません。- したがって、アイテムに交差軸方向のサイズを指定して STEP3. のふくらませを解除するか、コンテナに
align-items
を指定して STEP3. のふくらませを解除する必要があります (はず)。
- したがって、アイテムに交差軸方向のサイズを指定して STEP3. のふくらませを解除するか、コンテナに
-
STEP4. で、
なお、上図の HTML ファイルは以下です (解釈を説明するため恣意的に記述しています)。
https://cookiebox26.github.io/games/misc/sample-flex.html
一般的 (?) な説明
これ以降の文章による説明では、一般的といってもコンテナの主軸方向 flex-direction
がデフォルト値 row
であるものとします。row-reverse
, column
, column-reverse
にあてはめる場合は、ところどころ読み替える必要があります。
フレックスボックスは以下の 6 ステップの処理をしていると解釈できると思います。
- STEP1. コンテナにアイテムたちを自然に並べる
- STEP2. アイテムたちの幅をふくらませる
- STEP3. アイテムたちの高さをふくらませる
- STEP4. コンテナ内に横方向の重力を発生させる (
justify-content
) - STEP5. アイテムを自然な高さに戻し行内で縦方向の重力を発生させる (
align-items
) - STEP6. コンテナ内に縦方向の重力を発生させる (
align-content
)
STEP1. コンテナにアイテムたちを自然に並べる
まずはコンテナの右上端から右に自然に (サイズを伸縮させずに) アイテムたちを並べます。
アイテムがはみ出たときは、コンテナに flex-wrap: wrap(-reverse);
が指定されていれば折り返します。指定されていなければはみ出します。
STEP2. アイテムたちの幅をふくらませる
個々のアイテムの中に flex, flex-grow, flex-shrink, flex-basis
が指定されているものがあるときは、それにしたがってそのアイテムの横幅をふくらませ (ちぢませ) ます。
STEP3. アイテムたちの高さをふくらませる
次に、アイテムたちの高さを同じ行内で一番高いアイテムと同じ高さまでふくらませ、それでもまだコンテナの高さに余白があれば、すべての行がその余白を平等に分け合うようにさらにアイテムたちの高さをふくらませます。
ただし、高さが明示的に指定されたアイテムについては、いったん高さをふくらませた場合の配置にした後で、指定された高さにちぢめます。
STEP4. コンテナ内に横方向の重力を発生させる (justify-content
)
もしコンテナに justify-content
が指定されていたら、コンテナ内に横方向の重力を発生させてアイテムたちを移動します。start
ならコンテナ左端への重力 3、end
ならコンテナ右端への重力、center
ならコンテナ中央への重力、space-between
ならアイテム間に斥力を発生させます。
※ すでにどの行もコンテナの幅に余白がないようなときは何も起きません。
STEP5. アイテムを自然な高さに戻し行内で縦方向の重力を発生させる (align-items
)
もしコンテナに align-items
が指定されていたら、高さをふくらませていたアイテムたちを行内で元の高さにちぢめると共に、start
なら行の上端に向かって、end
なら行の下端に向かって、center
なら行の中央に向かって重力を発生させアイテムたちを移動します。ただし、個々のアイテムに align-self
が指定されたものがあるときは、そのアイテムにだけはその値にしたがった重力を作用させます。
※ アイテムを自然な高さに戻しても行の高さに余白ができないときは何も起きません。
STEP6. コンテナ内に縦方向の重力を発生させる (align-content
)
さらにコンテナに align-content
が指定されていたら、コンテナ内に縦方向の重力を作用させてアイテムたちを行単位で移動します。start
ならコンテナ上端への重力、end
ならコンテナ下端への重力、center
ならコンテナ中央への重力、space-between
なら行間に斥力を発生させます。
※ すでにコンテナの高さに余白がないようなときは何も起きません。
まとめ
フレックスボックスは 6 ステップの処理をしていると解釈すると、意味がないプロパティの指定を回避し (Ex. 余白がない方向に重力を発生させても移動できないので意味がない)、ほしい見た目に必要十分な CSS の記述をできる気がします。
というか本来は、STEP3. まででアイテムを自動的にふくらませきってもらって、人間は配置について何も考えなくてよいというのがフレックスボックスレイアウトの真価だと思うので (?)、「アイテムをふくらませずにこのサイズにしなきゃやーやーなの」とする時点でそれが台無し (?) だと思いますが、そうしてできた余白をどの方向に詰めたいのかに基づいて重力を発生させようと考えるとストレートフォワードに CSS を書ける気がします。
参考文献
下記のページ及びリンク先の各プロパティのページを参考にしています。