Mobile Typography: How to Proportionally Scale H1–H6 Tags Without Breaking Your Visual Hierarchy

Mobile Typography: How to Proportionally Scale H1–H6 Tags Without Breaking Your Visual Hierarchy

You push your site live, pull it up on your phone, and your beautiful H1 hero headline is eating half the screen. You shrink it with a media query. Now it looks fine — but your H2 and H3 are nearly identical in size. The visual hierarchy you spent hours building on desktop has completely collapsed on mobile. Your H4 and H5 are indistinguishable from each other, and nothing reads like a clear content structure anymore.

This is one of those problems that’s easy to dismiss as a minor visual detail. It’s not. When heading hierarchy breaks down, readers lose their scanning anchors. They can’t tell at a glance what’s a section title versus a sub-point. Engagement drops, time-on-page shrinks. I’m Rohan Ratnayake, and I’ve spent the last 5 years working as a front-end UI engineer specializing in responsive type systems for content-heavy web products — think editorial platforms, SaaS docs, and news sites. I’ve watched this heading collapse problem kill otherwise solid mobile experiences more times than I can count. The fix isn’t just “make the H1 smaller.” It’s rebuilding your entire heading scale to stay proportional across every screen width, not just at two breakpoints.

The mistake I learned the hard way: I once spent two days perfecting a desktop heading system for a client’s editorial platform using a tight modular scale, only to hand off CSS with a single @media block that just subtracted 12px from H1. The mobile editor flagged it immediately — “the H2 and H3 look the same size on my phone.” She was right. I’d fixed the symptom, not the system. This article gives you the framework I’ve used every time since.


Why “Just Add a Media Query” Doesn’t Actually Work

Most tutorials tell you to write a desktop style, then override it with a mobile media query. Simple. The problem is that approach gives you two static type scales — one for large screens and one for small — with a hard jump between them. Pull your browser window to a mid-size tablet width and everything looks wrong. Beyond that, when you only adjust H1, you’re not adjusting the ratios between heading levels. The proportional relationship between H1 and H2, H2 and H3, and so on is what creates hierarchy. Break those ratios and the whole structure reads flat.

ALSO READ:  CSS clamp() Explained: Write Zero Media Queries and Still Get Perfect Fluid Typography

Here’s what a typical broken approach looks like versus the problem it causes:

What Most Developers DoWhat Actually Happens on Mobile
Set H1 to 48px desktop, override to 28px mobileH2 at 36px desktop is now visually similar to the adjusted H1
Only add media query for H1H2–H6 never get adjusted, hierarchy collapses
Use vw units alone on headingsHeadings shrink to unreadable sizes on narrow screens
Hard breakpoint at 768pxHeading sizes jump abruptly, no smooth scaling

The root issue is treating heading size as an isolated property rather than a relational system.


The Concept of a Modular Type Scale (And Why It’s Your Starting Point)

A modular type scale means every heading size is calculated by multiplying a base size by a consistent ratio. On desktop, designers typically use a ratio somewhere between 1.25 (Major Third) and 1.414 (Augmented Fourth). On mobile, you need a tighter ratio — usually 1.2 or even 1.125 — because you have less horizontal space to create visual weight distinctions.

Here’s a concrete comparison. If your base is 1rem (16px) and you’re using the Major Third ratio (×1.25) for desktop versus a Minor Third (×1.2) for mobile:

Heading LevelDesktop (×1.25 ratio)Mobile (×1.2 ratio)
H148.83px (≈3.05rem)29.86px (≈1.87rem)
H239.06px (≈2.44rem)24.88px (≈1.55rem)
H331.25px (≈1.95rem)20.74px (≈1.30rem)
H425px (≈1.56rem)17.28px (≈1.08rem)
H520px (≈1.25rem)16px (≈1rem)
H616px (1rem)14px (≈0.875rem)

Notice that both scales maintain distinct visual separation between levels. That’s the point. You’re not just making things smaller — you’re rebuilding the proportional ladder for a narrower canvas. A tool like Modular Scale lets you generate these values instantly by picking a base and ratio.


clamp() Is the Real Solution — Here’s How to Use It on Headings

Manually managing two static scales still means a hard visual jump at your breakpoint. The CSS clamp() function lets your heading sizes scale fluidly between a minimum and maximum value based on viewport width — no media query required for the size transition itself.

ALSO READ:  Web Fonts for Dyslexia: The Letterform Guide Designers Actually Need

The syntax is: font-size: clamp(minimum, preferred, maximum);

The preferred value is typically a vw unit — viewport width percentage. This is what makes it fluid. But raw vw alone is dangerous because on very narrow screens it can drop below readable size, and on very wide screens it gets enormous. clamp() caps both ends.

Here’s a production-ready heading scale using clamp():

h1 { font-size: clamp(1.75rem, 5vw + 1rem, 3rem); }
h2 { font-size: clamp(1.5rem, 4vw + 0.75rem, 2.25rem); }
h3 { font-size: clamp(1.25rem, 3vw + 0.5rem, 1.875rem); }
h4 { font-size: clamp(1.1rem, 2.5vw + 0.4rem, 1.5rem); }
h5 { font-size: clamp(1rem, 2vw + 0.3rem, 1.25rem); }
h6 { font-size: clamp(0.875rem, 1.5vw + 0.25rem, 1rem); }

