The Box Model
Every element is a box: content, padding, border and margin, box-sizing, block and inline display, margin collapsing, and overflow.
Every element is a box
To lay out a page, the browser turns every element into a rectangle. The box model describes what that rectangle is made of, from the inside out:
-
Content: the text, image or child elements. Its
size is set by
widthandheight, or by the content itself. - Padding: space between the content and the border. The element's background fills it.
- Border: a line around the padding (it can have zero width).
- Margin: space outside the border that keeps other elements at a distance. It is always transparent.
Developer tools draw exactly this diagram for the selected element, with the real numbers filled in (see Debugging HTML and CSS with Developer Tools). How wide is the box below in total?
<div class="card">Meter KE-4471-0932</div>
.card {
width: 240px;
padding: 16px;
border: 4px solid steelblue;
margin: 24px;
background: aliceblue;
}
The visible box (border included) is 240 + 2 × 16 + 2 × 4 =
280px wide, and it takes up 280 + 2 × 24 = 328px of
space including its margins. The next section shows how to make
width mean the visible width instead.
Padding, border and margin
Padding
Padding is the space between an element's content and its border. It belongs to the element: the background color extends under it, and a click on the padding of a link or button counts as a click on the element. That makes padding the right tool for bigger, easier click targets.
Padding, margin and border widths share a shorthand that takes one to four values, going clockwise from the top:
| Shorthand | Top | Right | Bottom | Left |
|---|---|---|---|---|
padding: 1rem |
1rem | 1rem | 1rem | 1rem |
padding: 0.5rem 2rem |
0.5rem | 2rem | 0.5rem | 2rem |
padding: 1rem 2rem 0 |
1rem | 2rem | 0 | 2rem |
padding: 0 0 0 3rem |
0 | 0 | 0 | 3rem |
Each side also has its own property, such as
padding-left. Percentages in padding are calculated
from the width of the containing block, even for top and
bottom.
<p class="a">padding: 1rem</p>
<p class="b">padding: 0.5rem 2rem</p>
<p class="c">padding: 0 0 0 3rem</p>
p { background: lavender; border: 1px solid slategray; margin: 0 0 0.5rem; }
.a { padding: 1rem; }
.b { padding: 0.5rem 2rem; }
.c { padding: 0 0 0 3rem; }
Border
A border needs a width, a style and a color:
border: 1px solid gray. Without a style
(solid, dashed, dotted,
double) there is no border at all, and without a color
it uses the text color. Single sides work too:
border-bottom: 2px solid navy.
border-radius rounds the corners.
An outline looks like a border but is
not part of the box model: it takes no space and is
drawn outside the border. That is why browsers use it for the
keyboard focus indicator: showing it does not shift the layout.
Margin
Margin is the transparent space outside an element's border that separates it from its neighbors. It uses the same shorthand as padding. Margins differ from padding in three ways:
- They can be negative, which pulls the element (or its neighbor) closer, even into overlap.
-
The value
autotakes up the free space. A block with amax-widthandmargin: 0 autosits centered in its parent, the classic way to center a page column. (margin-inline: autois the logical-property form of the same thing.) - Vertical margins between blocks can collapse into one.
<main class="page">
<p>This column is at most 20rem wide and centered with margin: 0 auto.</p>
</main>
.page {
max-width: 20rem;
margin: 0 auto;
padding: 0 1rem;
border: 1px dashed gray;
}
The column is at most 20rem (320px) wide; the auto margins share the
rest of the width equally. In a frame narrower than that, the column
simply fills it: max-width is a limit, not a fixed
size.
Width, height and box-sizing
The property box-sizing decides
what width and height measure:
-
content-box(the default): only the content. Padding and border are added on top, as in the card example above. -
border-box: the content, padding and border together. Add padding and the content area shrinks; the visible box stays the size you set.
<div class="box content">content-box: 250px wide</div>
<div class="box border">border-box: 200px wide</div>
.box {
width: 200px;
padding: 20px;
border: 5px solid steelblue;
margin-bottom: 0.5rem;
background: aliceblue;
}
.content { box-sizing: content-box; } /* 200 + 40 + 10 */
.border { box-sizing: border-box; } /* exactly 200 */
border-box is so much easier that most stylesheets
switch every element to it in their first lines:
*,
*::before,
*::after {
box-sizing: border-box;
}
A side benefit: width: 100% plus padding no longer
overflows its parent. With content-box, a full-width
input with padding sticks out on the right.
Some more sizing rules worth knowing:
-
A block element without a
widthfills its parent's width automatically (width: auto). Settingwidth: 100%is rarely needed and can cause overflow when margins are added. -
heightis normally left alone: the content decides. A fixed height around text breaks as soon as the text is longer, is translated, or is zoomed. Usemin-heightwhen a box must be at least a certain size. -
max-widthkeeps things from getting too wide.img { max-width: 100%; height: auto; }lets images shrink with a narrow screen without distorting. -
A percentage
heightonly works when the parent has a definite height; otherwise it acts likeauto.
Normal flow and the display property
Before you add any layout CSS, the browser places boxes in normal flow: block boxes are stacked from top to bottom, each starting on a new line, and inline boxes are placed next to each other inside a line of text, wrapping to the next line when the row is full. Flexbox, grid and positioning are ways of changing that default.
The display property
decides which kind of box an element generates. Each HTML element
has a default from the browser stylesheet (div,
p and h1 are block; span,
a and strong are inline), and CSS can
change it without changing the meaning of the element:
| Value | Behavior |
|---|---|
block |
Starts on a new line and fills the available width. Respects
width, height, and all margins and
padding.
|
inline |
Flows inside the text. Ignores width and
height; vertical margins have no effect and
vertical padding overlaps the lines above and below.
|
inline-block |
Flows inside the text like a word, but is sized like a
block: width, height and vertical
spacing all work.
|
none |
Generates no box at all: the element is not shown and takes no space. Screen readers skip it too. |
flex, grid |
A block box whose children are laid out with flexbox or grid. |
<p>Status: <span class="inline">inline</span> and
<span class="inline-block">inline-block</span> sit in the text.</p>
<span class="block">A span with display: block</span>
span { background: lightyellow; border: 1px solid gray; padding: 0.5rem; }
.inline { width: 10rem; } /* ignored: inline boxes have no width */
.inline-block { display: inline-block; width: 10rem; }
.block { display: block; }
The terms block and inline are about boxes in CSS.
HTML has its own content categories (see
Text and Semantic Elements), and changing display does not change what an
element means or what it may contain. CSS also has a two-value
syntax that spells out both sides, such as
display: inline flow-root for what
inline-block does; it has been Baseline widely
available since January 2026.
Margin collapsing
In normal flow, when the bottom margin of one block meets the top margin of the next, they do not add up. They merge into a single margin as large as the larger of the two. This is margin collapsing, and it is deliberate: a paragraph with 1em of space above and below should be 1em from the next paragraph, not 2em.
<div class="normal">
<p class="first">margin-bottom: 2rem</p>
<p class="second">margin-top: 1rem (gap is 2rem)</p>
</div>
<div class="flex">
<p class="first">margin-bottom: 2rem</p>
<p class="second">margin-top: 1rem (gap is 3rem)</p>
</div>
.normal, .flex { border: 1px dashed gray; margin-bottom: 1rem; }
.flex { display: flex; flex-direction: column; }
p { margin: 0; background: honeydew; border: 1px solid seagreen; }
.first { margin-bottom: 2rem; }
.second { margin-top: 1rem; }
Margins collapse in three situations:
- Adjacent siblings, as above.
-
Parent and first or last child, when nothing
separates them (no border, padding or inline content). The child's
top margin then "leaks" out of the parent. The classic symptom:
you give the
h1inside a header a top margin, and the whole header moves down instead. - An empty block, whose own top and bottom margins collapse together.
Only vertical margins (in horizontal writing)
collapse, and only in normal block flow. They do not collapse inside
flex or grid containers, for floated or absolutely positioned
elements, or across the edge of a new block formatting context,
which display: flow-root creates. To stop a child's
margin leaking out of its parent, give the parent some padding or
display: flow-root. Many teams avoid the whole topic by
spacing elements with margins on one side only (for example only
margin-block-end), or with gap in a flex
or grid container.
Overflow
When content is bigger than its box, for example text in a box with a fixed height, it overflows. The overflow property decides what happens to the part that does not fit:
-
visible(default): the content spills out of the box; it takes up no space, so it can overlap whatever comes next. -
hidden: the content is cut off at the padding edge. Readers cannot reach it, so use this only for decoration. -
clip: likehidden, but the box cannot be scrolled even by script. scroll: always shows scrollbars.-
auto: shows a scrollbar only when needed. Usually the best choice for a scrolling area.
overflow-x and overflow-y set the two
directions separately.
<div class="box">overflow: visible (the default). The text spills out
of the box into the space below it.</div>
<div class="box hidden">overflow: hidden. The text is cut off, and the
reader has no way to get to the rest of it.</div>
<div class="box auto">overflow: auto. A scrollbar appears only when the
content does not fit in the box.</div>
.box {
width: 14rem;
height: 3rem;
padding: 0.25rem;
border: 1px solid gray;
margin-bottom: 2.5rem;
}
.hidden { overflow: hidden; }
.auto { overflow: auto; }
A common real-world overflow is horizontal: a long URL, meter ID or
email address without spaces cannot wrap, so it pushes past the edge
of a narrow column and causes a sideways scrollbar on a phone.
overflow-wrap: anywhere allows the browser to break
such words when there is no other way:
<p class="narrow">Export: https://portal.example.com/readings/2026/export-all-meters.csv</p>
<p class="narrow wrap">Export: https://portal.example.com/readings/2026/export-all-meters.csv</p>
.narrow { width: 12rem; border: 1px solid gray; }
.wrap { overflow-wrap: anywhere; }