Cover Image

You shipped a beautiful desktop design. Hierarchy was perfect — H1 big and commanding, H2s that pulled their weight, body text that breathed. Then you opened it on mobile and everything felt... off. Headings too cramped. Body text fighting for space. The whole visual rhythm collapsed.
If this sounds familiar, you're not alone — and it's probably not your eye. It's how most design workflows handle mobile typography: as an afterthought.
This guide fixes that. We'll build a mobile typography system that holds up across every screen width, using a fluid type scale, a pragmatic hierarchy rule, and a developer handoff that doesn't fall apart on contact.
Why Your Type Hierarchy Breaks on Mobile — and the Desktop-First Trap
Here's what almost always happens: you design at 1440px, set up a beautiful 6-level type scale (H1 through H6), and it looks harmonious. Then you get to mobile and everything crowds in.
There are three symptoms of this problem, and they each have a distinct cause.
The harmony ratio breaks. Most type scales use a ratio to generate heading sizes from body text — say, a Perfect Fourth (1.333×) or a Major Third (1.25×). A heading that's 3× the body text at 1440px becomes a heading that's only 1.5× the body at 375px. The math that worked at desktop doesn't hold at mobile because you're compressing a ratio designed for a wide canvas into a narrow one.
Breakpoints create hard jumps. The traditional responsive approach sets specific font sizes at specific breakpoints. H1 is 48px on desktop, but what happens at 375px? Usually someone overrides it — and that override doesn't always play nicely with the body text size. One breakpoint override cascades into five, and somewhere along the way the hierarchy you designed is gone.
Too many type levels for mobile. Desktop designs often have 5 or 6 heading levels. On mobile, you realistically have room for 3. When teams don't have a clear rule, they pick heading levels based on what "looks about right" in the browser — and the hierarchy dissolves.
The common thread: mobile is treated as a constraint on desktop hierarchy, not a design problem in its own right.
The Fluid Type Scale Solution — One Scale That Works Everywhere
The fix is to stop thinking in breakpoints and start thinking in fluid type scales. Instead of setting specific font sizes at specific viewport widths, you define a range and let CSS scale continuously between the two.
The CSS clamp() function does exactly this:
body {
font-size: clamp(1rem, 0.5vw + 0.75rem, 1.125rem);
/* 12px min | scales up to 18px max */
}
The three values in clamp() are: minimum, preferred, maximum. The preferred value uses viewport units (vw) to scale smoothly. As the viewport widens, the font grows. As it narrows, it shrinks — but never below the minimum, never above the maximum.
The math for the preferred value: minimum + (maximum − minimum) × (100vw − minimum_viewport) / (maximum_viewport − minimum_viewport).
The easy way to generate this without doing the math by hand: use a tool like Utopia or Type Scale. Both let you pick a modular ratio (Perfect Fourth 1.333 is a reliable default), enter your min/max viewport and font sizes, and copy out ready-to-use CSS custom properties.
The real payoff shows up when you pair a fluid body size with a fluid heading size using the same ratio. The heading-to-body ratio stays consistent whether you're at 1440px or 375px — you're not overriding anything at a breakpoint, you're using one system everywhere.
The 3-Level Mobile Hierarchy Rule
Here's a pragmatic rule that solves the "too many heading levels" problem: use 3 levels on mobile, never 6.
On desktop you might lean on H1 → H2 → H3 → H4 → body. On mobile, you design for H1 → H2 → body. Everything else either gets absorbed into one of those three levels or gets a styled variation rather than its own heading element.
The reason this works: at 375px wide, the visual space for a heading is small. An H3 that looks meaningfully different from body text at 1200px looks almost identical to body text at mobile. You're not communicating hierarchy at that point — you're adding noise.
How to collapse a desktop hierarchy into 3 levels: Start from the bottom. Everything that isn't H1 or a major section heading becomes body text. If you need a third level — say, a callout sub-heading that sits between H2 and body — style it as a slightly larger or bolder body paragraph instead of adding an H3 element.
The other thing that makes 3 levels work: the size difference between each level has to be larger on mobile than it is on desktop. A heading that's 1.5× the body text reads as a heading at 1200px. At 375px, you need it to be closer to 2× to register the same way. Fluid scales handle this naturally if you set the floor and ceiling values correctly.
Fixing Breakpoint-Jump Typography
The old way of handling responsive typography was setting specific font sizes at specific breakpoints:
/* Old approach — fragile */
h1 { font-size: 3rem; }
@media (max-width: 768px) {
h1 { font-size: 2rem; }
}
@media (max-width: 480px) {
h1 { font-size: 1.5rem; }
}
The problem: each breakpoint override is a point of failure. You override the H2 size at tablet width for visual balance. You forget to check if that same override still makes sense at 375px. Now your H2 is smaller than intended on mobile, and nobody caught it until QA.
Fluid scales remove the breakpoint dependency entirely. One clamp() value handles all viewport widths — no override at 768px, no override at 480px. The type scales smoothly as the viewport changes, and there's no single breakpoint where the hierarchy jumps.
That said, breakpoints still matter for layout containers (column counts, margins, padding) — just not for type sizes. Keep your fluid type scale global and your layout breakpoints focused on spacing.
Container queries are the next evolution here. Instead of responding to the viewport width, container queries let a component's typography respond to its own container's width:
.card {
container-type: inline-size;
}
.card h2 {
font-size: clamp(1rem, 4cqi + 0.5rem, 1.5rem);
/* cqi = 1% of container's inline size */
}
A card that lives in a narrow sidebar will have smaller type than the same card in a full-width section — automatically, without a single breakpoint. Container query support is solid in all major browsers in 2026, and this is a genuine step forward for component-level hierarchy control.
Mobile Typography Checklist — 9 Checks Before You Ship
Before your next responsive design goes live, work through this checklist:
1. Body text is at least 16px. Both the Apple Human Interface Guidelines and Material Design 3 mandate 16px as the minimum body size for mobile readability. If you're using clamp(), set your floor at 1rem (16px at default browser settings).
2. Line height is 1.4–1.6× for body text, tighter for headings (1.1–1.3×). More generous leading compensates for narrower line lengths on mobile.
3. All paragraphs have max-width: 65ch. This keeps line length in the readable 45–75 character range regardless of container width. Without it, a paragraph at full mobile width runs too long.
4. Every type element uses clamp() with verified floor and ceiling. Test at 375px (small phone), 768px (tablet), and 1440px (desktop) before calling it done. Verify the heading-to-body ratio feels intentional at each size.
5. Contrast ratio is at least 4.5:1 for body text, 3:1 for large text. WCAG 2.2 is now enforced more strictly. Use the browser DevTools accessibility panel or a tool like WebAIM Contrast Checker to verify.
6. font-display: swap is set on all web fonts. This prevents Flash of Invisible Text (FOIT) on slow mobile connections. Without it, your hierarchy is invisible to users until the font loads — and on mobile, that's a real scenario.
7. text-size-adjust: auto is set on html. This property tells iOS not to override font sizing when users zoom into input fields. It's frequently missing, and it's a common cause of hierarchy-busting zoom behaviour on iPhones.
8. No maximum-scale=1 on elements. This prevents users from zooming on form fields — a violation of WCAG 2.1 Success Criterion 1.4.4 and a frustrating accessibility failure.
9. Your fluid scale is tested at 375px, 768px, and 1440px before handoff. Not just visually — check that heading levels are still distinguishable and the body is comfortable to read at each size.
How to Hand Off Your Typography System to Developers Without Losing It
The handoff is where most typography systems quietly fall apart. Here's what actually works.
Use CSS custom properties as your primary spec format. A token sheet with variable names is more actionable than a Figma styles panel. Here's a practical example of what to include:
:root {
--font-family-primary: 'Inter', sans-serif;
--font-family-heading: 'Fraunces', serif;
/* Type scale ratio */
--type-scale: 1.333; /* Perfect Fourth */
/* Fluid sizes */
--size-body: clamp(1rem, 0.5vw + 0.75rem, 1.125rem);
--size-h2: clamp(1.333rem, 1.5vw + 1rem, 1.875rem);
--size-h1: clamp(1.777rem, 3vw + 1rem, 3rem);
/* Supporting */
--line-height-body: 1.6;
--line-height-heading: 1.2;
--letter-spacing-heading: -0.02em;
}
The key principle: never spec a font size without also spec-ing the line-height that goes with it. These two properties are married — changing one without the other is the single most common way developers accidentally break hierarchy.
Include the min/max viewport widths your fluid scale was designed for. If you designed for 375px–1440px and someone applies the scale at 320px, the floor value kicks in and the scale feels cramped. A simple note — "designed for 375px–1440px" — prevents this.
Avoid "small heading" language. "Make the H3 smaller" is less actionable than "H3 should be 1.2× the body size, capped at 1rem." Be specific about the relationship, not just the size.
The Short Version
Good mobile typography isn't about squeezing desktop hierarchy into a smaller space. It's about making deliberate decisions for the mobile context:
Build a fluid type scale once and let it scale everywhere — no breakpoint overrides for font sizes.
Commit to 3 heading levels on mobile and design the relationships between them explicitly.
Test your hierarchy at 375px, not just at your design canvas width.
Hand off in CSS variables — not Figma screenshots or prose descriptions.
Do those four things and your mobile typography will hold up. It might even be better than your desktop version.
Author