The Box Model
Margin, border, padding, content. Every element is a box.
Every element on a page is a box. Even the round avatars. Even the text. Even the things that look like nothing. The CSS box model describes how each of those boxes is constructed and how they push against each other. Master this and 80% of layout mysteries dissolve.
The four layers
Every box has four concentric rectangles. From innermost outward:
- Content - the actual text, image, or child elements.
- Padding - space inside the box, between content and border. Transparent. Inherits the background.
- Border - a line drawn around the padding. Can be colored, dashed, rounded.
- Margin - space outside the box, pushing other elements away. Always transparent.
box-sizing: the most important reset
By default, when you set width: 300px, that's the width of the content only. Padding and border get added on top, making the actual box wider. This is almost never what you want.
/* Default: content-box */
.thing {
width: 300px;
padding: 20px;
border: 2px solid;
/* Actual rendered width: 344px (300 + 20 + 20 + 2 + 2) */
}Switch to box-sizing: border-box and the width becomes the total box width, including padding and border. The content shrinks to fit.
/* Apply border-box to everything - the modern default */
*, *::before, *::after {
box-sizing: border-box;
}
.thing {
width: 300px;
padding: 20px;
border: 2px solid;
/* Actual rendered width: 300px */
}Margin collapse: the rule everyone trips on
Two vertical margins between sibling block elements collapse into one. The larger margin wins; they don't add up.
<p style="margin-bottom: 20px">First</p>
<p style="margin-top: 30px">Second</p>
<!-- The gap is 30px, not 50px -->It also collapses with the parent: if a child has margin-topand the parent has no padding or border, the child's margin pokes above the parent. This is a feature, not a bug, but it surprises every beginner.
Margin collapse only happens with vertical margins on block elements, and never inside flex or grid containers. Modern layouts using flex and grid sidestep it entirely.
display: flow-root on the parent, or use gap on a flex/grid container instead of margins on children. Both prevent the collapse.Shorthand: one, two, three, or four values
padding and margin are shorthand for four sides. The number of values changes meaning:
padding: 10px;- all four sides.padding: 10px 20px;- vertical | horizontal.padding: 10px 20px 30px;- top | horizontal | bottom.padding: 10px 20px 30px 40px;- top | right | bottom | left (clockwise from top).
Logical properties (the modern way)
margin-top and padding-leftare physical directions. They don't adapt to right-to-left languages like Arabic or vertical writing modes like traditional Japanese. Logical properties do.
margin-block-start/margin-block-end- top/bottom in horizontal text.margin-inline-start/margin-inline-end- left/right in horizontal LTR text.padding-block- shorthand for both block sides.padding-inline- shorthand for both inline sides.
/* Old (physical): only works for LTR horizontal text */
.button {
padding: 0.5rem 1rem;
margin-left: 1rem;
}
/* New (logical): works for any writing mode */
.button {
padding-block: 0.5rem;
padding-inline: 1rem;
margin-inline-start: 1rem;
}margin-left: 1rem, the spacing looks wrong when the language flips. margin-inline-start follows the text direction automatically.Visualize it
Drag the sliders. Watch the layers grow and shrink. Notice how padding grows the box (with border-box, content shrinks instead). Notice how margin pushes away the dotted neighbor.
.box {
width: 220px;
height: 110px;
padding: 20px;
border: 4px solid #1d4ed8;
margin: 16px;
box-sizing: border-box;
}min/max and the modern sizing keywords
Width and height accept far more than fixed pixels:
auto- let the browser compute it.100%- fill the container.min-content- as small as the content allows (the longest unbreakable word).max-content- as wide as the content wants to be (no wrapping).fit-content- somewhere between min and max; wraps but doesn't expand past the container.min-width,max-width,min-height,max-height- boundaries.
A common, useful pattern: max-width: 60ch on body text. chis the width of the "0" character in the current font, so 60ch is a comfortable line of about 60 characters. The line stays readable on any screen.
Quick quiz
With box-sizing: content-box (the default), you set width: 200px, padding: 20px, border: 2px. What's the rendered width?
Recap
- Every element is a box: content → padding → border → margin.
- Set
box-sizing: border-boxglobally. Width then includes padding and border. Sanity restored. - Margins collapse vertically between block siblings (and into their parent). Flex/grid
gapsidesteps it. - Padding/margin shorthand: 1 value (all), 2 (vertical/horizontal), 4 (top/right/bottom/left).
- Use logical properties (
margin-block,padding-inline) for RTL and writing-mode resilience. - Width keywords:
min-content,max-content,fit-content. Combine withmax-width: 60chfor readable text.