Styling the Box

What is the Box Model?

Every element on the page implements the HTML box model, which is the system by which a browser determines the white-space within and around the element. You can think of each element as being an onion, which has a core — the content-box — surrounded by three layers: the padding-box, which is contained by the border-box, which is in turn surrounded by the margin-box.

The Chrome Inspector provides a helpful diagram whenever you have an element selected, showing the dimensions of each of these boxes. Let's style .box-layers to demonstrate.

  1. Create a css folder and stylesheet, and link it to this document.
  2. Select the 'box-layers' div above, and add background-color: #eeeeee;.

There is now a light gray box showing immediately behind the paragraphs above. Note that the box is defined by the actual dimensions of the content (the words), and it grows to contain them as needed. This is the content-box.

  1. Add padding: 2rem; to your .box-layers selector.

We can now see that the box has padding between it's 'edge' and the actual content. The content-box itself is still immediately around the content, but there is a new layer surrounding it, the padding-box. Try inspecting in Chrome. Click on the div class="box-layers" element in the document outline,then hover over the word 'padding' the inspector's box-model diagram. You should see a green highlight on the rendered page indicating the element's padding-box. Note that the content-box shrunk to make room for the padding box.

  1. Add border: 10px solid #dddddd; to your .box-layers selector.

We've just added a border, which creates a new layer for the element, the border-box. Inspecting in chrome should highlight the border in yellow. Note that padding and content shrunk again to make room for the border.

  1. Add margin: 4rem; to your .box-layers selector.

This adds the margin-box to the element. In the inspector, we can see the margin as an orange layer. Note once again that the inner layers shrunk to make room for the margin. Also note that the background-color we assigned does not extend into the margin. Margin defines the space 'between' this element and the elements around it.

CSS shorthand for box-model properties

We added margin to the box above, but it added it all the way around. What if we only wanted to add space above and below, but not left and right?

  1. Change your margin rule to margin: 4rem 0;

We've just used css to provide two values for margin. The first (4rem) is the vertical margin, the second (0) is the horizontal margin. This same shorthand works with padding.

Similarly, if we provide four values, the browser will apply them to the element clockwise from the top (top right bottom left).

  1. Change your padding rule to padding: 2rem 1rem 4rem 1rem;

Additionally, there are css properties (border-top, border-right, padding-bottom, margin-left, etc.) to control each side of the box individually.

  1. Replace your border rule with border-top: 10px solid #dddddd;

Finally, note that the border property is itself a shorthand for three individual properies: border-width, border-style, and border-color.

Margin collapse

Consider the paragraphs in this section. There is vertical space between paragraphs, defined by margin.

You might control that margin with a style rule like p { margin: 1em 0; }. You might expect such a rule to create a 1em margin above each paragraph and 1em below, making a total space between paragraphs of 2em.

In fact, the space between two adjacent paragraphs remains only 1em. The reason is this: when two adjacent boxes both define a margin for the space between, the larger of the two values 'wins' and the other value is ignored.

Another quirk of margin-collapse is that margin can spill out of a parent container. Inspect the h2 tag below, which is contained within a div. If you inspect these elements and hover over them in the document outline, you'll find that the div is nestled tightly around the title, but the title's margin is spilling out past the div. This allows us to wrap a semantic element like a section around a block of text without having an unexpected style side effect.

Margin spiller!

However, watch what happens if we add a border to the div!

  1. Create a style rule for .h2-wrapper that sets border: 1px solid black;

If you inspect the h2 now, you'll see it's margin is contained entirely within the div. Adding a border on the parent container cancels the margin-collapse behavior. Adding padding does the same thing.

The box-sizing property

A block-level element normally expands to fill the width of it's parent — in this case, the page. We saw earlier that when we added padding, border, and margin to an element, that element "shrunk" to make room for the added layers, and the outer-most layer remained the full width of the page. This behavior is a little bit magical... the browser just assumes we want to keep the overall element within its parent, and adjusts accordingly. Let's see that happen again.

  1. Create the following ruleset:
    .box-sizing-example {
      background-color: #eeeeee;
      padding: 2rem;
      border: 10px solid #dddddd;
    }

We've wrapped this box with some padding and borders, and it has shrunk the content-box to make room accordingly. But what happens if we explicitly set the width of this element ourselves?

  1. Add width: 100%; to the ruleset above.

WTF? The box got wider and is now spilling out of the normal page column to the right! We set it to 100% width, which is the default behavior for a block-level element anyway... so what gives?

It turns out that by default, setting the width property tells the browser to make the content-box that width. The browser basically says "Oh, you are controlling width of the content box now? No problem, I'll just add these other layers outside now, instead of shrinking the content box to make room for them." The net effect is that by setting width, we can inadvertently make things 'spill out' to the right. This can cause very annoying problems with unintentional horizontal scrolling on the page.

There is, however, a solution: the box-sizing property.

  1. Add box-sizing: border-box; to the ruleset.

The box has shrunk down again, and it's edge is realigned with the document edge. The reason is this: box-sizing: border-box; tells the browser that when we set a width, we're talking about the width of the box measured at the outer-edge of it's border-box, not the edge of the content-box. So, the browser applies our width instruction at the border, and shrinks the padding and content boxes as needed to make them fit. Happy alignment once again!

width, height, and overflow

As you have deduced from the preceeding section, width and height are settable properties. Let's set width to 50% on the box below.

  1. Create a ruleset for .overflow-example.
  2. Set width: 50%;

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam nec scelerisque leo. Duis pellentesque sit amet elit ultricies tincidunt. Proin viverra tempus enim, et tempor quam pulvinar a. Integer interdum at mi id luctus. Aenean fringilla mauris quis sapien pretium, at aliquet diam consectetur. Maecenas non nibh malesuada, feugiat turpis ultrices, lobortis leo. Nam semper bibendum quam, vel pulvinar metus ultricies ut. Fusce aliquam porttitor massa non aliquam. Curabitur tristique tortor quis lacus blandit aliquam. Praesent vel malesuada dolor, ac luctus metus. Nullam vulputate nisl vulputate enim volutpat elementum.

The width of the box shrunk, and the box got taller to accomodate the text within, right? Height of a block-level element will automatically adjust to contain it's contents... until we tell it differently.

  1. Set height: 300px; on the box.

Nooo! We forced the size of the box, and now the content is spilling out! So much horrible spilling. How can we deal with this? The overflow property!

  1. Set overflow: hidden; on the box.

This hides anything that spills past the border box. We can also (shudder) make it scroll:

  1. Set overflow: auto; on the box.

The box is now a scrolling container, allowing the content inside to have it's own scrollbar. Neat. Now... never, ever do this. This is almost always a terrible UX choice, and there is also almost always a better way to solve whatever problem you want to use this for. Pretend I never showed it to you. The takeaway from this section should not be "I can make scrolling containers!" Instead, it should be "Don't set height on the box. Just let it stay flexible, growing automatically to hold it's content."