The Box Model
Every element on the page is a box — and understanding its four layers (content, padding, border, margin) is the key to controlling layout with confidence.
Have you ever tried to space things out on a page and felt like the browser was playing tricks on you? Elements overlapping, gaps that seem wrong, sizes that don't add up. The culprit is almost always a misunderstanding of the CSS Box Model — and once you grasp it, layout starts to feel logical rather than mysterious.
Every single element on a web page — a heading, a button, a paragraph — is rendered by the browser as a rectangular box with four distinct layers: content, padding, border, and margin. Learning what they do is the single most important concept in CSS layout.
Think of a framed painting on a wall
- Content — the painting itself.
- Padding — the white mat board between the painting and the frame, giving the artwork breathing room.
- Border — the physical frame around the mat.
- Margin — the empty wall space between this frame and the one hanging beside it.
The painting never touches the frame directly; the mat is in between. And the frame never touches the neighbouring painting; the wall gap separates them. That is exactly how CSS boxes work.
.card {
width: 300px; /* content area width */
height: 150px; /* content area height */
padding: 20px; /* space inside, between content and border */
border: 2px solid #333; /* line drawn around the box */
margin: 24px; /* space outside, pushing neighbours away */
}#What width Actually Controls (and Why It Surprises People)
By default, width and height set the size of the content area only — padding and border are added on top, making the element larger than you specified. With the styles below, the box occupies 250 px of horizontal space on screen — not 200 px:
.box {
width: 200px;
padding: 20px;
border: 5px solid black;
}
/* Rendered width: 200 + 20 + 20 + 5 + 5 = 250 px *//* Add this reset at the very top of every stylesheet */
*,
*::before,
*::after {
box-sizing: border-box;
}
.box {
width: 200px; /* now the true total rendered width */
padding: 20px;
border: 5px solid black;
/* content area shrinks to 150 px automatically */
}Always start with the border-box reset
The *, *::before, *::after { box-sizing: border-box; } snippet is the first thing to put in every new stylesheet. Without it, adding padding or a border will silently grow your elements and break your layout in ways that are frustrating to debug.
#Padding vs. Margin — and the Collapse Gotcha
Both create space, but they behave very differently:
- Padding is inside the border — it shares the element's background colour, and clicking in the padded area still counts as clicking the element.
- Margin is outside the border — always transparent, it pushes neighbouring elements away.
You can set each side independently, or use shorthand. Values go clockwise: top, right, bottom, left:
``css .box { padding: 10px 20px; /* top+bottom 10px, left+right 20px */ margin: 16px 8px; /* top+bottom 16px, left+right 8px */ } ``
Vertical margins collapse — they don't add up
When two block elements are stacked vertically and both have vertical margins, CSS takes the larger of the two as the gap — not the sum. This is called margin collapse.
If a heading has margin-bottom: 24px and a paragraph below has margin-top: 16px, the actual gap is 24 px, not 40 px.
Only vertical (top/bottom) margins collapse. Left and right margins always add up normally.
Workaround: use padding on a parent container, or switch to a flex or grid layout, which disables margin collapse between items.
You set an element's width to 400px, padding to 30px, and border to 5px — with no box-sizing reset applied. How wide does the element appear on screen?
*,
*::before,
*::after { box-sizing: border-box; }
.card {
width: 320px; /* total rendered width */
padding: 24px; /* inner breathing room */
border: 1px solid #ddd; /* subtle outline */
margin: 32px auto; /* centred, 32 px gap above and below */
background-color: white;
border-radius: 8px;
}
.card h2 {
margin-top: 0; /* kill default top margin — padding handles it */
margin-bottom: 12px;
}
.card p { margin: 0; line-height: 1.6; }Key takeaways
- Every HTML element is a box with four layers from inside out: content, padding, border, and margin.
- By default, width and height cover only the content area — padding and border are added on top, growing the element.
- Add box-sizing: border-box globally so that width means the total rendered size. Do this on every project.
- Padding is inside the border (shares the background); margin is outside (always transparent) and pushes neighbours away.
- Vertical margins between block elements collapse — the larger value wins instead of both adding together.
With no box-sizing reset applied, how wide does this element actually appear on screen?
.box {
width: 200px;
padding: 20px;
border: 5px solid black;
}Complete the reset so that width means the total rendered size, with padding and border carving into the content instead of growing the element.
*, *::before, *::after { box-sizing: ; }
This code has a bug — what's wrong?
.box {
padding: 10px 20px;
margin-collapse: none;
}A heading has margin-bottom: 24px and the paragraph directly below it has margin-top: 16px. Both are block elements stacked vertically. What is the actual gap between them?
h2 { margin-bottom: 24px; }
p { margin-top: 16px; }Build a styled profile card using the full box model. Create a .profile-card element that: (1) applies box-sizing: border-box globally, (2) has a fixed width of 360px, (3) has 32px of padding on all sides, (4) has a 2px solid border in a colour of your choice, (5) is centred on the page horizontally using margin auto, and (6) has a border-radius of 12px. Inside the card, make sure the h2 has no top margin so it sits flush against the inner padding.
Try it live — edit the code and hit Run to see it rendered: