The Box Model
Every element rendered on a webpage is a rectangular box. The CSS Box Model defines how content, padding, border, and margin combine to determine the total space an element occupies. Mastering it is essential to controlling layout.
What Is the Box Model
In CSS, every element generates a rectangular box. The box model describes how four concentric areas stack around the element's content:
- Content — The actual text, image, or child elements inside the box.
- Padding — Transparent space between the content and the border.
- Border — A visible (or invisible) line surrounding the padding.
- Margin — Transparent space outside the border that separates the element from its neighbors.
Visual Diagram
Below is a fully interactive representation of the box model, built with nested <div> elements. Each colored layer corresponds to one area of the model.
■ Margin ■ Border ■ Padding ■ Content
Total Element Size Calculation
Under the default content-box model, the total width and height of an element are calculated as:
Total Width = margin-left + border-left + padding-left + width + padding-right + border-right + margin-right Total Height = margin-top + border-top + padding-top + height + padding-bottom + border-bottom + margin-bottom
padding: 20px
border: 5px
margin: 15px
+ padding-left + padding-right: 20 + 20 = 40px
+ border-left + border-right: 5 + 5 = 10px
Visible box width: 250px
+ margin-left + margin-right: 15 + 15 = 30px
Total space occupied: 280px
All modern browsers display the box model visually in DevTools. Right-click an element, choose "Inspect", and look for the box model diagram in the Computed or Layout panel. Hover over the diagram sections to see each area highlighted on the page.
Content Area
The content area is the innermost part of the box model. It holds the element's actual content — text, images, or child elements. The size of the content area is controlled by the width and height properties, along with their min- and max- variants.
width & height
These properties set explicit dimensions for the content area. By default (with box-sizing: content-box), they do not include padding or border.
.box { width: 300px; height: 150px; } /* Auto is the default — block elements expand to fill parent width */ .auto-box { width: auto; /* default */ height: auto; /* grows with content */ }
min-width, max-width, min-height, max-height
These constrain the box's dimensions, creating flexible but bounded layouts. They are essential for responsive design.
.responsive-card { width: 100%; max-width: 600px; /* never wider than 600px */ min-width: 280px; /* never narrower than 280px */ } .text-container { min-height: 200px; /* at least this tall */ max-height: 80vh; /* at most 80% of viewport */ overflow-y: auto; /* scroll if content overflows */ }
max-width: 300px
min-width: 120px
min-height: 80px
max-width: 200px
max-height: 100px
overflow: auto
(resize your browser to see these constraints in action)
| Property | Default | Applies To | Description |
|---|---|---|---|
width | auto | All except inline | Sets the content width |
height | auto | All except inline | Sets the content height |
min-width | auto | All except inline | Minimum content width |
max-width | none | All except inline | Maximum content width |
min-height | auto | All except inline | Minimum content height |
max-height | none | All except inline | Maximum content height |
Prefer max-width: 100% on images and media to prevent them from overflowing their container: img { max-width: 100%; height: auto; }. This is one of the most common responsive patterns.
Padding
Padding is the transparent space between the content area and the border. It pushes the content inward. Padding is always non-negative (you cannot use negative values) and inherits the element's background color.
Individual Padding Properties
.box { padding-top: 20px; padding-right: 30px; padding-bottom: 20px; padding-left: 30px; }
Shorthand — padding
The padding shorthand accepts 1 to 4 values, applied clockwise starting from the top:
/* 1 value: all four sides */ .a { padding: 20px; } /* top=20 right=20 bottom=20 left=20 */ /* 2 values: vertical | horizontal */ .b { padding: 10px 30px; } /* top=10 right=30 bottom=10 left=30 */ /* 3 values: top | horizontal | bottom */ .c { padding: 10px 30px 20px; } /* top=10 right=30 bottom=20 left=30 */ /* 4 values: top | right | bottom | left (clockwise) */ .d { padding: 10px 20px 30px 40px; } /* top=10 right=20 bottom=30 left=40 */
(all sides equal)
(vertical | horizontal)
(top | horiz | bottom)
(top | right | bottom | left)
Percentage Padding
When you use a percentage value for padding, it is always calculated relative to the width of the containing block — even for vertical padding (padding-top and padding-bottom). This quirk is actually useful for creating aspect-ratio boxes.
/* Aspect ratio trick: 16:9 responsive box */ .aspect-16-9 { width: 100%; padding-top: 56.25%; /* 9/16 = 0.5625 = 56.25% */ height: 0; position: relative; } .aspect-16-9 > * { position: absolute; inset: 0; }
padding-top: 50% and padding-bottom: 50% are resolved against the element's containing block width, not height. This catches many developers off guard. Modern CSS offers aspect-ratio as a cleaner alternative for most use cases.
Border
The border wraps around the padding and content. Unlike padding and margin, borders are visible by default (when given a style). A border has three sub-properties: border-width, border-style, and border-color.
border-width
Sets the thickness of the border. Accepts length values or keywords (thin, medium, thick).
.box { border-width: 2px; /* all sides */ border-width: 1px 3px; /* vertical | horizontal */ border-width: 1px 2px 3px 4px; /* top | right | bottom | left */ } /* Individual sides */ .box { border-top-width: 3px; border-right-width: 1px; border-bottom-width: 3px; border-left-width: 1px; }
border-style
Defines the line pattern of the border. The border is invisible until you set a style (default is none). CSS defines ten border styles:
.box { border-style: solid; } /* continuous line */ .box { border-style: dashed; } /* series of dashes */ .box { border-style: dotted; } /* series of dots */ .box { border-style: double; } /* two parallel lines */ .box { border-style: groove; } /* carved into the page */ .box { border-style: ridge; } /* opposite of groove */ .box { border-style: inset; } /* sunken appearance */ .box { border-style: outset; } /* raised appearance */ .box { border-style: none; } /* no border (default) */ .box { border-style: hidden; } /* same as none, except in table border collapsing */
border-color
Sets the color of the border. Defaults to the element's color property value (i.e., currentColor).
.box { border-color: #e74c3c; /* all sides */ border-color: #e74c3c #3498db; /* vertical | horizontal */ border-color: #e74c3c #3498db #2ecc71 #e67e22; /* top | right | bottom | left */ }
border Shorthand
The border shorthand sets width, style, and color in a single declaration. Order does not matter, but style is required for the border to appear.
.box { border: 2px solid #3498db; } /* Individual side shorthands */ .box { border-top: 3px dashed #e74c3c; border-right: 1px solid #ccc; border-bottom: 3px double #2ecc71; border-left: 1px solid #ccc; }
(blockquote style)
(underline style)
The border shorthand resets all four sides. If you write border: 2px solid red; border-top: none;, it works. But if you reverse the order to border-top: none; border: 2px solid red;, the top border reappears because the shorthand overwrites the individual property. Always put the shorthand first, then override specific sides.
Border Radius
The border-radius property rounds the corners of an element's outer border edge. It is purely visual and does not affect the box model calculations.
Single Value
.rounded { border-radius: 8px; /* all four corners */ } .more-rounded { border-radius: 20px; /* more pronounced rounding */ }
Four Values (per corner)
Values go clockwise: top-left, top-right, bottom-right, bottom-left.
.custom-corners { border-radius: 10px 20px 30px 40px; /* top-left: 10px top-right: 20px bottom-right: 30px bottom-left: 40px */ } /* Individual corner properties */ .box { border-top-left-radius: 10px; border-top-right-radius: 20px; border-bottom-right-radius: 30px; border-bottom-left-radius: 0; }
Elliptical Radii with /
You can specify separate horizontal and vertical radii using a / separator, creating elliptical curves instead of circular ones.
.elliptical { border-radius: 50px / 20px; /* horizontal-radius: 50px vertical-radius: 20px */ } .organic { border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; /* creates a blob / organic shape */ }
Circles and Pills
/* Perfect circle (equal width and height required) */ .circle { width: 100px; height: 100px; border-radius: 50%; } /* Pill shape (works with any width) */ .pill { padding: 8px 24px; border-radius: 9999px; /* any very large value works */ }
circle
10px 30px
50% / 30%
blob
border-radius: 50% creates a circle only when the element is a square (equal width and height). For non-square elements, 50% creates an ellipse. Use a large pixel value like 9999px for pill-shaped buttons where the width varies.
Outline
An outline is a line drawn outside the border edge. Unlike borders, outlines do not take up space in the layout and do not affect the box model. They can overlap adjacent content.
Outline vs Border
| Feature | Border | Outline |
|---|---|---|
| Affects layout / box size | Yes | No |
| Can differ per side | Yes | No (uniform on all sides) |
| Follows border-radius | Yes | Yes (modern browsers) |
| Can be offset | No | Yes (outline-offset) |
| Part of box model | Yes | No |
.box { outline: 3px solid #e74c3c; outline-offset: 5px; /* space between border and outline */ } /* Individual properties */ .box { outline-width: 2px; outline-style: dashed; outline-color: #3498db; outline-offset: 4px; }
Takes up layout space
Does NOT take up space
6px
Pushed outward from box
offset
Negative offset goes inward
Accessibility and Focus Rings
Outlines are critical for keyboard accessibility. Browsers show a default outline when elements are focused via keyboard. Never remove the outline without providing an alternative visual indicator.
/* WRONG — removes all focus indicators */ *:focus { outline: none; /* Don't do this! */ } /* CORRECT — custom focus styles */ *:focus-visible { outline: 2px solid #6c8cff; outline-offset: 2px; } /* Hide outline for mouse clicks, show for keyboard */ button:focus:not(:focus-visible) { outline: none; } button:focus-visible { outline: 3px solid #6c8cff; outline-offset: 2px; border-radius: 4px; }
Press Tab to cycle through these elements and observe the browser's default focus ring (outline).
Removing outline on interactive elements without providing an alternative (such as box-shadow or a border change) makes your site unusable for keyboard-only users. Use :focus-visible to customize focus styles without harming accessibility.
Margin
Margin is the outermost layer of the box model — the transparent space outside the border that separates an element from its neighbors. Unlike padding, margins can be negative and can collapse with adjacent margins.
Individual Properties & Shorthand
/* Individual sides */ .box { margin-top: 20px; margin-right: 15px; margin-bottom: 20px; margin-left: 15px; } /* Shorthand (same rules as padding: 1/2/3/4 values) */ .a { margin: 20px; } /* all four sides */ .b { margin: 10px 30px; } /* vertical | horizontal */ .c { margin: 10px 30px 20px; } /* top | horizontal | bottom */ .d { margin: 10px 20px 30px 40px; } /* top | right | bottom | left */
Auto Centering
Setting margin-left and margin-right to auto horizontally centers a block-level element with a declared width. This is one of the most fundamental centering techniques in CSS.
.centered { width: 600px; /* must have an explicit width */ margin: 0 auto; /* top/bottom=0, left/right=auto */ } /* Also works with max-width for responsive centering */ .responsive-centered { max-width: 800px; margin-inline: auto; /* modern logical property */ }
margin: 0 auto
Negative Margins
Unlike padding, margins can be negative. Negative margins pull an element in the specified direction, or pull adjacent elements toward it.
/* Pull element upward */ .overlap-up { margin-top: -20px; } /* Extend beyond parent padding */ .full-bleed { margin-left: -20px; margin-right: -20px; }
Percentage Margins
Like percentage padding, all percentage margins (including top and bottom) are calculated relative to the width of the containing block.
.box { margin: 5%; /* all four margins = 5% of parent's width */ }
Both vertical and horizontal percentage margins resolve against the containing block's width for consistency. If vertical margins resolved against height, a circular dependency could occur: content height depends on margin, and margin depends on content height.
Margin Collapsing
Margin collapsing is one of the most confusing behaviors in CSS. When the vertical margins of two block-level elements touch (with nothing between them), they merge into a single margin equal to the larger of the two. This only happens with vertical margins, never horizontal.
When Margins Collapse
There are three main scenarios:
1. Adjacent Siblings
When two block-level siblings are stacked vertically, the bottom margin of the first and the top margin of the second collapse into one.
.box-a { margin-bottom: 30px; } .box-b { margin-top: 20px; } /* Resulting gap between them = 30px (NOT 50px) */ /* The larger margin wins */
Without collapse awareness (you might expect 50px):
Actual gap = 30px (collapsed), not 50px
2. Parent-Child Collapse
If a parent has no top padding, border, or anything else separating its top edge from its first child's top margin, the child's top margin escapes and collapses with the parent's margin.
/* The child's margin-top "leaks" out of the parent */ .parent { margin-top: 0; /* No padding-top, no border-top */ } .child { margin-top: 40px; /* This margin escapes the parent! */ }
Collapsed (no barrier):
(margin escapes parent)
Fixed (with padding):
(contained by parent's padding)
3. Empty Blocks
An element with no height, no padding, no border, and no content will have its own top and bottom margins collapse with each other.
/* This empty div's top and bottom margins collapse into one */ .empty { margin-top: 20px; margin-bottom: 30px; /* Resulting margin = 30px (the larger one) */ }
How to Prevent Margin Collapsing
Several techniques prevent margin collapse by introducing a separation between the margins:
/* 1. Add padding to the parent */ .parent { padding-top: 1px; } /* 2. Add border to the parent */ .parent { border-top: 1px solid transparent; } /* 3. Use overflow other than visible */ .parent { overflow: hidden; } /* or auto */ /* 4. Make parent a flex or grid container */ .parent { display: flex; flex-direction: column; } .parent { display: grid; } /* 5. Use display: flow-root (creates new BFC) */ .parent { display: flow-root; }
overflow: hidden
display: flex
display: flow-root
To avoid margin collapsing surprises, many developers adopt a "single-direction margin" convention: only use margin-bottom (or margin-top) for vertical spacing, never both. This makes spacing predictable and eliminates collapsing between siblings.
Margins never collapse in these contexts: between flex items, between grid items, inline-level elements, floated elements, absolutely or fixed positioned elements, or elements with overflow other than visible on the parent.
box-sizing
The box-sizing property determines what the width and height properties refer to. It has two possible values, and understanding the difference is critical.
content-box (default)
With content-box, the width and height set only the content area. Padding and border are added on top of the declared dimensions.
.content-box-demo { box-sizing: content-box; /* default */ width: 200px; padding: 20px; border: 5px solid; /* Rendered width = 200 + 20 + 20 + 5 + 5 = 250px */ }
border-box
With border-box, the width and height include padding and border. The content area shrinks to accommodate them. This is usually what developers want.
.border-box-demo { box-sizing: border-box; width: 200px; padding: 20px; border: 5px solid; /* Rendered width = exactly 200px */ /* Content area = 200 - 20 - 20 - 5 - 5 = 150px */ }
Visual Comparison
Both boxes have width: 250px, padding: 20px, border: 5px solid. Notice the difference in total rendered width.
content-box (default):
+ padding: 40px + border: 10px
Total rendered: 300px
border-box:
padding + border included
Total rendered: 250px
Universal Reset Pattern
Nearly every modern CSS project applies border-box globally. The recommended pattern uses the inherit value on * so components that opt into a different model can change it on a parent and have children inherit it.
/* Universal box-sizing reset — industry standard */ *, *::before, *::after { box-sizing: border-box; } /* Alternative: inheritable pattern */ html { box-sizing: border-box; } *, *::before, *::after { box-sizing: inherit; }
The border-box model is more intuitive: when you say width: 300px, the element is exactly 300px wide, regardless of padding and border. Every major CSS framework (Bootstrap, Tailwind, Normalize.css) applies this reset. Add it to the very top of your stylesheet.
Display and the Box Model
The display property fundamentally changes how the box model applies to an element. The two key display types — block and inline — behave very differently.
Block-Level Elements
Block-level elements (display: block) get the full box model treatment:
- Expand to fill 100% of the parent's width by default.
- Start on a new line.
width,height,margin,padding, andborderall work as expected.- Vertical margins collapse with adjacent blocks.
Inline Elements
Inline elements (display: inline) have a restricted box model:
widthandheightare ignored.- Horizontal margin and padding work normally.
- Vertical padding and border are rendered visually but do not push other content away (they overlap).
- Vertical margin is completely ignored.
- Do not start on a new line — they flow with text.
Inline-Block
display: inline-block gives you the best of both worlds: the element flows inline with text but respects all box model properties (width, height, vertical margin/padding).
/* Block: full box model, new line */ .block { display: block; } /* Inline: width/height/vertical margin ignored */ .inline { display: inline; } /* Inline-block: full box model, flows inline */ .inline-block { display: inline-block; }
Here is text with a display:inline (width/height ignored) element, followed by more text.
Here is text with a display:inline-block (width/height respected) element, followed by more text.
| Property | block | inline | inline-block |
|---|---|---|---|
width / height | Respected | Ignored | Respected |
Horizontal margin | Respected | Respected | Respected |
Vertical margin | Respected (collapses) | Ignored | Respected |
Horizontal padding | Respected | Respected | Respected |
Vertical padding | Respected | Visual only (overlaps) | Respected |
| Line break behavior | New line | Flows inline | Flows inline |
Vertical padding on inline elements is painted visually but does not affect line height or push surrounding content. This often causes overlapping backgrounds. If you need vertical spacing on an inline element, switch to inline-block or inline-flex.
Common Gotchas & Pro Tips
Common Gotchas
Without box-sizing: border-box, setting width: 100% on an element with padding or border causes it to overflow its parent. This is the number one box model bug for beginners. Always apply the universal reset.
/* BUG: overflows parent because padding is added to 100% */ .input { width: 100%; padding: 16px; /* box-sizing defaults to content-box */ /* Rendered width = 100% + 32px — overflows! */ } /* FIX */ .input { width: 100%; padding: 16px; box-sizing: border-box; /* Rendered width = exactly 100% */ }
content-box (overflows):
border-box (fits perfectly):
A common surprise: your first child's margin-top "escapes" its parent container, pushing the entire parent down instead of creating space inside the parent. Fix: add padding-top: 1px, overflow: hidden, or display: flow-root on the parent.
Setting width or height on a <span>, <a>, <strong>, or other inline elements has no effect. You must change the display to inline-block, block, flex, or inline-flex first.
height: 50% only works if the parent has an explicit (non-auto) height. If the parent's height is auto (the default), the percentage height resolves to auto and is effectively ignored. For full-page layouts, set html, body { height: 100%; }.
In older browsers, outlines are always rectangular, even on elements with rounded corners. Modern browsers (Chrome 94+, Firefox 88+, Safari 16.4+) render outlines that follow border-radius. If you must support older browsers, use box-shadow instead for a rounded focus indicator.
Pro Tips
Instead of margin-left / padding-right, use margin-inline-start / padding-inline-end. These logical properties adapt automatically for right-to-left (RTL) languages.
/* Physical (breaks in RTL) */ .card { padding-left: 20px; margin-right: 16px; } /* Logical (works in any writing mode) */ .card { padding-inline-start: 20px; margin-inline-end: 16px; }
When debugging layout, use outline: 1px solid red instead of border. Outlines do not affect layout or change the size of elements, so they will not shift things around while you are debugging.
/* Debugging helper: shows all element boxes without affecting layout */ * { outline: 1px solid rgba(255, 0, 0, 0.2); }
Flex and Grid containers support the gap property, which creates consistent spacing between children without worrying about margin collapsing, first/last child margins, or negative margins to undo row margins. Prefer gap whenever possible.
/* OLD approach: margin on children with negative margin on parent */ .grid { display: flex; flex-wrap: wrap; margin: -8px; } .grid > * { margin: 8px; } /* MODERN: clean gap property */ .grid { display: flex; flex-wrap: wrap; gap: 16px; }
Instead of the old padding-top: 56.25% trick for maintaining aspect ratios, modern CSS has a dedicated aspect-ratio property. It is cleaner, more readable, and does not require absolute positioning of children.
/* Modern aspect ratio */ .video-container { width: 100%; aspect-ratio: 16 / 9; } .square { width: 200px; aspect-ratio: 1; /* shorthand for 1/1 */ }
You can use box-shadow with no blur and no spread to create a visual border that does not take up space (like outline but with per-side control and radius following). Multiple shadows let you create multi-colored borders or inset effects.
/* "Border" using box-shadow (no layout impact) */ .shadow-border { box-shadow: 0 0 0 3px #6c8cff; border-radius: 8px; } /* Double border effect */ .double-border { box-shadow: 0 0 0 3px #6c8cff, 0 0 0 6px #a78bfa; }
"border"
"border"
"border"
Quick Reference: Box Model Properties
| Area | Properties | Can Be Negative? | Affects Layout? |
|---|---|---|---|
| Content | width, height, min-*, max-* | No | Yes |
| Padding | padding, padding-* | No | Yes |
| Border | border, border-* | No | Yes |
| Outline | outline, outline-* | No (offset can be) | No |
| Margin | margin, margin-* | Yes | Yes (collapses vertically) |