ToolBox Hub

CSS Units Complete Guide - px, rem, em, vh, vw and More

CSS Units Complete Guide - px, rem, em, vh, vw and More

Master every CSS unit with this comprehensive guide. Learn when to use px, rem, em, vh, vw, ch, and other units for responsive, accessible web design. Includes practical examples and comparison tables.

March 2, 202618 min read

Introduction: Why CSS Units Matter

CSS units determine the size of every element on your web page -- from font sizes and spacing to layout dimensions and animations. Choosing the right unit for the right context is one of the most important decisions in responsive, accessible web design.

Using the wrong units leads to layouts that break on different screen sizes, text that is too small to read on mobile, and designs that do not respect user accessibility preferences. Using the right units creates flexible, responsive interfaces that adapt gracefully to any device and respect user settings.

This guide covers every CSS unit you need to know in 2026, with practical advice on when and how to use each one. If you need to convert between different measurement units, try our Unit Converter tool.

Absolute Units

Absolute units represent fixed measurements. They do not change based on the parent element, viewport, or user settings.

Pixels (px)

Pixels are the most commonly used absolute unit in web development. One CSS pixel corresponds to one device pixel on a standard-density display, but on high-DPI (retina) displays, one CSS pixel may map to multiple device pixels.

.box {
  width: 300px;
  height: 200px;
  border: 1px solid #333;
  padding: 16px;
}

When to use pixels:

  • Borders and outlines (border: 1px solid black)
  • Box shadows (box-shadow: 0 2px 4px rgba(0,0,0,0.1))
  • Fine visual details that should not scale
  • Media query breakpoints (@media (min-width: 768px))
  • Fixed-size elements like icons

When NOT to use pixels:

  • Font sizes (use rem instead)
  • Spacing and padding (use rem or em instead)
  • Layout widths (use percentages, fr, or viewport units)
  • Anything that should respond to user font size preferences

Other Absolute Units

UnitDescriptionEquivalentUse Case
pxPixels1pxScreen elements
cmCentimeters37.8pxPrint stylesheets
mmMillimeters3.78pxPrint stylesheets
inInches96pxPrint stylesheets
ptPoints1.33px (1/72 of an inch)Print stylesheets
pcPicas16px (1/6 of an inch)Print stylesheets

Note: Physical units (cm, mm, in, pt, pc) are only meaningful in print stylesheets. On screens, they are simply converted to pixels using the standard 96 DPI ratio.

/* Print stylesheet using physical units */
@media print {
  body {
    font-size: 12pt;
    margin: 1in;
  }

  h1 {
    font-size: 18pt;
    margin-bottom: 0.5cm;
  }
}

Relative Units: Font-Based

Relative units are calculated based on another value -- the parent element's font size, the root font size, or the viewport dimensions. They are essential for responsive design.

rem (Root em)

rem stands for "root em" and is relative to the root element's (<html>) font size. By default, browsers set the root font size to 16px, so 1rem = 16px.

html {
  font-size: 16px; /* This is the browser default */
}

h1 {
  font-size: 2rem;    /* 32px */
  margin-bottom: 1rem; /* 16px */
}

p {
  font-size: 1rem;     /* 16px */
  line-height: 1.5rem; /* 24px */
  margin-bottom: 1rem; /* 16px */
}

.card {
  padding: 1.5rem;     /* 24px */
  border-radius: 0.5rem; /* 8px */
}

Why rem is the best unit for most things:

  1. Respects user preferences: If a user sets their browser font size to 20px (for accessibility), all rem-based values scale proportionally
  2. Consistent: Unlike em, rem always references the root, so there is no compounding effect
  3. Predictable: Easy to calculate -- if root is 16px, 1.5rem is always 24px

The 62.5% trick (use with caution):

/* Makes rem calculations easier: 1rem = 10px */
html {
  font-size: 62.5%; /* 62.5% of 16px = 10px */
}

body {
  font-size: 1.6rem; /* Restore to 16px equivalent */
}

h1 {
  font-size: 3.2rem; /* 32px */
}

.spacing {
  padding: 2.4rem;   /* 24px */
}

This technique makes math easier but can cause issues with third-party components that assume the default root font size. Use it carefully.

