CSSBeginner

CSS Units: px, rem, em, % and Viewport Units

Understand absolute and relative CSS units, learn when to use px, rem, em, percentages, vw and vh, and avoid the classic em-compounding trap.

All CSS lessons

What you will learn

Nearly every size in CSS needs a unit: the px in font-size: 20px. There are many units, and choosing the right one decides whether your page adapts nicely to phones, big screens and visitors who change their font size. In this lesson you will learn what each common unit means (px, %, em, rem, vw, vh), see them side by side on one page, and get simple rules for picking one.

The HTML we will style

All the examples use this one test page. Notice the classes: each one is a “handle” that the CSS grabs.

<h1 class="page-title">Units Lab</h1>

<!-- 1. A fixed size in pixels -->
<div class="box box-px">width: 200px</div>

<!-- 2. A percentage of the parent's width -->
<div class="wrapper">
  <div class="box box-percent">width: 50% of the wrapper</div>
</div>

<!-- 3. em: sizes stack up when elements are nested -->
<p class="em-1">
  em level 1
  <span class="em-2">em level 2
    <span class="em-3">em level 3</span>
  </span>
</p>

<!-- 4. rem: every level is based on the root, so no stacking -->
<p class="rem-1">
  rem level 1
  <span class="rem-2">rem level 2
    <span class="rem-3">rem level 3</span>
  </span>
</p>

<!-- 5. Viewport units -->
<div class="hero">
  <h2 class="hero-title">This hero is 40vh tall</h2>
</div>
Selector Matches this element Used to demonstrate
.box every <div> that has the class box shared look (background, padding)
.box-px the first .box a size in px
.wrapper the <div> around the second box the parent for %
.box-percent the box inside .wrapper a size in %
.em-1, .em-2, .em-3 the paragraph and its two nested <span> elements em stacking up
.rem-1, .rem-2, .rem-3 the second paragraph and its nested spans rem staying steady
.hero the big <div> at the bottom vh and vw

Notice that some elements have two classes, like class="box box-px". The first class gives the shared look and the second gives the specific size.

Absolute vs relative units

CSS units come in two families:

  • Absolute units always mean the same size. px is the only one you need.
  • Relative units are calculated from something else: a parent, the root, the font size or the screen. %, em, rem, vw and vh are relative.

Relative units are what make a design flexible, so you will use them a lot.

px: pixels

A pixel is one dot on a screen. It is the most predictable unit: 200px is always 200 pixels wide (CSS pixels, which the browser scales on high-density screens so they stay about the same physical size).

/* the first .box */
.box-px {
  width: 200px;
}

Use px for things that should not scale, such as thin borders (1px), small shadows and fine details.

Other absolute units exist (cm, mm, in, pt), mostly designed for print. You almost never need them on the web.

%: a percentage of the parent

A percentage is calculated from the parent element.

/* the parent: exactly 400px wide */
.wrapper {
  width: 400px;
  background-color: #eee;
}

/* the child inside .wrapper: 50% of 400px = 200px */
.box-percent {
  width: 50%;
}

If you later change the wrapper to 600px, the child follows automatically and becomes 300px. Notes:

  • A percentage width is based on the parent’s width.
  • A percentage height only works if the parent has an explicit height. If it does not, the percentage is ignored.
  • For font-size, 150% means 1.5 times the parent’s font size.

em: relative to the font size

1em equals the current font size. It is convenient, but it has a well-known trap.

For the font-size property, em refers to the parent’s font size. Each nested level multiplies again:

/* <p class="em-1"> */
.em-1 {
  font-size: 1.5em;
}

/* <span class="em-2"> inside .em-1 */
.em-2 {
  font-size: 1.5em;
}

/* <span class="em-3"> inside .em-2 */
.em-3 {
  font-size: 1.5em;
}

Start from the default 16px:

  • .em-1 = 1.5 × 16 = 24px
  • .em-2 = 1.5 × 24 = 36px
  • .em-3 = 1.5 × 36 = 54px

Every level got 1.5em, yet the text grows bigger and bigger. This is called compounding, and it causes many “why is my text huge?” bugs.

For other properties such as padding, margin or width, em refers to the element’s own font size. That is useful for things that should scale with their text:

.box {
  font-size: 18px;
  padding: 0.5em 1em;   /* 9px top and bottom, 18px left and right */
}

If you change the box’s font size, its padding scales with it. (Buttons and cards are the most common places to use this.)

rem: relative to the root

rem means “root em”: it always refers to the font size of the root element (<html>), no matter how deeply an element is nested. The default is 16px, so:

Value Pixels (default)
1rem 16px
1.5rem 24px
2rem 32px
0.875rem 14px
0.5rem 8px

