CSS Reset, box-sizing and Margin Collapse
Learn why browsers need a CSS reset, apply box-sizing: border-box to every element, write a small modern reset and understand margin collapse.
What you will learn
In the last lesson you saw that width: 200px can produce a 250px box, and that every browser has its own opinions about margins. This lesson fixes both. You will learn what a CSS reset is and why it exists, how to turn on box-sizing: border-box for the whole page, how to write a small modern reset you can copy into any project, and how margin collapse works, a behaviour that confuses almost every beginner.
The HTML we will style
The practice page has three small experiments. Read the HTML and find each class:
<h1 class="page-title">Reset Lab</h1>
<!-- Part 1: box-sizing bug. Both cards are width: 100% -->
<div class="card card-a">Card A: width 100% + padding + border</div>
<div class="card card-b">Card B: same rules</div>
<!-- Part 2: margins between siblings -->
<div class="stack">
<div class="stack-item item-1">Item 1 (margin-bottom: 40px)</div>
<div class="stack-item item-2">Item 2 (margin-top: 30px)</div>
</div>
<!-- Part 3: margin between parent and child -->
<div class="outer">
<div class="inner">Inner (margin-top: 30px)</div>
</div>
| Selector | Matches this element | Experiment |
|---|---|---|
.card |
both <div>s with the class card |
the box-sizing bug |
.card-a, .card-b |
the first and second card | (extra hooks if you want to style them separately) |
.stack |
the <div> that wraps two items |
groups the sibling experiment |
.stack-item |
both items inside .stack |
shared look |
.item-1 |
the first item | bottom margin of 40px |
.item-2 |
the second item | top margin of 30px |
.outer |
the grey parent <div> |
parent-and-child experiment |
.inner |
the gold child inside .outer |
top margin of 30px |
Why do we need a reset?
Every browser ships with a built-in default stylesheet (called the user-agent stylesheet). That is why an unstyled page is not completely plain: headings are big and bold, paragraphs have space between them, lists are indented, and the whole page has a gap around the edge. A few of these defaults are:
bodyhas an 8px margin.h1has a large top and bottom margin,phas a margin of about1em.ulandolhave 40px of left padding.- Buttons and form fields do not use the font of the rest of your page.
Different browsers used to disagree on these defaults, and even now they are not always what your design needs. A reset is a few lines of CSS at the top of your stylesheet that removes or evens out the surprises, so that you start from a predictable, clean base.
Types of reset
- A classic “reset everything” file (like Eric Meyer’s reset) zeroes out margins and padding on all elements. It is very old and rather heavy-handed.
- Normalize.css keeps useful defaults but smooths out differences between browsers.
- A small modern reset is a handful of lines that fix the most common problems. This is what most developers write today, and what you will use.
Avoid this popular one-liner:
* { margin: 0; padding: 0; }. It removes the space between paragraphs, the bullets’ indent inside lists and more, so you then have to restore everything by hand. It also forces you to style every element from scratch.
box-sizing: border-box for everything
Remember the problem from the box model lesson: by default width only measures the content, and padding and border are added on top. Here is the bug that causes in real life. Both .card elements ask for the full width:
.card {
width: 100%;
padding: 20px;
border: 3px solid crimson;
background-color: mistyrose;
margin-bottom: 10px;
}
width: 100% should fill the row exactly. But the browser adds 20 + 20 of padding and 3 + 3 of border on top, so each card is 46px too wide and sticks out of the page. You will see a horizontal scrollbar.
The fix is to include padding and border inside the width:
.card {
box-sizing: border-box;
width: 100%;
padding: 20px;
border: 3px solid crimson;
background-color: mistyrose;
margin-bottom: 10px;
}
Now the card is exactly as wide as the row, padding and all. Writing this on every element would be tedious, so you apply it to all elements at once with the universal selector:
*,
*::before,
*::after {
box-sizing: border-box;
}
Read it like this:
*is every element (you met it in the selectors lesson).*::beforeand*::afterare the extra “generated” content some CSS adds around elements. You will learn about these pseudo-elements later; for now just know that including them makesborder-boxtruly apply to everything.- The commas group three selectors into one rule.
Put these three lines at the very top of every stylesheet you write. From then on, width: 300px means a 300px box, no matter how much padding or border you add.
A small modern reset
Here is a compact reset you can copy into every new project. Each part is explained below:
/* 1. Include padding and border in every element's size */
*,
*::before,
*::after {
box-sizing: border-box;
}
/* 2. Remove the 8px page margin and set comfortable text */
body {
margin: 0;
line-height: 1.6;
}
/* 3. Make media responsive */
img,
video,
svg {
display: block;
max-width: 100%;
}
/* 4. Let form controls use the page font */
input,
button,
textarea,
select {
font: inherit;
}
- Part 1 you already know.
- Part 2 removes the default gap around the page (
bodymargin) so your layout starts right at the edge, and sets a readable line height that every element inherits. - Part 3 stops images from overflowing their container:
max-width: 100%means “never wider than the parent”.display: blockremoves the small gap that inline images leave underneath. - Part 4 fixes a classic annoyance: buttons and inputs ignore your font by default and use a small system font.
font: inherittells them to copy the font from their parent.
Nothing here is magic. You can add or remove lines to suit your project. Just keep it small and understand every line.
Margin collapse
Now the strangest behaviour in the box model. When the vertical margins of two blocks touch, they do not add up. They collapse into one margin, and the larger one wins.
Case 1: siblings
Two blocks stacked one above the other:
.stack-item {
background-color: lightgreen;
padding: 10px;
}
/* the first <div class="stack-item item-1"> */
.item-1 {
margin-bottom: 40px;
}
/* the second <div class="stack-item item-2"> */
.item-2 {
margin-top: 30px;
}
You might expect 40 + 30 = 70px between them. The real gap is 40px, the larger of the two. The margins overlap instead of adding.
Case 2: parent and first child
A child’s top margin can “escape” through its parent if nothing separates them:
.outer {
background-color: lightgray;
margin-top: 20px;
}
/* the gold <div class="inner"> inside .outer */
.inner {
margin-top: 30px;
padding: 10px;
background-color: gold;
}
You would expect a 30px gap inside the grey box, above the gold one. Instead the gold box sits flush against the top of the grey box, and the whole grey box moves down. The child’s margin collapsed with the parent’s margin, so the larger one (30px) is applied outside, above the grey box.
To stop the child’s margin escaping, put something between them. Any one of these works:
.outer {
display: flow-root; /* the modern, clean fix */
}
display: flow-rootmakes the parent contain its children’s margins (it does nothing else).- Adding a border or padding to the parent (even
padding-top: 1px) also stops the collapse. overflow: hiddenworks too, but it can clip content, so it is not the first choice.
When margins do NOT collapse
- Horizontal (left and right) margins never collapse. Only top and bottom do.
- Margins do not collapse when padding or a border sits between them.
- Items inside flexbox and grid containers (later lessons) do not collapse their margins.
A tip that avoids most surprises
Many developers style vertical spacing in one direction only: for example, give elements only a margin-bottom and never a margin-top. Then two margins never meet, and the spacing is easy to predict.
Putting it together
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
line-height: 1.6;
}
.card {
width: 100%;
padding: 20px;
border: 3px solid crimson;
background-color: mistyrose;
margin-bottom: 10px;
}
.stack-item {
background-color: lightgreen;
padding: 10px;
}
.item-1 {
margin-bottom: 40px;
}
.item-2 {
margin-top: 30px;
}
.outer {
display: flow-root;
background-color: lightgray;
margin-top: 20px;
}
.inner {
margin-top: 30px;
padding: 10px;
background-color: gold;
}
Common mistakes
- Putting the reset below other rules. Reset styles must come first, otherwise they can override the styles you wrote earlier.
- Using
* { margin: 0; padding: 0 }and forgetting to restore lists. Bullets then sit outside the text. - Only setting
box-sizingon some elements. Use the*, *::before, *::afterrule once, at the top. - Adding two margins and expecting them to add up. Vertical margins collapse.
- Wondering where the gap went when a child’s
margin-topmoves the whole parent. That is parent-child collapse. - Not knowing about the 8px
bodymargin, then chasing a mystery gap around the page. - Copying a giant reset without reading it. Small and understood beats large and mysterious.
Practice
- Click Practice in Editor. You will see a horizontal scrollbar. Fix it by adding the three-line
box-sizingrule at the top. - Add
body { margin: 0; }and notice how the page moves closer to the edge. - Measure the gap between
.item-1and.item-2with DevTools. Then change.item-2tomargin-top: 60pxand measure again. Which value wins? - Make the gold
.innerbox sit inside the grey box with a 30px gap above it, usingdisplay: flow-rooton.outer. - Solve the same problem a second way, using
padding-topon.outerinstead offlow-root. - Rewrite the sibling example so it uses only
margin-bottomon both items, with nomargin-topat all.
Recap
- Browsers apply a default stylesheet, and a reset gives you a predictable starting point.
- Use a small modern reset instead of removing all margins and padding.
*, *::before, *::after { box-sizing: border-box; }makeswidthinclude padding and border on every element. Put it at the top of every stylesheet.- Vertical margins collapse: touching margins combine into one, and the larger wins. Horizontal margins never collapse.
- A child’s top margin can escape its parent. Stop it with
display: flow-root, padding or a border. - Next you will decorate boxes with backgrounds, borders, rounded corners and shadows.