Skip to content
· 12 min read · 0 views

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.

// 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. See also Part 1 — 10 CSS Text Effects.


In Part 1 we covered glitch, typewriter, gradient, wave, blur reveal, neon, retro, scramble, split, and stroke animations. This post continues with 10 more text effects — from cinematic blur-to-focus reveals to cyberpunk RGB glitch. All pure CSS, all customizable through CSS custom properties.

11. Blur to Focus

A cinematic text reveal — starts fully blurred and smoothly sharpens into crystal clarity.

How It Works

The animation combines three properties for a cinematic feel: filter: blur() goes from 12px to 0, opacity fades in from 0 to 1, and transform: scale() subtly shrinks from 1.05 to 1. The ease-out timing makes the sharpening feel fast at the start then gently settles. The forwards fill mode keeps the final state visible — this is a one-shot entrance, not a loop.

.text-blur-focus {
  --tbf-color: #1e293b;
  --tbf-speed: 1.5s;
  color: var(--tbf-color);
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  filter: blur(12px);
  opacity: 0;
  animation: tbf-focus var(--tbf-speed) ease-out forwards;
}

@keyframes tbf-focus {
  0% {
    filter: blur(12px);
    opacity: 0;
    transform: scale(1.05);
  }
  50% {
    opacity: 0.6;
  }
  100% {
    filter: blur(0px);
    opacity: 1;
    transform: scale(1);
  }
}
<div class="text-blur-focus">Focus</div>

Tip: Use a light color like #ffffff on a dark background for maximum cinematic impact. Increase --tbf-speed to 3s for a slower, more dramatic reveal.


12. Typewriter Delete Loop

Types text character by character, then deletes and retypes in a continuous loop — the classic terminal effect.

How It Works

This builds on the typewriter from Part 1 but adds a delete phase using alternate direction. The width animates from 0 to 10ch (typing) then back to 0 (deleting) using steps(10) for mechanical precision. The infinite alternate creates the endless type-delete loop. A second animation handles the blinking cursor with a step-end timing for instant on/off.

.text-typewriter-delete {
  --ttd-color: #10b981;
  --ttd-speed: 3s;
  color: var(--ttd-color);
  font-size: 1.5rem;
  font-family: monospace;
  border-right: 2px solid var(--ttd-color);
  white-space: nowrap;
  overflow: hidden;
  width: 10ch;
  animation: ttd-type var(--ttd-speed) steps(10) infinite alternate,
             ttd-cursor 0.5s step-end infinite alternate;
}

@keyframes ttd-type {
  0% { width: 0; }
  50% { width: 10ch; }
  100% { width: 0; }
}

@keyframes ttd-cursor {
  0% { border-color: var(--ttd-color); }
  50% { border-color: transparent; }
}
<div class="text-typewriter-delete">hello world</div>

Key detail: The width: 10ch must match the character count. For “hello world” (11 chars including space), use width: 11ch and steps(11).


13. Floating Letters

Each letter gently floats up and down in a wave — playful and airy.

How It Works

Each character gets its own <span> with a staggered animation-delay (0s, 0.1s, 0.2s, etc.). The animation is a simple translateY bounce — the staggered delays create the floating wave. The calc(-1 * var(--tf-distance)) in the keyframe lets you control the float height with a single CSS variable.

.text-float {
  --tf-color: #6366f1;
  --tf-speed: 2s;
  --tf-distance: 8px;
  color: var(--tf-color);
  font-size: 2rem;
  font-weight: 700;
  display: flex;
  gap: 2px;
}

.text-float span {
  display: inline-block;
  animation: tf-float var(--tf-speed) ease-in-out infinite;
}

.text-float span:nth-child(1) { animation-delay: 0s; }
.text-float span:nth-child(2) { animation-delay: 0.1s; }
.text-float span:nth-child(3) { animation-delay: 0.2s; }
.text-float span:nth-child(4) { animation-delay: 0.3s; }
.text-float span:nth-child(5) { animation-delay: 0.4s; }

