Font Size Conversion: px, pt, em, rem, % and When to Use Each

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

UnitRelative toScales with user settings?Best for
pxNothing — absolute in CSSZoom onlyBorders, shadows, hairlines
pt1/72 inchZoom onlyPrint stylesheets
remRoot element font sizeYesFont sizes, layout spacing
emParent element font sizeYesPadding and margins inside a component
%Parent element font sizeYesSame as em; older syntax
chWidth of the "0" glyphYesLine-length limits
exx-height of the fontYesRare typographic fine-tuning
vw / vhViewport dimensionsNoFluid type, with limits
pc12 pointsZoom onlyLegacy print work
cm / mm / inPhysical lengthZoom onlyPrint 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.

PixelsremPointsPercentTypical use
10px0.625rem7.5pt62.5%Fine print, legal text
11px0.6875rem8.25pt68.75%Dense table data
12px0.75rem9pt75%Captions, labels — the practical minimum
13px0.8125rem9.75pt81.25%Secondary text
14px0.875rem10.5pt87.5%UI text, buttons, form labels
16px1rem12pt100%Body text — the baseline
18px1.125rem13.5pt112.5%Comfortable long-form body
20px1.25rem15pt125%Lead paragraphs, h5
24px1.5rem18pt150%h4, small headings
28px1.75rem21pt175%h3
32px2rem24pt200%h2
36px2.25rem27pt225%h2 large
40px2.5rem30pt250%h1 on mobile
48px3rem36pt300%h1
56px3.5rem42pt350%Hero heading
64px4rem48pt400%Large hero
72px4.5rem54pt450%Display type
96px6rem72pt600%Oversized display
// The conversions, in full rem = px ÷ 16 px = rem × 16 pt = px × 0.75 // because 72 ÷ 96 = 0.75 px = pt × 1.333… // because 96 ÷ 72 = 1.333… percent = rem × 100

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:

/* Each level multiplies the last */ .card { font-size: 1.2em; } /* 16 × 1.2 = 19.2px */ .card .title{ font-size: 1.2em; } /* 19.2 × 1.2 = 23.04px */ .card .title span { font-size: 1.2em; } /* 23.04 × 1.2 = 27.65px */ /* Same rule written in rem — no compounding */ .card { font-size: 1.2rem; } /* 19.2px */ .card .title{ font-size: 1.2rem; } /* 19.2px */ .card .title span { font-size: 1.2rem; } /* 19.2px */

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.

.button { font-size: 1rem; /* fixed relative to root */ padding: 0.75em 1.5em; /* scales with this button's text */ border-radius: 0.375em; border: 1px solid; /* px — a hairline should stay a hairline */ } .button--large { font-size: 1.25rem; } /* padding follows automatically */ .button--small { font-size: 0.875rem; } /* so does this */

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 defaultText set to 1remText set to 16px
16px (default)16px16px
20px (Large)20px16px
24px (Very large)24px16px
12px (Small)12px16px

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.

/* clamp(minimum, preferred, maximum) */ h1 { font-size: clamp(2rem, 1.5rem + 2.5vw, 4rem); } /* At 320px wide → 2rem (the floor) At 768px wide → ~2.7rem At 1440px wide → ~3.75rem At 2560px wide → 4rem (the ceiling) */ body { font-size: clamp(1rem, 0.95rem + 0.25vw, 1.25rem); }

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:

PropertyRecommendedWhy
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.
/* Set line-height unitless so it inherits proportionally */ body { font-size: 1.125rem; line-height: 1.6; /* NOT 1.6rem — see below */ } /* ch is the width of the "0" glyph, so measure is expressed in roughly the units that matter */ .prose { max-width: 68ch; } h1 { font-size: clamp(2rem, 1.5rem + 2.5vw, 3.5rem); line-height: 1.15; letter-spacing: -0.02em; }

⚠️ 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.

RatioNameSizes from 1remCharacter
1.125Major second1, 1.125, 1.266, 1.424, 1.602Very subtle; dense interfaces
1.200Minor third1, 1.2, 1.44, 1.728, 2.074Comfortable; the safe default
1.250Major third1, 1.25, 1.563, 1.953, 2.441Clear hierarchy; good for content sites
1.333Perfect fourth1, 1.333, 1.777, 2.369, 3.157Strong contrast; editorial
1.618Golden ratio1, 1.618, 2.618, 4.236, 6.854Dramatic; grows fast, needs few steps
:root { --ratio: 1.25; --text-sm: 0.8rem; --text-base: 1rem; --text-md: 1.25rem; --text-lg: 1.563rem; --text-xl: 1.953rem; --text-2xl: 2.441rem; --text-3xl: 3.052rem; }

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.

@media print { body { font-size: 11pt; /* 10–12pt is the readable range on paper */ line-height: 1.4; /* paper needs less leading than screens */ color: #000; } h1 { font-size: 20pt; } h2 { font-size: 16pt; } h3 { font-size: 13pt; } /* Show link destinations, since a reader cannot click paper */ a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; } }

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.

P

Written by Paras

We build free, browser-based file tools and write the reference material we wish existed when we were looking things up. Spotted an error? Tell us and we will fix it.