em (Relative to Parent)

em is relative to the font size of the element itself (for font-related properties) or the parent element (for other properties). This makes it useful for component-level scaling but can be tricky due to compounding.

.parent {
  font-size: 18px;
}

.child {
  font-size: 1.2em;  /* 18px * 1.2 = 21.6px */
  padding: 1em;      /* 21.6px (relative to own font-size) */
}

.grandchild {
  font-size: 1.2em;  /* 21.6px * 1.2 = 25.92px -- compounding! */
}

The compounding problem:

/* Each nested level gets larger */
ul { font-size: 1.1em; }

/*
  Level 1: 16px * 1.1 = 17.6px
  Level 2: 17.6px * 1.1 = 19.36px
  Level 3: 19.36px * 1.1 = 21.3px
  Level 4: 21.3px * 1.1 = 23.4px
  -- Text keeps growing with nesting!
*/

When em is genuinely useful:

em shines when you want spacing to scale with the element's own font size. This is particularly useful for buttons and inline components:

/* Button that scales proportionally */
.button {
  font-size: 1rem;       /* Base size from root */
  padding: 0.5em 1em;    /* Scales with font-size */
  border-radius: 0.25em; /* Scales with font-size */
}

.button--large {
  font-size: 1.25rem;    /* Everything else scales automatically */
}

.button--small {
  font-size: 0.875rem;   /* Padding and radius scale down too */
}

Comparison: rem vs. em

Aspectremem
ReferenceRoot element font sizeParent/self font size
CompoundingNoYes
PredictabilityHighLower (depends on context)
Best forFont sizes, spacing, layoutComponent-level proportional scaling
AccessibilityRespects root font size settingsRespects parent font size

ch (Character Width)

ch is equal to the width of the "0" (zero) character in the current font. It is useful for constraining text width to a readable line length.

/* Optimal reading width */
.article-content {
  max-width: 65ch;  /* Approximately 65 characters per line */
  margin: 0 auto;
}

/* Input field sized for expected content */
.zip-code-input {
  width: 6ch;  /* Wide enough for 5 digits + some padding */
}

.phone-input {
  width: 15ch;
}

Why ch matters for readability: Research suggests that the optimal line length for reading is 45-75 characters. Using ch units makes it easy to enforce this regardless of font size.

ex (x-height)

ex is equal to the height of the lowercase "x" character in the current font. It is rarely used directly but can be useful for precise vertical alignment.

/* Vertically center an icon with text */
.icon-inline {
  height: 1ex;
  vertical-align: middle;
}

lh and rlh (Line Height Units)

lh is equal to the computed line-height of the element, while rlh is equal to the root element's line-height.

/* Space elements by line-height multiples */
.paragraph {
  margin-bottom: 1lh; /* One line of spacing */
}

.section {
  margin-bottom: 2rlh; /* Two root line-heights of spacing */
}

cap, ic, and Other Advanced Units

UnitDescriptionUse Case
capHeight of capital lettersAligning with uppercase text
icWidth of the CJK "water" ideographCJK typography
lhLine height of elementVertical rhythm
rlhRoot line heightConsistent vertical spacing

Viewport Units

Viewport units are relative to the browser viewport (the visible area of the web page).

vw and vh (Viewport Width and Height)