@keyframes tf-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(calc(-1 * var(--tf-distance))); }
}
<div class="text-float"><span>F</span><span>l</span><span>o</span><span>a</span><span>t</span></div>

Tip: Increase --tf-distance to 16px for bigger floats, or speed it up with --tf-speed: 1s for a more energetic wave.


14. Gradient Shift

Animated gradient colors flow continuously across the text — eye-catching and modern.

How It Works

This is the same background-clip: text technique from Part 1’s Gradient Text, but simpler — just two colors instead of three. The gradient is 200% wide, and background-position animates from 0% to 200% with linear timing for a constant-speed color flow. The first color repeats at the end of the gradient for a seamless loop.

.text-gradient-shift {
  --tgs-color1: #f43f5e;
  --tgs-color2: #8b5cf6;
  --tgs-speed: 3s;
  font-size: 2.5rem;
  font-weight: 800;
  background: linear-gradient(90deg, var(--tgs-color1), var(--tgs-color2), var(--tgs-color1));
  background-size: 200% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: tgs-shift var(--tgs-speed) linear infinite;
}

@keyframes tgs-shift {
  0% { background-position: 0% 50%; }
  100% { background-position: 200% 50%; }
}
<div class="text-gradient-shift">Gradient</div>

Tip: Try #ff6b6b and #feca57 for a warm sunset vibe, or #3b82f6 and #8b5cf6 for a cool purple-blue.


15. Bounce In Text

Each letter bounces in from below with elastic overshoot — playful entrance animation.

How It Works

Each letter starts invisible at translateY(40px) below its position. The cubic-bezier(0.34, 1.56, 0.64, 1) curve is key — the 1.56 overshoot creates the elastic bounce. At 60% the letter actually goes above its final position (translateY(-5px)), then settles at 100%. The staggered delays (0.08s apart) create the cascade entrance.

.text-bounce-in {
  --tbi-color: #f97316;
  --tbi-speed: 0.6s;
  color: var(--tbi-color);
  font-size: 2rem;
  font-weight: 700;
  display: flex;
  gap: 2px;
}

