%

A share of some other value. Which value depends on the property.

Safe to useBaseline: widely available

First version with support, from MDN browser data
BrowserSince
Chrome1+
Chrome Android18+
Edge12+
Firefox1+
Firefox Android4+
Safari1+
Safari iOS1+

Formula N% = N/100 × the reference value of the property

How it works

Put 10% on a child inside a box 400px wide and 300px tall and the answer depends on the property: width gives 40px, height gives 30px, margin-block-start gives 40px, and font-size gives a tenth of the parent’s text size. A percentage means nothing until you know which property it sits on, and every surprise in this unit comes from that.

The surprising ones first. padding and margin on all four sides are measured against the width of the box that contains them (its height in vertical text), so in that box margin-block-start: 10% is 40px and not 30px. line-height takes the font size of the element it sits on, and the result is turned into a length before it is inherited, so a child with larger text keeps the parent’s number, unlike a unitless line height, which is inherited as a ratio. translate uses the element’s own box, so translate: 50% on a 100px-wide element moves it 50px. The plainer ones: font-size uses the parent’s font size, so 120% is 1.2em; width and the horizontal offsets use the containing block’s width; height and the vertical offsets use its height, but only when that height is definite, and if the parent is as tall as its content, height: 50% has nothing to be half of and behaves as auto.

When a percentage misbehaves, find which of these it belongs to before changing the value.

Try it

One percentage, seven references

Change the size of the box. Each row is a different property, and each takes its percentage of a different thing.

400
300
DeclarationResolved toMeasured against
width: 50%The width of the containing block
height: 50%The height of the containing block, which has to be set
padding-block-start: 10%The width of the containing block
margin-block-start: 10%The width of the containing block
translate: 50%The width of the element itself (100px here)
font-size: 120%The font size of the parent (16px here)
line-height: 150%The text size set on the element, 20px here
The same as a table
Percentages in a box 400px wide and 300px tall
DeclarationResolved toMeasured against
width: 50%200pxThe width of the containing block
height: 50%150pxThe height of the containing block, which has to be set
padding-block-start: 10%40pxThe width of the containing block
margin-block-start: 10%40pxThe width of the containing block
translate: 50%50pxThe width of the element itself (100px here)
font-size: 120%19.2pxThe font size of the parent (16px here)
line-height: 150%30pxThe text size set on the element, 20px here

What changes it

Moves with
  • page zoom
Stays put under
  • the reader's text size
  • the window size
  • the font in use
  • the query container
  • phone toolbars
  • the writing mode

And whatever moves the property's own reference: the parent's width, the element's box, the inherited font size.

Reach for it when

Widths that share a parent, and translate() or border-radius, which take their percentage of the element's own box.

Watch out

In a box 400px wide, padding-block: 10% is 40px whatever the height of the box. In horizontal text, padding and margin take their percentage from the width on all four sides.

Example 5% of the container's width, not of its height.
.story-head {
  padding-block: 5%;
}

MDN (opens in a new tab)Specification (opens in a new tab)