Effects / CSS
Glitch effect
Text or images that jitter, split into RGB channels and slice horizontally in short bursts.
GLITCH
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.