/* Full-screen hero section */
.hero {
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Responsive typography */
h1 {
  font-size: 5vw; /* Scales with viewport width */
}

Important: 100vh on mobile browsers does not account for the browser's address bar and navigation. This led to the creation of new viewport units.

The Mobile Viewport Problem

On mobile browsers, the viewport height changes as the address bar shows and hides during scrolling. The old vh unit is based on the largest possible viewport (address bar hidden), which causes content to be clipped when the address bar is visible.

dvh, svh, lvh (Dynamic, Small, and Large Viewport Height)

CSS now provides three variants to handle the mobile viewport:

/* svh: Small viewport height (address bar visible) */
.safe-full-height {
  height: 100svh; /* Never clips behind the address bar */
}

/* lvh: Large viewport height (address bar hidden) */
.max-full-height {
  height: 100lvh; /* Full height when address bar hides */
}

/* dvh: Dynamic viewport height (changes as address bar shows/hides) */
.dynamic-full-height {
  height: 100dvh; /* Adjusts in real-time */
}

Which to use:

  • svh: Safe default -- content is always fully visible
  • lvh: When you want the maximum possible height
  • dvh: When you want the height to animate with the address bar

The same applies to width units: svw, lvw, dvw.

vi and vb (Viewport Inline and Block)

These units are writing-mode aware:

  • vi = viewport size in the inline direction (width for horizontal text, height for vertical text)
  • vb = viewport size in the block direction (height for horizontal text, width for vertical text)
/* Writing-mode aware layout */
.container {
  max-inline-size: 90vi;   /* 90% of viewport in inline direction */
  margin-block: 5vb;        /* 5% of viewport in block direction */
}

vmin and vmax

  • vmin = the smaller of vw and vh
  • vmax = the larger of vw and vh
/* Square element that fits in any viewport */
.square {
  width: 50vmin;
  height: 50vmin;
}

/* Typography that scales well in both orientations */
h1 {
  font-size: 8vmin; /* Works in portrait and landscape */
}

Viewport Units Comparison

UnitDescriptionMobile Address Bar
vw1% of viewport widthNot affected
vh1% of viewport heightUses large viewport
svh1% of small viewport heightAlways safe
lvh1% of large viewport heightMaximum height
dvh1% of dynamic viewport heightAnimates with bar
vminSmaller of vw/vhInherits from vh
vmaxLarger of vw/vhInherits from vh

Percentage (%)

Percentages are relative to the parent element's corresponding property. The reference changes depending on which property you are setting.

.parent {
  width: 800px;
  font-size: 20px;
  line-height: 1.5;
}

.child {
  width: 50%;        /* 400px (50% of parent width) */
  margin-left: 10%;  /* 80px (10% of parent width) */
  font-size: 80%;    /* 16px (80% of parent font-size) */
  padding: 5%;       /* 40px (5% of parent WIDTH, not height!) */
}

Important gotcha: Vertical padding and margin percentages are calculated based on the parent's width, not its height. This is actually useful for creating aspect-ratio boxes (though the aspect-ratio property is now preferred).

/* Old aspect-ratio hack using percentage padding */
.video-container {
  position: relative;
  width: 100%;
  padding-bottom: 56.25%; /* 16:9 aspect ratio */
}

/* Modern approach */
.video-container {
  width: 100%;
  aspect-ratio: 16 / 9;
}

Container Query Units

Container query units are relative to the size of a query container, enabling truly component-based responsive design.

cqw, cqh, cqi, cqb, cqmin, cqmax

.card-container {
  container-type: inline-size;
  container-name: card;
}

.card-title {
  font-size: clamp(1rem, 4cqi, 2rem); /* Scales with container inline size */
}

.card-description {
  font-size: clamp(0.875rem, 3cqi, 1.125rem);
}
UnitDescription
cqw1% of container width
cqh1% of container height
cqi1% of container inline size
cqb1% of container block size
cqminSmaller of cqi and cqb
cqmaxLarger of cqi and cqb

The fr Unit (Fractional)

The fr unit is used exclusively in CSS Grid to distribute available space proportionally.

.grid {
  display: grid;

  /* Three columns: 1 part, 2 parts, 1 part */
  grid-template-columns: 1fr 2fr 1fr;
  /* With 1200px container: 300px, 600px, 300px */

  /* Mixed units: fixed sidebar, flexible content */
  grid-template-columns: 250px 1fr;

  /* Multiple rows */
  grid-template-rows: auto 1fr auto;
  /* Header, flexible content area, footer */

  gap: 1rem;
}
/* Responsive grid with fr units */
.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 1.5rem;
}

fr vs percentages in Grid:

/* These look similar but behave differently */
.grid-percent {
  grid-template-columns: 25% 50% 25%;
  gap: 1rem;
  /* Columns + gaps > 100%, causing overflow! */
}

.grid-fr {
  grid-template-columns: 1fr 2fr 1fr;
  gap: 1rem;
  /* fr units account for the gap automatically */
}

CSS Functions with Units

clamp() - Responsive Values with Constraints

