Front-End · 7 min read · Updated

CSS Units Explained: px vs rem vs em vs vw (and When to Use Each)

px, rem, em, %, vw, ch – which CSS unit should you use? A clear guide with a live demo, a cheat-sheet table and accessibility advice.

Px vs rem: ruler Measurement
Photo: Dawid%20Ma%u0142ecki via Stocksnap (CC0)

CSS has more than a dozen length units, and the choice between them affects accessibility, responsiveness and how easy your code is to maintain. Luckily, you only need a handful in daily work, and the big everyday decision is usually px vs rem. This guide explains the important ones, shows them side by side and ends with simple rules you can follow on every project.

For a shorter introduction, see the CSS Units lesson.

Absolute vs relative units

Absolute units have a fixed size. On screens, the only one you will use is px. Units like cm, mm and pt exist mainly for print stylesheets.

Relative units are calculated from something else: the font size of the root element, the parent element, the viewport, or the container. Relative units are what make layouts flexible.

px – the CSS pixel

A CSS pixel is not one physical dot on the screen. On a high-density phone display, one CSS pixel may be drawn with two or three device pixels. That is why a 16px font looks a similar size on a cheap laptop and an expensive phone.

Pixels are predictable, which makes them good for things that should not scale with text: borders, box shadows, small icon sizes and hairline dividers.

Watch out: Setting all font sizes in px can stop text from following the user’s browser font-size preference. Some people set a larger default text size because of low vision. Browser zoom still works with px, but the default font-size setting is not respected the same way. Use rem for font sizes.

rem – relative to the root font size

1rem equals the font size of the <html> element. In most browsers that is 16px by default, so 1.5rem is 24px. If a user sets their default to 20px, 1.5rem becomes 30px – your whole design scales with their choice.

Because rem always refers to the same root value, it does not compound. A 1.2rem heading inside a 0.9rem card is still 1.2rem. That predictability is why rem is the default choice for font sizes and most spacing.

Tip: Avoid the old trick of setting html { font-size: 62.5%; } to make 1rem equal 10px. It works, but it forces you to reset body text everywhere and can confuse third-party components. Thinking in sixteenths is easier than it sounds: 0.75rem = 12px, 0.875rem = 14px, 1.25rem = 20px.

em – relative to the current font size

For most properties, 1em equals the element’s own computed font size. (For the font-size property itself, it refers to the parent’s font size.) This is useful when something should scale with its own text.

The classic example is a button. If padding is in em, a small button and a large button keep the same proportions automatically:

.btn       { font-size: 1rem;    padding: 0.5em 1em; }
.btn-small { font-size: 0.875rem; }
.btn-large { font-size: 1.25rem; }
/* each size gets proportional padding without extra rules */

The downside of em is compounding. If a list sets font-size: 1.2em and you nest a list inside it, the inner list is 1.2 × 1.2 = 1.44 times the base size. Use em on purpose, for local scaling, not as a general replacement for rem.

% – relative to the parent

Percentages depend on the property. For width, it is the parent’s width. For font-size, it is the parent’s font size. For padding and margin – even vertical ones – it is the parent’s width, which surprises many people. Use % mainly for widths, such as width: 100% or max-width: 100% on images.

vw, vh and the newer viewport units

1vw is 1% of the viewport width and 1vh is 1% of the viewport height. They are handy for full-screen sections and fluid sizing.

On mobile, 100vh has a known problem: the browser address bar appears and disappears, so the visible height changes. Newer units solve this and are supported in current major browsers:

UnitMeaningGood for
svhSmall viewport height – browser UI fully shownHero sections that must never be cut off
lvhLarge viewport height – browser UI hiddenBackgrounds that can extend under the bar
dvhDynamic – updates as browser UI shows or hidesFull-height app layouts (can cause small jumps)
vmin / vmaxThe smaller / larger of vw and vhSquare elements that fit any orientation

Watch out: Never set font size in vw alone, such as font-size: 4vw. On a phone it becomes tiny, on a big monitor huge, and zooming has little effect. Combine it with rem inside clamp() instead (see below).

ch – the width of a character

1ch is the width of the “0” character in the current font. It is ideal for limiting line length: max-width: 65ch keeps paragraphs at a comfortable reading width whatever the font size. This simple rule improves readability more than most people expect – see Typography Rules for UI.

