Code With Joad

Photo of Jody LeCompte

Posts about web and software development by Jody LeCompte

The CSS Box Model

How Things are Sized on the Web

Published February 07, 2019

Sizing elements on your web pages can sometimes be a little tricky. You set your width and your height, you did all the math, and even drew a wireframe. Now something is off with everything's sizing. Why does this happen sometimes?

Learning Goals

  • Understand how the below topics result in the size of an HTML element
  • Understand the difference between inline, inline-block, and block level elements.
  • Understand the CSS Box Model
  • Understand the difference between border-box and content-box box sizing.

Prerequisites

Only basic knowledge of HTML and CSS are required for this post. It's intended for use by those newer to web development. Experienced developers may still find it helpful but may want to skip around.

This post will not cover newer additions to CSS such as Flexbox or CSSGrid.

Inline vs Block Level Elements

Let's begin with only the concept of a box. The first property that begins to determine the size of that block is its level. The two most common are block level and inline level elements.

We will build our way up to full impact of this setting, but let's start with the idea of <body> as the largest box. When it has no children elements, it will have a width equal to the viewport and a height of zero. It is our first example of a block level element.

There are a few distinctions that define a block level element:

  • Each element will appear a new line, stacked one above the next.
  • Each element will have a width of 100% of its parent character.
  • Each element will only have the height necessary to contain itself and its children.

To contrast, an inline element will behave as follows:

  • Each element will appear side by side until forced to wrap.
  • Each element will only take as much space as necessary.
  • Setting an explicit height or width has no effect

Some other common block level elements you've more than likely used before are <div>, <p> and ul. Some examples of inline level elements are <span>, <a>, and <img>.

Brief aside: There are also inline-block level elements. They are a hybrid type that behave like inline elements in regards to flow but allow a height or width to be set.

The CSS Box Model

On a fundamental level, arranging elements is just putting smaller boxes inside larger boxes. Each of these boxes is defined by its content, padding, border, and margin sizing. The layout of these properties is called The CSS Box Model which is pictured below.

CSS Box Model
( CSS Box Model, Wikipedia )

By default, sizing begins with the content box found at the center of the model. When you set the width or height of an element, this is the part of the box that is set to those values. Then the padding, border, and finally margin are added. This default box sizing is called content-box sizing.

This is where a ton of beginner mistakes happen. It's a more than reasonable expectation for an element to be the width or height you gave it. Consider the following CSS:

.element  {
    width: 100px;
    margin: 15px;
    padding: 15px;
    border: 2px solid #000;
}

This actually gives you a width of 164 pixels using the following calculation:

 15px +  // Left Margin
  2px +  // Left Border
 15px +  // Left Padding
100px +  // Content Box
 15px +  // Right Padding
  2px +  // Right Border
 15px    // Right Margin

Reminder: Inline Level Elements

As a reminder, height and width is ignored by inline level elements. All other behavior described above is the same for both.

Border-Box Box Sizing

There is another setting for box-sizing called border-box sizing. I personally prefer because I think the mental model matches what people would naturally expect. If you were scratching your head during my previous explanation thinking, "But Joad...I don't think this is right", then you may already be using it.

It is enabled like this:

.element {
    box-sizing: border-box;
}

The difference is exactly as the name suggests. A height or width you set is applied to the border-box instead of the content box. The trade off is that since your element won't grow, extra space is removed from the conent box instead. If you are not careful, this can lead to having insufficient room for your content.

Be mindful of your margin. Even though it's outside of the visible portion of your element, it is still part of the total size and effects your elements placement inside its parent container.

To re-visit our previous example, with box sizing of border box, our element would now be 100 pixels wide as we have designated (without margin), but the content box will now only be 66 pixels wide. You can see a real example and experiment using this CodePen.

Border-Box as a Default

If border-box sizing sounds like the behavior you are used to but you haven't made the change yourself, it may be because of your CSS framework of choice. A lot of developers agree that border-box tends to be a more sane default for sizing and frameworks such as Bootstrap often set the box-sizing for all elements. Normalize.CSS has this same behavior as well.

When in doubt, you can always inspect the element with your browser's developer tools. This will allow you to see the browser generated box model for that particular element and see precisely how the browser decided to size it.

Conclusion

CSS is very simple syntactically, but it carries a lot of nuance and gotchas in its application. There are element levels such as inline-flex or positioning options such as fixed positioning that will change the rules slightly. You should still now feel comfortable knowing how 99% of your elements will be sized before you even get to the refresh button to check your latest code.