Skip to content

CSS Units — px, em, rem, %, vw, and vh

Unit choice is the foundation of responsive CSS. A stylesheet built entirely on px values fights the browser at every breakpoint. A stylesheet built on rem, %, and vw/vh flexes naturally. You have already used several of these units — this lesson completes the picture and gives you clear rules for when to reach for each one.

px is an absolute unit. One CSS pixel corresponds to a physical display pixel (adjusted for device pixel ratio, but the key point is that it does not scale with font size or container size).

.tour-card {
border: 1px solid #e0ddd8; /* border thickness — px is correct here */
border-radius: 8px; /* corner radius */
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); /* shadow offset */
}

Use px for: borders, box-shadows, outlines, and other decorative details where a sub-pixel size would look wrong or where the value should not scale with text size.

Avoid px for: font sizes, padding, margin, and container widths — these should scale with either the root font size or the container.

em is relative to the font-size of the current element’s parent. If the parent has font-size: 20px, then 1em = 20px, 1.5em = 30px.

.tour-card-body {
padding: 1.5em; /* 1.5× the card's own font-size */
}

The compounding problem: if you nest elements with em font sizes, each level multiplies. A child at 1.5em inside a parent at 1.5em gives you 1.5 × 1.5 = 2.25 times the root size — often unintended.

Use em for: padding and margin on components where the spacing should scale proportionally with that component’s text size. Good for buttons and badges. Avoid it for font sizes on body text and headings.

rem (root em) is relative to the font-size of the <html> element. The browser default is 16px, so 1rem = 16px by default — but it respects any user override.

h1 { font-size: 2.5rem; } /* 40px at default root */
h2 { font-size: 1.875rem; } /* 30px */
h3 { font-size: 1.25rem; } /* 20px */
p { font-size: 1rem; } /* 16px — the base */
.section-padding {
padding: 4rem 2rem; /* scales with root font size */
}

rem does not compound — it always refers to the root. This makes it the most predictable unit for typography and spacing.

Why rem for accessibility: users who need larger text can increase their browser’s base font size (e.g., to 20px). Elements sized in rem scale automatically. Elements sized in px do not — they remain fixed even when the user has explicitly requested larger text.

Use rem for: font sizes, padding, margin, and gap values throughout the stylesheet.

% is relative to the parent element’s corresponding dimension. For width: 50%, the reference is the parent’s width. For height: 50%, it is the parent’s height (which only works if the parent has a defined height).

.content-wrapper {
width: 90%; /* 90% of the viewport or containing block */
max-width: 1200px; /* never wider than 1200px */
margin: 0 auto; /* centered */
}
.tour-card img {
width: 100%; /* fills the card regardless of card width */
height: auto;
}

The width: 90%; max-width: 1200px pattern is the standard approach for page-width containers: fluid on small screens, capped on large ones.

Use % for: container widths, image widths, and any value that should be proportional to its parent’s size.

1vw equals 1% of the browser viewport width. 100vw is the full viewport width.

.hero-title {
font-size: clamp(2rem, 5vw, 4rem); /* scales with viewport, clamped between 2rem and 4rem */
}

vw is useful for fluid type scaling with clamp() — font sizes that grow gradually as the viewport widens, without needing explicit breakpoints. clamp(min, preferred, max) sets a minimum, a preferred (fluid) value, and a maximum.

Use vw for: fluid typography with clamp(), full-bleed sections where you need to break out of a constrained container.

1vh equals 1% of the browser viewport height. 100vh is the full viewport height.

.hero {
min-height: 100vh; /* at least the full screen height */
}
.full-screen-section {
min-height: 100vh;
display: flex;
align-items: center;
}

Use vh for: hero sections that should fill the screen, full-screen landing sections.

Note: On mobile, 100vh can include the browser’s address bar height, which causes content to be hidden behind it. The newer svh (small viewport height) unit accounts for this, but min-height: 100vh is still a reasonable and widely understood starting point.

UnitRelative toBest for
pxNothing (absolute)Borders, shadows, small decorative details
emParent element font-sizeComponent padding/margin (proportional to that component’s text)
remRoot (<html>) font-sizeFont sizes, page-level spacing, gap
%Parent element dimensionContainer widths, image widths
vwViewport widthFluid typography (clamp()), full-bleed widths
vhViewport heightHero heights, full-screen sections

The analogy: absolute units are like inches on a ruler — they are the same everywhere. Relative units are like proportions — “one-quarter of the available space” adapts to whatever container or screen you’re in.

Apply responsive units to the STO wrapper and hero:

  1. In style.css, add a content wrapper with fluid width and a max-width cap:
.content-wrapper {
width: 90%;
max-width: 1200px;
margin: 0 auto;
}
  1. Update the hero section height to use vh:
.hero {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
  1. In your HTML, wrap the tour card section in a .content-wrapper div if it isn’t already.

  2. Open the browser and resize the window. The content wrapper should stay centered and never exceed 1200px. The hero should always fill the viewport height.

  3. Try reducing width: 90% to width: 100% and notice that the content now touches the edges of the screen. The 90% value provides breathing room on small screens without needing padding on the body.

  • px is absolute — use it for borders and decorative details that should not scale.
  • em is relative to the parent’s font size — compounding makes it tricky for font sizes; better for component spacing.
  • rem is relative to the root font size — the preferred unit for font sizes and spacing throughout the stylesheet; respects user browser preferences.
  • % is relative to the parent’s dimension — the standard unit for container widths.
  • vw / vh are viewport-relative — useful for hero heights (100vh) and fluid typography (clamp()).

Lesson 03 covers the viewport meta tag — a short but critical HTML element without which none of your responsive CSS will work on mobile devices.