px vs rem vs em vs vw side by side

This demo shows boxes sized in different units. Change the root font size with the buttons and watch which boxes respond. Then resize the preview to see the vw box change.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CSS units demo</title>
<style>
  body { font-family: system-ui, sans-serif; margin: 16px; }
  .row { display: flex; align-items: center; gap: 12px; margin: 8px 0; }
  .bar { height: 24px; background: #3b6fd8; border-radius: 4px; }
  .label { width: 90px; font-size: 14px; }
  .px  { width: 160px; }
  .rem { width: 10rem; }
  .em-parent { font-size: 1.5rem; }
  .em  { width: 10em; }
  .vw  { width: 30vw; }
  button { font: inherit; padding: 0.4em 0.8em; margin-right: 6px; }
</style>
</head>
<body>
  <p>Root font size: <strong id="size">16px</strong></p>
  <button data-size="12">12px</button>
  <button data-size="16">16px</button>
  <button data-size="22">22px</button>
  <div class="row"><span class="label">160px</span><div class="bar px"></div></div>
  <div class="row"><span class="label">10rem</span><div class="bar rem"></div></div>
  <div class="row em-parent"><span class="label">10em*</span><div class="bar em"></div></div>
  <div class="row"><span class="label">30vw</span><div class="bar vw"></div></div>
  <p style="font-size:14px">* the em bar sits inside a parent with font-size 1.5rem</p>
  <script>
    document.querySelectorAll('button').forEach(function (btn) {
      btn.addEventListener('click', function () {
        var s = btn.dataset.size + 'px';
        document.documentElement.style.fontSize = s;
        document.getElementById('size').textContent = s;
      });
    });
  </script>
</body>
</html>

Fluid sizes with clamp()

clamp(min, preferred, max) lets a value grow with the viewport but never go below a minimum or above a maximum. Mixing rem and vw in the middle value keeps it responsive and zoom-friendly.

h1 {
  font-size: clamp(1.75rem, 1.2rem + 2.5vw, 3rem);
}
.section {
  padding-block: clamp(2rem, 5vw, 5rem);
}

A cheat sheet you can follow

What you are sizingRecommended unit
Body and heading font sizesrem (or clamp() with rem + vw)
Spacing (margin, padding, gap)rem; em inside components that should scale with their text
Borders, outlines, shadowspx
Line heightUnitless number, e.g. 1.5
Widths of layout columns%, fr (in Grid) or rem max-widths
Readable text widthch, e.g. max-width: 65ch
Full-screen sectionssvh / dvh with a min-height
Media query breakpointspx or em, used consistently

Why unitless line height? If you write line-height: 1.5, each child calculates its own line height from its own font size. With line-height: 24px, a larger heading inside would inherit 24px and its lines would overlap.

Units in design tools

Figma works in pixels. That is fine – designers can keep using a 4px or 8px spacing scale, and developers convert: 8px = 0.5rem, 16px = 1rem, 24px = 1.5rem, 32px = 2rem. Agreeing on this scale in a design system makes handoff much smoother. Store the values as Figma variables and as CSS custom properties with the same names. See Design Systems for Beginners.

Once you have settled px vs rem for each job, apply them in layouts with Responsive Design Breakpoints and Flexbox vs Grid.

Frequently asked questions

Is rem better than px?

For font sizes and most spacing, yes, because rem respects the user’s default font-size setting. Px is still the right choice for borders, shadows and other fine details.

What is the difference between em and rem?

Rem is always relative to the root html element’s font size. Em is relative to the current element’s font size (or the parent’s, when used for font-size), so it can compound when elements are nested.

How many pixels is 1rem?

By default 16px in most browsers, but it changes if the user or your CSS changes the root font size. That flexibility is the reason to use it.

Why does 100vh cause problems on phones?

Mobile browser toolbars change the visible height while scrolling. Use svh, lvh or dvh, which were designed for this, depending on whether you want the smallest, largest or live viewport height.

Should line-height have a unit?

Usually no. A unitless value such as 1.5 is multiplied by each element’s own font size, so nested text with different sizes stays readable.

Further reading

Keep reading

All articles