What is the box model?
The CSS box model is the foundational concept behind every layout on the web. It describes how every HTML element is rendered as a rectangular box with four distinct layers: content, padding, border and margin. Whether you are styling a simple paragraph or building a complex dashboard, the box model determines how much space an element occupies and how it relates to its neighbours.
Think of it like a picture frame. The picture itself is the content. The matting around it is the padding. The frame is the border. And the space between this frame and the next one on the wall is the margin. Every element on a web page works exactly this way — nested boxes inside nested boxes.
The four layers
Content is the innermost layer — the text, image, video or other media the element holds. Its size is set with width and height (or by the content itself if those are not specified).
Padding sits between the content and the border. It adds breathing room inside the element so text does not crowd the edges. Padding is transparent by default, so the background colour or image of the element shows through it.
Border wraps the padding and content. It has width, style and colour. Borders can be decorative or structural — they are the visible edge that separates the element from the outside world.
Margin is the outermost layer. It pushes other elements away. Unlike padding, margin is always transparent and sits outside the element’s border. Margins are the primary tool for controlling spacing between elements.
box-sizing: content-box vs border-box
The box-sizing property changes how the browser interprets width and height.
With the default value, content-box, the width and height you set apply only to the content area. Padding and border are added on top. So a div with width: 200px, padding: 20px and a 4px border actually renders at 248px wide. This is counter-intuitive and is the single most common source of layout bugs for beginners.
With border-box, width and height include padding and border. The same div with width: 200px, padding: 20px and a 4px border stays exactly 200px wide — the content area shrinks to make room. This is how most developers expect sizing to work, and it is why a global reset like this is standard practice:
/* reset.css */
*,
*::before,
*::after {
box-sizing: border-box;
}
Border-box makes layouts predictable. You set a width, and the element respects it. There is no mental arithmetic to figure out why your columns are wider than expected. Use it everywhere and forget the headaches.
Block vs inline vs inline-block
Every element has a default display behaviour that controls how it participates in layout.
Block elements start on a new line and stretch to fill the full width of their parent. They stack vertically. Examples include div, p, h1 through h6, section, article, header, footer and ul. Block elements accept width, height, margin on all sides and padding on all sides.
Inline elements flow within text without breaking the line. They only take up as much width as their content needs. Examples include span, a, strong, em, img and code. Inline elements ignore width and height, and vertical margin and padding do not affect surrounding layout — they visually shift but do not push other elements.
Inline-block elements are a hybrid. They flow inline like text but behave like blocks internally — they accept width, height, margin and padding on all sides. Navigation links, badges and tags are classic use cases. They remain in the text flow but give you full control over sizing and spacing.
| Property | Block | Inline | Inline-block |
|---|---|---|---|
| Starts on new line | Yes | No | No |
| Width/height | Yes | No | Yes |
| Vertical margin/padding | Yes | No (visual only) | Yes |
| Horizontal margin/padding | Yes | Yes | Yes |
The display property
The display property is the most powerful layout tool in CSS. It controls not only the box model behaviour but also how an element participates in layout algorithms.
The most common values:
block— full-width box, stacks vertically.inline— flows with text, no box-model sizing.inline-block— inline flow with box-model sizing.none— removes the element from layout entirely. It takes no space and is not rendered.flex— turns the element into a flex container. Children become flex items with one-dimensional layout control.grid— turns the element into a grid container. Children are placed in a two-dimensional grid.inline-flex— flex container that flows inline.inline-grid— grid container that flows inline.
Modern CSS gives you flex and grid for layout, but understanding block and inline is still essential because they are the foundation that flex and grid build on. Every element without an explicit display value falls back to block or inline depending on the element type.
Width and height calculations
How width and height are calculated depends entirely on box-sizing.
With content-box:
Actual width = width + padding-left + padding-right + border-left + border-right
Actual height = height + padding-top + padding-bottom + border-top + border-bottom
With border-box:
Actual width = width (padding and border are included)
Actual height = height (padding and border are included)
A practical consequence: with content-box, setting width: 100% on an element with padding or border will cause horizontal overflow. With border-box it works as expected. This is one of the strongest arguments for always using border-box.
For sizing within a container, remember that percentages for width refer to the parent’s content width (even with border-box), while percentages for height require the parent to have an explicit height — otherwise the percentage is treated as auto.
Overflow and scrolling
When content is larger than its container, the overflow property decides what happens.
overflow: visible(default) — content spills outside the box. It is visible but can overlap siblings.overflow: hidden— content is clipped at the box edge. No scrollbar, no way to see the rest.overflow: scroll— a scrollbar appears whether it is needed or not.overflow: auto— a scrollbar appears only when content overflows. This is usually the best choice.overflow-xandoverflow-ylet you control horizontal and vertical overflow independently.
Overflow is especially important with fixed-width containers, modals, code blocks and any element whose content might grow. Without it, unexpected horizontal scrollbars on the page are common.
Margin collapse
Vertical margins have a quirk that surprises nearly every beginner: they collapse. When two vertical margins touch, the larger one wins instead of the two adding together.
/* style.css */
.box-a { margin-bottom: 30px; }
.box-b { margin-top: 20px; }
/* The gap between them is 30px, not 50px */
Margin collapse happens in three situations:
- Adjacent siblings — the bottom margin of one and the top margin of the next merge.
- Parent and first child — the parent’s top margin collapses with its first child’s top margin (if the parent has no border, padding or content to separate them).
- Parent and last child — same as above but for the bottom.
Margin collapse never happens with:
- Horizontal margins.
- Flex and grid items (the box model is different inside these containers).
- Elements with
overflowset to anything other thanvisible. - Elements with
borderorpaddingthat separate the margins.
Understanding margin collapse prevents the “why is this gap the wrong size” problem that drives developers to add arbitrary padding or negative margins.
Positioning: static, relative, absolute, fixed, sticky
The position property takes an element out of or modifies its place in normal document flow.
static is the default. The element sits in normal flow, and top, right, bottom, left and z-index have no effect.
relative keeps the element in flow but lets you offset it with top, right, bottom and left. The original space is preserved — it is like nudging the element visually while keeping its layout slot.
absolute removes the element from flow entirely. It is positioned relative to its nearest positioned ancestor — any ancestor with position set to relative, absolute, fixed or sticky. If no such ancestor exists, it uses the viewport. Absolute elements do not affect the layout of siblings or parents.
fixed also removes the element from flow, but positions it relative to the viewport. It stays in the same place when the page scrolls. Use it for sticky headers, floating action buttons and modals that must stay visible.
sticky is a hybrid. The element scrolls normally until it reaches a threshold (top, right, bottom or left), then it “sticks” in place. It is the modern replacement for JavaScript scroll listeners. Navigation bars that stay at the top while you scroll are the classic use case.
/* style.css */
.sticky-nav {
position: sticky;
top: 0;
z-index: 10;
}
Z-index and stacking context
When elements overlap, z-index determines which one appears on top. It only works on positioned elements — those with position set to anything other than static.
But z-index is not a simple global number. It creates or participates in a stacking context. A stacking context is a self-contained layer that encapsulates its children. A child with z-index: 9999 inside a stacking context with z-index: 1 will never appear above an element with z-index: 2 in the parent context.
Stacking contexts are created by:
- Elements with
positionandz-indexother thanauto. - Elements with
opacityless than 1. - Elements with
transform,filter,backdrop-filterorperspective. - Elements with
isolation: isolate. - Elements inside a flex or grid container with a
z-index.
Understanding stacking contexts is the key to solving “z-index doesn’t work” problems. The solution is almost never a bigger number — it is understanding which stacking context your element lives in.
Layout best practices
- Always use
box-sizing: border-boxglobally. It eliminates an entire class of sizing bugs. - Avoid
width: 100%with padding on content-box elements. Use border-box instead. - Prefer
max-widthoverwidthfor content that should not stretch too wide. - Use
margin: autofor horizontal centering inside block containers. - Use
overflow: autoinstead ofoverflow: hiddenwhen you want scrollbars for overflowed content. - Avoid giving fixed
heightto containers with dynamic content — let them grow with the content. - For vertical spacing, be aware of margin collapse. Use gap in flex/grid or padding on a parent instead.
- Never use
position: absolutefor general layout — it breaks the document flow and makes responsive design harder. - Use
position: stickyinstead of JavaScript for scroll-aware headers and sidebars. - Keep stacking contexts shallow. Overlapping
z-indexvalues across deeply nested components leads to confusion. - Test layouts at multiple widths. The box model behaves differently when the viewport shrinks.
Common mistakes
- Forgetting to set
box-sizing: border-boxand getting unexpected widths. - Using
widthon inline elements and wondering why nothing changes. - Applying
marginon inline elements and not getting the spacing expected. - Using
position: absolutewithout a positioned parent, causing elements to fly to the viewport corner. - Confusion when
z-indexdoes not work — usually a stacking context issue. - Surprised by margin collapse between parent and child elements.
- Setting a fixed height on a container and watching content overflow invisibly.
- Using
overflow: hiddento “fix” layout when the real problem is incorrect sizing.
When to use the box model vs Flexbox or Grid
The box model is not a layout system on its own — it is the foundation that all CSS layouts build on. Flexbox and Grid do not replace the box model; they use it. Every flex item and grid cell still has content, padding, border and margin.
Use the box model directly for:
- Controlling spacing inside and around individual elements.
- Setting explicit sizes for cards, buttons, inputs and containers.
- Understanding why elements overflow or do not fit their parents.
Use Flexbox when you need to align and distribute items along one axis — navigation bars, card rows, centreing content.
Use Grid when you need two-dimensional layout with rows and columns — page shells, dashboards, image galleries.
The best CSS developers reach for the box model first to understand what is happening, then layer flex or grid on top for higher-level layout. Learning the box model is not separate from learning modern layout — it is the prerequisite that makes everything else make sense.