.text-bounce-in span {
  display: inline-block;
  opacity: 0;
  transform: translateY(40px);
  animation: tbi-bounce var(--tbi-speed) cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

.text-bounce-in span:nth-child(1) { animation-delay: 0s; }
.text-bounce-in span:nth-child(2) { animation-delay: 0.08s; }
.text-bounce-in span:nth-child(3) { animation-delay: 0.16s; }
.text-bounce-in span:nth-child(4) { animation-delay: 0.24s; }
.text-bounce-in span:nth-child(5) { animation-delay: 0.32s; }
.text-bounce-in span:nth-child(6) { animation-delay: 0.40s; }

@keyframes tbi-bounce {
  0% {
    opacity: 0;
    transform: translateY(40px);
  }
  60% {
    opacity: 1;
    transform: translateY(-5px);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}
<div class="text-bounce-in"><span>B</span><span>o</span><span>u</span><span>n</span><span>c</span><span>e</span></div>

Tip: The forwards fill mode means this is a one-shot entrance. To replay, remove and re-add the class with JavaScript.


16. Cascade

Letters cascade down like a waterfall — dramatic vertical reveal with overshoot settle.

How It Works

Letters start above their position at translateY(-30px) with opacity: 0. At 50% they become visible, at 70% they overshoot below (translateY(5px)), then settle at 100%. This overshoot-then-settle pattern mimics a physical drop with bounce. The 0.1s stagger between each letter creates the waterfall cascade timing.

.text-cascade {
  --tc-color: #0ea5e9;
  --tc-speed: 0.8s;
  color: var(--tc-color);
  font-size: 2rem;
  font-weight: 700;
  display: flex;
  gap: 2px;
}

.text-cascade span {
  display: inline-block;
  opacity: 0;
  transform: translateY(-30px);
  animation: tc-drop var(--tc-speed) ease-in forwards;
}

.text-cascade span:nth-child(1) { animation-delay: 0s; }
.text-cascade span:nth-child(2) { animation-delay: 0.1s; }
.text-cascade span:nth-child(3) { animation-delay: 0.2s; }
.text-cascade span:nth-child(4) { animation-delay: 0.3s; }
.text-cascade span:nth-child(5) { animation-delay: 0.4s; }
.text-cascade span:nth-child(6) { animation-delay: 0.5s; }
.text-cascade span:nth-child(7) { animation-delay: 0.6s; }

@keyframes tc-drop {
  0% {
    opacity: 0;
    transform: translateY(-30px);
  }
  50% {
    opacity: 1;
  }
  70% {
    transform: translateY(5px);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}
<div class="text-cascade"><span>C</span><span>a</span><span>s</span><span>c</span><span>a</span><span>d</span><span>e</span></div>

17. RGB Glitch

Red and blue color channels split apart with a jittery skew — cyberpunk aesthetic.

How It Works

This uses ::before and ::after pseudo-elements to create two color-separated copies of the text — red on top, blue behind. Each copy animates independently with small translate offsets, while the parent element adds a subtle skew() wobble. The red and blue keyframes use mirrored movements (when red goes left, blue goes right) to create the channel-separation effect.

.text-glitch-rgb {
  --tgr-color: #ffffff;
  --tgr-speed: 2s;
  position: relative;
  font-size: 2.2rem;
  font-weight: 800;
  color: var(--tgr-color);
  animation: tgr-skew var(--tgr-speed) infinite;
}

.text-glitch-rgb::before,
.text-glitch-rgb::after {
  content: 'GLITCH';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.text-glitch-rgb::before {
  color: #ff0000;
  animation: tgr-red var(--tgr-speed) infinite;
  clip-path: inset(0 0 0 0);
}

.text-glitch-rgb::after {
  color: #0000ff;
  animation: tgr-blue var(--tgr-speed) infinite;
  clip-path: inset(0 0 0 0);
}

@keyframes tgr-skew {
  0%, 100% { transform: skew(0deg); }
  20% { transform: skew(-2deg); }
  40% { transform: skew(0deg); }
  60% { transform: skew(1deg); }
  80% { transform: skew(-1deg); }
}

@keyframes tgr-red {
  0%, 100% { transform: translate(0); }
  20% { transform: translate(-3px, 2px); }
  40% { transform: translate(2px, -1px); }
  60% { transform: translate(-1px, 1px); }
  80% { transform: translate(3px, -2px); }
}

@keyframes tgr-blue {
  0%, 100% { transform: translate(0); }
  20% { transform: translate(3px, -2px); }
  40% { transform: translate(-2px, 1px); }
  60% { transform: translate(1px, -1px); }
  80% { transform: translate(-3px, 2px); }
}
<div class="text-glitch-rgb">GLITCH</div>

Note: The content: 'GLITCH' in the pseudo-elements must match the actual text content for the effect to work. Update it if you change the word.


18. Wave 3D

Text waves with 3D perspective — letters rotate in depth while bouncing up and down.

How It Works

The parent sets perspective: 300px which enables 3D transforms for child elements. Each letter combines rotateX() with translateY() across 4 keyframe stops — creating a tumbling wave motion. The transform-origin: bottom makes the letter pivot from its base rather than its center, which looks more natural for a wave.

.text-wave-3d {
  --tw3-color: #3b82f6;
  --tw3-speed: 2s;
  color: var(--tw3-color);
  font-size: 2rem;
  font-weight: 800;
  display: flex;
  gap: 2px;
  perspective: 300px;
}

.text-wave-3d span {
  display: inline-block;
  animation: tw3-wave var(--tw3-speed) ease-in-out infinite;
  transform-origin: bottom;
}

.text-wave-3d span:nth-child(1) { animation-delay: 0s; }
.text-wave-3d span:nth-child(2) { animation-delay: 0.1s; }
.text-wave-3d span:nth-child(3) { animation-delay: 0.2s; }
.text-wave-3d span:nth-child(4) { animation-delay: 0.3s; }

@keyframes tw3-wave {
  0%, 100% {
    transform: rotateX(0deg) translateY(0);
  }
  25% {
    transform: rotateX(30deg) translateY(-8px);
  }
  50% {
    transform: rotateX(-10deg) translateY(4px);
  }
  75% {
    transform: rotateX(15deg) translateY(-4px);
  }
}
<div class="text-wave-3d"><span>W</span><span>A</span><span>V</span><span>E</span></div>

Tip: Increase perspective to 600px for subtler depth, or decrease to 150px for more extreme 3D.


19. Pop In

Letters pop in with scale overshoot and a tiny rotation twist — fun and bouncy.

How It Works

Letters start at scale(0) with a slight rotate(-15deg). The cubic-bezier(0.34, 1.56, 0.64, 1) overshoot curve makes them pop past scale(1) to scale(1.15) at 70% before settling. The subtle rotation twist adds personality — each letter wiggles slightly as it appears.

.text-pop {
  --tp-color: #f97316;
  --tp-speed: 0.5s;
  color: var(--tp-color);
  font-size: 2rem;
  font-weight: 800;
  display: flex;
  gap: 2px;
}

.text-pop span {
  display: inline-block;
  opacity: 0;
  transform: scale(0);
  animation: tp-pop var(--tp-speed) cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

.text-pop span:nth-child(1) { animation-delay: 0s; }
.text-pop span:nth-child(2) { animation-delay: 0.1s; }
.text-pop span:nth-child(3) { animation-delay: 0.2s; }
.text-pop span:nth-child(4) { animation-delay: 0.3s; }

@keyframes tp-pop {
  0% {
    opacity: 0;
    transform: scale(0) rotate(-15deg);
  }
  70% {
    transform: scale(1.15) rotate(3deg);
  }
  100% {
    opacity: 1;
    transform: scale(1) rotate(0deg);
  }
}
<div class="text-pop"><span>P</span><span>O</span><span>P</span><span>!</span></div>

Tip: Speed this up to 0.3s for snappy UI feedback, or slow to 1s for a more dramatic entrance.


20. Rain Drop

Letters drip down into place like raindrops — wet, fluid entrance with vertical squash.

How It Works

Letters fall from translateY(-50px) with scaleY(1.3) — stretched vertically like a falling droplet. At 70% they overshoot below position with scaleY(0.9) — squashed like they hit the ground. The elastic cubic-bezier(0.34, 1.56, 0.64, 1) gives the bounce-back spring. The 0.15s stagger between letters creates the dripping sequence.

.text-rain-drop {
  --trd-color: #0ea5e9;
  --trd-speed: 0.8s;
  color: var(--trd-color);
  font-size: 2rem;
  font-weight: 700;
  display: flex;
  gap: 2px;
}

.text-rain-drop span {
  display: inline-block;
  opacity: 0;
  transform: translateY(-50px);
  animation: trd-drop var(--trd-speed) cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

.text-rain-drop span:nth-child(1) { animation-delay: 0s; }
.text-rain-drop span:nth-child(2) { animation-delay: 0.15s; }
.text-rain-drop span:nth-child(3) { animation-delay: 0.3s; }
.text-rain-drop span:nth-child(4) { animation-delay: 0.45s; }
.text-rain-drop span:nth-child(5) { animation-delay: 0.6s; }

@keyframes trd-drop {
  0% {
    opacity: 0;
    transform: translateY(-50px) scaleY(1.3);
  }
  50% {
    opacity: 1;
  }
  70% {
    transform: translateY(5px) scaleY(0.9);
  }
  100% {
    opacity: 1;
    transform: translateY(0) scaleY(1);
  }
}
<div class="text-rain-drop"><span>R</span><span>a</span><span>i</span><span>n</span><span>y</span></div>

Tip: Use #38bdf8 on a dark background for a realistic rain feel, or #22d3ee for a neon-rain cyberpunk vibe.


What’s Next?

That’s 20 text effects covered across Part 1 and this post. But CSSKit has 310 animations total across 11 categories. In the next post, we’ll move into hover effects — buttons that fill, borders that draw themselves, and cards that flip in 3D.

Explore all animations live at CSSKit or star the repo on GitHub.

You might also like

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.

Discussion