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 — absolute pixels
Section titled “px — absolute pixels”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 — relative to parent font size
Section titled “em — relative to parent font size”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 — relative to root font size
Section titled “rem — relative to root font size”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.
% — relative to parent dimension
Section titled “% — relative to parent dimension”% 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.
vw — viewport width
Section titled “vw — viewport width”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.
vh — viewport height
Section titled “vh — viewport height”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.
When to use each unit — quick reference
Section titled “When to use each unit — quick reference”| Unit | Relative to | Best for |
|---|---|---|
px | Nothing (absolute) | Borders, shadows, small decorative details |
em | Parent element font-size | Component padding/margin (proportional to that component’s text) |
rem | Root (<html>) font-size | Font sizes, page-level spacing, gap |
% | Parent element dimension | Container widths, image widths |
vw | Viewport width | Fluid typography (clamp()), full-bleed widths |
vh | Viewport height | Hero 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.
Exercise
Section titled “Exercise”Apply responsive units to the STO wrapper and hero:
- 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;}- Update the hero section height to use
vh:
.hero { min-height: 100vh; display: flex; align-items: center; justify-content: center;}-
In your HTML, wrap the tour card section in a
.content-wrapperdiv if it isn’t already. -
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.
-
Try reducing
width: 90%towidth: 100%and notice that the content now touches the edges of the screen. The90%value provides breathing room on small screens without needing padding on the body.
pxis absolute — use it for borders and decorative details that should not scale.emis relative to the parent’s font size — compounding makes it tricky for font sizes; better for component spacing.remis 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/vhare 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.