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:

  1. Content: the text, image or child elements. Its size is set by width and height, or by the content itself.
  2. Padding: space between the content and the border. The element's background fills it.
  3. Border: a line around the padding (it can have zero width).
  4. Margin: space outside the border that keeps other elements at a distance. It is always transparent.
The box model: the content area sits in the middle, surrounded by padding, then the border, then the margin on the outside. margin border padding content width × height padding-bottom margin-bottom
The four layers of a box. Padding is inside the border and shows the background; margin is outside it and 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 auto takes up the free space. A block with a max-width and margin: 0 auto sits centered in its parent, the classic way to center a page column. (margin-inline: auto is 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 width fills its parent's width automatically (width: auto). Setting width: 100% is rarely needed and can cause overflow when margins are added.
  • height is normally left alone: the content decides. A fixed height around text breaks as soon as the text is longer, is translated, or is zoomed. Use min-height when a box must be at least a certain size.
  • max-width keeps things from getting too wide. img { max-width: 100%; height: auto; } lets images shrink with a narrow screen without distorting.
  • A percentage height only works when the parent has a definite height; otherwise it acts like auto.

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 h1 inside 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: like hidden, 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; }