CSS Box Models

CSS
A look at the CSS 2.1 and CSS 3 box models and how making just one subtle change can make your life easier.

CSS 2.1 Box Model

Let's first start with a simple box defined in the CSS 2.1 box model:

#box {
  margin: 10px;
  border: 1px solid black;
  width: 200px;
  padding: 12px;
}

If you asked someone what they thought would be the total box size of the definition above, some would say it is 200 pixels. "Aha! Tricked you fool!" they would say. When I first started out with CSS, this confused the hell out of me and I was the guy wearing the dunce cap. Even today I have to mentally picture the box model in my head when doing any sort of layout work. Something like this:

CSS2 box model

To arrive at the total width and height of a box it is calculated as follows:

  total box width = ml + bl + pl + w + pr + br+ mr
  total box height = mt + bt + pt + h + pb + bb + mb

So 200 pixels would be wrong, rather the answer is 246 pixels (20 margin + 2 border + 200 width + 24 padding).

In fluid liquid layouts, where percentages are used, things get a bit tricky. In the example box below, margins, padding, and width are specified in percentages. If you total up the width, it is 100% plus 2 pixels, contrary to what you would think it is (100%):

#box {
  margin: 1%;
  border: 1px solid black;
  width: 96%;
  padding: 1%;
}

This is ok when the box stands alone in your layout. But lets say you put 2 boxes side by side of each other and do this in a 100% width container. What will happen in this case?

CSS2 box model

.container {
  float: left;
  clear: both;
  width: 100%; /* fills its parent */
  background-color: red;
}
.box {
  float: left;
  margin: 1%;
  border: 1px solid black;
  width: 46%;
  padding: 1%;
  background-color: #ccc;
}
<div class="container">
  <div class="box">
    Left floated box
  </div>
  <div class="box">
    Right floated box
  </div>
</div>

The answer is, the boxes will break the container. The right box will be stacked underneath the left box. "Damn those borders! To hell with those two pixels!"

Floating boxes stacked

Now you may be thinking, "Not a big deal. I'll just adjust the width from 46% to 45% to allow for the border to work itself in". And while you maybe right, another problem surfaces that you can't talk your way out of. Pay attention in particular how much space is off to the right of the container versus what is on the left.

Floating boxes spacing problem

What should have been specified in the CSS 2.1 box model, is that the border should have been part of the width.

How To Get Around This In CSS 2

To get around this problem, there is a compromise. Simply use width: auto; on the floated boxes (you can also use display: block and don't specify a width). This will result in this look:

Floating boxes width auto

By default, block level elements are set to auto. This means in the CSS 2 box calculation, the width is automatically calculated. The browser will take the block's parent container's width and then subtract padding, margin, and border to arrive at the width. So if the parent container is 1000 pixels in width, and the floated box has 300 pixels of margin, border, and padding, the width will be 700 pixels.

"Use width: 100% on containers. and width: auto on block elements"

If there are children within the parent container, the browser will take into account their total widths and subtract it form the parent's remaining space. Then, apply the calculation relative to that remaining space for the next block.

With a width: 100% rule, you are telling the browser to make the box to be the same size as the parent container's width (not total width) plus the boxes padding, margin, and border. That's why in some cases when you use this rule you will see your box lie outside it's parent container.

CSS 3 Box Model

In CSS3 you can change the way the browser renders any element that uses a width or height rule. There are three modes:

  1. padding-box
  2. content-box
  3. border-box

box-sizing: padding-box

Padding only is drawn inside the height and width. The content box width and height is subtracted from the padding. Ugh. Whatever.

box-sizing: content-box

This is the CSS 2.1 box model as described above. The width and height are the content box. Padding and border are rendered outside the content box.

box-sizing: border-box

Padding and border is rendered inside the content-box. The width and height are subtracted from padding and border. So if you want 200 pixels of width, you get exactly that. Everything after that is additive. if you want padding of 10 pixels you get just that. Border of 1 pixel? That gets added too. And if you want 12 pixels of margin, there you go.

No more silly mental gyrations.

Oh yeah, and if you don't want to have to type this silly stuff out every time, do this in your main css file:

* {
  box-sizing: border-box:;
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
}

This is the model I prefer and gives us our sanity back.

CSS4 box model

Filed under: