CSS Font-Size- Complete Styling Guide
CSS Font-Size: The Complete Styling Guide
Font-size controls one of the most fundamental aspects of web design: how big your text appears. Get it wrong, and your site becomes unreadable. Get it right, and your content just works.
This guide covers every unit, technique, and modern approach you actually need.
Font-Size Units: What Works and What Doesn't
CSS offers multiple ways to set font size. Here's the breakdown:
Absolute Units
Pixels (px) are the most common choice. They give you exact control over size.
- px values are predictable across browsers
- They don't scale when users change browser defaults
- Accessibility advocates frown on them
Points (pt) belong in print stylesheets. Stop using them on the web.
Relative Units
Em (em) is relative to the parent element's font size. If a parent has font-size: 16px and you set child to 1.5em, the child gets 24px.
The problem: em units compound. Nest three elements with 1.5em each and your font grows faster than intended.
Rem (rem) fixes this. It's always relative to the root element (html), not the parent. This makes calculations predictable.
- 1rem = browser's default font size (usually 16px)
- No compounding issues
- Works well with user font size preferences
Percent (%) works like em but as a percentage. 100% = inherited size. 150% = 1.5x inherited.
The Modern Approach: Root-Relative Units
Use rem for almost everything. It's the most maintainable option.
For responsive typography, combine rem with viewport units.
- vw (viewport width) — 1vw = 1% of viewport width
- vh (viewport height) — 1vh = 1% of viewport height
- vmin / vmax — smallest or largest viewport dimension
Font-Size Comparison Table
| Unit | Relative To | Compound Effect | Accessibility | Use Case |
|---|---|---|---|---|
| px | Nothing | No | Poor | Icons, precise layouts |
| em | Parent element | Yes | Good | Component-specific sizing |
| rem | Root element | No | Good | Most typography |
| % | Parent element | Yes | Good | Form inputs, legacy support |
| vw | Viewport width | No | Good | Fluid headings |
CSS Functions for Font-Size
calc() — Combine Units
calc() lets you mix units. Useful for fluid layouts:
font-size: calc(1rem + 2vw);
This adds a viewport-relative component to a base size. Your text grows as the viewport expands.
clamp() — The Modern Standard
clamp() is the best tool for fluid typography. It takes three values:
font-size: clamp(1rem, 2.5vw + 0.5rem, 2rem);
- First value: minimum size
- Middle value: preferred size (fluid)
- Last value: maximum size
Your text will never go below 1rem or above 2rem. Between those bounds, it scales with viewport.
This replaces entire media query chains for font-size. One declaration handles mobile through desktop.
Setting a Base Font Size
Most browsers default to 16px. You can change this on the html element:
html {
font-size: 16px;
}
Some developers set it to 62.5% (10px) to make rem calculations easier. 1.6rem becomes 16px. It's a shortcut, but it breaks if third-party styles reset the root.
Stick with 100% or 16px. The math is simple enough: 1.6rem = 16px, 2rem = 32px. Learn it once.
Responsive Font Sizing: How To
Method 1: Media Queries
The traditional approach:
body {
font-size: 1rem;
}
@media (min-width: 768px) {
body {
font-size: 1.125rem;
}
}
@media (min-width: 1200px) {
body {
font-size: 1.25rem;
}
}
This works. It's readable and maintainable. The downside: you need multiple breakpoints and values.
Method 2: Fluid Typography with clamp()
The modern approach:
body {
font-size: clamp(1rem, 0.5rem + 2.5vw, 1.25rem);
}
h1 {
font-size: clamp(1.75rem, 1rem + 4vw, 4rem);
}
One declaration handles all screen sizes. No breakpoints needed for font-size.
Method 3: Container Queries (Newer)
Container queries let font-size respond to the parent container, not the viewport. This matters for reusable components:
.card {
container-type: inline-size;
}
.card h2 {
font-size: clamp(1rem, 4cqi, 2rem);
}
Browser support is good in 2024. Use it for component-level typography systems.
Common Mistakes
Using px for Body Text
px values ignore user preferences. Users who need larger text get stuck with your fixed sizes. Use rem or clamp().
Overusing viewport Units
vw-based font sizes can get too small on mobile or too large on wide screens. Always wrap them in clamp() with min/max bounds.
Forgetting the html Font Size
If you change the root font-size, every rem value in your stylesheet scales. This is either a feature or a bug depending on whether you intended it.
Compound em Sizing Without Tracking
Nested elements with em can grow unexpectedly. Use rem for global typography, em only for component-level scaling.
Accessibility Considerations
Font-size affects who can read your content. Basic rules:
- Body text should be at least 16px (or 1rem)
- Line height should be 1.4 to 1.6 for body text
- Avoid text that fits exactly in the viewport — users need room to zoom
- Test at 200% zoom — everything should remain readable
Users change their browser's default font size for a reason. Respecting rem units means your site adapts to their needs automatically.
Typography Scale
A traditional scale uses these ratios:
- Minor second — 1.067 ratio
- Major second — 1.125 ratio
- Minor third — 1.2 ratio
- Major third — 1.25 ratio
Example using Major third (1.25):
--text-xs: 0.64rem; /* ~10px */
--text-sm: 0.8rem; /* ~13px */
--text-base: 1rem; /* 16px */
--text-lg: 1.25rem; /* 20px */
--text-xl: 1.563rem; /* 25px */
--text-2xl: 1.953rem; /* 31px */
--text-3xl: 2.441rem; /* 39px */
--text-4xl: 3.052rem; /* 49px */
Define these as CSS custom properties. Use them consistently throughout your site.
Quick Reference
- Use rem for most typography
- Use clamp() for fluid headings and responsive body text
- Use px only for icons and decorative elements that shouldn't scale
- Define a typography scale as custom properties
- Test at 200% zoom for accessibility
That's the whole guide. Font-size isn't complicated once you understand the units. rem for consistency, clamp() for fluid scaling, and always respect user preferences.