Now the same nested example with rem gives steady results:

/* <p class="rem-1"> */
.rem-1 {
  font-size: 1.5rem;
}

/* <span class="rem-2"> inside it */
.rem-2 {
  font-size: 1.5rem;
}

/* <span class="rem-3"> inside that */
.rem-3 {
  font-size: 1.5rem;
}

All three levels are 24px, because each one is calculated from the root, not from its parent. Compare this with the em result above to feel the difference (use Try it on both).

Why rem is good for accessibility

Many visitors raise their browser’s default font size because it is easier on their eyes. Sizes written in rem grow with that setting. Sizes written in px stay fixed and ignore what the visitor asked for. This is the main reason professional stylesheets use rem for text and spacing.

vw and vh: the viewport

The viewport is the visible area of the page in the browser window.

  • 1vw = 1% of the viewport width.
  • 1vh = 1% of the viewport height.

So 100vw is the full width of the window and 50vh is half its height.

/* the <div class="hero"> */
.hero {
  height: 40vh;
  background-color: steelblue;
  color: white;
}

The hero always fills 40% of the window height, whatever the device. Some extras:

  • vmin and vmax are 1% of the smaller or larger viewport side.
  • min-height: 100vh is the classic way to make a section at least as tall as the screen.
  • On phones, 100vh can be taller than the visible area because of the browser’s address bar. The newer 100dvh (“dynamic viewport height”) solves this.
  • 100vw includes the scrollbar, so a 100vw element can cause a small sideways scroll. width: 100% is usually safer for full-width blocks.

In the editor: the preview sits inside a frame, so vh and vw are measured against the preview area, not your whole screen.

Unitless values

Some properties take plain numbers, or 0, with no unit:

  • line-height: 1.6
  • opacity: 0.5
  • font-weight: 700
  • margin: 0 (zero never needs a unit, 0px is the same)

ch: a unit for reading width

One more unit worth knowing is ch, which is roughly the width of the digit “0” in the current font. It is perfect for limiting the width of text:

.wrapper {
  max-width: 65ch;
}

Lines of about 60 to 75 characters are the easiest to read.

Which unit should I use?

What you are sizing Good choice
Font sizes rem
Spacing (padding, margin, gaps) rem (or em inside a component)
Thin borders, shadows, tiny details px
Widths inside a parent %, or max-width
Full-screen sections vh / dvh
Readable text width ch
Line height a unitless number

If you are unsure, use rem for text and spacing, % for widths, and px for borders.

Putting it together

.page-title {
  font-size: 2.5rem;
  margin-bottom: 1.5rem;
}

.box {
  background-color: lightblue;
  padding: 0.75rem;
  margin-bottom: 0.75rem;
}

.wrapper {
  width: 100%;
  max-width: 600px;
}

.box-percent {
  width: 50%;
}

.hero {
  min-height: 40vh;
  background-color: steelblue;
  color: white;
}

Common mistakes

  • Missing units: width: 200 or font-size: 20 is invalid. Only 0 may skip the unit.
  • A space between the number and the unit: 20 px is invalid. Write 20px.
  • Compounding em sizes on nested elements. Use rem for font sizes to avoid it.
  • A percentage height with no parent height. It quietly does nothing.
  • Using px for all text sizes, which ignores the visitor’s font-size preference.
  • width: 100vw causing horizontal scroll, because it includes the scrollbar.
  • Using vh for text size, which makes text tiny on short windows and huge on tall ones.
  • Mixing many units randomly. Choose a small set and use it consistently.

Practice

  1. Click Practice in Editor. Change .wrapper to width: 600px and watch .box-percent change without editing it.
  2. Add the em and rem rules for .em-1 to .rem-3. Measure the three levels with DevTools (Computed tab) and confirm 24px, 36px, 54px, and then 24px three times.
  3. Change the .rem-1 font size to 2rem. Then change the browser’s default font size in its settings and watch the rem text grow but not the px text.
  4. Give .hero a height of 40vh, then 80vh, and resize the preview to see it react.
  5. Convert these px values to rem (assume 16px): 24px, 12px, 40px, 10px.
  6. Fix the errors: width: 300;, font-size: 1.5 rem;, padding: 10 px;.

Recap

  • CSS sizes need a unit, except for 0 and unitless properties like line-height and opacity.
  • px is fixed. Use it for borders, shadows and tiny details.
  • % is relative to the parent. em is relative to the font size and compounds when nested. rem is relative to the root and stays predictable.
  • vw and vh are percentages of the viewport width and height. Great for full-screen sections.
  • rem respects the visitor’s font settings, so it is the best choice for text and spacing.
  • Next you will learn the box model, which decides how big every element really is.