CSSフレックスボックスの計算ミス!私も間違えていたwidth:calc() の正しい書き方
こんにちは!
今日は、私自身も長らく間違えて覚えていたCSSのフレックスボックスレイアウト計算について、正しい知識を共有したいと思います。
問題の発見:なぜかピッタリ収まらないフレックスアイテム
数週間前、3カラムのフレックスボックスレイアウトを実装していたとき、なぜか最後の行で要素が微妙にずれてしまう現象に悩まされました。コードを見直すと、私はずっとこう書いていました。
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.flex-item {
width: calc(100% / 3 - 20px);
margin-bottom: 30px;
}
しかし、この計算式は実は数学的に正しくないのです!
正しい計算と間違った計算
width: calc(100% / 列数 - 間隔);
width: calc((100% - 間隔の合計) / 列数);
または、モダンなflexboxの場合は
.container {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.flex-item {
flex: 0 0 calc((100% - (列数-1) * 20px) / 列数);
}
width: calc((100% - (列数-1) * 間隔) / 列数);
1番目の書き方:間隔の合計が既に分かっている場合にシンプルに書けます。
ただし「間隔の合計」を事前に計算する必要があります
例:3カラムで間隔20pxなら「間隔の合計」は40px
2番目の書き方:変数やカスタムプロパティを使う場合に便利(列数や間隔を変更しやすい)
「列数-1」は隣り合う要素間の間隔の数
例:3カラムなら間隔は2つ、4カラムなら間隔は3つ
なぜ間違いが広がるのか?
日本のWeb制作の記事やブログで、この間違った計算式が広まっている理由をいくつか考えてみました。
- コピペ文化 誰かが一度書いた間違った記述がコピーされ続けることで、誤りが拡散します
- ほぼ動くという間違った計算式でも、見た目上はほぼ動いてしまうため合っているように見えるので、問題に気づきにくいのです
- 数学的な考え方の違い プログラミングとデザインの両方を扱うフロントエンド開発では、数学的な厳密さよりも見た目の調整に注力しがちです
- 分かりやすさの優先 実は間違っていても、width: calc(100% / 列数 - 間隔);という式は直感的に理解しやすいと感じる人が多いのです
具体例で見る違い
例として、親要素の幅が900pxで、要素間の間隔を20pxとする3カラムのフレックスボックスレイアウトを考えてみましょう。
width: calc(100% / 3 - 20px);
計算結果:900px ÷ 3 - 20px = 300px - 20px = 280px
各要素の幅が280pxなら、3つ並べると280px × 3 = 840px
間隔の合計は20px × 2 = 40px
合計: 840px + 40px = 880px
つまり、20px分の隙間ができてしまいます!
width: calc((100% - 2 * 20px) / 3);
計算結果: (900px - 40px) ÷ 3 = 860px ÷ 3 = 約286.7px
各要素の幅が約286.7pxなら、3つ並べると286.7px × 3 = 860px
間隔の合計は20px × 2 = 40px
合計: 860px + 40px = 900px
ぴったり900pxになりました!
間違いを防ぐための方法
- Flexboxのgapプロパティを使う
.container {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.flex-item {
flex: 1 0 calc((100% - 40px) / 3);
/* もしくは最小幅を設定 */
min-width: calc((100% - 40px) / 3);
}
これならブラウザが間隔を自動的に処理してくれます。
2. 数式をコメントで書き残す
/* (100% - (n-1)*gap) / n */
.item {
width: calc((100% - 40px) / 3);
}
- 小さなテスト環境で常に確認する。デバッグツールで幅を確認する習慣をつけましょう。
まとめ
長い間、私も間違った計算式を使っていましたが、この「謎のズレ」に悩まされた経験から正しい知識を得ることができました。みなさんも、レイアウトを実装する際には、ぜひ正しい計算式を使ってください。
もし「あれ?なんかずれてる?」と思ったら、この記事を思い出してみてください!
ちなみに最近のブラウザなら Flexboxのgapプロパティを使うのが一番簡単で確実な方法です。これなら間隔の計算ミスの心配もありません。さらにflex-growとflex-basisをうまく組み合わせれば、レスポンシブ対応も簡単になります。
皆さんはどんな「長年勘違いしていた」ことがありますか?コメントで教えてください!
Discussion