Module 3: Box Model & Spacing
The Box Model: Content, Padding, Border and Margin
How every element becomes a rectangle, how its real size is calculated, and how margins collapse in ways that surprise everyone.
Every element on a page, including text, images and buttons, is a rectangular box. Layout is the job of placing those rectangles. If you understand what is inside one box and how it is measured, most layout bugs become easy to diagnose.
Four layers#
┌───────────────────────────── margin ─────────────────────────────┐
│ ┌─────────────────────────── border ───────────────────────┐ │
│ │ ┌───────────────────────── padding ────────────────┐ │ │
│ │ │ │ │ │
│ │ │ content │ │ │
│ │ │ (width × height) │ │ │
│ │ │ │ │ │
│ │ └──────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
- Content is where text and child elements live.
widthandheightsize this area by default. - Padding is space inside the box, between the content and the border. The background color and image extend under it.
- Border is the edge line. It has width, style and color.
- Margin is space outside the box, pushing neighbors away. It is always transparent, and the background does not reach it.
You can see this diagram for any element in DevTools. Select an element and open the Computed tab, or hover over it in the Elements panel to see colored overlays for each layer.
Doing the math#
With the default sizing model, width is the width of the content only.
.card {
width: 300px;
padding: 20px;
border: 5px solid #333;
margin: 10px;
}
Content: 300px
Padding: 20px × 2 = 40px
Border: 5px × 2 = 10px
────────────────────────────
Rendered box width: 350px
Space it occupies (with margin): 370px
So a box "300px wide" ends up 350px wide on screen. This default surprises everyone once. The next lesson shows how to change it.
Shorthand for the four sides#
margin, padding and border-width accept one to four values:
.a { padding: 10px; } /* all sides */
.b { padding: 10px 20px; } /* top & bottom | left & right */
.c { padding: 10px 20px 30px; } /* top | left & right | bottom */
.d { padding: 10px 20px 30px 40px; } /* top | right | bottom | left */
The order goes clockwise from the top. The mnemonic is TRouBLe: top, right, bottom, left. You can also set one side: margin-left, padding-block-start, and so on.
Modern CSS also offers logical properties that follow the writing direction, such as margin-inline (left and right in English) and padding-block (top and bottom). They matter when your site supports right-to-left languages, because the layout flips without extra CSS.
Centering with auto margins#
A block element with a width and margin-inline: auto centers itself horizontally. The browser splits the remaining space equally on each side.
.container {
max-width: 60rem;
margin-inline: auto;
}
It only works for horizontal centering of a block with a set or limited width. Vertical auto margins on a normal block resolve to zero. They do work inside flex and grid containers, which you will use in Module 5.
Margin collapse#
This is the part of the box model that looks like a bug and is not.
When the vertical margins of two blocks touch, they do not add up. They merge into one margin equal to the larger of the two.
<p class="first">First</p>
<p class="second">Second</p>
.first { margin-bottom: 40px; }
.second { margin-top: 24px; }
First
↕ 40px (not 64px: the margins collapsed to the larger one)
Second
Collapsing happens in three situations:
- Adjacent siblings, as above.
- Parent and first or last child. If the parent has no padding, border or content separating it from its child's margin, the child's margin pokes out through the parent.
- Empty blocks. An element with no height, padding or border has its own top and bottom margins collapse together.
The second one produces the famous bug where a child's margin-top appears to push the whole parent down instead of creating space inside it.
.parent { background: #eef; } /* no padding or border */
.child { margin-top: 30px; } /* the gap appears ABOVE .parent, not inside it */
Collapse does not happen when:
- The parent has padding or a border between it and the child.
- The parent creates a new block formatting context (for example with
overflow: auto,display: flow-root, ordisplay: flex). - The margins belong to flex or grid items. Those never collapse.
- The margins are horizontal. Left and right margins never collapse.
The cleanest fix for the parent-child case is display: flow-root on the parent. It exists exactly for this purpose and has no side effects.
A good habit that sidesteps most surprises: space things with margin in one direction only (say, margin-top on everything after the first), or use gap in flex and grid.
Inline elements ignore parts of the box#
An inline element like span or a sits in a line of text. Its horizontal margin and padding work. Its width and height are ignored, and vertical margin does not push anything. Vertical padding paints but does not affect the lines around it.
a { padding: 20px; } /* the background gets taller, but lines do not move apart */
Switch to display: inline-block or block when you need real box behavior. The display lesson further down covers that.
Negative margins#
Margins can be negative, pulling an element toward or over its neighbors. Use sparingly, for deliberate overlaps or to cancel a container's padding. Padding and border cannot be negative.
Common mistakes#
- Calculating widths wrong and having two
50%columns with padding wrap onto separate lines. - Expecting margins to add between stacked blocks.
- Wondering why a child's margin escapes its parent.
- Setting
widthandheighton inline elements and getting no result. - Using padding on a clickable element's parent when the link itself should have the padding, which leaves dead zones that are not clickable.
- Percentage padding and margin being relative to the container's width, even for top and bottom.
Practice#
- Build a
.cardwithwidth: 300px,padding: 20px,border: 5px solidandmargin: 10px. Use DevTools to confirm the rendered width. Predict, then check. - Create two stacked paragraphs with
margin-bottom: 40pxandmargin-top: 24px. Measure the gap. Then put each in a flex column container and measure again. - Reproduce the parent-child margin escape with a colored parent and fix it in three different ways: padding,
overflow: auto, anddisplay: flow-root. Which has side effects? - Center a 600px-max container with auto margins, then do it again using logical properties.