CSS units: px, em, rem, %, vw and vh

Absolute and relative units, what each one is relative to, and how to choose for type and spacing.

  • Beginner
  • 7 min read
  • Updated 17 Oct 2026

What you will learn

  • Distinguish absolute and relative units
  • Choose units for type and spacing
  • Explain em versus rem
  • Use percentages and viewport units appropriately

Almost every size in CSS needs a unit: font sizes, padding, widths, gaps. The unit decides what the number is measured against. Good unit choices make a design respect user settings and adapt to different screens with less code.

Absolute units: px

A CSS pixel, px, is a fixed unit. It is not tied to physical screen pixels; on a high-density phone screen, one CSS pixel may cover several device pixels. What matters is that 16px is always 16px, whatever the context.

CSS
.card {
    border: 1px solid #d9d9d9;
    border-radius: 8px;
}

Pixels are a good fit for small details that should not scale with text: hairline borders, small radii, shadow offsets.

CSS also defines physical units such as cm, mm, in and pt. They are only useful for print stylesheets. On screens, ignore them.

Relative units

Relative units are measured against something else: the font size, the parent's size, or the viewport. That is what makes them flexible.

rem: relative to the root font size

1rem equals the font size of the root <html> element. Browsers default that to 16px, but users can change it in their browser settings, for example to make all text larger.

CSS
h1 {
    font-size: 2.5rem;   /* 40px at the default, larger if the user asks */
}

p {
    font-size: 1rem;
    margin-bottom: 1.5rem;
}

Because every rem refers to the same root value, it is predictable anywhere in the page. And because it follows the user's preference, it is the respectful choice for text.

Do not set html { font-size: 10px; } or similar to make rem maths easier. A fixed pixel value on the root overrides the user's chosen default text size. If you want a different base, use a percentage such as html { font-size: 100%; }, which keeps the user's setting.

em: relative to the current font size

1em equals the font size of the element itself. When used for font-size, it is relative to the parent's font size.

CSS
.button {
    font-size: 1.125rem;
    padding: 0.5em 1em;   /* scales with this button's text */
}

.button-small {
    font-size: 0.875rem;  /* padding shrinks automatically */
}

That is the strength of em: spacing that tracks a component's own text size. A large button gets proportionally larger padding with no extra rules.

em compounds, rem does not

The trap with em for font sizes is that it multiplies through nesting:

HTML
<ul class="menu">
    <li>Products
        <ul class="menu">
            <li>Bread</li>
        </ul>
    </li>
</ul>
CSS
.menu {
    font-size: 0.8em;
}

The outer list is 0.8 times the body text. The inner list is 0.8 times that, so 0.64. Each level shrinks again. Using 0.8rem instead gives both lists the same size.

UnitRelative toCompounds when nested?Typical use
remRoot (html) font sizeNoFont sizes, most spacing
emElement's own font sizeYes, for font-sizePadding and gaps that scale with a component's text

Percentages

A percentage is relative to something in the parent, and what depends on the property:

CSS
.sidebar {
    width: 25%;        /* 25% of the containing block's width */
}

.lead {
    font-size: 125%;   /* 125% of the parent's font size */
}

A surprising one: vertical padding and margin percentages are calculated from the width of the containing block, not its height. And height: 50% only works if the parent has a defined height; otherwise it is usually ignored.

Viewport units: vw and vh

1vw is 1% of the viewport width; 1vh is 1% of the viewport height.

CSS
.hero {
    min-height: 60vh;
}

.full-bleed {
    width: 100vw;
}

Use them with care:

  • 100vw includes the width of a vertical scrollbar on desktop, so width: 100vw can cause a horizontal scrollbar. width: 100% is usually what you want.
  • On mobile, 100vh is measured with the browser's toolbars hidden, so content can be cut off when they are showing. Newer units such as dvh and svh solve this. They are covered in the Responsive Web Design course.

Never size text in vw alone, as in font-size: 4vw. It ignores the user's text size setting and does not grow when the user zooms, which is an accessibility failure. Fluid type combines rem and viewport units safely with clamp(), which the Responsive Web Design course teaches.

Unitless values

A few properties take plain numbers. The most important is line-height:

CSS
body {
    line-height: 1.5;  /* 1.5 times each element's own font size */
}

A unitless line height is recalculated for every element, so headings and small print each get proportional spacing. line-height: 24px would be fixed and look cramped on large headings. Zero lengths need no unit either: margin: 0.

Mixing units with calc()

calc() lets you combine units in one value:

CSS
.content {
    width: calc(100% - 2rem);
}

Leave spaces around + and - inside calc(); calc(100%-2rem) is invalid.

A practical default

CSS
html {
    font-size: 100%;           /* respect the user's setting */
}

body {
    font-size: 1rem;
    line-height: 1.5;
}

h1 { font-size: 2.25rem; }
h2 { font-size: 1.75rem; }

.card {
    padding: 1.5rem;
    border: 1px solid #d9d9d9;  /* px for hairlines */
    border-radius: 0.5rem;
}

.content {
    max-width: 65ch;           /* about 65 characters per line */
}

ch is the width of the "0" character in the current font. max-width: 65ch is a neat way to keep lines of text at a comfortable reading length.

Testing your units

  1. In your browser settings, change the default font size to "Very large" and reload. Text set in rem should grow; anything that stays tiny is fixed in px.
  2. Zoom to 200% with Ctrl and + (Cmd and + on macOS). The layout should reflow without overlapping or cutting off text.
  3. In DevTools, the Computed tab shows every length converted to pixels, which helps when tracing compounding em values.

Summary

  • px is fixed; use it for borders, small radii and shadow offsets.
  • rem follows the root font size and the user's preference; use it for type and most spacing.
  • em follows the element's own font size and compounds when nested.
  • Percentages depend on the property and the parent; vw and vh follow the viewport.
  • Use unitless line-height, never size text in vw alone, and test with a larger default font size.