clamp() is one of the most powerful CSS functions for responsive design. It takes three values: minimum, preferred, and maximum.

/* Responsive font size that never gets too small or too large */
h1 {
  font-size: clamp(1.5rem, 4vw, 3rem);
  /* Minimum: 1.5rem (24px)
     Preferred: 4vw (scales with viewport)
     Maximum: 3rem (48px) */
}

/* Responsive container width */
.container {
  width: clamp(320px, 90%, 1200px);
}

/* Responsive spacing */
section {
  padding: clamp(1rem, 5vw, 4rem);
}

min() and max()

/* Width is the smaller of 90% or 1200px */
.container {
  width: min(90%, 1200px);
}

/* At least 300px wide, but can grow */
.sidebar {
  width: max(300px, 25%);
}

/* Combine for complex responsive values */
.card {
  width: min(100% - 2rem, 600px);
  padding: max(1rem, 2vw);
}

calc() - Arithmetic with Units

calc() lets you mix different units in calculations:

.sidebar-layout {
  /* Full width minus sidebar */
  .main-content {
    width: calc(100% - 280px);
  }

  /* Centered with max-width and auto margins */
  .content {
    width: calc(100% - 2 * 1.5rem);
    max-width: 800px;
    margin: 0 auto;
  }
}

/* Fluid typography using calc */
h1 {
  /* Base size + scaling factor */
  font-size: calc(1.5rem + 1.5vw);
}

/* Viewport-based spacing with minimum */
.hero {
  padding-top: calc(2rem + 5vh);
  padding-bottom: calc(2rem + 5vh);
}

Practical Recommendations: Which Unit When?

Font Sizes

/* Root font size: use percentage or px */
html {
  font-size: 100%; /* Respects user browser settings */
}

/* All other font sizes: use rem */
body { font-size: 1rem; }       /* 16px */
h1 { font-size: 2.5rem; }      /* 40px */
h2 { font-size: 2rem; }        /* 32px */
h3 { font-size: 1.5rem; }      /* 24px */
small { font-size: 0.875rem; } /* 14px */

/* Responsive font sizes: use clamp with rem and vw */
h1 {
  font-size: clamp(2rem, 5vw, 3.5rem);
}

Spacing (Padding, Margin, Gap)

/* Use rem for consistent spacing */
.card {
  padding: 1.5rem;
  margin-bottom: 2rem;
}

.grid {
  gap: 1.5rem;
}

/* Use em for spacing that should scale with font size */
.button {
  padding: 0.5em 1em;
}

Layout Widths

/* Use percentage, fr, or viewport units */
.container {
  width: min(90%, 1200px);
  margin: 0 auto;
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}

/* Full-bleed sections */
.hero {
  width: 100vw;
  margin-left: calc(-50vw + 50%);
}

Borders and Shadows

/* Use px for fine visual details */
.card {
  border: 1px solid #e0e0e0;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  border-radius: 0.5rem; /* rem for border-radius is OK */
}

Media Queries

/* Use px or em for breakpoints */
@media (min-width: 768px) {
  /* Tablet and up */
}

@media (min-width: 1024px) {
  /* Desktop and up */
}

/* em-based breakpoints respect user zoom */
@media (min-width: 48em) {
  /* 48em = 768px at default font size */
}

Complete Recommendation Table

Use CaseRecommended UnitReasoning
Font sizesremRespects user preferences, no compounding
Responsive font sizesclamp(rem, vw, rem)Scales smoothly with constraints
Spacing (padding, margin)remConsistent, scales with root font
Button paddingemScales with button's own font size
Container widths%, min(), clamp()Flexible and responsive
Grid columnsfrDistributes space proportionally
Line lengthchOptimizes for readability
BorderspxFine detail, should not scale
Box shadowspxFine detail, consistent appearance
Full-screen sectionsdvhAccounts for mobile address bar
Media query breakpointspx or emConsistent trigger points
Border radiusrem or pxEither works; rem scales slightly

Accessibility and CSS Units

Choosing the right CSS units is directly related to accessibility:

Respect User Font Size Settings

Users may increase their browser's default font size for readability. Using rem for font sizes and spacing respects this preference:

/* Good: Scales with user font size preferences */
body { font-size: 1rem; }
h1 { font-size: 2.5rem; }
.container { padding: 1.5rem; }

/* Bad: Ignores user preferences */
body { font-size: 16px; }
h1 { font-size: 40px; }
.container { padding: 24px; }

Zoom Support

Users should be able to zoom to 200% without horizontal scrolling (WCAG 2.1 Success Criterion 1.4.10):

/* Good: Responsive at any zoom level */
.content {
  max-width: min(90%, 65ch);
  margin: 0 auto;
  padding: 1.5rem;
}

/* Bad: Fixed width breaks at high zoom */
.content {
  width: 960px;
  margin: 0 auto;
  padding: 24px;
}

Touch Targets

Interactive elements should be at least 44x44 CSS pixels (WCAG 2.5.5):

.button {
  min-height: 2.75rem; /* 44px */
  min-width: 2.75rem;
  padding: 0.75rem 1.5rem;
}

/* Ensure adequate spacing between touch targets */
.nav-list li + li {
  margin-top: 0.5rem;
}

Common Mistakes and How to Avoid Them

Mistake 1: Using px for Font Sizes

/* Bad: Does not scale with user preferences */
body { font-size: 16px; }
h1 { font-size: 32px; }

/* Good: Scales with user preferences */
body { font-size: 1rem; }
h1 { font-size: 2rem; }

Mistake 2: Using vh for Full-Height Mobile Layouts

/* Bad: Clips behind mobile address bar */
.mobile-layout { height: 100vh; }

/* Good: Accounts for mobile address bar */
.mobile-layout { height: 100dvh; }

/* Safest: Fallback for older browsers */
.mobile-layout {
  height: 100vh;
  height: 100dvh;
}

Mistake 3: Compounding em Values

/* Bad: Font size grows with nesting */
li { font-size: 1.1em; }

/* Good: Consistent regardless of nesting */
li { font-size: 1.1rem; }

Mistake 4: Using vw for Font Sizes Without Constraints

/* Bad: Too small on mobile, too large on desktop */
h1 { font-size: 5vw; }

/* Good: Constrained with clamp */
h1 { font-size: clamp(1.5rem, 5vw, 3rem); }

Mistake 5: Percentage Padding Confusion

/* Surprise: Vertical padding is based on WIDTH */
.box {
  padding-top: 10%;    /* 10% of parent's WIDTH, not height */
  padding-bottom: 10%; /* Same -- based on WIDTH */
}

CSS Units in Modern Frameworks

Tailwind CSS

Tailwind uses a spacing scale based on rem:

{/*  Tailwind spacing: 1 unit = 0.25rem = 4px */}
<div class="p-4 m-6 text-lg">
  {/*  p-4 = padding: 1rem (16px) */}
  {/*  m-6 = margin: 1.5rem (24px) */}
  {/*  text-lg = font-size: 1.125rem (18px) */}
</div>

CSS Modules / CSS-in-JS

// Styled Components / Emotion
const Card = styled.div`
  padding: 1.5rem;
  margin-bottom: 2rem;
  font-size: 1rem;
  border: 1px solid #e0e0e0;
  border-radius: 0.5rem;
  max-width: min(100%, 600px);
`;

Conclusion

CSS units are a foundational topic that affects every aspect of web development -- layout, typography, accessibility, and responsiveness. The key insight is that there is no single "best" unit; the right choice depends on the context.

Key takeaways:

  1. Use rem as your default for font sizes, spacing, and most measurements
  2. Use px for fine details like borders, box shadows, and outlines
  3. Use fr for Grid layouts to distribute space proportionally
  4. Use dvh instead of vh for full-height mobile layouts
  5. Use ch for line lengths to optimize readability
  6. Use clamp() for responsive values with minimum and maximum constraints
  7. Use em sparingly for proportional component scaling (like button padding)
  8. Always think about accessibility -- choose units that respect user preferences

Mastering CSS units takes practice, but the principles are clear: prefer relative units over absolute ones, think about how your design will respond to different contexts, and always consider accessibility.

For quick unit conversions in your development workflow, try our Unit Converter tool. You can also use our Color Picker for CSS color values and our CSS-related developer tools for other web development tasks.

Related Posts