Text Mask Reveal
Every landing page opening wants this, and almost every AI-generated version clips the descenders off the letters. The fix is two lines of CSS that nobody writes down.
Live demo
Typography that earns attention
Watch the descender on the “g” — it is not clipped.
The prompt
Animate a large headline so each line slides up from behind a hard edge on page load. Structure: - Wrap every line of the headline in its own span with display: block and overflow: hidden. Put the actual text in a nested span that will be translated. - Give each inner span a CSS variable --i (0, 1, 2...) used as animation-delay: calc(var(--i) * 90ms). Motion: - Inner span starts at transform: translateY(115%) and animates to translateY(0) over 900ms with cubic-bezier(.22, 1, .36, 1). - Use animation-fill-mode: forwards. Critical detail — do not skip this: - The inner span must have padding-bottom: 0.12em and margin-bottom: -0.12em. Without it, overflow: hidden on the parent clips the descenders of g, y, p, j and the text looks broken. - Use translateY(115%) rather than 100% so the baseline clears the mask edge during the first frames. Constraints: - Only animate transform. Never animate line-height, font-size or margin. - Respect prefers-reduced-motion: show the headline immediately, no animation. - The text must remain real text in the DOM (not an image, not split into per-character spans) so it stays selectable and indexable.
What actually makes it work
- The mask is a clipping box, not a fade.
overflow: hiddenon a block-level wrapper creates a hard horizontal edge. Sliding the child up from below that edge reads as the text emerging from solid ground — far cleaner than animating opacity. - The descender fix. This is the detail AI output almost always omits.
overflow: hiddenclips at the content box, so the tails of g, y, p and j get sliced. Addingpadding-bottom: 0.12emextends the box downward andmargin-bottom: -0.12empulls the layout back so nothing shifts. The clipped area is now empty padding instead of letterforms. - 115%, not 100%. At exactly 100% the glyphs sit flush against the mask edge and you see a hairline of the top serif during the first frame. The extra 15% clears it.
- Stagger is what sells it. All three lines at once looks like a slide transition. 90ms apart reads as deliberate typesetting.
Compatibility and performance
| Aspect | Detail |
|---|---|
| Browser support | Universal. Overflow clipping and transforms have worked everywhere for a decade. |
| Cost | Compositor-only. A handful of layers for under a second. |
| Cumulative layout shift | None, provided the negative margin matches the padding. |
The one thing to watch is that overflow: hidden creates a new formatting context. If a line contains a tooltip or a dropdown that needs to escape the box, it will be clipped too. In that case animate the whole block instead of individual lines.
When not to use it
Don't apply it to body copy. This is a display-type effect. On a paragraph it makes reading feel like waiting.
Don't delay the headline past ~600ms. People decide whether to stay before your animation finishes. The first line should be readable almost immediately — which is why the stagger starts at 0ms, not after a 400ms lead-in.
Don't replicate it on every section. Once per page, at the top. Repeating it turns an entrance into a tic.