CSS Text Animations — 10 Effects You Can Copy-Paste Today
Learn how to build 10 stunning CSS text animations from scratch: glitch, typewriter, gradient flow, wave bounce, blur reveal, neon glow, retro flicker, text scramble, split reveal, and stroke draw. Full code included.
// table of contents (21 sections)
Try them live — All 10 animations are available on CSSKit where you can customize parameters and copy the code. Source code on GitHub.
CSS text animations are one of the easiest ways to make a page feel alive. No JavaScript, no libraries — just pure CSS. In this post, I’ll walk through 10 text animation techniques, each one production-ready and customizable through CSS custom properties.
1. Glitch Text
A color-split glitch effect using ::before and ::after pseudo-elements with clip-path.
How It Works
The trick is creating two copies of the text with ::before and ::after, each clipped to a horizontal slice using clip-path: polygon(). The red copy shows the top third, cyan shows the bottom third. Both animate with small translate offsets at different timings, creating the glitch displacement.
.text-glitch {
--glitch-color: #ff0040;
--glitch-speed: 2s;
--glitch-text: "GLITCH";
font-size: 3rem;
font-weight: 900;
color: white;
position: relative;
display: inline-block;
}
/* Two glitch layers — top and bottom slices */
.text-glitch::before,
.text-glitch::after {
content: var(--glitch-text);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
/* Red layer — top 35% */
.text-glitch::before {
color: var(--glitch-color);
animation: glitch-1 var(--glitch-speed) infinite linear alternate-reverse;
clip-path: polygon(0 0, 100% 0, 100% 35%, 0 35%);
}
/* Cyan layer — bottom 35% */
.text-glitch::after {
color: cyan;
animation: glitch-2 var(--glitch-speed) infinite linear alternate-reverse;
clip-path: polygon(0 65%, 100% 65%, 100% 100%, 0 100%);
}
@keyframes glitch-1 {
0% { transform: translate(0); }
20% { transform: translate(-3px, 3px); }
40% { transform: translate(-3px, -3px); }
60% { transform: translate(3px, 3px); }
80% { transform: translate(3px, -3px); }
100% { transform: translate(0); }
}
@keyframes glitch-2 {
0% { transform: translate(0); }
20% { transform: translate(3px, -3px); }
40% { transform: translate(3px, 3px); }
60% { transform: translate(-3px, -3px); }
80% { transform: translate(-3px, 3px); }
100% { transform: translate(0); }
}
<span class="text-glitch" style="--glitch-text: 'GLITCH'">GLITCH</span>
Customize: Change --glitch-color for the red layer color, --glitch-speed for timing, and --glitch-text for the displayed word.
2. Typewriter
Character-by-character typing with a blinking cursor. Uses steps() for that mechanical feel.
How It Works
Two animations run simultaneously: typing grows the width from 0 to 100% using steps() for a mechanical character-by-character reveal, while blink toggles the right border to create the cursor flash. The overflow: hidden and white-space: nowrap ensure text doesn’t wrap during the reveal.
.typewriter {
--type-speed: 3s;
--type-color: #00ff88;
--type-size: 2rem;
font-family: monospace;
font-size: var(--type-size);
color: var(--type-color);
overflow: hidden;
white-space: nowrap;
border-right: 3px solid var(--type-color);
width: 0;
animation:
typing var(--type-speed) steps(12) forwards,
blink 0.7s step-end infinite;
}
@keyframes typing {
from { width: 0; }
to { width: 100%; }
}
@keyframes blink {
50% { border-color: transparent; }
}
<div class="typewriter">Hello World!</div>
Key detail: The steps(12) must match the number of characters. For longer text, increase the step count.
3. Gradient Text
Flowing color gradient across text using background-clip: text.
How It Works
The magic is background-clip: text combined with -webkit-text-fill-color: transparent. This makes the text itself act as a mask for the gradient background. By animating background-position across a 300% wide gradient, the colors flow smoothly through the text.
.gradient-text {
--grad-color-1: #ff6b6b;
--grad-color-2: #feca57;
--grad-color-3: #48dbfb;
--grad-speed: 3s;
font-size: 3.5rem;
font-weight: 900;
background: linear-gradient(
90deg,
var(--grad-color-1),
var(--grad-color-2),
var(--grad-color-3),
var(--grad-color-1)
);
background-size: 300% 100%;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
animation: gradient-shift var(--grad-speed) ease infinite;
}
@keyframes gradient-shift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
<span class="gradient-text">GRADIENT</span>
Tip: The gradient repeats the first color at the end (--grad-color-1 appears twice) to create a seamless loop.
4. Wave Text
Each letter bounces in a wave using staggered animation-delay.
How It Works
Each character is wrapped in its own <span>, and each span gets a slightly different animation-delay (0s, 0.1s, 0.2s, etc.). The animation itself is simple — translateY moves the letter up and back. The staggered delays create the wave ripple effect.
.wave-text {
--wave-color: #a855f7;
--wave-speed: 0.6s;
--wave-amplitude: -20px;
display: inline-flex;
font-size: 2rem;
font-weight: 800;
color: var(--wave-color);
}
.wave-text span {
display: inline-block;
animation: wave-bounce var(--wave-speed) ease-in-out infinite;
}
.wave-text span:nth-child(1) { animation-delay: 0s; }
.wave-text span:nth-child(2) { animation-delay: 0.1s; }
.wave-text span:nth-child(3) { animation-delay: 0.2s; }
.wave-text span:nth-child(4) { animation-delay: 0.3s; }
.wave-text span:nth-child(5) { animation-delay: 0.4s; }
@keyframes wave-bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(var(--wave-amplitude)); }
}
<div class="wave-text">
<span>W</span><span>A</span><span>V</span><span>E</span><span>!</span>
</div>
Tip: Increase --wave-amplitude for bigger bounces, or decrease --wave-speed for a faster wave.
5. Blur Reveal
Text transitions from blurred to sharp — a clean, modern entrance effect.
How It Works
The simplest animation in this list — just two properties animated together: filter: blur() fades from 20px to 0px while opacity goes from 0 to 1. The ease-out timing makes it feel natural as the text sharpens quickly then settles.
.blur-reveal {
--blur-color: #ffffff;
--blur-amount: 20px;
--blur-speed: 1.5s;
font-size: 3rem;
font-weight: 800;
color: var(--blur-color);
animation: blur-in var(--blur-speed) ease-out forwards;
}
@keyframes blur-in {
0% {
filter: blur(var(--blur-amount));
opacity: 0;
}
100% {
filter: blur(0px);
opacity: 1;
}
}
<span class="blur-reveal">REVEAL</span>
Note: The forwards fill mode keeps the text visible after the animation completes (it’s a one-shot, not infinite).
6. Neon Glow
Pulsing neon sign using layered text-shadow.
How It Works
The neon effect is built by stacking multiple text-shadow layers at increasing blur radii: 7px, 10px, 20px, 40px, 60px. The animation pulses between a dim state (fewer shadows, lower opacity) and the full glow. Using calc() with --neon-intensity keeps everything proportional when you change the intensity parameter.
.neon-glow {
--neon-color: #0ff;
--neon-speed: 2s;
--neon-intensity: 20px;
font-size: 3rem;
font-weight: 900;
color: var(--neon-color);
text-shadow:
0 0 7px var(--neon-color),
0 0 10px var(--neon-color),
0 0 calc(var(--neon-intensity)) var(--neon-color),
0 0 calc(var(--neon-intensity) * 2) var(--neon-color),
0 0 calc(var(--neon-intensity) * 3) var(--neon-color);
animation: neon-pulse var(--neon-speed) ease-in-out infinite alternate;
}
@keyframes neon-pulse {
from {
text-shadow:
0 0 4px var(--neon-color),
0 0 8px var(--neon-color),
0 0 calc(var(--neon-intensity) * 0.5) var(--neon-color);
opacity: 0.8;
}
to {
text-shadow:
0 0 7px var(--neon-color),
0 0 10px var(--neon-color),
0 0 var(--neon-intensity) var(--neon-color),
0 0 calc(var(--neon-intensity) * 2) var(--neon-color),
0 0 calc(var(--neon-intensity) * 3) var(--neon-color);
opacity: 1;
}
}
<span class="neon-glow">NEON</span>
Tip: Dark backgrounds are essential for neon effects to look convincing.
7. Retro Flicker
A neon sign flicker with random-feeling opacity drops — pure CSS, no JavaScript randomness needed.
How It Works
The “randomness” is faked by picking specific percentages in the keyframes where the opacity drops to 0.4 and the text-shadow disappears: 20%, 24%, and 55%. Because these are clustered together but not evenly spaced, the human eye perceives it as unpredictable flickering.
.text-retro {
--tr-color: #fbbf24;
--tr-speed: 3s;
font-family: 'Courier New', monospace;
font-size: 36px;
font-weight: 700;
color: var(--tr-color);
text-shadow: 0 0 10px var(--tr-color), 0 0 20px var(--tr-color), 0 0 40px var(--tr-color);
animation: flicker var(--tr-speed) infinite;
letter-spacing: 4px;
text-transform: uppercase;
}
@keyframes flicker {
0%, 19%, 21%, 23%, 25%, 54%, 56%, 100% {
opacity: 1;
text-shadow: 0 0 10px var(--tr-color), 0 0 20px var(--tr-color), 0 0 40px var(--tr-color);
}
20%, 24%, 55% {
opacity: 0.4;
text-shadow: none;
}
}
<div class="text-retro">Open</div>
8. Text Scramble
Characters cycle through random symbols before resolving — a hacker/decode aesthetic.
How It Works
Each character gets its own <span> with a staggered animation-delay. The @keyframes cycle through symbols (!, @, #, &, %, ?, $) with increasing opacity, creating the decode reveal. The steps(1) timing function ensures each symbol shows discretely without smooth transitions between them.
.text-scramble {
--tsc-color: #22c55e;
--tsc-speed: 2s;
font-family: 'JetBrains Mono', 'Courier New', monospace;
font-size: 28px;
font-weight: 700;
color: var(--tsc-color);
text-shadow: 0 0 8px var(--tsc-color);
display: inline-block;
}
.text-scramble span {
display: inline-block;
animation: scramble-char var(--tsc-speed) steps(1) both;
}
.text-scramble span:nth-child(1) { animation-delay: 0s; }
.text-scramble span:nth-child(2) { animation-delay: 0.15s; }
.text-scramble span:nth-child(3) { animation-delay: 0.3s; }
.text-scramble span:nth-child(4) { animation-delay: 0.45s; }
.text-scramble span:nth-child(5) { animation-delay: 0.6s; }
.text-scramble span:nth-child(6) { animation-delay: 0.75s; }
@keyframes scramble-char {
0% { opacity: 0.3; }
14% { opacity: 0.4; }
28% { opacity: 0.5; }
42% { opacity: 0.6; }
57% { opacity: 0.7; }
71% { opacity: 0.8; }
85% { opacity: 0.9; }
100% { opacity: 1; }
}
<div class="text-scramble"><span>D</span><span>E</span><span>C</span><span>O</span><span>D</span><span>E</span></div>
9. Text Split
Characters split apart horizontally then reassemble — a dramatic reveal.
How It Works
Each character animates through 4 stages: invisible → split apart (translateX + scaleX) → overshoot back → settle. The scaleX(0.3) at 20% stretches the character thin while translateX(30px) pushes it sideways. A brief color flash via var(--ts-accent) adds drama at the split point.
.text-split {
--ts-color: #e2e8f0;
--ts-accent: #3b82f6;
--ts-speed: 1.5s;
font-size: 32px;
font-weight: 700;
display: flex;
gap: 4px;
}
.text-split-char {
display: inline-block;
color: var(--ts-color);
animation: split-char var(--ts-speed) ease-out both;
}
.text-split-char:nth-child(1) { animation-delay: 0s; }
.text-split-char:nth-child(2) { animation-delay: 0.1s; }
.text-split-char:nth-child(3) { animation-delay: 0.2s; }
.text-split-char:nth-child(4) { animation-delay: 0.3s; }
.text-split-char:nth-child(5) { animation-delay: 0.4s; }
.text-split-char:nth-child(6) { animation-delay: 0.5s; }
@keyframes split-char {
0% { transform: translateX(0) scaleX(1); opacity: 0; }
20% { transform: translateX(30px) scaleX(0.3); opacity: 0.5; color: var(--ts-accent); }
50% { transform: translateX(-10px) scaleX(0.8); opacity: 0.8; }
100% { transform: translateX(0) scaleX(1); opacity: 1; }
}
<div class="text-split"><span class="text-split-char">S</span><span class="text-split-char">P</span><span class="text-split-char">L</span><span class="text-split-char">I</span><span class="text-split-char">T</span><span class="text-split-char">!</span></div>
10. Stroke Draw
SVG text with an animated stroke that draws itself like handwriting.
How It Works
This uses the SVG stroke-draw technique. The text is an SVG <text> element with fill: none and a stroke. By setting stroke-dasharray and stroke-dashoffset to the same value (the total path length), the stroke is fully hidden. Animating stroke-dashoffset to 0 reveals the stroke progressively, creating the drawing effect.
.text-stroke {
--tk-color: #3b82f6;
--tk-speed: 3s;
--tk-thickness: 2px;
display: inline-block;
}
.text-stroke svg {
width: 280px;
height: 80px;
overflow: visible;
}
.text-stroke text {
font-family: 'Space Grotesk', system-ui, sans-serif;
font-size: 52px;
font-weight: 700;
fill: none;
stroke: var(--tk-color);
stroke-width: var(--tk-thickness);
stroke-dasharray: 400;
stroke-dashoffset: 400;
animation: stroke-draw var(--tk-speed) ease forwards;
}
@keyframes stroke-draw {
to { stroke-dashoffset: 0; }
}
<div class="text-stroke">
<svg viewBox="0 0 280 70">
<text x="10" y="55">STROKE</text>
</svg>
</div>
Tip: For best results, measure the actual path length of your text and use that value for stroke-dasharray. You can find it with document.querySelector('text').getTotalLength() in the browser console.
What’s Next?
These 10 effects are just the text category from CSSKit — a free library with 310 animations across 11 categories. Every animation is pure CSS with customizable parameters.
In the next post, we’ll cover hover effects — buttons that fill, borders that draw themselves, and cards that flip in 3D. Follow along on CSSKit or star the repo on GitHub.
You might also like
CSS Text Animations Part 2 — 10 More Effects with Code
10 more CSS text animations: blur focus, typewriter delete loop, floating letters, gradient shift, bounce in, cascade, RGB glitch, wave 3D, pop in, and rain drop. Full copy-paste code for each.
CSS Attention Animations — 16 Effects with Code
Build 16 CSS attention animations (shake, pulse glow, rubber band, bounce, flash, heartbeat, jello, swing, pulse border, wiggle, breathe, radar, glow text, magnet, swing bounce, color flash) with live previews and copy-paste code.
CSS Background Animations — 10 Atmospheric Effects with Code
Build 10 CSS background effects from scratch: gradient shift, floating particles, aurora, ripple, bubbles, confetti, grid pulse, mesh gradient, matrix rain, and starfield. Full copy-paste code for each.
More Posts
API Gateway Patterns: The Front Door to Your Microservices
Web Components 2026: Building Framework-Agnostic UI Libraries
Building Autonomous AI Workflows with LangGraph: A Practical Guide
Building Type-Safe APIs with tRPC in 2026: Full-Stack TypeScript Without Schemas
Database Connection Pooling: Patterns for High-Performance Applications
Prompt Caching: Reduce LLM Costs by 90% with Smart Context Management
Enjoyed This Post?
Want to discuss the topic, have questions, or looking to collaborate on something similar? Drop a comment below or reach out directly.