The vw + rem pattern inside the preferred value (sometimes called a “responsive fluid formula”) is key. The rem component acts as a floor booster so sizes don’t compress too aggressively on narrow widths. You can read through the MDN documentation on clamp() for full browser support details — it’s been solid across all major browsers since 2020.


Maintaining Visual Distance Between Heading Levels on Small Screens

Here’s what catches people off guard even after they implement clamp() correctly: H4, H5, and H6 tend to converge on small screens because there’s not much range to work with below H3. If your H4 minimum lands at 1.1rem and H5 minimum lands at 1rem, those are 1.6px apart at 16px base size. A reader can’t tell them apart.

Two practical ways to handle this:

  • Use weight as a differentiator. Keep H4 at medium weight (500–600) and drop H5 to regular weight (400). This creates separation without needing size differences.
  • Use letter-spacing. H5 and H6 with slightly increased letter-spacing (0.02em–0.05em) read as visually subordinate even when the size gap is tiny.
  • Question whether you need H5 and H6 at all on mobile. In most content, H4 is already a deep sub-level. If H5 and H6 exist in your markup, make sure they’re doing meaningful structural work, not just visual decoration.
HeadingMobile Size StrategyDifferentiation Method
H1Large clamp max, strong visual anchorSize + weight (700–900)
H2Clear step down from H1Size + weight (600–700)
H3Readable but subordinate to H2Size + weight (500–600)
H4Tight gap from H3, needs helpSize + medium weight (500)
H5Near base sizeWeight (400) + letter-spacing
H6At or near base sizeLight weight + uppercase or tracking

CSS Custom Properties for a Maintainable System

Hard-coding six separate clamp() values works, but maintaining them across a large project is tedious. A cleaner approach uses CSS custom properties as a type scale token system:

:root {
  --step-0: clamp(0.875rem, 1.5vw + 0.25rem, 1rem);
  --step-1: clamp(1rem, 2vw + 0.3rem, 1.25rem);
  --step-2: clamp(1.1rem, 2.5vw + 0.4rem, 1.5rem);
  --step-3: clamp(1.25rem, 3vw + 0.5rem, 1.875rem);
  --step-4: clamp(1.5rem, 4vw + 0.75rem, 2.25rem);
  --step-5: clamp(1.75rem, 5vw + 1rem, 3rem);
}

h6 { font-size: var(--step-0); }
h5 { font-size: var(--step-1); }
h4 { font-size: var(--step-2); }
h3 { font-size: var(--step-3); }
h2 { font-size: var(--step-4); }
h1 { font-size: var(--step-5); }

Now when a client asks you to tighten the mobile type scale, you change six values in one place. Every heading updates. This also makes design tokens trivial to pass from a design system into your CSS.

ALSO READ:  Dark Mode Typography: The Exact WCAG Contrast Math Your Text Needs to Pass

Testing Your Heading Scale — The Real Checklist

Implementing the scale is step one. Verifying it holds up under real conditions is where most developers skip corners.

Things to test specifically for heading hierarchy on mobile:

  • Resize Chrome DevTools from 320px to 428px to 768px. Watch for any two adjacent heading levels that look the same size at any breakpoint.
  • Check nesting. Drop an H3 inside a section that already has an H2 and H1 above it. On a 375px screen, is the visual ladder still readable?
  • Test on an actual device, not just a simulator. Screen rendering, subpixel aliasing, and OS font scaling can make the same CSS look slightly different than DevTools suggests.
  • Check dark/light mode. Font weight renders differently on dark backgrounds — what looks bold in light mode can look heavier in dark mode, affecting perceived size differences between heading levels.

FAQs

Can I use vw units directly on heading font sizes without clamp()?

You can, but it’s risky. Raw vw means there’s no floor, so on a 320px screen an H1 set to 5vw renders at 16px — same as body text. Always wrap vw-based sizes in clamp() to set a readable minimum.

Should I use rem or px for the min and max values inside clamp()?

Use rem. If a user has changed their browser’s default font size for accessibility reasons, rem values respect that preference. px values don’t, which can create accessibility problems for users who rely on browser font scaling.

What if my CMS outputs H-tags and I can’t control which levels get used?

This is common with WordPress or Contentful content. Your safest move is to write your heading CSS to be visually correct regardless of nesting depth — meaning even if an editor drops an H2 directly after an H1 on the same screen section, the size distinction is still clear. The clamp() approach handles this well because it creates consistent relative sizing independent of context.


Wrapping Up

The core tension here is simple: desktop heading sizes are designed for wide canvases with room to breathe, but mobile screens compress everything — and static media query overrides don’t preserve the proportional relationships that make visual hierarchy actually work.

The practical path forward: build a fluid modular scale using clamp() with a tighter ratio for narrow screens, use CSS custom properties to keep it maintainable, and lean on font weight and letter-spacing to create separation between H4–H6 where size alone isn’t enough. Then test it at real viewport widths on a real device.

If you’re starting from scratch, generate your scale values at Modular Scale, convert them to clamp() formulas using the preferred = vw + rem pattern above, and drop them into your root token set. That single afternoon of work will save you from media query patches for the life of the project.