What Is the Box Model?
Every HTML element is a rectangular box. The CSS box model describes how that box is constructed from four layers: content, padding, border, and margin.
+----------------------------------------------+
| Margin |
| +----------------------------------------+ |
| | Border | |
| | +----------------------------------+ | |
| | | Padding | | |
| | | +----------------------------+ | | |
| | | | Content | | | |
| | | | | | | |
| | | +----------------------------+ | | |
| | +----------------------------------+ | |
| +----------------------------------------+ |
+----------------------------------------------+
Each layer serves a different purpose:
- Content — the actual text, images, or child elements.
- Padding — space between the content and the border. Background color fills this area.
- Border — visible line around the element. Has width, style, and color.
- Margin — space outside the border. Transparent. Pushes other elements away.
.box {
width: 300px; /* content width */
padding: 20px; /* space inside */
border: 2px solid; /* visible border */
margin: 16px; /* space outside */
}
Content Area
The content area holds the element's actual content — text, images, child elements. Its size is controlled by width, height, min-width, max-width, min-height, and max-height.
.content-box {
width: 200px;
height: 100px;
min-width: 150px;
max-width: 400px;
}
By default, width and height set the content area size only. Padding and border are added on top. This is the content-box model (more on that in the box-sizing section).
Intrinsic vs Extrinsic Sizing
/* Extrinsic sizing — you set the size */
.box { width: 300px; }
/* Intrinsic sizing — content determines the size */
.box { width: auto; } /* default for block elements */
.box { width: min-content; } /* shrink to narrowest content */
.box { width: max-content; } /* expand to widest content */
.box { width: fit-content; } /* min-content <= width <= max-content */
max-content: "This is a really long paragraph that takes up the full natural width"
min-content: "This is a
really long
paragraph
that takes
up the
full
natural
width"
fit-content: somewhere between, depending on available space
Padding
Padding creates space between the content and the border. Background color and images extend into the padding area.
.box {
/* Individual sides */
padding-top: 10px;
padding-right: 20px;
padding-bottom: 10px;
padding-left: 20px;
/* Shorthand: all sides */
padding: 10px;
/* Shorthand: vertical | horizontal */
padding: 10px 20px;
/* Shorthand: top | horizontal | bottom */
padding: 10px 20px 15px;
/* Shorthand: top | right | bottom | left (clockwise) */
padding: 10px 20px 15px 5px;
}
The shorthand follows a clockwise pattern: top, right, bottom, left (think of a clock starting at 12).
top
|
left ---+--- right
|
bottom
Padding can use any length unit: px, em, rem, %, vh, etc. Percentage padding is calculated relative to the parent's width (even for vertical padding — this is intentional and useful for aspect ratio hacks).
/* Aspect ratio using padding (old technique) */
.aspect-ratio-16-9 {
width: 100%;
padding-top: 56.25%; /* 9/16 = 0.5625 = 56.25% */
position: relative;
}
/* Modern approach (preferred) */
.aspect-ratio-16-9 {
aspect-ratio: 16 / 9;
}
Border
The border sits between padding and margin. It has three properties: width, style, and color.
.box {
/* Individual properties */
border-width: 2px;
border-style: solid;
border-color: #333;
/* Shorthand */
border: 2px solid #333;
/* Individual sides */
border-top: 2px solid red;
border-right: 1px dashed blue;
border-bottom: 2px solid red;
border-left: 1px dashed blue;
/* Border radius */
border-radius: 8px; /* all corners */
border-radius: 50%; /* circle (if square element) */
border-radius: 8px 0 8px 0; /* top-left, top-right, bottom-right, bottom-left */
}
Border styles:
.borders {
border-style: none; /* no border (default) */
border-style: solid; /* solid line */
border-style: dashed; /* dashes */
border-style: dotted; /* dots */
border-style: double; /* two lines */
border-style: groove; /* 3D groove */
border-style: ridge; /* 3D ridge */
border-style: inset; /* 3D inset */
border-style: outset; /* 3D outset */
}
Outline vs Border
outline looks similar to border but is NOT part of the box model. It doesn't affect layout and doesn't take up space.
.box {
border: 2px solid blue; /* part of box model, affects layout */
outline: 2px solid red; /* NOT part of box model, no layout impact */
}
+--outline (no space)--+
| +--border (space)--+ |
| | padding | |
| | content | |
| +------------------+ |
+----------------------+
outline is used for focus indicators (accessibility). Never remove it without providing an alternative:
/* BAD — removes keyboard focus indicator */
*:focus { outline: none; }
/* GOOD — custom focus style */
*:focus-visible {
outline: 2px solid #4A90D9;
outline-offset: 2px;
}
Margin
Margin creates space outside the border. It's transparent — the parent's or page background shows through.
.box {
/* Same shorthand patterns as padding */
margin: 16px; /* all sides */
margin: 16px 24px; /* vertical | horizontal */
margin: 16px 24px 8px 24px; /* top | right | bottom | left */
/* Auto centering */
margin: 0 auto; /* horizontally center a block element */
}
margin: auto
auto margins absorb available space. This is how block elements are horizontally centered:
.centered {
width: 600px; /* must have explicit width */
margin: 0 auto; /* auto left + auto right = centered */
}
In flexbox, margin: auto absorbs space in all directions:
.flex-container { display: flex; }
/* Push item to the right */
.push-right { margin-left: auto; }
/* Center in both axes */
.flex-center { margin: auto; }
Negative Margins
Margins can be negative. This pulls the element (or its neighbors) toward it.
.overlap {
margin-top: -20px; /* pulls element up 20px */
}
.expand {
margin-left: -16px;
margin-right: -16px; /* element extends beyond parent padding */
}
Parent with 16px padding:
+--------------------+
| +--------------+ | <- normal child
| | content | |
| +--------------+ |
| |
|+------------------+| <- child with margin: 0 -16px
|| full-width || extends into parent padding
|+------------------+|
+--------------------+
Negative margins are useful but fragile. Prefer padding or grid/flexbox adjustments when possible.
box-sizing: content-box vs border-box
This is one of the most important CSS properties to understand.
content-box (Default)
width and height set the content area only. Padding and border are added outside.
.content-box {
box-sizing: content-box; /* default */
width: 300px;
padding: 20px;
border: 2px solid;
}
/* Total width = 300 + 20 + 20 + 2 + 2 = 344px */
|--2--|----20----|-------300-------|----20----|--2--|
border padding content padding border
|------------------344px-total--------------------|
border-box
width and height include content, padding, AND border. The content area shrinks to accommodate.
.border-box {
box-sizing: border-box;
width: 300px;
padding: 20px;
border: 2px solid;
}
/* Total width = 300px (content = 300 - 20 - 20 - 2 - 2 = 256px) */
|--2--|---20----|------256--------|---20----|--2--|
border padding content padding border
|------------------300px-total--------------------|
Why border-box Is Better
With content-box, setting width: 50% + padding: 20px makes the element wider than 50%. This breaks layouts.
/* BUG with content-box */
.column {
width: 50%;
padding: 20px;
/* Actual width = 50% + 40px — overflows parent */
}
/* WORKS with border-box */
.column {
box-sizing: border-box;
width: 50%;
padding: 20px;
/* Actual width = exactly 50% */
}
The Universal Reset
Every modern project should include this reset:
*, *::before, *::after {
box-sizing: border-box;
}
This sets border-box on every element. Every major CSS framework and reset stylesheet includes this. It's safe and recommended.
Margin Collapse
Margin collapse is one of the most confusing behaviors in CSS. Adjacent vertical margins don't add up — they collapse into a single margin equal to the larger value.
When Margins Collapse
Adjacent siblings — top margin of one element collapses with bottom margin of the previous element:
.box-a { margin-bottom: 30px; }
.box-b { margin-top: 20px; }
/* Actual gap between them: 30px (not 50px) */
/* The larger margin wins */
Without collapse (NOT how CSS works):
[Box A]
30px
20px
[Box B]
= 50px gap
With collapse (how CSS actually works):
[Box A]
30px (larger wins)
[Box B]
= 30px gap
Parent and first/last child — if a parent has no padding, border, or overflow that separates it from its child, the child's margin collapses with the parent's:
.parent {
margin-top: 0;
/* no padding or border */
}
.child {
margin-top: 40px;
/* This margin escapes the parent! */
}
/* Result: 40px margin appears ABOVE the parent, not inside it */
BUG (margin collapse):
40px gap
+----------+
| parent |
| [child] |
+----------+
FIX (add padding or border):
+----------+
| 40px gap |
| [child] |
+----------+
Empty elements — if an element has no height, padding, border, or content, its top and bottom margins collapse with each other:
.empty {
margin-top: 20px;
margin-bottom: 30px;
/* Collapses to 30px total */
}
When Margins DON'T Collapse
Margins do not collapse when:
- Elements are in a flex container (
display: flex) - Elements are in a grid container (
display: grid) - Element has overflow other than
visible(likeoverflow: hidden) - Element is floated
- Element has padding or border separating parent from child
- Element is absolutely positioned
/* No collapse in flexbox */
.flex-parent {
display: flex;
flex-direction: column;
}
.child-a { margin-bottom: 30px; }
.child-b { margin-top: 20px; }
/* Actual gap = 50px (no collapse) */
Fixing Unwanted Margin Collapse
/* Method 1: Add padding to parent */
.parent {
padding-top: 1px; /* prevents child margin from escaping */
}
/* Method 2: Add border to parent */
.parent {
border-top: 1px solid transparent;
}
/* Method 3: Use overflow */
.parent {
overflow: hidden; /* or overflow: auto */
}
/* Method 4: Use display: flow-root (modern, clean) */
.parent {
display: flow-root; /* creates new block formatting context */
}
/* Method 5: Use flexbox or grid */
.parent {
display: flex;
flex-direction: column;
}
display: flow-root is the cleanest fix — it creates a new block formatting context without side effects.
Common Layout Bugs
Bug 1: Element Wider Than Expected
/* content-box: width + padding + border > container */
.element {
width: 100%;
padding: 20px;
border: 1px solid;
/* Total = 100% + 42px — overflows */
}
/* Fix: use border-box */
.element {
box-sizing: border-box;
width: 100%;
padding: 20px;
border: 1px solid;
/* Total = exactly 100% */
}
Bug 2: Collapsed Parent
/* Parent has no height because children are floated or absolute */
.parent {
background: blue; /* invisible — 0 height */
}
.child {
float: left; /* removed from flow */
}
/* Fix: clearfix or display: flow-root */
.parent {
display: flow-root;
}
Bug 3: Margin Escape
/* Child's margin appears outside the parent */
.parent { background: blue; }
.child { margin-top: 40px; }
/* Fix: add padding or use flow-root */
.parent {
display: flow-root;
/* or padding-top: 1px; */
}
Bug 4: Percentage Height Not Working
/* BUG: height: 50% does nothing */
.parent { /* no explicit height */ }
.child { height: 50%; }
/* Percentage heights need an explicit height on the parent */
.parent { height: 400px; } /* or min-height, or flex/grid sizing */
.child { height: 50%; } /* now = 200px */
Bug 5: Horizontal Scroll from Overflow
/* BUG: page has horizontal scrollbar */
.full-width {
width: 100vw; /* includes scrollbar width on some browsers */
}
/* Fix: use 100% instead */
.full-width {
width: 100%;
}
Debugging in DevTools
Chrome DevTools Box Model View
- Right-click any element and select Inspect.
- In the Computed tab, find the box model diagram.
- It shows exact values for content, padding, border, and margin.
- Hover over each section to highlight it on the page.
The computed box model panel shows:
margin
+---------------+
| border |
| +-----------+ |
| | padding | |
| | +-------+ | |
| | |content| | |
| | | WxH | | |
| | +-------+ | |
| +-----------+ |
+---------------+
Click values to edit them live.
Useful Debug Techniques
/* Highlight all boxes on the page */
* {
outline: 1px solid red; /* outline doesn't affect layout */
}
/* Highlight specific elements */
.debug {
outline: 2px solid blue;
background: rgba(0, 0, 255, 0.1);
}
Using outline instead of border for debugging is important — outlines don't affect the box model or layout.
DevTools Tips
- Computed tab shows the final calculated values including inheritance.
- Hover over elements in the Elements panel to see their box model highlighted on the page.
- Edit values live by clicking on numbers in the box model diagram.
- Search for
box-sizingin computed styles to verify if border-box is applied. - Check for margin collapse by comparing the computed margin values with the actual visual gap.
Box Model Properties Summary
| Property | Inside Box Model? | Affects Layout? | Part of width/height? |
|---|---|---|---|
| content (width/height) | Yes | Yes | Yes (both models) |
| padding | Yes | Yes | Only in border-box |
| border | Yes | Yes | Only in border-box |
| margin | Outside the box | Yes | No (neither model) |
| outline | No | No | No |
| box-shadow | No | No | No |
Key Takeaways
- Every element is a box: content + padding + border + margin.
- Always use
box-sizing: border-boxglobally. It makeswidthandheightinclude padding and border. - Vertical margins collapse between siblings and between parent/child. Horizontal margins never collapse.
- Margin collapse doesn't happen in flexbox or grid containers.
display: flow-rootis the cleanest way to prevent margin escape.- Percentage padding/margin is always relative to the parent's width (even vertical).
- Use
outlinefor debugging — it doesn't affect layout. Useborderfor design. - DevTools box model view is your best friend for debugging sizing issues.
margin: 0 autocenters block elements horizontally (requires explicitwidth).- Never remove
outlineon:focuswithout providing an alternative focus style.