SolutionsCase StudiesAI ToolsResourcesAboutContact
Get Your Free AI Automation Audit Book a Free 30-Minute Strategy Call
Playground~/frontend Open editor

~/css/glitch-text

7 CSS Glitch Text Effects

7 Pure CSSPublished 2026-10-05Free · no sign-up

Seven glitch effects for tech, gaming and music sites: an RGB split with jumping slices, a link that glitches only when hovered, CRT scanlines with a faint flicker, horizontal slices that shift, a skewed jitter, chromatic noise from text-shadows and a 404 message with a glitching number.

01. RGB Split Glitch

GlitchText

Two copies of the text in cyan and magenta jitter sideways behind the real one, clipped to thin slices that jump around. The copies come from attr(data-text) in pseudo-elements, so the word appears once in the DOM and is read once.

View code
<p class="gl1" data-text="SIGNAL">SIGNAL</p>
.gl1 { position: relative; margin: 0; color: #f8fafc; font: 900 56px Inter, system-ui, sans-serif; letter-spacing: .06em; }
.gl1::before, .gl1::after { content: attr(data-text); position: absolute; inset: 0; }
.gl1::before { color: #22d3ee; transform: translateX(-3px); clip-path: inset(10% 0 60% 0); animation: gl1a 2.6s steps(1) infinite; mix-blend-mode: screen; }
.gl1::after { color: #f0f; transform: translateX(3px); clip-path: inset(55% 0 15% 0); animation: gl1b 3.1s steps(1) infinite; mix-blend-mode: screen; }
@keyframes gl1a { 0% { clip-path: inset(10% 0 60% 0); } 20% { clip-path: inset(70% 0 5% 0); } 40% { clip-path: inset(30% 0 45% 0); } 60% { clip-path: inset(0 0 85% 0); } 80% { clip-path: inset(50% 0 30% 0); } }
@keyframes gl1b { 0% { clip-path: inset(55% 0 15% 0); } 25% { clip-path: inset(5% 0 75% 0); } 50% { clip-path: inset(40% 0 40% 0); } 75% { clip-path: inset(80% 0 0 0); } }
@media (prefers-reduced-motion: reduce) { .gl1::before, .gl1::after { animation: none; } }

02. Glitch Only on Hover

GlitchHover

A link that is perfectly calm until it is hovered or focused, then glitches for a fraction of a second with shifted colour copies. Running the effect only on interaction keeps the page readable and turns the glitch into feedback.

View code
<a class="gl2" href="#enter" data-text="Enter the site">Enter the site</a>
.gl2 { position: relative; display: inline-block; color: #e2e8f0; font: 800 26px Inter, system-ui, sans-serif; text-decoration: none; }
.gl2::before, .gl2::after { content: attr(data-text); position: absolute; inset: 0; opacity: 0; pointer-events: none; }
.gl2::before { color: #22d3ee; } .gl2::after { color: #f472b6; }
.gl2:hover::before, .gl2:focus-visible::before { opacity: .8; animation: gl2 .35s steps(2) 2; }
.gl2:hover::after, .gl2:focus-visible::after { opacity: .8; animation: gl2 .35s steps(2) 2 reverse; }
@keyframes gl2 { 0% { transform: translate(-3px, 1px); clip-path: inset(0 0 60% 0); } 50% { transform: translate(3px, -1px); clip-path: inset(40% 0 0 0); } 100% { transform: translate(0); clip-path: inset(0); opacity: 0; } }
.gl2:focus-visible { outline: 2px solid #22d3ee; outline-offset: 4px; }
@media (prefers-reduced-motion: reduce) { .gl2::before, .gl2::after { display: none; } }

03. CRT Scanlines with Flicker

GlitchRetro

Green terminal text behind horizontal scanlines and a faint flicker, the look of an old CRT monitor. The scanlines are a repeating linear gradient in a pseudo-element, and the flicker is a small opacity change well below anything that could count as flashing.

View code
<div class="gl3"><p>&gt; booting studio_os<br>&gt; loading assets ... ok<br>&gt; ready_</p></div>
.gl3 { position: relative; width: 280px; max-width: 100%; padding: 18px; box-sizing: border-box; border-radius: 14px; background: radial-gradient(ellipse at center, #062b17, #020a05); overflow: hidden; animation: gl3 4s infinite; }
.gl3::after { content: ""; position: absolute; inset: 0; background: repeating-linear-gradient(transparent 0 2px, rgba(0,0,0,.35) 2px 4px); pointer-events: none; }
.gl3 p { margin: 0; color: #4ade80; font: 500 15px/1.7 "JetBrains Mono", ui-monospace, monospace; text-shadow: 0 0 6px rgba(74,222,128,.7); }
@keyframes gl3 { 0%, 92%, 100% { opacity: 1; } 94% { opacity: .9; } 96% { opacity: .96; } }
@media (prefers-reduced-motion: reduce) { .gl3 { animation: none; } }

04. Slice Shift Glitch

GlitchClip-path

Horizontal slices of the word slide sideways by different amounts for a few frames, then snap back. Three stacked copies each show one slice through clip-path and share a stepped animation, while the original word stays as the readable layer.

View code
<p class="gl4"><span class="t">ERROR</span><span class="s s1" aria-hidden="true">ERROR</span><span class="s s2" aria-hidden="true">ERROR</span></p>
.gl4 { position: relative; display: inline-grid; margin: 0; font: 900 60px Inter, system-ui, sans-serif; color: #101828; }
.gl4 span { grid-area: 1 / 1; }
.gl4 .s { color: #dc2626; }
.gl4 .s1 { clip-path: inset(20% 0 55% 0); animation: gl4 2.8s steps(1) infinite; }
.gl4 .s2 { clip-path: inset(62% 0 18% 0); animation: gl4 2.8s steps(1) infinite reverse; }
@keyframes gl4 { 0%, 80%, 100% { transform: none; opacity: 0; } 82% { transform: translateX(-8px); opacity: 1; } 86% { transform: translateX(6px); opacity: 1; } 90% { transform: translateX(-3px); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .gl4 .s { display: none; } }

05. Skew Jitter

GlitchTransform

The whole word skews and shifts sharply for a moment every few seconds, like a dropped video frame. It uses steps(1) so each keyframe holds without easing, which gives the hard, digital feel that smooth easing would soften.

View code
<p class="gl5">NO SIGNAL</p>
.gl5 { margin: 0; color: #fde047; font: 900 44px Inter, system-ui, sans-serif; letter-spacing: .05em; animation: gl5 3s steps(1) infinite; }
@keyframes gl5 { 0%, 88%, 100% { transform: none; } 90% { transform: skewX(18deg) translateX(-6px); } 93% { transform: skewX(-10deg) translateX(4px); } 96% { transform: none; } 97% { transform: skewX(6deg); } }
@media (prefers-reduced-motion: reduce) { .gl5 { animation: none; } }

06. Colour Noise Shadow

GlitchShadow

Red and blue text-shadows wobble around the word at slightly different rates, creating chromatic noise without any extra elements. The offsets are only a few pixels so the word stays perfectly readable.

View code
<p class="gl6">Static</p>
.gl6 { margin: 0; color: #f8fafc; font: 900 54px Inter, system-ui, sans-serif; animation: gl6 1.6s steps(4) infinite; }
@keyframes gl6 { 0% { text-shadow: 2px 0 #ef4444, -2px 0 #3b82f6; } 25% { text-shadow: -1px 1px #ef4444, 2px -1px #3b82f6; } 50% { text-shadow: 3px -1px #ef4444, -1px 1px #3b82f6; } 75% { text-shadow: -2px 0 #ef4444, 1px 1px #3b82f6; } 100% { text-shadow: 2px 0 #ef4444, -2px 0 #3b82f6; } }
@media (prefers-reduced-motion: reduce) { .gl6 { animation: none; text-shadow: 2px 0 #ef4444, -2px 0 #3b82f6; } }

07. Glitchy 404 Block

Glitch404

A not-found message with a glitching 404, a plain-language explanation and a link home. The glitch is decoration on the number only; the heading text, the help and the link carry everything a visitor needs.

View code
<section class="gl7"><h3><span class="n" data-text="404" aria-hidden="true">404</span><span class="sr">Error 404:</span> Page not found</h3><p>The page may have moved. Try the home page or search.</p><a href="#home">Go to the home page</a></section>
.gl7 { width: 280px; max-width: 100%; text-align: center; font-family: Inter, system-ui, sans-serif; }
.gl7 h3 { display: grid; gap: 4px; margin: 0 0 8px; color: #e2e8f0; font-size: 18px; }
.gl7 .n { position: relative; color: #fff; font-size: 80px; font-weight: 900; line-height: 1; }
.gl7 .n::before, .gl7 .n::after { content: attr(data-text); position: absolute; inset: 0; }
.gl7 .n::before { color: #22d3ee; clip-path: inset(0 0 65% 0); animation: gl7 2.4s steps(1) infinite; }
.gl7 .n::after { color: #f472b6; clip-path: inset(60% 0 0 0); animation: gl7 2.4s steps(1) infinite reverse; }
.gl7 .sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.gl7 p { margin: 0 0 14px; color: #94a3b8; font-size: 14px; }
.gl7 a { display: inline-block; padding: 10px 16px; border-radius: 8px; background: #f8fafc; color: #0f172a; font-weight: 700; font-size: 14px; text-decoration: none; }
.gl7 a:focus-visible { outline: 3px solid #22d3ee; outline-offset: 2px; }
@keyframes gl7 { 0%, 85%, 100% { transform: none; } 87% { transform: translateX(-5px); } 91% { transform: translateX(4px); } 95% { transform: translateX(-2px); } }
@media (prefers-reduced-motion: reduce) { .gl7 .n::before, .gl7 .n::after { animation: none; display: none; } }

About these CSS Glitch Text Effects

Copies from attr()

Most glitches layer coloured copies of the text. Generate them with content: attr(data-text) in ::before and ::after, so the word exists once in the DOM and is read once.

Slices with clip-path

clip-path: inset(top 0 bottom 0) shows a horizontal band of a copy. Changing the band with steps(1) keyframes makes it jump between positions with the hard, digital feel a glitch needs.

Avoid flashing

Effects that flash more than three times a second can trigger seizures. Keep glitches to small areas and brief bursts with long pauses between them, and stop them under prefers-reduced-motion.

Glitch the decoration, not the message

Use the effect on a logo, a number or a heading, and keep the explanation and any links in plain, still text, as the 404 demo does.

Frequently asked questions

Do glitch effects need JavaScript?

No. Every demo here is pure CSS.

Why steps(1)?

It holds each keyframe without easing in between, so the shifts snap rather than slide.

Will the copies be read by screen readers?

Generated content can be read in some browsers, so the 404 demo also hides the decorated number and provides plain text.