Flow

Effects / CSS

Glitch effect

Text or images that jitter, split into RGB channels and slice horizontally in short bursts.

Prompt to build it

Build a glitch-text title. Use ::before/::after copies in red and cyan with mix-blend-mode screen, animate clip-path inset slices and small translateX jumps in 0.3s bursts every 3s. Make it responsive, cap devicePixelRatio at 2, pause when off-screen, and show a still frame when prefers-reduced-motion is set. No external libraries.

Tested code

One self-contained HTML file with no libraries: the same code that runs above. Your AI gets it from Flow's get_effect tool.

Show the code
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Glitch effect | Flow effect</title> <!-- Flow effect: Glitch effect (https://flow.donta.io/effects/glitch-effect) Self-contained: no libraries. Copy the .fx-stage element, the CSS and the script into your project and size .fx-stage however you like. --> <style> :root { --display: "Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif; --body: ui-sans-serif, system-ui, sans-serif; } html, body { margin: 0; min-height: 100%; background: #0e0e10; display: grid; place-items: center; } .fx-stage { width: min(100vw, 960px); } /* Stage that every effect fills. Container units (cqw/cqmin) size the art. */ .fx-stage { position: relative; aspect-ratio: 4 / 3; overflow: hidden; border-radius: 16px; container-type: size; background: #111; isolation: isolate; } .fx-fill { position: absolute; inset: 0; } .fx-fallback { position: absolute; inset: 0; } .fx-center { display: grid; place-items: center; } /* ── Glitch ───────────────────────────────────── */ .fx-glitch { background: #050507; } .fx-glitch-text { position: relative; font: 800 17cqmin/1 var(--display); letter-spacing: -0.02em; color: #f2f2f2; text-shadow: -0.4cqmin 0 rgba(255, 43, 85, 0.6), 0.4cqmin 0 rgba(34, 230, 255, 0.6); } .fx-glitch-text::before, .fx-glitch-text::after { content: attr(data-text); position: absolute; inset: 0; mix-blend-mode: screen; } .fx-glitch-text::before { color: #ff2b55; animation: fx-glitch-a 2s infinite steps(1); } .fx-glitch-text::after { color: #22e6ff; animation: fx-glitch-b 2s infinite steps(1); } @keyframes fx-glitch-a { 0%, 60%, 88%, 100% { clip-path: inset(0 0 100% 0); translate: 0; } 64% { clip-path: inset(10% 0 60% 0); translate: -3cqmin 0; } 70% { clip-path: inset(55% 0 20% 0); translate: 2.5cqmin 0; } 76% { clip-path: inset(30% 0 45% 0); translate: -1.5cqmin 0; } 82% { clip-path: inset(70% 0 5% 0); translate: 3cqmin 0; } } @keyframes fx-glitch-b { 0%, 60%, 88%, 100% { clip-path: inset(0 0 100% 0); translate: 0; } 66% { clip-path: inset(40% 0 35% 0); translate: 3cqmin 0; } 72% { clip-path: inset(5% 0 75% 0); translate: -2.5cqmin 0; } 78% { clip-path: inset(62% 0 12% 0); translate: 2cqmin 0; } 84% { clip-path: inset(20% 0 58% 0); translate: -3cqmin 0; } } @media (prefers-reduced-motion: reduce) { .fx-stage *, .fx-stage *::before, .fx-stage *::after { animation-play-state: paused !important; } } </style> </head> <body> <div class="fx-stage"> <div class="fx-fill fx-center fx-glitch"><div class="fx-glitch-text" data-text="GLITCH">GLITCH</div></div> </div> </body> </html>

How it works

Two copies of the text in red and cyan, offset and clipped to random horizontal slices with clip-path, fire in short bursts between long calm periods.

Guardrails

  • Keep bursts short and rare; never flash more than 3 times a second.
  • Respect prefers-reduced-motion: show a still frame instead of the animation.
  • Pause when off-screen or when the tab is hidden (IntersectionObserver + visibilitychange).
  • Keep text off busy animated areas, or give it a solid backing that passes WCAG contrast.
  • One showpiece effect per page. If everything moves, nothing stands out.