CSS Box Model: Margin, Padding, Border and Display

Every element is drawn as nested rectangles: the content, then padding (space inside the border, painted with the background), then the border, then margin (transparent space outside that pushes neighbours away). With box-sizing: border-box, the width you set includes padding and border, which makes layouts far easier to predict. The display property decides how boxes flow.

The four layers, inside out
LayerWhat it doesGets the background?
ContentHolds text, images and child elementsYes
PaddingBreathing room between content and borderYes
BorderA visible line (or nothing) around the paddingIts own border colour
MarginGap between this box and its neighboursNo, always transparent

Updated

Move the four sliders and the diagram, the measured total size and the CSS all change together. Below the visualiser you can flip box-sizing, watch two margins collapse into one, and compare block, inline, inline-block, flex, grid and none side by side on the same three items.

Margin or padding? Pick by the job

Which one to reach for
You wantUse
The background colour to cover the spacepadding
A bigger tap area on a buttonpadding
Space between two separate cardsmargin, or gap on the parent
One item pushed to the far end of a flex rowmargin-left: auto
A fixed-width block centredmargin-inline: auto
Space that can never collapse with a neighbourpadding, or gap

Margin collapsing, seen live

The first pair shows two siblings whose 24px and 40px margins meet: the gap is 40px, not 64px. The second pair sits in a flow-root container, which stops the parent and child margins merging, and the third uses flex, where nothing collapses.

Sibling and parent-child collapse

Edit the margins and watch the gaps. Adding padding-top: 1px to the outer box also stops the parent and child merging.

