Your Hero Looks Great at 1440px. Then Someone Opens 1897×812.
A field guide to fluid display typography, container queries and the wide-but-short viewport bugs that normal responsive testing misses.
Responsive design is often tested as a sequence of widths:
390 → 768 → 1024 → 1440 → 1920That model is useful, but incomplete.
A real interface also has height, browser chrome, zoom, font metrics, side panels and content constraints. A layout that looks perfect at 1920×1080 can break badly at 1897×812 even though the width barely changed.
This is especially common in creative portfolios where typography is intentionally large.
The trap: sizing local text with global viewport width
Imagine a project panel with a copy column that occupies roughly one third of the screen.
Then its title uses:
.project-title {
font-size: 7vw;
}
}At 1900 pixels wide, that produces a font size around 133 pixels.
But the title does not have 1900 pixels available. It might have only 430 pixels.
The font is scaling against the wrong coordinate system.
That is how a title such as:
Dev Notebecomes:
Dev
Noteor starts colliding with metadata below it.
Container units fix the coordinate system
Container query units let a component scale against its own available space.
.project-panel {
container-type: inline-size;
}
.project-title {
font-size: clamp(3.5rem, 12cqw, 7.5rem);
}Now the title responds to the panel instead of the browser window.
That is a much better model for reusable editorial components:
viewport → layout decides panel width → typography responds to panelinstead of:
viewport → typography guesses how much space the panel probably hasContainer units are not a replacement for clamp(). They make the middle value of clamp() more meaningful.
Width is not enough for cinematic layouts
Creative landing pages frequently use the full viewport height.
That means a viewport can be “desktop wide” but “laptop short.”
I treat this as its own responsive profile.
@media (min-width: 981px) and (max-height: 900px) {
.project-panel {
min-height: 78vh;
}
.project-title {
font-size: clamp(3.75rem, 10cqw, 6.5rem);
}
}This is not a random patch if height genuinely changes the composition.
The important distinction is whether the breakpoint corresponds to a layout mode or to a single screenshot.
“1897px needs 4px less padding” is a patch.
“Wide displays below 900px height need a denser editorial composition” is a layout rule.
white-space: nowrap is a contract
Preventing a heading from wrapping can be correct, but only when the surrounding layout agrees to make room for it.
.project-title {
white-space: nowrap;
}This says: the title is one visual unit.
Once you make that contract, you need a fallback strategy for small screens:
@media (max-width: 720px) {
.project-title {
white-space: normal;
max-width: 10ch;
}
}Intentional wrapping is good.
Accidental wrapping is the bug.
The difference is whether the break is part of the design system.
ch is useful, but it is not a magic measure of words
Designers often use:
max-width: 9ch;for display headings.
That can produce beautiful editorial shapes, but ch is based on the advance width of the 0 glyph. It does not mean “nine characters of any text will fit.”
W, M, punctuation and different font weights can vary dramatically.
For static copy, that variation can be art-directed manually.
For dynamic titles such as blog posts or case studies, a fixed ch width should be treated as a visual preference, not a guarantee.
I usually combine it with an actual layout constraint:
.case-title {
width: min(100%, 11ch);
text-wrap: balance;
}and test the longest realistic content.
Balance body headlines; compose display headlines
text-wrap: balance is excellent for medium-length headings.
.section-heading h2 {
max-width: 18ch;
text-wrap: balance;
}It helps avoid a final line containing one lonely word.
But giant hero typography often needs manual composition.
<h1>
<span>SELECTED</span>
<span>WORK</span>
</h1>In that case, the line break is part of the artwork. Letting the browser rebalance it would weaken the composition.
A useful distinction is:
- reading typography → let the browser help,
- display composition → control the lines deliberately.
Clipping can make good typography look broken
Large text is often placed inside masks for animation:
.title-line {
overflow: hidden;
}Then the glyph itself is translated during reveal.
This can accidentally cut off:
- ascenders,
- descenders,
- italic overshoot,
- text shadows,
- outline strokes,
- transformed glyph edges.
A tiny amount of mask padding often fixes the visual quality:
.title-mask {
overflow: hidden;
padding-inline: 0.04em;
margin-inline: -0.04em;
}The outer geometry stays aligned while the glyph gets breathing room.
This matters even more when GSAP is translating characters individually.
Do not let animation push important text outside the safe area
Suppose a hero title already fills almost the entire viewport width.
Then a scroll animation adds:
gsap.to(title, {
xPercent: -8,
scrollTrigger: { scrub: true },
});If the section also uses overflow: hidden, you have effectively designed intentional clipping.
Sometimes that is the goal. Often it is not.
For oversized typography I define a motion safe area separate from the layout safe area.
The title can occupy 96% of the viewport, but its animated travel may be limited to 2% in either direction.
That is enough to create movement without destroying legibility.
Test aspect ratios, not just devices
My responsive test matrix now includes shapes, not just widths:
390 × 844 — tall mobile
844 × 390 — landscape mobile
1024 × 768 — classic tablet
1366 × 768 — common laptop
1536 × 864 — laptop / desktop
1897 × 812 — wide and short
1920 × 1080 — standard desktop
2560 × 1440 — large desktopThe odd-looking entries are the useful ones.
They expose assumptions.
I also zoom the browser to 110% and 125%. A composition that survives moderate zoom is usually based on stronger constraints than one tuned to a single screenshot.
Responsive typography is geometry
Typography in an expressive interface is not a final coat of paint. It is one of the largest geometric systems on the page.
The most reliable approach is to make every size answer three questions:
- What space is this text actually allowed to use?
- Is the line break intentional or accidental?
- What happens when width and height change independently?
When those answers are encoded in the component instead of patched per screenshot, the design starts to feel much more resilient.
The goal is not to make the interface look identical everywhere.
The goal is to make the composition remain intentional everywhere.