A responsive font size is text that stays readable at every screen width: about 16 px for body copy on phones, headings that grow smoothly with the screen instead of jumping at breakpoints, and sizes set in rem so they follow the visitor's own text-size setting and zoom. The modern way to do it is one line of CSS per level with clamp(). This guide gives the sizes that work on mobile, the CSS to copy, and the mistakes that make fluid type unreadable or unzoomable. It is part of our guide on how to make a website mobile friendly.
Quick answer
- Body text: 16 px (1rem) on phones, with a line height of about 1.5. Going larger on desktop (17–20 px) is fine; going smaller on phones is not.
- Nothing under 12 px, including captions, footers and legal text. getReport counts text under 12 px at each width.
- Form fields at 16 px or more, or iOS Safari zooms the page when someone taps them.
- Use
rem, notpx, for font sizes andhtml { font-size: 100% }, so visitors who set a bigger default text size get it. - Fluid headings with
clamp():font-size: clamp(1.75rem, 1.2rem + 2.5vw, 3rem)grows with the screen between two limits. - Never size text in
vwalone. It stops text from growing when visitors zoom, which fails WCAG 1.4.4. - Check it with the free mobile-friendly test, which renders your page at 360 to 1440 px and flags text under 12 px.
What size should text be on mobile?
There is no legal minimum font size, but there are clear conventions:
| Text | Phone | Desktop | Why |
|---|---|---|---|
| Body | 16 px (1rem) | 16–20 px | Browser default; readable at arm's length |
| Form inputs | 16 px minimum | 16 px | Below 16 px, iOS Safari zooms in on focus |
| Small print, captions | 12–14 px | 12–14 px | Anything smaller is hard to read on a phone |
| H1 | 28–36 px | 40–64 px | Should fit a short title in two or three lines at 360 px |
| H2 | 22–28 px | 28–40 px | Clear step down from H1 |
| Line height (body) | 1.5 | 1.5–1.6 | WCAG 1.4.12 tests text at 1.5 |
The 16 px baseline is not arbitrary. It is the default font size in every major browser, the size platform guidelines use for body text (Material Design's largest body style is 16 sp; Apple's default body text on iOS is 17 pt), and the size iOS Safari treats as large enough not to zoom into form fields.
"Text too small to read" was one of the issues in Google's Mobile Usability report until Google retired it, along with the Mobile-Friendly Test, on 1 December 2023. The problem did not go away with the report: small text still sends visitors back to the search results.
Line length
Size and line length work together. Comfortable reading is roughly 45–75 characters per line, a range typographers have used for decades. A phone at 16 px gives about 35–45 characters, which is fine. A desktop layout with 16 px text across a 1,200 px column gives 150; cap the text column instead:
/* main stylesheet */
.prose { max-width: 65ch; }Use rem so visitors can make text bigger
Browsers let people choose a default text size: Chrome under Settings → Appearance → Font size, Firefox under Settings → General → Fonts, and phones through their accessibility settings. Sizes in rem are relative to that default; sizes in px ignore it.
/* keep the visitor's default (16 px unless they changed it) */
html { font-size: 100%; }
body { font-size: 1rem; line-height: 1.5; }
small, .caption { font-size: 0.8125rem; } /* 13 px at the default */
input, select, textarea { font-size: max(16px, 1rem); }Avoid the old html { font-size: 62.5% } trick, which makes 1rem equal 10 px for easier arithmetic. It works, but every size then depends on remembering to set it back up, and components copied from elsewhere end up tiny.
Use em or rem in media queries too, so breakpoints move when the visitor's text size changes; our guide to media queries and breakpoints explains why.
Fluid type with clamp()
The traditional way to make type responsive is a new size at each breakpoint:
h1 { font-size: 1.75rem; }
@media (min-width: 48em) { h1 { font-size: 2.5rem; } }
@media (min-width: 64em) { h1 { font-size: 3rem; } }That works, but the heading jumps at 768 px and 1,024 px and is either too small or too large in between. clamp(), supported in every current browser, replaces it with one line:
h1 { font-size: clamp(1.75rem, 1.2rem + 2.5vw, 3rem); }It reads as: never smaller than 1.75rem (28 px), never larger than 3rem (48 px), and in between, 1.2rem plus 2.5 % of the viewport width. At 360 px wide that is about 28 px, at 1,280 px about 51 px capped to 48 px.
How to calculate the middle value
Pick the size you want at the narrowest and widest screen, then solve for a straight line between them. For 28 px at 360 px and 48 px at 1,280 px:
- Slope: (48 − 28) ÷ (1280 − 360) = 0.0217, which is 2.17vw.
- Intercept: 28 − 0.0217 × 360 = 20.2 px, which is 1.26rem.
- Result:
clamp(1.75rem, 1.26rem + 2.17vw, 3rem).
Many online "fluid type calculators" do the same arithmetic. What matters is that the middle value is rem plus vw, never vw alone.
A fluid type scale
Apply the same idea to every level, and keep body text close to fixed, because fluid body text rarely helps:
:root {
--step--1: clamp(0.8125rem, 0.79rem + 0.1vw, 0.875rem); /* small: 13–14 px */
--step-0: clamp(1rem, 0.96rem + 0.2vw, 1.125rem); /* body: 16–18 px */
--step-1: clamp(1.25rem, 1.15rem + 0.45vw, 1.5rem); /* h3: 20–24 px */
--step-2: clamp(1.5rem, 1.3rem + 0.9vw, 2rem); /* h2: 24–32 px */
--step-3: clamp(1.75rem, 1.26rem + 2.17vw, 3rem); /* h1: 28–48 px */
}
body { font-size: var(--step-0); }
h1 { font-size: var(--step-3); }
h2 { font-size: var(--step-2); }
h3 { font-size: var(--step-1); }Keep fluid type zoomable
WCAG 2.2 success criterion 1.4.4 (Resize Text) requires that text can be enlarged to 200 % without losing content or function. Fluid type can quietly break it:
vwalone does not zoom. Browser zoom makes CSS pixels bigger, which makes the viewport narrower in CSS pixels, so text sized invwstays the same size on screen or even shrinks.font-size: 5vwfails 1.4.4.- Adding
remfixes most of it, because therempart grows with zoom and with the visitor's text-size setting. - A wide clamp range can still cap growth. When a visitor zooms, the maximum stops the text growing further. As a rule of thumb from Maxwell Barvian's analysis of fluid type and WCAG in Smashing Magazine, keeping the maximum at no more than 2.5 times the minimum lets text reach 200 % at every width. The scale above stays well within that.
Test it: at 1,280 px wide, zoom the browser to 200 % and check that headings and body text are roughly twice as large. Our guide to the viewport tag and pinch-zoom covers zoom on phones, where maximum-scale=1 and user-scalable=no must stay out of the viewport tag.
Mobile browsers that change your font size
Two browser behaviours surprise people:
- Font boosting without a viewport tag. Without
<meta name="viewport" content="width=device-width, initial-scale=1">, phones lay the page out at desktop width and some browsers enlarge paragraphs they judge unreadable, so text sizes come out uneven. Add the viewport tag and the browser uses your sizes. - iOS text inflation in landscape. Safari on iOS can enlarge text when a phone is rotated.
-webkit-text-size-adjust: 100%(and the unprefixedtext-size-adjust: 100%) onhtmlstops it without blocking user zoom. Do not usenone, which can also stop desktop Safari users from enlarging text.
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }Fonts affect readability too
Two fonts at the same pixel size can look very different, because x-heights differ. A font with a small x-height may need 17–18 px to read like 16 px in a system font. Check real text at 360 px on a real phone, not only the number in the CSS. If you use a web font, load it so text shows immediately in a fallback font; the font-display fix page and our guide to system fonts versus web fonts cover the speed side.
How to check your font sizes
- Render the page at phone widths. The free mobile-friendly test loads your page in Chromium and resizes it to 360, 414, 768, 1024 and 1440 px. At each width it counts text smaller than 12 px and names where it is, alongside sideways scrolling and small tap targets.
- Inspect computed sizes. In Chrome DevTools, select a paragraph and open Computed → font-size, at the 360 px device preset. Check body, captions, footer links, form inputs and buttons.
- Change the browser's default text size to "Large" or "Very large" and reload. Text set in
remshould grow; text that stays the same is inpx. - Zoom to 200 % at desktop width and confirm that text doubles and nothing is cut off.
- Run an accessibility check. The accessibility checker runs axe-core, which catches related problems such as low contrast on small text.
Common mistakes
- Body text at 14 px on phones because it looked right in a desktop mockup.
- Headings in
vwonly, which stop zooming and become huge on wide screens. - Form inputs at 14 px, then
maximum-scale=1added to stop the iOS zoom. Set inputs to 16 px instead. - Light grey 12 px text in footers and captions; small text needs more contrast, not less.
62.5 %onhtmlwith components that assume a 16 px root.- Setting sizes in
pxin a page builder, which ignores the visitor's text-size setting. Most builders acceptremorem.
Questions people ask
What is the minimum font size for mobile?
Use 16 px for body text and form inputs on phones, and keep small print such as captions and footer text at 12 px or more. WCAG sets no minimum pixel size, but it requires text to resize to 200 %, and iOS Safari zooms into form fields under 16 px. Set sizes in rem so visitors who choose larger text in their browser get it.
How do I make font size responsive in CSS?
Set body text in rem, then use clamp() for headings: font-size: clamp(1.75rem, 1.26rem + 2.17vw, 3rem) grows a heading smoothly from 28 px on a phone to 48 px on a desktop. Always combine vw with rem in the middle value, keep html at font-size: 100 %, and cap the text column at about 65ch for comfortable line length.
Is it bad to use vw units for font size?
Using vw alone is bad for accessibility. Text sized only in viewport units does not grow when a visitor zooms the browser, which fails WCAG 1.4.4 Resize Text, and it becomes very large on wide screens. Use vw only inside clamp() together with a rem value and sensible minimum and maximum sizes, so zoom and text-size settings still work.
Why does iPhone zoom in when I tap a form field?
Because the field's font size is under 16 px. iOS Safari zooms the page so the text you type is readable, then leaves the page zoomed. The fix is to set inputs, selects and textareas to at least 16 px, for example input { font-size: max(16px, 1rem); }. Don't disable zoom in the viewport tag instead; that blocks visitors who need to enlarge text.