Units & Sizing Functions
Every size in CSS needs a unit: font sizes, widths, padding, gaps. Picking the right unit is what makes a design scale smoothly from a small phone to a large monitor, and what makes it respect a reader who has set a bigger default font size.
In this lesson you will learn the units that matter in modern CSS and the four maths functions, calc(), min(), max() and clamp(), that let one value adapt to the space it has.
Absolute units: px
A CSS pixel (px) is a fixed size. It is not the same as a physical dot on your screen: a high-resolution phone uses several device dots for one CSS pixel, so 16px text looks about the same size on most screens.
Pixels are fine for things that should not scale with text, such as a 1px border or a small shadow. Other absolute units (cm, mm, in, pt) are mainly for print style sheets.
Font-relative units: rem and em
remis relative to the font size of the root element (<html>). In most browsers that is16pxby default, so1remis 16px and1.5remis 24px.emis relative to the font size of the current element. When used forfont-sizeitself, it is relative to the parent's font size.chis about the width of the "0" character in the current font, which makes it handy for line lengths:max-width: 65chkeeps paragraphs comfortable to read.
Use rem for font sizes. Many people, especially older readers and people with low vision, increase the default font size in their browser settings. Sizes in rem grow with that setting; sizes in px ignore it.
The danger with em is that it compounds: an em inside an em multiplies.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>rem vs em</title>
<style>
body { font-family: system-ui, sans-serif; padding: 1rem; }
.em-box { font-size: 1.2em; }
.rem-box { font-size: 1.2rem; }
div { border-left: 3px solid #8aa1c1; padding-left: 0.6rem; margin-top: 0.3rem; }
.btn { font-size: 1rem; padding: 0.5em 1em; background: #0b6e4f; color: white; border: none; }
.btn.big { font-size: 1.5rem; }
</style>
</head>
<body>
<div class="em-box">1.2em
<div class="em-box">1.2em inside 1.2em
<div class="em-box">and again: keeps growing</div>
</div>
</div>
<div class="rem-box">1.2rem
<div class="rem-box">1.2rem inside 1.2rem
<div class="rem-box">and again: stays the same</div>
</div>
</div>
<p><button class="btn">Book ticket</button> <button class="btn big">Book ticket</button></p>
</body>
</html>The nested em boxes keep getting bigger, while the rem boxes stay the same size. The buttons show where em is the right choice: their padding is in em, so the bigger button gets proportionally bigger padding without any extra rules.
Percentages
A percentage is relative to something else, and what that is depends on the property. For width, it is the width of the parent (strictly, the containing block). For font-size, it is the parent's font size.
One surprise: padding and margin percentages are always based on the parent's width, even for top and bottom.
Viewport units
Viewport units are relative to the browser window (the viewport):
| Unit | Means |
|---|---|
vw | 1% of the viewport width |
vh | 1% of the viewport height |
svh | 1% of the small viewport height (mobile browser bars shown) |
lvh | 1% of the large viewport height (bars hidden) |
dvh | 1% of the dynamic viewport height (updates as bars show and hide) |
On phones, the address bar and toolbar slide in and out as you scroll. Old 100vh often equals the height with the bars hidden, so a "full-screen" section is taller than the visible area and its bottom is cut off. The newer units fix this:
.hero {
min-height: 100svh; /* always fits when the browser bars are visible */
}
.app-shell {
height: 100dvh; /* follows the bars as they move */
}svh is the safe choice for most full-height sections. dvh is good for app-like layouts, but because it changes while scrolling it can make content jump. These units are supported in current versions of all major browsers. There are matching width units too (svw, lvw, dvw).
Two more unit families appear later in the course: fr in CSS Grid Basics and container units like cqi in Container Queries.
Maths functions
calc()
calc() does arithmetic, and it can mix units, which is impossible to do by hand:
.sidebar-layout main {
width: calc(100% - 18rem); /* full width minus a sidebar */
}
.sticky-offset {
top: calc(var(--header-height) + 1rem); /* works with custom properties */
}Always put spaces around + and - inside calc(). calc(100%-2rem) is invalid.
min(), max() and clamp()
min(a, b)uses whichever value is smaller.max(a, b)uses whichever value is larger.clamp(minimum, preferred, maximum)uses the preferred value, but never goes below the minimum or above the maximum.
These replace many media queries. Run this example and resize the Try-it window:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>clamp and min</title>
<style>
body { font-family: system-ui, sans-serif; margin: 0; background: #f3f5f8; }
.container {
width: min(100% - 2rem, 40rem);
margin-inline: auto;
background: white;
padding: clamp(1rem, 4vw, 2.5rem);
}
h1 {
font-size: clamp(1.75rem, 1.2rem + 3vw, 3rem);
line-height: 1.15;
}
</style>
</head>
<body>
<div class="container">
<h1>Kochi Marathon 2026</h1>
<p>Registration is open for the 5 km, 10 km and half marathon routes along the waterfront.</p>
</div>
</body>
</html>The container is the full width minus 2rem on small screens, but never wider than 40rem, so the text never stretches into very long lines. The heading grows smoothly with the window between 1.75rem and 3rem, and the padding does the same.
Common mistakes
- Font sizes in
px. They ignore the user's font-size setting. Userem. 100vhon mobile. Content hides behind the browser bars. Use100svhor100dvh.- No spaces in
calc(). Writecalc(100% - 2rem), notcalc(100%-2rem). - Missing units.
width: 300is ignored. Only0can be written without a unit. - Deep
emnesting. Sizes compound unexpectedly. Preferremunless you want scaling with the local text.
Key points
- Use
remfor font sizes so text respects the reader's browser settings. emscales with the element's own font size; it suits padding on buttons but compounds when nested.- Percentages depend on the property; padding and margin percentages use the parent's width.
- Prefer
svhordvhovervhfor full-height sections on phones. calc()mixes units;min(),max()andclamp()create sizes that adapt without media queries.
Exercise
Create a card for a cricket coaching camp in Rohtak. Make the card min(100% - 2rem, 30rem) wide and centred, give the heading a fluid size with clamp() between 1.5rem and 2.5rem, and set paragraph text to 1rem with a maximum line length of 60ch. Give a button padding in em units.
Show solution
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Coaching camp</title>
<style>
body { font-family: system-ui, sans-serif; margin: 0; padding-block: 1rem; }
.card {
width: min(100% - 2rem, 30rem);
margin-inline: auto;
padding: 1.25rem;
border: 1px solid #c9d3df;
border-radius: 10px;
}
h2 { font-size: clamp(1.5rem, 1rem + 2vw, 2.5rem); }
p { font-size: 1rem; max-width: 60ch; }
button { font-size: 1rem; padding: 0.6em 1.2em; }
</style>
</head>
<body>
<div class="card">
<h2>Summer Cricket Camp, Rohtak</h2>
<p>Daily batting, bowling and fielding drills for players aged 10 to 16.</p>
<button>Register</button>
</div>
</body>
</html>min() picks the smaller of the two widths, so the card fills small screens but stops growing at 30rem.
Quick Quiz
1. The root font size is 16px. How big is 2rem?
rem always uses the root element's font size, so 2rem is 2 x 16px.
2. Why can height: 100vh cause problems on phones?
The svh and dvh units account for browser bars that slide in and out.
3. What does clamp(1rem, 5vw, 2rem) return on a very wide screen where 5vw is 60px?
clamp() never goes above its maximum, so the value stops at 2rem.
4. Which calc() is valid?
The + and - operators need spaces on both sides.
Learn CSS with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
