📏 CSS Units
Every size in CSS — font sizes, widths, margins, paddings — needs a unit. Choosing the right unit makes the difference between a layout that breaks on different screen sizes and one that adapts gracefully.
Absolute units — always the same physical size regardless of context (e.g. px).
Relative units — scale based on something else: a parent element, the root font size, or the viewport (e.g. rem, %, vw).
Absolute Units
Absolute units produce a fixed size. They are not affected by the user's browser font-size settings or screen size.
| Unit | Name | Equivalent | Use when |
|---|---|---|---|
px |
Pixel | 1/96 of 1 inch | Borders, shadows, precise UI details |
pt |
Point | 1/72 of 1 inch | Print stylesheets only |
cm |
Centimeter | 96/2.54 px | Print stylesheets only |
mm |
Millimeter | 1/10 of 1 cm | Print stylesheets only |
in |
Inch | 96 px | Print stylesheets only |
For screen design, px is the only absolute unit you will realistically use.
The others (pt, cm, mm, in) exist mainly for print CSS.
px — Pixels
The pixel is the most familiar CSS unit. On a standard screen, 1px equals
one device pixel. On high-DPI (retina) screens the browser scales automatically, so your
CSS pixels still look sharp.
/* ✅ Borders — thin, precise lines */
.card {
border: 1px solid #ddd;
border-radius: 8px;
}
/* ✅ Box shadows — precise offsets */
.card {
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
}
/* ✅ Fixed-size icons or images */
.icon {
width: 24px;
height: 24px;
}
/* ❌ Avoid px for font sizes — blocks user zoom preferences */
body {
font-size: 16px; /* works, but rem is better here */
}
Relative Units
Relative units are the foundation of responsive, accessible web design. Instead of being fixed, they scale based on another value.
% — Percentage
A percentage is relative to the parent element's corresponding property.
For width/height it's the parent's width/height; for font-size it's
the parent's font size.
.container {
width: 800px;
}
/* This child will always be exactly half the parent */
.half {
width: 50%; /* = 400px */
}
/* Common pattern: full-width sections */
.section {
width: 100%;
padding: 5%; /* padding also relative to parent WIDTH */
}
/* Two equal columns side by side */
.column {
width: 50%;
float: left;
}
height: 50% only works if the parent has a defined height.
If the parent's height is auto (default), the percentage is ignored.
/* ❌ Won't work — parent has no fixed height */
.parent { /* height: auto */ }
.child { height: 50%; } /* has no effect */
/* ✅ Works — parent height is defined */
.parent { height: 400px; }
.child { height: 50%; } /* = 200px */
em — Relative to the element's font size
1em equals the current element's font size.
If no font size is set on the element, it inherits from the parent.
This makes em great for component-level spacing that scales with text.
.button {
font-size: 16px;
/* em is relative to this element's font-size (16px) */
padding: 0.75em 1.5em; /* = 12px 24px */
border-radius: 0.25em; /* = 4px */
}
.button--large {
font-size: 20px;
/* Padding now scales automatically: 15px 30px */
}
em compounds when nested. If a parent is 1.2em
and a child is also 1.2em, the child ends up at 1.44em
(1.2 × 1.2) relative to the root. This can cause unexpected sizes in deep nesting.
body { font-size: 16px; }
.a { font-size: 1.2em; } /* 19.2px */
.a .b { font-size: 1.2em; } /* 23.04px — compounding! */
rem — Relative to the root font size
rem stands for root em. It is always relative to the
<html> element's font size — never the parent. This avoids the
compounding problem of em and is the recommended unit for font
sizes and spacing.
/* Root font size (browser default is 16px) */
html {
font-size: 16px; /* 1rem = 16px everywhere */
}
h1 { font-size: 2rem; } /* 32px */
h2 { font-size: 1.5rem; } /* 24px */
h3 { font-size: 1.25rem; } /* 20px */
p { font-size: 1rem; } /* 16px */
small { font-size: 0.875rem; } /* 14px */
/* Spacing scale using rem */
.section {
padding: 2rem; /* 32px */
margin-bottom: 1.5rem; /* 24px */
}
When a user increases their browser's default font size (e.g., from 16px to 20px),
rem values scale with it — so your entire layout grows proportionally.
px values stay fixed and ignore the user's preference.
This is why rem is preferred for font sizes and layout spacing.
html { font-size: 16px; }
.parent {
font-size: 20px;
}
.child {
font-size: 1.5em; /* 30px — relative to parent (20px) */
margin: 1.5rem; /* 24px — always relative to html (16px) */
}
vw / vh — Viewport Width and Height
1vw = 1% of the viewport width.
1vh = 1% of the viewport height.
100vw = full width of the browser window.
/* Full-screen hero section */
.hero {
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
/* Responsive heading that scales with viewport */
h1 {
font-size: 5vw; /* on a 1200px screen = 60px */
}
/* Sticky sidebar with full viewport height */
.sidebar {
height: 100vh;
position: sticky;
top: 0;
overflow-y: auto;
}
On mobile browsers, 100vh includes the browser's address bar,
which can cause content to be hidden behind it. Modern browsers added
svh (small viewport height) and dvh (dynamic viewport height)
to solve this:
.hero {
height: 100vh; /* classic — may overlap address bar */
height: 100svh; /* small viewport — excludes browser chrome */
height: 100dvh; /* dynamic — updates when address bar hides */
}
vmin / vmax
vmin is 1% of the smaller dimension (width or height).
vmax is 1% of the larger dimension.
/* A square that fits inside any screen orientation */
.square {
width: 80vmin;
height: 80vmin;
/* Portrait 390×844: 80 × 3.9px = 312px */
/* Landscape 844×390: 80 × 3.9px = 312px — same! */
}
/* Responsive font that avoids getting too big on wide screens */
h1 {
font-size: 8vmin;
}
ch — Character width
1ch equals the width of the "0" (zero) character
in the current font. It's ideal for sizing text inputs and readable line lengths.
/* Readable text width — 45–75 characters per line */
article {
max-width: 65ch;
}
/* Form input sized to fit exactly a phone number */
input[type="tel"] {
width: 12ch;
}
/* ZIP code field */
input[name="zip"] {
width: 5ch;
}
ex — x-height
1ex equals the height of the lowercase letter "x" in the current font.
Rarely used in practice, but useful for fine-tuning icon alignment with text.
/* Vertically center a small inline icon with text */
.icon {
vertical-align: -0.15ex;
}
Quick Reference: Which Unit to Use?
| Property | Recommended unit | Why |
|---|---|---|
| Font size (body) | rem |
Respects user preferences, no compounding |
| Font size (component) | rem or em |
em if you want it to scale with parent text |
| Padding / margin | rem |
Consistent spacing scale across the site |
| Component spacing | em |
Scales with the component's own font size |
| Layout widths | % or rem |
% for fluid, rem for max-width |
| Full-screen sections | vw / dvh |
Fills the viewport regardless of content |
| Borders, shadows | px |
Should stay sharp and thin at all sizes |
| Border radius | px or rem |
px for fixed roundness, rem to scale |
| Text input widths | ch |
Directly matches the expected character count |
| Readable text column | ch or rem |
max-width: 65ch is a proven reading width |
| Square that fits screen | vmin |
Works in both portrait and landscape |
Practical Patterns
Responsive Typography Scale
/* Set the base size once on html */
html {
font-size: 16px; /* 1rem = 16px */
}
/* Scale up for large screens */
@media (min-width: 1200px) {
html { font-size: 18px; } /* All rem values grow automatically */
}
h1 { font-size: 2.5rem; }
h2 { font-size: 2rem; }
h3 { font-size: 1.5rem; }
p { font-size: 1rem; }
Fluid Viewport Font Size with clamp()
The clamp(min, preferred, max) function lets a value grow with
the viewport but stay within limits.
/* Font grows from 1rem (mobile) to 1.5rem (desktop),
scaling smoothly based on viewport width */
h1 {
font-size: clamp(1.5rem, 4vw, 3rem);
/* min preferred max */
}
p {
font-size: clamp(1rem, 1.5vw, 1.25rem);
}
Full-Height Hero Section
.hero {
/* Fallback for older browsers */
height: 100vh;
/* Modern: avoids the mobile address-bar overlap */
height: 100dvh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 2rem;
}
Self-Contained Button Component
/* Using em for padding — scales with the button's own font-size */
.btn {
font-size: 1rem;
padding: 0.6em 1.4em; /* 9.6px 22.4px */
border: 2px solid currentColor;
border-radius: 0.3em;
}
.btn--small {
font-size: 0.875rem;
/* padding/radius scale down automatically — no extra rules needed */
}
.btn--large {
font-size: 1.25rem;
/* padding/radius scale up automatically */
}
Readable Article Layout
article {
/* ~65 characters wide — proven comfortable reading line length */
max-width: 65ch;
/* Centered with breathing room */
margin: 0 auto;
padding: 2rem 1rem;
/* Comfortable line height */
line-height: 1.6;
font-size: 1.125rem;
}
Summary
- px — fixed pixel; use for borders, shadows, icons
- % — relative to parent; use for fluid layout widths
- em — relative to element's font size; use for component-level spacing
- rem — relative to root font size; use for font sizes and global spacing
- vw / vh — relative to viewport; use for full-screen sections
- dvh / svh — viewport height that handles mobile browser bars
- vmin / vmax — relative to the smaller/larger viewport dimension
- ch — width of "0"; use for input widths and readable text columns
clamp(min, fluid, max)combines units for smooth responsive scaling- Default to rem for fonts and px for thin decorative lines