CSS Sizing Units
Absolute units have a fixed physical size and do not scale relative to anything. px (pixels) is by far the most common absolute unit for screen-based layouts. Other absolute units like cm, mm, in, pt, and pc are primarily used for print stylesheets.
One CSS pixel equals 1/96th of an inch. On modern high-DPI screens, one CSS pixel may be rendered using multiple physical pixels (2x, 3x) to maintain sharpness. Always use px for borders, shadows, and fine visual details that should not scale.
| 1 | /* Absolute units */ |
| 2 | .px-example { |
| 3 | border: 1px solid #00FF41; /* fine border */ |
| 4 | box-shadow: 0 2px 4px rgba(0,0,0,0.5); /* shadows in px */ |
| 5 | border-radius: 4px; /* consistent corner radius */ |
| 6 | } |
| 7 | |
| 8 | /* Physical units — rarely used on screen */ |
| 9 | .print-only { |
| 10 | width: 6in; /* inches */ |
| 11 | height: 9in; |
| 12 | font-size: 12pt; /* points — 1pt = 1/72 of an inch */ |
| 13 | margin: 2cm; /* centimeters */ |
| 14 | } |
| 15 | |
| 16 | /* When to use px */ |
| 17 | /* - Borders */ |
| 18 | /* - Box shadows */ |
| 19 | /* - Border-radius */ |
| 20 | /* - Fine positioning */ |
| 21 | /* - Fixed-width containers */ |
Relative units scale based on other values. They are essential for responsive, accessible designs. The three most commonly used relative units are %, em, and rem.
| Unit | Relative To | Best For | Example |
|---|---|---|---|
| % | Parent's same property | Widths, heights, font-size, padding | width: 50% |
| em | Parent's font-size | Spacing relative to text size | padding: 1em |
| rem | Root font-size (usually 16px) | Accessible, predictable sizing | font-size: 1.25rem |
| 1 | /* Percentage — based on parent */ |
| 2 | .percent-parent { |
| 3 | width: 400px; |
| 4 | } |
| 5 | |
| 6 | .percent-child { |
| 7 | width: 50%; /* 200px — half of parent */ |
| 8 | padding-bottom: 25%; /* 100px — 25% of parent width */ |
| 9 | } |
| 10 | |
| 11 | /* Padding percentages are ALWAYS based on parent width (even for vertical) */ |
| 12 | /* Font-size percentages are based on parent font-size */ |
| 13 | |
| 14 | /* em — based on parent font-size */ |
| 15 | .parent-text { |
| 16 | font-size: 16px; |
| 17 | } |
| 18 | |
| 19 | .child-em { |
| 20 | font-size: 1.5em; /* 24px = 16 * 1.5 */ |
| 21 | padding: 1em; /* 24px — based on this element's computed font-size */ |
| 22 | margin-bottom: 2em; /* 48px */ |
| 23 | } |
| 24 | |
| 25 | /* The compounding problem with em */ |
| 26 | .nested-em { |
| 27 | font-size: 1.2em; /* 1.2 × parent */ |
| 28 | /* Nested: 1.2 × 1.2 = 1.44em */ |
| 29 | /* Deeply nested: values compound and get unpredictable */ |
| 30 | } |
| 31 | |
| 32 | /* rem — based on root font-size, no compounding */ |
| 33 | :root { font-size: 16px; } /* default, explicit for clarity */ |
| 34 | |
| 35 | .child-rem { |
| 36 | font-size: 1.25rem; /* 20px */ |
| 37 | padding: 1rem; /* 16px — always based on root, not parent */ |
| 38 | margin: 1.5rem; /* 24px */ |
| 39 | } |
info
Viewport units are relative to the browser viewport size. They are ideal for full-screen layouts, hero sections, and responsive typography that scales with the window.
| Unit | Relative To | Example |
|---|---|---|
| vw | 1% of viewport width | width: 50vw |
| vh | 1% of viewport height | height: 100vh |
| vmin | 1% of smaller viewport dimension | font-size: 5vmin |
| vmax | 1% of larger viewport dimension | font-size: 3vmax |
| dvh / svh / lvh | Dynamic / small / large viewport height | height: 100dvh |
| dvw / svw / lvw | Dynamic / small / large viewport width | width: 100dvw |
| 1 | /* Viewport units — relative to browser window */ |
| 2 | .hero { |
| 3 | height: 100vh; /* exactly full viewport height */ |
| 4 | width: 100vw; /* full viewport width */ |
| 5 | } |
| 6 | |
| 7 | /* Dynamic viewport units — better for mobile */ |
| 8 | .mobile-hero { |
| 9 | height: 100dvh; /* accounts for dynamic toolbar */ |
| 10 | /* dvh changes when mobile browser chrome shows/hides */ |
| 11 | } |
| 12 | |
| 13 | /* Fluid typography with clamp() */ |
| 14 | .fluid-text { |
| 15 | font-size: clamp(1rem, 2.5vw, 3rem); |
| 16 | /* Minimum 1rem, preferred 2.5vw, maximum 3rem */ |
| 17 | } |
| 18 | |
| 19 | /* Responsive spacing */ |
| 20 | .responsive-section { |
| 21 | padding: clamp(16px, 4vw, 64px); |
| 22 | } |
| 23 | |
| 24 | /* vmin for maintaining proportions */ |
| 25 | .square { |
| 26 | width: 50vmin; |
| 27 | height: 50vmin; |
| 28 | /* Always a square, max 50% of the smaller viewport dimension */ |
| 29 | } |
warning
The ch unit equals the width of the "0" character in the current font. The ex unit equals the x-height of the font (the height of the "x" character). These units are useful for typography-relative sizing.
| 1 | /* ch unit — width of the "0" character */ |
| 2 | .article-body { |
| 3 | max-width: 65ch; /* optimal line length for readability */ |
| 4 | /* Typically 60-75ch for body text */ |
| 5 | } |
| 6 | |
| 7 | .monospace-block { |
| 8 | width: 80ch; /* 80 character columns */ |
| 9 | font-family: "JetBrains Mono", monospace; |
| 10 | } |
| 11 | |
| 12 | /* ex unit — x-height of the font */ |
| 13 | .drop-cap::first-letter { |
| 14 | font-size: 3ex; /* 3x the x-height */ |
| 15 | /* More accurate than em for vertical alignment of initials */ |
| 16 | } |
| 17 | |
| 18 | /* ch is also great for input field sizing */ |
| 19 | input[name="zipcode"] { |
| 20 | width: 5ch; /* fits 5 characters */ |
| 21 | } |
These constraints set boundaries on element sizing, enabling responsive designs that adapt within limits. They are essential for creating flexible layouts that don't break at extreme sizes.
| 1 | /* min- and max- constraints */ |
| 2 | .responsive-container { |
| 3 | width: 80%; |
| 4 | max-width: 1200px; /* never wider than 1200px */ |
| 5 | min-width: 320px; /* never narrower than 320px */ |
| 6 | } |
| 7 | |
| 8 | .content-area { |
| 9 | min-height: 400px; /* ensures minimum space */ |
| 10 | max-height: 80vh; /* prevents excessive height */ |
| 11 | overflow-y: auto; /* scroll if content exceeds */ |
| 12 | } |
| 13 | |
| 14 | /* Sticky footer pattern with min-height */ |
| 15 | .page-layout { |
| 16 | min-height: 100vh; /* at least full viewport height */ |
| 17 | display: flex; |
| 18 | flex-direction: column; |
| 19 | } |
| 20 | |
| 21 | .main-content { |
| 22 | flex: 1; /* grows to fill space, pushes footer down */ |
| 23 | } |
| 24 | |
| 25 | /* Responsive card with constraints */ |
| 26 | .card { |
| 27 | width: clamp(280px, 30%, 400px); |
| 28 | /* Fluid width: min 280px, preferred 30%, max 400px */ |
| 29 | } |
| 30 | |
| 31 | /* Typography constraints */ |
| 32 | .headline { |
| 33 | font-size: clamp(1.5rem, 4vw, 3.5rem); |
| 34 | /* Fluid font-size with safe boundaries */ |
| 35 | } |
The aspect-ratio property sets a preferred aspect ratio for an element. It is especially useful for images, videos, embeds, and cards that need to maintain proportions regardless of content or container size.
| 1 | /* aspect-ratio — maintain proportions */ |
| 2 | .video-container { |
| 3 | width: 100%; |
| 4 | aspect-ratio: 16 / 9; /* 16:9 widescreen */ |
| 5 | /* Height is auto-calculated from width */ |
| 6 | } |
| 7 | |
| 8 | .square-card { |
| 9 | width: 200px; |
| 10 | aspect-ratio: 1; /* 1:1 square */ |
| 11 | } |
| 12 | |
| 13 | .image-gallery-item { |
| 14 | width: 100%; |
| 15 | aspect-ratio: 4 / 3; /* 4:3 standard photo ratio */ |
| 16 | object-fit: cover; /* for <img> elements */ |
| 17 | } |
| 18 | |
| 19 | /* aspect-ratio works with min-/max- constraints */ |
| 20 | .responsive-video { |
| 21 | width: 100%; |
| 22 | max-width: 800px; |
| 23 | aspect-ratio: 16 / 9; |
| 24 | /* width shrinks on small screens, height follows proportionally */ |
| 25 | } |
| 26 | |
| 27 | /* Fallback for older browsers — padding hack */ |
| 28 | .legacy-video { |
| 29 | position: relative; |
| 30 | padding-top: 56.25%; /* 9/16 * 100 = 56.25% */ |
| 31 | } |
| 32 | .legacy-video > * { |
| 33 | position: absolute; |
| 34 | top: 0; left: 0; |
| 35 | width: 100%; height: 100%; |
| 36 | } |
Intrinsic sizing keywords allow elements to size based on their content rather than their parent. These keywords are particularly useful in Grid and Flexbox contexts for precise sizing behavior.
| 1 | /* Intrinsic sizing keywords */ |
| 2 | .fit-content { |
| 3 | width: fit-content; /* as wide as content, but no wider than parent */ |
| 4 | /* Falls back to max-content if content wants to be wider than parent */ |
| 5 | } |
| 6 | |
| 7 | .min-content { |
| 8 | width: min-content; /* as narrow as possible */ |
| 9 | /* Width of the longest word or fixed-width element */ |
| 10 | } |
| 11 | |
| 12 | .max-content { |
| 13 | width: max-content; /* as wide as content wants to be */ |
| 14 | /* Ignores parent width — can overflow */ |
| 15 | } |
| 16 | |
| 17 | /* Practical use cases */ |
| 18 | .tooltip { |
| 19 | width: fit-content; /* wraps content neatly */ |
| 20 | max-width: 300px; |
| 21 | } |
| 22 | |
| 23 | .badge { |
| 24 | width: min-content; /* compact badge, breaks long words */ |
| 25 | } |
| 26 | |
| 27 | /* In Grid contexts */ |
| 28 | .grid-layout { |
| 29 | display: grid; |
| 30 | grid-template-columns: min-content 1fr min-content; |
| 31 | /* Side columns size to content, center fills remaining space */ |
| 32 | } |
| 33 | |
| 34 | /* In Flex contexts */ |
| 35 | .sidebar { |
| 36 | flex: 0 0 fit-content; /* sidebar sizes to its content */ |
| 37 | max-width: 300px; |
| 38 | } |
best practice