CSS offers roughly a dozen ways to state a font size, and the choice is not merely stylistic — it determines whether a user who needs larger text actually gets it. This page has the conversion tables, the arithmetic behind them, and a clear answer on which unit belongs where.
The two numbers to memorise
1rem = 16px by default, and 1pt = 1.333px. Everything else on this page derives from those. If you want one rule: use rem for font sizes, em for padding that should track its own element's text, and px only for hairlines and borders.
The units, and what each is relative to
| Unit | Relative to | Scales with user settings? | Best for |
|---|---|---|---|
px | Nothing — absolute in CSS | Zoom only | Borders, shadows, hairlines |
pt | 1/72 inch | Zoom only | Print stylesheets |
rem | Root element font size | Yes | Font sizes, layout spacing |
em | Parent element font size | Yes | Padding and margins inside a component |
% | Parent element font size | Yes | Same as em; older syntax |
ch | Width of the "0" glyph | Yes | Line-length limits |
ex | x-height of the font | Yes | Rare typographic fine-tuning |
vw / vh | Viewport dimensions | No | Fluid type, with limits |
pc | 12 points | Zoom only | Legacy print work |
cm / mm / in | Physical length | Zoom only | Print stylesheets only |
💡 The CSS pixel is not a screen pixel
CSS defines its absolute units by fixed relationships: 1in = 96px, 1pt = 1/72in, 1pc = 12pt. These hold regardless of your actual display density. A CSS pixel is a unit of apparent size — on a high-density phone one CSS pixel may cover nine physical pixels. That is why 16px text looks about the same physical size on a phone and a monitor despite wildly different panel densities.
px to rem conversion table
Assuming the default root size of 16px. This is the table you will use most.
| Pixels | rem | Points | Percent | Typical use |
|---|---|---|---|---|
| 10px | 0.625rem | 7.5pt | 62.5% | Fine print, legal text |
| 11px | 0.6875rem | 8.25pt | 68.75% | Dense table data |
| 12px | 0.75rem | 9pt | 75% | Captions, labels — the practical minimum |
| 13px | 0.8125rem | 9.75pt | 81.25% | Secondary text |
| 14px | 0.875rem | 10.5pt | 87.5% | UI text, buttons, form labels |
| 16px | 1rem | 12pt | 100% | Body text — the baseline |
| 18px | 1.125rem | 13.5pt | 112.5% | Comfortable long-form body |
| 20px | 1.25rem | 15pt | 125% | Lead paragraphs, h5 |
| 24px | 1.5rem | 18pt | 150% | h4, small headings |
| 28px | 1.75rem | 21pt | 175% | h3 |
| 32px | 2rem | 24pt | 200% | h2 |
| 36px | 2.25rem | 27pt | 225% | h2 large |
| 40px | 2.5rem | 30pt | 250% | h1 on mobile |
| 48px | 3rem | 36pt | 300% | h1 |
| 56px | 3.5rem | 42pt | 350% | Hero heading |
| 64px | 4rem | 48pt | 400% | Large hero |
| 72px | 4.5rem | 54pt | 450% | Display type |
| 96px | 6rem | 72pt | 600% | Oversized display |
The em compounding trap
This is the single most common source of mysterious font-size bugs, and it is worth seeing concretely.
em is relative to the parent's computed font size. Nest elements that each use em and the multiplications stack:
The classic symptom is a nested list where each level of indentation gets smaller, or a component that renders correctly on its own and shrinks when placed inside another component. Nothing in the CSS looks wrong — the sizes are simply multiplying.
✅ The rule that resolves it
rem for font sizes, em for spacing that should follow its own text. Padding written as 0.75em 1.5em on a button scales automatically when you make the button's text bigger — which is exactly what you want, and what a small-button/large-button variant needs. Font size in rem is stable regardless of nesting. Together they behave predictably.
Why the unit is an accessibility decision
Browsers expose a default font size setting. Users who need larger text — because of low vision, or a large monitor viewed from a distance, or simply preference — change it there. It is a real setting that real people use.
Text sized in rem honours it, because the root size is that setting. Text sized in px ignores it completely.
| User's browser default | Text set to 1rem | Text set to 16px |
|---|---|---|
| 16px (default) | 16px | 16px |
| 20px (Large) | 20px | 16px |
| 24px (Very large) | 24px | 16px |
| 12px (Small) | 12px | 16px |
It is worth being accurate about the scale of this: browser zoom scales px too, so px-based text is not unreachable. But zoom enlarges the entire layout, including images and horizontal scrolling, which is a much blunter instrument than "make the text bigger". Someone who wants larger text and an unchanged layout can only get it from relative units.
🚨 Never disable zoom
<meta name="viewport" content="user-scalable=no"> and maximum-scale=1 prevent pinch-zoom on mobile. For a user with low vision this can make a site simply unusable, and it fails WCAG 1.4.4 outright. There is no design justification that outweighs this. Remove it if it is in your template — it often is, copied from a tutorial written in 2013.
Fluid type with clamp()
Viewport units let type scale with screen width, but used alone they are dangerous: font-size: 5vw is unreadably small on a phone and absurd on an ultrawide monitor, and — critically — it ignores the user's font size setting entirely. clamp() solves this by bounding the fluid value.
The important detail is the rem component in the middle value. A preferred value of pure vw makes the text depend only on viewport width, so a user's font size preference has no effect at all. Mixing a rem base with a vw increment keeps the type responsive to both the screen and the user.
Line height and measure
Font size alone does not determine readability. Two other numbers matter as much:
| Property | Recommended | Why |
|---|---|---|
line-height |
1.5–1.6 for body, 1.1–1.3 for headings | WCAG 1.4.12 requires that at least 1.5 is possible without loss of content. Large type needs proportionally less. |
| Line length (measure) | 45–75 characters, ideally around 66 | Longer lines make the eye lose its place returning to the next line; much shorter breaks reading rhythm. |
letter-spacing |
0 for body; slight negative for large headings | Type designers already spaced the font. Large sizes look loose because spacing is optically proportional. |
⚠️ Always write line-height without a unit
line-height: 1.6 inherits as a multiplier, so a child with larger text gets proportionally more leading. line-height: 1.6rem inherits as a fixed length — so a heading at 3rem inside that element gets 1.6rem of line height and the lines overlap. This is one of the most common CSS typography bugs and the fix is deleting three characters.
Building a type scale
Rather than choosing sizes ad hoc, derive them from a ratio. Each step multiplies the previous one, which produces a set of sizes that look deliberately related.
| Ratio | Name | Sizes from 1rem | Character |
|---|---|---|---|
| 1.125 | Major second | 1, 1.125, 1.266, 1.424, 1.602 | Very subtle; dense interfaces |
| 1.200 | Minor third | 1, 1.2, 1.44, 1.728, 2.074 | Comfortable; the safe default |
| 1.250 | Major third | 1, 1.25, 1.563, 1.953, 2.441 | Clear hierarchy; good for content sites |
| 1.333 | Perfect fourth | 1, 1.333, 1.777, 2.369, 3.157 | Strong contrast; editorial |
| 1.618 | Golden ratio | 1, 1.618, 2.618, 4.236, 6.854 | Dramatic; grows fast, needs few steps |
Three practical notes. Larger ratios need fewer steps — a golden-ratio scale reaches display sizes in four steps and going further produces absurd numbers. A ratio that works on desktop is often too aggressive on mobile, so many designs use a smaller ratio below a breakpoint. And a scale is a starting point, not a law; if a heading needs to sit between two steps, it needs to sit between two steps.
Font sizes for print stylesheets
Print is the one place where pt is the correct unit, because points map to physical measurements that printers understand.
Print needs less line height than screens — paper has higher effective resolution and no backlight glare, so 1.3–1.4 reads comfortably where a screen wants 1.5–1.6.
Working with text?
Count words and characters, check reading time, or convert between text cases — all instantly, all in your browser.
Open the Word Counter →The rules, condensed
- 1rem = 16px, 1pt = 1.333px. Everything else follows.
- rem for font sizes — it honours the user's browser setting; px does not.
- em for internal spacing so padding tracks its own element's text.
- px only for hairlines — borders and shadows that should not grow.
- em compounds when nested. This is the cause of most shrinking-text bugs.
- line-height must be unitless so it inherits as a multiplier.
- Avoid the 62.5% trick — it overrides the accessibility setting rem exists to respect.
- Never set
user-scalable=no. Ever.
Frequently Asked Questions
What is 12pt in pixels?
16 pixels. CSS defines one inch as exactly 96 pixels and one point as 1/72 inch, so 1pt = 96/72 = 1.333px. That makes 12pt equal to 16px — which is also the default browser font size, and not a coincidence: 12 point has been the standard document body size for centuries.
Should I use px or rem for font sizes?
Use rem. A user who has increased their default font size in browser settings — often because they need to — sees rem-based text scale accordingly, while px-based text ignores them entirely. Browser zoom scales both, so px is not as harmful as often claimed, but rem respects a setting px cannot see.
What is the difference between em and rem?
em is relative to the font size of the parent element, so it compounds — nested elements each multiply the previous size. rem is relative to the root element only, so 1.5rem is the same size everywhere regardless of nesting. Use rem for type and em for spacing that should scale with its own element's text.
Why is 16px the default font size?
It comes from print. Twelve point has been the standard body size for printed text for centuries, and 12pt equals exactly 16px at the CSS definition of 96 pixels per inch. Every major browser adopted 16px as its default and none has changed it, so it functions as the web's baseline.
What does the 62.5% trick do and should I use it?
Setting html { font-size: 62.5% } makes the root 10px so that 1.6rem equals 16px, simplifying mental arithmetic. It is not recommended any more: it overrides the user's chosen default font size, which defeats the main reason to use rem in the first place. Use a preprocessor function or just learn the small conversion table instead.