CSS Text Animations: Typewriter, Gradient Sweep, Reveal and More
Master CSS text animations in 2026 — typewriter effects, gradient sweeps, and cinematic reveals with clean, copy-paste code examples you'll actually use.
Why Text Animations Are Having a Moment Right Now
Scroll through any design-forward site in 2026 and you'll notice one thing immediately — the text is moving. Not in a chaotic, early-2000s marquee tag way. Purposefully. Kinetically. In a way that makes you stop.
The reason is partly technical. CSS has caught up to what designers have been asking for since at least 2018. @keyframes, clip-path, background-clip: text, and CSS custom properties now combine to let you build animations that previously required canvas or a heavy JS library.
Honestly, most of the flashy text effects you see on award-winning sites are 20-40 lines of CSS. That's it. No Three.js. No GSAP license. Just cascade and keyframes. If you've been putting this off, stop.
That said, text animation done badly destroys readability and tanks your Core Web Vitals. The goal here is to show you the patterns that look great and perform well — not just the ones that look impressive in a CodePen.
The Typewriter Effect: Still Effective, Often Misused
The typewriter effect has been around forever, but people keep botching it. The classic approach uses steps() on width with a matching overflow: hidden — works great for monospace fonts where every character is exactly the same width.
Here's a clean version you can drop straight into a project:
.typewriter {
font-family: 'Courier New', monospace;
font-size: 1.5rem;
white-space: nowrap;
overflow: hidden;
border-right: 2px solid currentColor;
width: 0;
animation:
typing 2.4s steps(30, end) forwards,
blink 0.75s step-end infinite;
}
@keyframes typing {
to { width: 30ch; }
}
@keyframes blink {
0%, 100% { border-color: transparent; }
50% { border-color: currentColor; }
}The steps(30, end) value needs to match your character count — 30 characters, 30 steps. Get that wrong and the animation either finishes too early or keeps going past the text. Worth noting: this breaks badly with variable-width fonts. You'll want to either stick to monospace or use a JS-driven approach for proportional typefaces.
One more thing — if you're building in React, wrap this in a component that resets the animation on remount. Otherwise users who navigate away and back won't see the effect again, which is just sad.
Gradient Sweep Text: The Effect Everyone Wants
Gradient text is everywhere. Done right, it's beautiful. Done wrong, it looks like a 2019 Instagram Stories template. The secret is motion — a static gradient is fine, but an animated sweep is what makes people screenshot your landing page.
The technique relies on three properties working together: background-clip: text, color: transparent, and an animated background-position. You set the background wider than the element — typically 200% — then slide it across.
.gradient-sweep {
font-size: 3rem;
font-weight: 800;
background: linear-gradient(
90deg,
#6366f1,
#a855f7,
#ec4899,
#6366f1
);
background-size: 200% auto;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
animation: sweep 3s linear infinite;
}
@keyframes sweep {
to { background-position: 200% center; }
}In practice, the -webkit-background-clip prefix still matters in 2026 for Safari. Don't drop it. The standard background-clip: text alone will leave you with a support ticket from your marketing team about the Mac demo.
If you want to push further with these effects, the glassmorphism generator on Empire UI lets you experiment with color combinations and export ready-to-use CSS — useful for finding a palette before you commit to code.
Reveal Animations: Clip-Path is Your Best Friend
Reveal effects — where text appears to slide up from below or wipe in from one side — are cinematic without being distracting. They work because they mimic how print design has used masks for decades. CSS clip-path is the modern equivalent.
The key insight: you're not moving the text, you're moving the visible window around it. The text is already in its final position; you're just hiding parts of it.
.reveal-up {
display: inline-block;
clip-path: inset(100% 0 0 0);
animation: revealUp 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
animation-delay: 0.2s;
}
@keyframes revealUp {
to { clip-path: inset(0% 0 0 0); }
}That cubic-bezier(0.16, 1, 0.3, 1) is an ease-out spring curve — fast start, gentle land. It feels physical. The default ease looks cheap next to it, especially on headings above 48px.
Quick aside: stagger these when you have multiple lines. A 0.1s delay between each line turns a plain heading into something that feels like a theatrical moment. You can do this cleanly in React with index-based animation-delay on a mapped array.
Shimmer, Glitch, and Blur Effects Worth Knowing
Beyond the big three, there's a set of text effects that show up constantly in UI-forward projects. Shimmer (a light sweep over solid text), glitch (RGB offset flicker), and blur-in (text materialising from focus) each solve a different vibe.
Shimmer is just a gradient sweep on a ::before or ::after pseudo-element with mix-blend-mode: overlay. Glitch effects abuse text-shadow with offset copies in red and cyan, flickering via @keyframes with random clip regions. The blur-in is the simplest: filter: blur(8px) to filter: blur(0) with a simultaneous opacity fade.
For components that take these effects seriously and pre-package them for production use, browse the components on Empire UI — there are animated typography components that handle the edge cases you'd otherwise spend an afternoon discovering.
Look, you could reinvent each of these from scratch. But shimmer effects in particular have a dozen gotchas around will-change, GPU compositing, and performance on low-end Android devices. Using a tested component for anything that'll be above the fold is just rational.
Performance and Accessibility You Can't Ignore
Animated text is an accessibility minefield if you're not careful. Users with vestibular disorders can trigger nausea from motion-heavy UI. The prefers-reduced-motion media query exists for exactly this reason — and using it isn't optional if you care about inclusive design.
@media (prefers-reduced-motion: reduce) {
.typewriter,
.gradient-sweep,
.reveal-up {
animation: none;
clip-path: none;
color: inherit;
background: none;
-webkit-background-clip: unset;
background-clip: unset;
}
}On the performance side: animate opacity, transform, and clip-path — these are composited by the browser and don't trigger layout. Animating width (like old-school typewriter code) forces reflow on every frame, which will hurt on long text or slower devices.
Add will-change: transform sparingly — it promotes an element to its own GPU layer, which is great for complex animations but wasteful if applied wholesale. One element per animation group is usually enough. And if you're stacking multiple text animations on a single page, profile it in Chrome DevTools with CPU throttled to 4x before shipping.
Combining Effects for a Signature Look
The real magic happens when you combine these techniques. A heading that reveals up, then has a gradient sweep running across it, then settles — that's a three-act micro-story told in 800ms. You can chain animations using comma-separated values in the animation property.
If you're working in a design system context, think of these as composable primitives. A data-animate attribute that maps to a set of predefined keyframe combinations scales much better than one-off inline styles per component. The gradient generator can help you nail the color story before you wire up the motion.
That said, restraint is a feature. One hero text with full-motion treatment. Supporting copy that maybe just fades in at 300ms. Navigation that doesn't move at all. The contrast between animated and static elements is what makes the animated parts land. If everything moves, nothing moves.
For inspiration on how animation combines with visual style, look at how glassmorphism components handle layered motion — it's a useful mental model for keeping text animation from fighting the rest of your UI rather than complementing it.
FAQ
Yes, with the caveat that you still need -webkit-background-clip: text alongside the standard property for Safari. All major browsers support background-clip: text now, but dropping the prefix will break on WebKit without warning.
Only if you animate layout-triggering properties like width or font-size. Stick to opacity, transform, and clip-path — those are GPU-composited and won't affect your CLS or LCP scores.
The cleanest pattern is a useEffect that toggles a CSS class after mount, so the animation resets on each component lifecycle. Alternatively, update the animation with a key prop change to force a remount when the text content changes.
For one-off hero sections, scratch is fine. For a design system or component library, pre-built animations save significant time on edge cases around performance and accessibility that aren't obvious until you're already in production.