何が起きたのか?
今回、図の左側のようなレイアウトにしたかったのですが、右側のようなレイアウト(いわゆるカラム落ち)になってしまい「ん?何で??」となりました。
最初に書いたコード
<div class="container">
<div class="item">item1</div>
<div class="item">item2</div>
<div class="item">item3</div>
<div class="item">item4</div>
</div>
.container {
width: 500px;
height: 500px;
background-color: lightcyan;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
}
.item {
width: 250px;
height: 50px;
background-color: bisque;
}
親要素 .container
の width を 500px としています。
その内側に4つの子要素 .item
を配置しており、親要素の半分の 250px としています。
結果、子要素は2つ並んで下に落ちていくようなレイアウトになります。
ここまでは、想定通りのレイアウトになりました。
子要素に枠線を付けてみた
次に、子要素に対して枠線を付けてみました。
.item {
width: 250px;
height: 50px;
background-color: bisque;
border: 1px solid brown; /* ここを追加 */
}
すると、冒頭で紹介した図の右側のレイアウトになってしまいました。
想定では(枠線を付ける前と同じように)item2 は item1 の右側に配置されると考えていました。
なぜカラム落ちが発生したのか?
今回のカラム落ちを説明するにあたり、ボックスモデルを理解しておく必要があります。
全ての HTML 要素はボックスと呼ばれる四角形の表示領域を持っています。内側から「①テキストや画像などの内容が入るコンテンツ」「②パディング」「③ボーダー」「④マージン」という構造になっており、これをボックスモデルと呼びます。
ブラウザの開発者ツールを使えば簡単に確認することができ、1度はご覧になられた経験がある方も多いのではないでしょうか。
実は、デフォルトでは、width:100px と指定した場合、①コンテンツのボックス幅が 100px になります。そこに、②パディングのボックス幅や③ボーダーのボックス幅が乗っかってきて、その合計値が最終的なその要素の幅となります。
これは「width:100px と指定しても、最終的な要素の幅は 100px を超える場合がある」という事を意味します。
今回のケースでは、子要素1つ分の最終的な幅は 250px + 2px(左右の border)で 252px となります。子要素を横に2つ並べるならば 504px となり、親要素の 500px を超えるためカラム落ちが発生します。
どうすれば良いか?
今回のケースでカラム落ちを解消する方法としてパッと思いつくのは、子要素の width を 248px に変更することです。250px から ボーダーの 2px を引き算するわけです。
たしかに、この方法でカラム落ちは解消できます。
ですが、padding や border の値を変更する度に、それに連動して、width 値を(計算して)再設定しないとカラム落ちが発生してしまいます。
box-sizing で解決!
こういった場合に便利なのが box-sizing というプロパティです。
box-sizing プロパティで、要素の幅(と高さ)をどこのブロックまでにするのかを指定することができ、設定値は content-box
と border-box
があります。
-
content-box
- width(とheight)は①コンテンツのボックスのみを含み、その他のボックスは含まない
- こちらが既定値
-
border-box
- width(とheight)は①コンテンツのボックスに加えて、②パディングと③ボーダーのボックスも含む
図で表現すると次のようになります。
今回作成した CSS ファイルに box-sizing: border-box
を指定すると、「①コンテンツのボックス幅」+「②パディングのボックス幅+③ボーダーのボックス幅」が250pxになるように「①コンテンツのボックス幅」が自動的に縮小されるようになります。
結果、カラム落ちが解消されます。
.item {
width: 250px;
height: 50px;
background-color: bisque;
border: 1px solid brown;
box-sizing: border-box; /* ここを追加 */
}
このようにしておけば、border が 2px, 3px, ... と変化したとしても、①コンテンツのボックス幅が自動的に縮小されていくので、自分で計算して width 値を再設定する必要がなくなります。
参考にした記事
さいごに
業務でも box-sizing プロパティを見かけたことはあったのですが、深くは気にしたことがなくスルーしていたように思います。
分からないことはその場で調べるクセを付けていきたいものですね。