CSS : 要素数・ブラウザ幅が可変長なサイトでflexをキレイに使う

月花です。
今回はCSSの備忘録です。

内容は、幅が可変長のサイトにおける、flexboxで要素は左寄せ、全体は中央寄せとする方法です。

テキストだと説明しづらいので、画像をつかっていきます。

やりたいこと

このようなレイアウトを組みたいとする。
f:id:gekka9:20170728122308p:plain
コードでは下記のようになる。

See the Pen zdvwqQ by gekka (@gekka9) on CodePen.

しかし、同じCSSで横幅が少しでも異なると

See the Pen zdvwBQ by gekka (@gekka9) on CodePen.


このように、一見入りそうだけど、実はマージン込みでは入らず、下に落ちてしまう。
この右側のスキマが気になるので、直していく。

よくある失敗例

flexには、幅全体を使って等間隔に割り付ける、 justify-content:space-around という指定がある。
しかし、これを単純につかってしまうと・・・。

See the Pen YxyZMX by gekka (@gekka9) on CodePen.

このように、最下段がおかしなことになる。

解決方針

一段あたりの要素の個数が決まっているなら、よくあるハウツーでは剰余の数だけ空の要素を入れればいい。
しかし今回は、ブラウザの幅によって個数を変えて、常に入りうる最大の数を一段に押し込みたい。

つまり、下記のようになるのが理想である。
f:id:gekka9:20170728122322p:plain

このためには、下記の X から Y を計算し、 Y/2 を margin-left に設定することでできるはずだ。
f:id:gekka9:20170728122327p:plain
これも、数か幅のどちらかが固定ならば、シンプルに定まるものだが、その場合は計算せずとも space-around を使えばよいだけだ。

今回は可変長のため、一行あたりに何個入っているかをHTMLとCSSは知らないので、全体の幅から要素の横幅に個数をかけたものを引くなどというような、個数を用いる計算はできない。

そこで、個数に依存しない計算方法として剰余を用い、
・ Y = 100%(px) mod X(px)
と求めることができる。

もし、CSS の calc に剰余が実装されているならば、これでいけるはずだった。
しかし現実は非情である。実装されてないばかりか、そもそもcalcはモダンブラウザしか使えないのでIEが死ぬ。

ここはおとなしくJavaScriptを持ち出すことにする。

JavaScript を使う戦略

上記の、 Y = 100%(px) mod X(px) という計算式において、 100% と X をピクセルで用いるには、単純にJSで幅を取ってやればいいだけなので、ページロード時とリサイズ時に計算をして、CSSを書き換えてやる。
ただし、 X にマージンを含めなければならないため、 .outerWidth(true) を用いることが必要なことに留意する。

See the Pen oejwep by gekka (@gekka9) on CodePen.

これで、どのようなブラウザの幅でも、どのような要素でも柔軟に対応できる要素グリッドが出来上がった。