The box model.
Why layout breaks. And how to fix it.
Every element on every page is a rectangle. Those rectangles have four layers — content, padding, border, and margin — and understanding them is the difference between "CSS works" and "CSS makes sense." 80% of "why is my layout broken" questions are box-model questions. This lesson covers all four layers, the one CSS rule that should be in every file, and the reason your element is 42 pixels wider than you asked for.
Every element is a box with four layers: content (text/image), padding (space inside the border), border (visible edge), margin (space outside). By default (box-sizing: content-box), width only covers the content — padding and border add to the total. Set *, *::before, *::after { box-sizing: border-box; } at the top of every CSS file so width includes padding and border. This single rule prevents most layout bugs.
Before this lesson: complete Lesson 1. You need to know how to target elements before you can size them.
📦 The four layers
Content, padding, border, margin — every element has all four. Toggle each to see the effect.
.box {
/* CONTENT — the text or image itself */
width: 200px;
height: 80px;
/* PADDING — space INSIDE the border */
padding: 20px;
/* BORDER — the visible edge */
border: 3px solid #3b82f6;
/* MARGIN — space OUTSIDE the border */
margin: 16px;
/* Background fills content + padding, not margin /
background: rgba(59, 130, 246, 0.15);
color: #e2e8f0;
font-family: system-ui, sans-serif;
font-size: 14px;
box-sizing: content-box; / the default — explained below */
}
Blue outline = border. Light blue fill = padding + content. Empty space = margin.
Content
The actual text, image, or child elements. Sized by width and height. Everything else is space around it.
Padding
Space inside the border, between content and edge. Takes the element's background color. Use to give content breathing room. padding: 20px applies to all four sides.
Border
The visible line around padding. Takes width, style, and color — border: 1px solid #333. Sits between padding and margin.
Margin
Space outside the border, between this element and others. Always transparent — never takes the background color. Use to separate elements from each other.
Padding vs margin — the simplest test. Set a background color on the element. The background fills the content and padding but not the margin. If the space is colored, it's padding. If it's transparent, it's margin. This test resolves 100% of padding-vs-margin confusion.
🔑 box-sizing: border-box — the fix
The single CSS rule that prevents most layout bugs. See the difference side by side.
/* DEFAULT (content-box) — width does NOT include padding or border /
.content-box {
width: 300px;
padding: 20px;
border: 5px solid #ef4444;
box-sizing: content-box;
/ Total actual width = 300 + 20 + 20 + 5 + 5 = 350px */
}
/* BORDER-BOX — width DOES include padding and border /
.border-box {
width: 300px;
padding: 20px;
border: 5px solid #10b981;
box-sizing: border-box;
/ Total actual width = 300px (padding and border fit inside) */
}
/* The universal reset — put this at the top of every CSS file */
*, *::before, *::after {
box-sizing: border-box;
}
Both boxes have width: 300px; padding: 20px; border: 5px. Only the box-sizing is different.
content-box (default)
border-box
Why content-box is the default — and why it's wrong. CSS was designed before layout was a priority. The original spec set width to mean "content width," with padding and border added on top. This made sense for typography (a paragraph's width is the text width, plus padding). But it makes layout math painful: every time you add padding, the total width changes. Border-box flips this: width means "total width including padding and border." This matches how designers and developers think about layout — you say "this column is 300px" and it's actually 300px. Every modern CSS framework, reset stylesheet, and site uses border-box. Copy the universal reset above to every project.
The universal selector reset is free. *, *::before, *::after { box-sizing: border-box; } adds about 0.001ms of overhead. It affects every element in the document. The ::before and ::after pseudo-elements are included because they can also have padding and borders, and forgetting them creates subtle bugs. Copy this line verbatim to every stylesheet you write. It's the most valuable 60 characters in CSS.
📐 Display — block vs inline vs inline-block
How elements behave in the layout flow. The other half of the layout puzzle.
/* BLOCK — starts on new line, takes full width */
.block {
display: block;
background: rgba(59,130,246,0.2);
padding: 12px;
margin: 8px 0;
}
/* INLINE — flows with text, ignores width/height/margin-top /
.inline {
display: inline;
background: rgba(16,185,129,0.2);
padding: 4px 8px;
/ width: 200px; height: 100px; margin-top: 20px; — these have NO effect on inline */
}
/* INLINE-BLOCK — flows inline BUT accepts width, height, margins */
.inline-block {
display: inline-block;
background: rgba(251,191,36,0.2);
padding: 12px 20px;
margin: 8px;
width: 120px;
text-align: center;
}
Block elements (stack vertically):
Inline elements (flow with text):
Text with inline span and another inline span flowing together.
Inline-block (inline flow, box properties):
block
Starts on a new line. Takes full width by default. Accepts width, height, all margins. Examples: div, p, h1, section.
inline
Flows with text. Width = content width. Ignores width, height, and vertical margins. Examples: span, a, strong, em.
inline-block
Flows inline with text but accepts width, height, padding, and margins. The hybrid. Useful for buttons, tags, and inline components.
none
Element is removed from the layout entirely. Takes no space, invisible to screen readers. Use to hide things conditionally. Opposite: display: block or display: flex.
Modern layouts rarely use inline-block. Flexbox and grid replaced almost every use case for it. Buttons are typically flex containers themselves, tags are flex or inline-flex, and card layouts use grid. When you see inline-block in older code, it's usually doing something that flexbox handles better. Learn it for legacy code, prefer flexbox for new code.
📏 Width and height — the right way
Fixed vs flexible. Why max-width beats width for responsive layouts.
/* FIXED width — breaks on narrow screens /
.fixed {
width: 600px; / always 600px, even if viewport is 400px */
background: rgba(239,68,68,0.2);
padding: 16px;
}
/* FLEXIBLE width — adapts to container /
.flexible {
width: 100%; / fill parent /
max-width: 600px; / but never wider than 600px */
background: rgba(16,185,129,0.2);
padding: 16px;
}
/* Horizontal centering — the classic pattern /
.centered {
width: 100%;
max-width: 500px;
margin: 0 auto; / auto left/right margin = centered */
background: rgba(59,130,246,0.2);
padding: 16px;
}
/* Min and max — constrain a dimension without fixing it /
.constrained {
min-width: 200px; / never narrower than 200px /
max-width: 400px; / never wider than 400px /
width: 50%; / prefer 50% of parent, within min/max */
background: rgba(251,191,36,0.2);
padding: 16px;
}
Fixed width: 600px — overflows on narrow screens
Flexible: width 100% + max-width 600px
Centered: max-width 500px + margin 0 auto
width vs max-width
width is the exact width — always. max-width is the ceiling — element shrinks on smaller screens. Use max-width for responsive layouts.
margin: 0 auto
Horizontal centering for block elements with a set width. The auto on left and right shares the leftover space equally. Only works when width is defined.
min-width / max-width
Constrain a dimension without fixing it. min-width: 200px; max-width: 400px; width: 50% means "prefer 50%, but stay between 200-400."
height
Rarely set explicitly — content usually determines height. Use min-height for "at least this tall." Setting fixed height causes content overflow that's hard to debug.
Never set fixed width on responsive layouts. width: 1200px on a container means a horizontal scrollbar on any screen narrower than 1200px. Almost every visitor is narrower than 1200px. Fix: width: 100%; max-width: 1200px; margin: 0 auto; — the container fills the viewport up to 1200px, then centers. This pattern is in every modern website.
🔻 Margin collapse — the surprise
Vertical margins between block elements don't add. The larger one wins.
/* Element A: margin-bottom: 20px /
/ Element B: margin-top: 30px */
/* Intuition says: gap = 20 + 30 = 50px /
/ Reality says: gap = 30px (the LARGER margin) */
.element-a {
margin-bottom: 20px;
padding: 12px;
background: rgba(239,68,68,0.2);
}
.element-b {
margin-top: 30px;
padding: 12px;
background: rgba(59,130,246,0.2);
}
/* COLLAPSE happens for: vertical margins between adjacent block elements /
/ COLLAPSE does NOT happen for: horizontal margins, inline elements,
or elements inside flex/grid containers (they don't collapse) */
/* Fix 1: Use padding instead */
.fixed-a { padding-bottom: 20px; }
.fixed-b { padding-top: 30px; }
/* Fix 2: Use flexbox or grid on the parent — children don't collapse /
.parent {
display: flex;
flex-direction: column;
gap: 30px; / gap replaces margins entirely */
}
Two boxes with margin-bottom: 20px and margin-top: 30px. The gap is 30px (larger), not 50px (sum).
Gap above = 30px, not 50px
When it collapses
Adjacent vertical margins between block elements. Sibling elements, or a parent's margin and its first/last child's margin. Collapsing applies only to vertical margins between block elements in normal flow.
When it doesn't
Horizontal margins never collapse. Inline and inline-block elements don't collapse. Children of flex or grid containers don't collapse with each other (flex gap does the spacing instead).
The fix: use gap
If you're using flexbox or grid, use gap: 20px on the parent. No collapsing, exactly the spacing you specify, and no need for per-child margins.
Or use padding
For vertical rhythm in non-flex layouts, prefer padding over margin. Padding never collapses. The downside: padding has the background color, so it doesn't work if the element needs a colored boundary.
In practice, this rarely bites. Because gap on flex and grid containers has replaced almost every use of vertical margins between elements. If you write display: flex; flex-direction: column; gap: 20px; on a parent, you never have to worry about collapsing. Modern layouts rarely rely on margin for spacing between siblings. Learn about collapse for the cases where it happens — legacy code, adjacent paragraphs, adjacent sections — but don't overthink it.
🏆 Challenge
Three tasks. Each exercises a different box-model skill.
Task 1 — Predict the width
Given this CSS, what is the actual rendered width of the element in pixels?
div {
width: 300px;
padding: 20px;
border: 5px solid black;
box-sizing: content-box;
}
Then answer again if box-sizing: border-box were used instead.
Verify by building the page and inspecting the div in DevTools. The computed width is shown in the Styles panel.
Task 2 — Centered card
Build a card with these properties:
1. Width: flexible, but max 500px
2. Horizontally centered on the page
3. Padding: 24px on all sides
4. Light border: 1px solid #334155
5. Border-radius: 12px
6. Content: a title (h2) and paragraph
Use box-sizing: border-box, max-width, and margin: 0 auto. Verify by resizing the browser — the card should shrink on narrow screens but stay centered.
Task 3 — Fix the broken layout
Here's a layout with three common box-model bugs. Fix each:
1. div { width: 100%; padding: 20px; } — content overflows horizontally
2. div { width: 800px; } — horizontal scroll on mobile
3. Two paragraphs: p { margin: 20px 0; } — spacing between them is 20px not 40px
For #1: the fix involves box-sizing: border-box.
For #2: replace with width: 100%; max-width: 800px; margin: 0 auto;.
For #3: either accept the collapse (it's often what you want) or switch to padding.
⚠️ Common mistakes
The box-model bugs that catch every beginner.
Without it, every element is wider than you think. Padding and border add to the total width, causing overflow, broken grids, and endless debugging. Fix: universal reset at the top of every CSS file.
width: 800px causes horizontal scroll on every mobile device. Fix: width: 100%; max-width: 800px; — full width on mobile, capped on desktop.
Padding is inside the border (has background). Margin is outside (transparent). Set a background color to test which is which. Padding pushes content in; margin pushes other elements away.
height: 100px on a paragraph clips content that's longer than 100px. Fix: use min-height, or let the content determine height naturally.
width: 200px on a span has no effect — inline elements ignore width and height. Fix: use display: inline-block or display: block.
Adding more margin doesn't increase the gap — the larger margin wins. Fix: use padding, or use display: flex; gap: 20px on the parent.
Same as #5 — inline elements ignore width. If you need a fixed-width inline element (like a badge or tag), use display: inline-block.
width: 300px + border: 10px without box-sizing: border-box = 320px total. Add box-sizing: border-box and it becomes 300px total (with border inside).
➡️ What's next
You understand the boxes. Next: make them look good.
❓ Frequently asked questions
What is the CSS box model?
Every HTML element is rendered as a rectangular box with four layers: content, padding, border, and margin. Together these four layers are the CSS box model. Understanding it is essential — most CSS layout bugs are box-model bugs. Use DevTools to inspect any element and see the four layers visually.
What is the difference between padding and margin?
Padding is space INSIDE the border — it pushes content away from the border. Margin is space OUTSIDE the border — it pushes other elements away from this element. Padding has the element's background color; margin is always transparent. Use padding to give content breathing room, margin to separate elements from each other.
What is box-sizing: border-box?
By default, CSS uses box-sizing: content-box — width and height apply only to the content area, so padding and border add to the total size. With box-sizing: border-box, width and height include padding and border. This is more intuitive and is why most modern sites set border-box globally.
Why is my element wider than I set it to?
Because of content-box sizing (the default). If you set width: 300px and padding: 20px and border: 1px, the element is actually 342px wide (300 + 20 + 20 + 1 + 1). Fix: use box-sizing: border-box. Add the universal border-box reset to the top of your CSS file.
What is the difference between display: block, inline, and inline-block?
Block elements (div, p, h1) start on a new line and take full width. Inline elements (span, a, strong) stay in the text flow and only take up as much width as their content. Inline-block is a hybrid: it flows inline with text but accepts width, height, and vertical margins like a block.
Do margins collapse?
Yes — vertical margins between adjacent block elements collapse. If element A has margin-bottom: 20px and element B has margin-top: 30px, the gap is 30px (the larger margin wins). This only applies to vertical margins between block elements. Fix: use gap on flex or grid containers, or use padding.
What is the difference between width and max-width?
width sets the exact width — the element is always that wide, even if the screen is narrower (causing horizontal scroll). max-width sets the maximum width — the element is at most that wide, but shrinks on smaller screens. For responsive layouts, prefer max-width: 1200px with width: 100%.
How do I center a div?
Horizontal centering: give the div a max-width and margin: 0 auto. This works for block elements with a set width. Modern approach: use flexbox on the parent — display: flex; justify-content: center; align-items: center. Grid also works: display: grid; place-items: center.