#15DaysOfCSS Day 2: Box model

Boxes in boxes in boxes

You have probably heard of the box model before. Padding, border, margin, yeah yeah, next topic.

Oh come now... don't you know us well enough by now to know there's more to it than that?

First, let's point you to a few resources that talk about the box model in detail. Then we'll highlight a few points everyone seems to forget about in regards to the box model.

📦 Everything is a box 📦

It doesn't get said often enough. If there's an HTML element on your web page, there's a box associated with it.

In your web browser, go to your favorite page, go to the devtools, and enter this style:

* { border: 1px solid red; } 

As you suspected, this will select everything on your web page and put a red box around it. Those are all of your HTML elements.

If you're writing HTML that looks like this:

<div>
  <div>
    <div>
      <div>
        <div>
          <p>Hello!</p>
        </div>
      </div>
    </div>
  </div>
</div>

Well, your borders are going to be super ugly. Perhaps this will cause you to question why this type of code is so easy to find. 😉

💡 Pro tip: Clean HTML makes CSS much easier to work with.💡

⭕️ So if everything is a box, how do you make a circle?

Magic! 🦄 (Code is demonstrated in today's example CodePen.)

Sample HTML (it will work with any element):

<div></div> 

CSS:

div {
  background-color: red;
  width: 200px;
  height: 200px;
  border-radius: 50%;
}

Set an equal width and height on any element to make a square. Round the corners at 50%, and the box will appear to be a circle. But functionally, it's still a box.

Padding, margin, border

🎒 Most likely you are familiar with these properties. If not, have a look at the Frontend Masters Bootcamp notes on the box model.

Here's the parts you may not be familiar with.

Borders: Shorthand in shorthand

border: 1px solid red is Jen's favorite debugging tool. If you can't see it, you can't style it. Stick a border on it, and many of your CSS issues will be clearer.

That declaration is shorthand for a series of declarations:

border-width: 1px;
border-style: solid;
border-color: red;

💡 🤯 But each of these declarations is ALSO shorthand! 🤯 💡

Remember that with border, padding, and margin, there is a shorthand that may comprise one, two, three, or four values. Top, Right, Bottom, Left: Remember the order and stay out of TRouBLe. (Or remember the order as the position of clock hands.)

Therefore, this is valid code (see today's CodePen), even if it has zero design sense:

border-width: 10px 5px 2px 20px;
border-style: solid dashed dotted double;
border-color: red blue green purple;

The border-width example works above only if the unit of measure is the same for all 4 values, at least in Chrome and Firefox on Mac. That seems buggy to us.

Margins collapse vertically

When two margins meet in a vertical direction and fall in love... they collapse vertically. This is a good thing and it makes perfect sense if you consider HTML that's styled by the browser in its default stylesheet.

How many times have you tried this? You want to remove the space between the H3 and the paragraph. That space is caused by margin that the browser includes in its default stylesheet.

<h3>I am heading 3</h3> 
<p>I am a paragraph.</p> 

So you write some CSS:

h3 { margin-bottom: 0 !important; } 

Yet that CSS "doesn't work."

Your browser’s default stylesheet says that H3 has a bottom margin of 18px. The paragraph has a top margin of 16px.

If these values added, you'd have a distance of 34px between these elements, and you would have a disproportionately large space between them. Instead, these margins collapse, so you wind up with a workable space between the H3 and the paragraph of 18px - the larger of the two values.

When you set the H3 to zero margin on the bottom, the paragraph still has 16px of margin on its top.

💖 Your CSS worked just fine, and you didn't need that !important. 💖

Your paragraph's margin is now the larger of the two margins -- 0px and 16px.

If you want to get rid of the space, therefore, you need to zero out the margins at the bottom of the H3 AND the top of the paragraph.

h3 { margin-bottom: 0; } 
p { margin-top: 0; } 

content-box model by default

Let's say we have a box (any box, any HTML element) on our web page with the following styles:

.box {
   width: 240px;
   border: 2px solid red;
   padding: 10px;
   margin: 6px;
}

How wide is the box?

If you said "240px," you're wrong! By default, under the content box model in your web browser, 240px refers to the width of the content inside of your box. However, this box also contains padding, border, and margin that are part of the box's overall width. To calculate the full width of this box, you'd need to do the following math:

6px + 2px + 10px + 240px + 10px + 2px + 6px = 276px

That is the left margin + left border + left padding + content width + right padding + right border + right margin = the full width of the box.

This is the default method of calculation of box dimensions in CSS as defined by your browser. It's called the content box model, and the CSS that defines it looks something like this:

html {
   box-sizing: content-box;
}
*, *::before, *::after {
   box-sizing: inherit;
}

box-sizing, like most box model CSS properties, is not inherited. Therefore, if we want it to apply to all elements in our document, we set it on the html element first. Then we say we want all elements in the document, as well as the nodes before and after each element, to be set to the content box model.

border-box to the rescue

Consider this same example again, this time with the border box model:

.box {
   width: 240px;
   border: 2px solid red;
   padding: 10px;
   margin: 6px;
}

How wide is the box? You didn't say "240px" this time, we know 🤣

The border box says that we'll consider the width, border, and padding properties combined as a single unit. In this case, if it's 240px, the browser will make its own adjustments to the content to accommodate the border and padding widths declared here.

To calculate the total width of the box, then, we'd only need to consider margin and the value of the width property:

6px + 240px + 6px = 252px total box width

That is the left margin + the value of width + right margin = 252px.

Then how wide is the content?

Great question. How wide is the content under the border box model?

240px - 10px -10px - 2px - 2px = 216px

Here we take the value of width and subtract the left and right padding and the left and right border widths.

border-box for the win

We recommend using the border box model for all of your CSS work. It will make your layout work MUCH EASIER.

Include the following code at the very top of your CSS. In some reset or normalize stylesheets (like Bootstrap's Reboot stylesheet), it may already be included.

html {
  box-sizing: border-box;
}
*, *::before, *::after {
  box-sizing: inherit;
}

We've included examples of a border box and a content box in today's CodePen example.

🎉📚Get the #15DaysOfCSS e-book📚🎉

These #15DaysOfCSS posts will be compiled into an e-book — pre-order now!

Email is great, and blogs are awesome, but it can be challenging to use them as a reference in the future. We'll be assembling this month's work into an e-book.

Pre-order the book


🖥 Today’s CodePen examples

Today’s CodePen examples map out the code described in this email.

Check out today's examples


👩🏽‍💻 Challenge: Calculating content widths and total widths

👩🏽‍💻 Today’s challenge is on Github, not CodePen! There are a series of worksheets that will ask you to calculate widths based on provided padding, border, margin, and width values using the content box and border box models. We’ve given you the answers, too, so you can check your work.

Bring on the worksheets!


📚 More information and examples

📚 CSS Tricks: Box Sizing

📚 CSS Tricks: The CSS Box Model

📚 Interneting is Hard: CSS Box Model

📚 Shorthand explained at Selectutorial

📚 Frontend Masters Bootcamp: Box model