<style>
  .a { margin-bottom: 24px; background: #dbeafe }
  .b { margin-top: 40px; background: #fde68a }
  .outer { background: #f1f5f9 }
  .inner { margin-top: 30px; background: #bbf7d0 }
  .safe { display: flow-root; background: #f1f5f9 }
  div { padding: 6px 10px }
</style>
<div class="a">margin-bottom: 24px</div>
<div class="b">margin-top: 40px (gap is 40px)</div>
<div class="outer"><div class="inner">child margin leaks out of the grey parent</div></div>
<div class="safe"><div class="inner">flow-root keeps it inside</div></div>

Border styles and radius

All eight visible border styles

groove, ridge, inset and outset shade the border to fake depth. They look best at 4px or wider.

<style>
  .grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px }
  .grid div { border: 5px solid #4F98FB; padding: 10px 4px; text-align: center; font-size: 13px }
</style>
<div class="grid">
  <div style="border-style: solid">solid</div><div style="border-style: dashed">dashed</div>
  <div style="border-style: dotted">dotted</div><div style="border-style: double">double</div>
  <div style="border-style: groove">groove</div><div style="border-style: ridge">ridge</div>
  <div style="border-style: inset">inset</div><div style="border-style: outset">outset</div>
</div>

Radius shapes: rounded, pill, circle, ellipse

A huge radius such as 999px makes a pill of any length. 50% on a square gives a circle.

<style>
  .row { display: flex; gap: 14px; align-items: center; flex-wrap: wrap }
  .row div { background: #0f172a; color: #fff; padding: 10px 16px; font-size: 13px }
</style>
<div class="row">
  <div style="border-radius: 10px">10px</div>
  <div style="border-radius: 999px">pill</div>
  <div style="border-radius: 50%; width: 70px; height: 70px; display: grid; place-items: center; padding: 0">circle</div>
  <div style="border-radius: 40px / 16px">40px / 16px</div>
  <div style="border-radius: 18px 0">18px 0</div>
</div>

Every display value on the same three items

display values compared
ValueNew line?Width and height work?Typical useTailwind
blockYesYesSections, paragraphs, cardsblock
inlineNoNoWords inside a sentenceinline
inline-blockNoYesBadges, buttons in a line of textinline-block
flexYesYesRows or columns of itemsflex
inline-flexNoYesAn icon and label inside textinline-flex
gridYesYesTwo-dimensional layoutsgrid
inline-gridNoYesA small grid that sits in a lineinline-grid
flow-rootYesYesContains floats and child marginsflow-root
contentsBox removedNo box to sizeLet children join the parent layoutcontents
noneRemoved from layoutNot renderedHide completelyhidden

block, inline, inline-block, flex and grid side by side

Each row holds the same three spans with width: 80px and padding. Only inline ignores the width.

<style>
  .demo span { width: 80px; padding: 6px; margin: 3px; background: #dbeafe; border: 1px solid #4F98FB; font-size: 13px }
  .demo { border: 1px dashed #94a3b8; margin-bottom: 8px; padding: 4px }
  h4 { margin: 4px 0; font: 600 12px monospace }
</style>
<h4>display: block</h4><div class="demo"><span style="display:block">One</span><span style="display:block">Two</span><span style="display:block">Three</span></div>
<h4>display: inline</h4><div class="demo"><span>One</span><span>Two</span><span>Three</span></div>
<h4>display: inline-block</h4><div class="demo"><span style="display:inline-block">One</span><span style="display:inline-block">Two</span><span style="display:inline-block">Three</span></div>
<h4>parent display: flex</h4><div class="demo" style="display:flex"><span>One</span><span>Two</span><span>Three</span></div>
<h4>parent display: grid (2 columns)</h4><div class="demo" style="display:grid;grid-template-columns:1fr 1fr"><span>One</span><span>Two</span><span>Three</span></div>

display: none vs visibility: hidden vs opacity: 0

Three ways to hide, compared
PropertyKeeps its space?Clickable or focusable?Read by screen readers?Can transition?
display: noneNoNoNoOnly with allow-discrete in newer browsers
visibility: hiddenYesNoNoYes, switches at the end or start
opacity: 0YesYesYesYes, smoothly

The middle item hidden three ways

Notice the gap left behind by visibility and opacity, and the closed gap with display: none.

<style>
  .row { display: flex; gap: 6px; margin-bottom: 8px }
  .row div { flex: 0 0 70px; padding: 8px; background: #fde68a; text-align: center; font-size: 13px }
</style>
<div class="row"><div>A</div><div style="display:none">B</div><div>C</div> display: none</div>
<div class="row"><div>A</div><div style="visibility:hidden">B</div><div>C</div> visibility: hidden</div>
<div class="row"><div>A</div><div style="opacity:0">B</div><div>C</div> opacity: 0</div>

The border-box reset

Apply border-box everywhere

The pseudo-elements are included because they are boxes too. Tailwind's Preflight ships this rule already.

*, *::before, *::after {
  box-sizing: border-box;
}

Tailwind equivalents

Box model utilities in Tailwind (default spacing scale, 1 unit = 0.25rem)
CSSTailwind
padding: 1remp-4
padding-inline: 1.5rempx-6
margin-top: 2remmt-8
margin-inline: automx-auto
border-width: 1px / 2pxborder / border-2
border-style: dashedborder-dashed
border-radius: 0.5remrounded-lg
border-radius: 9999pxrounded-full
box-sizing: border-box / content-boxbox-border / box-content
visibility: hiddeninvisible
opacity: 0opacity-0

Border styles

border-style keywords
Keyword
solid
dashed
dotted
double
groove
ridge
inset
outset

content-box versus border-box in numbers

With content-box, total width equals width plus left and right padding plus left and right border. The margin then adds outside that. This was the original CSS behaviour, and it is still the browser default for most elements.

With border-box, the width you write is measured to the outer edge of the border. Padding and border eat into the content area instead of growing the box, so a two-column layout of 50% plus 50% stays on one line however much padding you add.

Borders beyond a plain line

The border shorthand takes a width, a style and a colour in any order. The styles are solid, dashed, dotted, double, groove, ridge, inset, outset, none and hidden. A border with style none has zero width whatever width you wrote, which surprises people who set only border-width.

border-radius rounds the corners of the border, background and outline in current browsers. One value rounds all four corners; a slash sets separate horizontal and vertical radii for elliptical corners, and 50% on a square turns it into a circle.

How display changes the box

block boxes start on a new line and stretch to fill their container. inline boxes flow inside a line of text and ignore width and height. inline-block flows like text but accepts sizes and vertical margins, which makes it handy for badges and buttons.

flex and grid make the element a block on the outside and a layout container on the inside. Their children stop behaving as block or inline and follow the flex or grid rules instead, with gap available for spacing. contents removes the box itself while keeping its children, but it has a history of accessibility bugs, so test it with a screen reader before relying on it.

How it works

  1. Set a width and height for the content area, then add padding, border and margin with the sliders.
  2. Switch box-sizing between content-box and border-box and note how the rendered width changes.
  3. Read the total width and height the element really occupies, margins included.
  4. Copy the generated CSS, then scroll down for the margin collapse and display demos.

Tips

Frequently asked questions

What is the difference between margin and padding?

Padding sits inside the border, so it is filled by the element's background and is part of its clickable area. Margin sits outside the border, is always transparent and only separates the element from others. Vertical margins between blocks can also collapse together, while padding never collapses.

Why is my element wider than the width I set?

Under the default box-sizing: content-box, width applies to the content only, and padding plus border are added on top. A 300px box with 20px padding and a 2px border renders 344px wide. Switch to box-sizing: border-box and it stays 300px, with the content shrinking to fit.

When do margins collapse?

Top and bottom margins of block boxes in normal flow merge when they touch: between siblings, and between a parent and its first or last child when no border, padding or inline content separates them. The larger margin wins. Margins never collapse inside flex or grid containers, or horizontally.

What is the difference between display: none and visibility: hidden?

display: none removes the element from layout entirely, so the space closes up and screen readers skip it. visibility: hidden keeps the space reserved but paints nothing, and the content is also hidden from assistive technology. opacity: 0 keeps both the space and the ability to be clicked or focused.

Can I set width on an inline element?

No. Width, height and vertical margins are ignored on a plain inline box such as a span. Vertical padding is painted but does not push lines apart. Change it to inline-block, or make the parent a flex container, and those sizes start to apply.

Related: Flexbox and grid cheat sheet, CSS calc, min, max and clamp, How to centre a div, CSS position, CSS shadow generator.

Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.

More in Guides

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap