16 CSS Glitch Text Effects11 / 16
Glitch Text Reveal Intro
Page-load title reveal where the headline scales up from zero opacity while heavily distorted, then resolves into clean solid white typography in under 1.2 seconds -- a one-shot entry animation with a JS replay trigger.
Published
The code
<div class="gt-11">
<div class="gt-11__scene" id="gt-11-scene">
<h1 class="gt-11__title" data-text="CODEFRONTS">CODEFRONTS</h1>
<span class="gt-11__tagline">developer gallery · 2027</span>
</div>
<button class="gt-11__replay" id="gt-11-replay">↺ Replay Intro</button>
</div><div class="gt-11">
<div class="gt-11__scene" id="gt-11-scene">
<h1 class="gt-11__title" data-text="CODEFRONTS">CODEFRONTS</h1>
<span class="gt-11__tagline">developer gallery · 2027</span>
</div>
<button class="gt-11__replay" id="gt-11-replay">↺ Replay Intro</button>
</div>.gt-11,
.gt-11 *,
.gt-11 *::before,
.gt-11 *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.gt-11 ::selection {
background: #10b981;
color: #000;
}
.gt-11 {
--emerald: #10b981;
--teal: #14b8a6;
--bg: #010a07;
--text: #ecfdf5;
min-height: 100vh;
background: var(--bg);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 16px;
padding: 48px 20px;
font-family: 'Inter', system-ui, sans-serif;
position: relative;
overflow: hidden;
}
.gt-11__scene {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
/* Main reveal — title enters distorted, resolves cleanly */
.gt-11__title {
position: relative;
font-size: clamp(36px, 7vw, 72px);
font-weight: 900;
letter-spacing: -1px;
color: var(--text);
animation: gt-11-reveal-main 1.2s cubic-bezier(0.23,1,0.32,1) both;
}
@keyframes gt-11-reveal-main {
0% {
opacity: 0;
transform: scale(0.85) translateY(10px);
filter: blur(4px);
text-shadow: none;
}
20% {
opacity: 0.7;
transform: scale(1.04) translateY(-4px);
filter: blur(1px);
text-shadow: -8px 0 var(--emerald), 8px 0 rgba(0,255,200,0.5), 0 0 30px rgba(16,185,129,0.6);
}
40% {
opacity: 0.5;
transform: scale(0.97) translateY(2px);
text-shadow: 4px -2px var(--teal), -4px 2px rgba(16,185,129,0.4);
}
60% {
opacity: 0.9;
transform: scale(1.01) translateY(-1px);
text-shadow: 0 0 20px rgba(16,185,129,0.3);
}
80% {
opacity: 1;
transform: scale(1.002) translateY(0);
text-shadow: 0 0 10px rgba(16,185,129,0.15);
}
100% {
opacity: 1;
transform: scale(1) translateY(0);
text-shadow: none;
}
}
/* Channel offsets during reveal */
.gt-11__title::before {
content: attr(data-text);
position: absolute;
inset: 0;
font: inherit;
color: var(--emerald);
clip-path: polygon(0 0, 100% 0, 100% 40%, 0 40%);
animation: gt-11-channel-top 1.2s steps(1) both;
}
.gt-11__title::after {
content: attr(data-text);
position: absolute;
inset: 0;
font: inherit;
color: var(--teal);
clip-path: polygon(0 60%, 100% 60%, 100% 100%, 0 100%);
animation: gt-11-channel-bot 1.2s steps(1) both;
}
@keyframes gt-11-channel-top {
0%,
100% {
opacity: 0;
transform: translateX(0);
}
10% {
opacity: 1;
transform: translateX(-12px);
}
30% {
opacity: 0.8;
transform: translateX(8px);
}
50% {
opacity: 0.4;
transform: translateX(-3px);
}
70% {
opacity: 0.1;
}
80% {
opacity: 0;
}
}
@keyframes gt-11-channel-bot {
0%,
100% {
opacity: 0;
transform: translateX(0);
}
10% {
opacity: 1;
transform: translateX(12px);
}
30% {
opacity: 0.8;
transform: translateX(-8px);
}
50% {
opacity: 0.4;
transform: translateX(3px);
}
70% {
opacity: 0.1;
}
80% {
opacity: 0;
}
}
.gt-11__tagline {
font-size: 13px;
letter-spacing: 6px;
color: var(--emerald);
text-transform: uppercase;
opacity: 0;
animation: gt-11-fade-in 0.5s ease 1s both;
}
@keyframes gt-11-fade-in {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 0.7;
transform: translateY(0);
}
}
/* Replay trigger */
.gt-11__replay {
margin-top: 12px;
font-size: 11px;
letter-spacing: 3px;
color: rgba(16,185,129,0.4);
cursor: pointer;
border: none;
background: none;
font-family: inherit;
text-transform: uppercase;
transition: color 0.2s;
padding: 6px 12px;
}
.gt-11__replay:hover {
color: var(--emerald);
}
@media (prefers-reduced-motion: reduce) {
.gt-11__title,
.gt-11__title::before,
.gt-11__title::after,
.gt-11__tagline {
animation: none;
opacity: 1;
}
.gt-11__title::before,
.gt-11__title::after {
display: none;
}
}.gt-11,
.gt-11 *,
.gt-11 *::before,
.gt-11 *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.gt-11 ::selection {
background: #10b981;
color: #000;
}
.gt-11 {
--emerald: #10b981;
--teal: #14b8a6;
--bg: #010a07;
--text: #ecfdf5;
min-height: 100vh;
background: var(--bg);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 16px;
padding: 48px 20px;
font-family: 'Inter', system-ui, sans-serif;
position: relative;
overflow: hidden;
}
.gt-11__scene {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
/* Main reveal — title enters distorted, resolves cleanly */
.gt-11__title {
position: relative;
font-size: clamp(36px, 7vw, 72px);
font-weight: 900;
letter-spacing: -1px;
color: var(--text);
animation: gt-11-reveal-main 1.2s cubic-bezier(0.23,1,0.32,1) both;
}
@keyframes gt-11-reveal-main {
0% {
opacity: 0;
transform: scale(0.85) translateY(10px);
filter: blur(4px);
text-shadow: none;
}
20% {
opacity: 0.7;
transform: scale(1.04) translateY(-4px);
filter: blur(1px);
text-shadow: -8px 0 var(--emerald), 8px 0 rgba(0,255,200,0.5), 0 0 30px rgba(16,185,129,0.6);
}
40% {
opacity: 0.5;
transform: scale(0.97) translateY(2px);
text-shadow: 4px -2px var(--teal), -4px 2px rgba(16,185,129,0.4);
}
60% {
opacity: 0.9;
transform: scale(1.01) translateY(-1px);
text-shadow: 0 0 20px rgba(16,185,129,0.3);
}
80% {
opacity: 1;
transform: scale(1.002) translateY(0);
text-shadow: 0 0 10px rgba(16,185,129,0.15);
}
100% {
opacity: 1;
transform: scale(1) translateY(0);
text-shadow: none;
}
}
/* Channel offsets during reveal */
.gt-11__title::before {
content: attr(data-text);
position: absolute;
inset: 0;
font: inherit;
color: var(--emerald);
clip-path: polygon(0 0, 100% 0, 100% 40%, 0 40%);
animation: gt-11-channel-top 1.2s steps(1) both;
}
.gt-11__title::after {
content: attr(data-text);
position: absolute;
inset: 0;
font: inherit;
color: var(--teal);
clip-path: polygon(0 60%, 100% 60%, 100% 100%, 0 100%);
animation: gt-11-channel-bot 1.2s steps(1) both;
}
@keyframes gt-11-channel-top {
0%,
100% {
opacity: 0;
transform: translateX(0);
}
10% {
opacity: 1;
transform: translateX(-12px);
}
30% {
opacity: 0.8;
transform: translateX(8px);
}
50% {
opacity: 0.4;
transform: translateX(-3px);
}
70% {
opacity: 0.1;
}
80% {
opacity: 0;
}
}
@keyframes gt-11-channel-bot {
0%,
100% {
opacity: 0;
transform: translateX(0);
}
10% {
opacity: 1;
transform: translateX(12px);
}
30% {
opacity: 0.8;
transform: translateX(-8px);
}
50% {
opacity: 0.4;
transform: translateX(3px);
}
70% {
opacity: 0.1;
}
80% {
opacity: 0;
}
}
.gt-11__tagline {
font-size: 13px;
letter-spacing: 6px;
color: var(--emerald);
text-transform: uppercase;
opacity: 0;
animation: gt-11-fade-in 0.5s ease 1s both;
}
@keyframes gt-11-fade-in {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 0.7;
transform: translateY(0);
}
}
/* Replay trigger */
.gt-11__replay {
margin-top: 12px;
font-size: 11px;
letter-spacing: 3px;
color: rgba(16,185,129,0.4);
cursor: pointer;
border: none;
background: none;
font-family: inherit;
text-transform: uppercase;
transition: color 0.2s;
padding: 6px 12px;
}
.gt-11__replay:hover {
color: var(--emerald);
}
@media (prefers-reduced-motion: reduce) {
.gt-11__title,
.gt-11__title::before,
.gt-11__title::after,
.gt-11__tagline {
animation: none;
opacity: 1;
}
.gt-11__title::before,
.gt-11__title::after {
display: none;
}
}(function() {
const btn = document.getElementById('gt-11-replay');
const scene = document.getElementById('gt-11-scene');
if (!btn || !scene) return;
btn.addEventListener('click', function() {
/* Force re-run by cloning node */
const clone = scene.cloneNode(true);
scene.parentNode.replaceChild(clone, scene);
});
})();(function() {
const btn = document.getElementById('gt-11-replay');
const scene = document.getElementById('gt-11-scene');
if (!btn || !scene) return;
btn.addEventListener('click', function() {
/* Force re-run by cloning node */
const clone = scene.cloneNode(true);
scene.parentNode.replaceChild(clone, scene);
});
})();Here's a working CSS Glitch Text Effect from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Glitch Text Reveal Intro
Source: https://codefronts.com/motion/css-glitch-text-effect/glitch-text-reveal-intro/
Page-load title reveal where the headline scales up from zero opacity while heavily distorted, then resolves into clean solid white typography in under 1.2 seconds -- a one-shot entry animation with a JS replay trigger.
## HTML
```html
<div class="gt-11">
<div class="gt-11__scene" id="gt-11-scene">
<h1 class="gt-11__title" data-text="CODEFRONTS">CODEFRONTS</h1>
<span class="gt-11__tagline">developer gallery · 2027</span>
</div>
<button class="gt-11__replay" id="gt-11-replay">↺ Replay Intro</button>
</div>
```
## CSS
```css
.gt-11,
.gt-11 *,
.gt-11 *::before,
.gt-11 *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.gt-11 ::selection {
background: #10b981;
color: #000;
}
.gt-11 {
--emerald: #10b981;
--teal: #14b8a6;
--bg: #010a07;
--text: #ecfdf5;
min-height: 100vh;
background: var(--bg);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 16px;
padding: 48px 20px;
font-family: 'Inter', system-ui, sans-serif;
position: relative;
overflow: hidden;
}
.gt-11__scene {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
/* Main reveal — title enters distorted, resolves cleanly */
.gt-11__title {
position: relative;
font-size: clamp(36px, 7vw, 72px);
font-weight: 900;
letter-spacing: -1px;
color: var(--text);
animation: gt-11-reveal-main 1.2s cubic-bezier(0.23,1,0.32,1) both;
}
@keyframes gt-11-reveal-main {
0% {
opacity: 0;
transform: scale(0.85) translateY(10px);
filter: blur(4px);
text-shadow: none;
}
20% {
opacity: 0.7;
transform: scale(1.04) translateY(-4px);
filter: blur(1px);
text-shadow: -8px 0 var(--emerald), 8px 0 rgba(0,255,200,0.5), 0 0 30px rgba(16,185,129,0.6);
}
40% {
opacity: 0.5;
transform: scale(0.97) translateY(2px);
text-shadow: 4px -2px var(--teal), -4px 2px rgba(16,185,129,0.4);
}
60% {
opacity: 0.9;
transform: scale(1.01) translateY(-1px);
text-shadow: 0 0 20px rgba(16,185,129,0.3);
}
80% {
opacity: 1;
transform: scale(1.002) translateY(0);
text-shadow: 0 0 10px rgba(16,185,129,0.15);
}
100% {
opacity: 1;
transform: scale(1) translateY(0);
text-shadow: none;
}
}
/* Channel offsets during reveal */
.gt-11__title::before {
content: attr(data-text);
position: absolute;
inset: 0;
font: inherit;
color: var(--emerald);
clip-path: polygon(0 0, 100% 0, 100% 40%, 0 40%);
animation: gt-11-channel-top 1.2s steps(1) both;
}
.gt-11__title::after {
content: attr(data-text);
position: absolute;
inset: 0;
font: inherit;
color: var(--teal);
clip-path: polygon(0 60%, 100% 60%, 100% 100%, 0 100%);
animation: gt-11-channel-bot 1.2s steps(1) both;
}
@keyframes gt-11-channel-top {
0%,
100% {
opacity: 0;
transform: translateX(0);
}
10% {
opacity: 1;
transform: translateX(-12px);
}
30% {
opacity: 0.8;
transform: translateX(8px);
}
50% {
opacity: 0.4;
transform: translateX(-3px);
}
70% {
opacity: 0.1;
}
80% {
opacity: 0;
}
}
@keyframes gt-11-channel-bot {
0%,
100% {
opacity: 0;
transform: translateX(0);
}
10% {
opacity: 1;
transform: translateX(12px);
}
30% {
opacity: 0.8;
transform: translateX(-8px);
}
50% {
opacity: 0.4;
transform: translateX(3px);
}
70% {
opacity: 0.1;
}
80% {
opacity: 0;
}
}
.gt-11__tagline {
font-size: 13px;
letter-spacing: 6px;
color: var(--emerald);
text-transform: uppercase;
opacity: 0;
animation: gt-11-fade-in 0.5s ease 1s both;
}
@keyframes gt-11-fade-in {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 0.7;
transform: translateY(0);
}
}
/* Replay trigger */
.gt-11__replay {
margin-top: 12px;
font-size: 11px;
letter-spacing: 3px;
color: rgba(16,185,129,0.4);
cursor: pointer;
border: none;
background: none;
font-family: inherit;
text-transform: uppercase;
transition: color 0.2s;
padding: 6px 12px;
}
.gt-11__replay:hover {
color: var(--emerald);
}
@media (prefers-reduced-motion: reduce) {
.gt-11__title,
.gt-11__title::before,
.gt-11__title::after,
.gt-11__tagline {
animation: none;
opacity: 1;
}
.gt-11__title::before,
.gt-11__title::after {
display: none;
}
}
```
## JavaScript
```js
(function() {
const btn = document.getElementById('gt-11-replay');
const scene = document.getElementById('gt-11-scene');
if (!btn || !scene) return;
btn.addEventListener('click', function() {
/* Force re-run by cloning node */
const clone = scene.cloneNode(true);
scene.parentNode.replaceChild(clone, scene);
});
})();
```Here's a working CSS Glitch Text Effect from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Glitch Text Reveal Intro
Source: https://codefronts.com/motion/css-glitch-text-effect/glitch-text-reveal-intro/
Page-load title reveal where the headline scales up from zero opacity while heavily distorted, then resolves into clean solid white typography in under 1.2 seconds -- a one-shot entry animation with a JS replay trigger.
## HTML
```html
<div class="gt-11">
<div class="gt-11__scene" id="gt-11-scene">
<h1 class="gt-11__title" data-text="CODEFRONTS">CODEFRONTS</h1>
<span class="gt-11__tagline">developer gallery · 2027</span>
</div>
<button class="gt-11__replay" id="gt-11-replay">↺ Replay Intro</button>
</div>
```
## CSS
```css
.gt-11,
.gt-11 *,
.gt-11 *::before,
.gt-11 *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.gt-11 ::selection {
background: #10b981;
color: #000;
}
.gt-11 {
--emerald: #10b981;
--teal: #14b8a6;
--bg: #010a07;
--text: #ecfdf5;
min-height: 100vh;
background: var(--bg);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 16px;
padding: 48px 20px;
font-family: 'Inter', system-ui, sans-serif;
position: relative;
overflow: hidden;
}
.gt-11__scene {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
/* Main reveal — title enters distorted, resolves cleanly */
.gt-11__title {
position: relative;
font-size: clamp(36px, 7vw, 72px);
font-weight: 900;
letter-spacing: -1px;
color: var(--text);
animation: gt-11-reveal-main 1.2s cubic-bezier(0.23,1,0.32,1) both;
}
@keyframes gt-11-reveal-main {
0% {
opacity: 0;
transform: scale(0.85) translateY(10px);
filter: blur(4px);
text-shadow: none;
}
20% {
opacity: 0.7;
transform: scale(1.04) translateY(-4px);
filter: blur(1px);
text-shadow: -8px 0 var(--emerald), 8px 0 rgba(0,255,200,0.5), 0 0 30px rgba(16,185,129,0.6);
}
40% {
opacity: 0.5;
transform: scale(0.97) translateY(2px);
text-shadow: 4px -2px var(--teal), -4px 2px rgba(16,185,129,0.4);
}
60% {
opacity: 0.9;
transform: scale(1.01) translateY(-1px);
text-shadow: 0 0 20px rgba(16,185,129,0.3);
}
80% {
opacity: 1;
transform: scale(1.002) translateY(0);
text-shadow: 0 0 10px rgba(16,185,129,0.15);
}
100% {
opacity: 1;
transform: scale(1) translateY(0);
text-shadow: none;
}
}
/* Channel offsets during reveal */
.gt-11__title::before {
content: attr(data-text);
position: absolute;
inset: 0;
font: inherit;
color: var(--emerald);
clip-path: polygon(0 0, 100% 0, 100% 40%, 0 40%);
animation: gt-11-channel-top 1.2s steps(1) both;
}
.gt-11__title::after {
content: attr(data-text);
position: absolute;
inset: 0;
font: inherit;
color: var(--teal);
clip-path: polygon(0 60%, 100% 60%, 100% 100%, 0 100%);
animation: gt-11-channel-bot 1.2s steps(1) both;
}
@keyframes gt-11-channel-top {
0%,
100% {
opacity: 0;
transform: translateX(0);
}
10% {
opacity: 1;
transform: translateX(-12px);
}
30% {
opacity: 0.8;
transform: translateX(8px);
}
50% {
opacity: 0.4;
transform: translateX(-3px);
}
70% {
opacity: 0.1;
}
80% {
opacity: 0;
}
}
@keyframes gt-11-channel-bot {
0%,
100% {
opacity: 0;
transform: translateX(0);
}
10% {
opacity: 1;
transform: translateX(12px);
}
30% {
opacity: 0.8;
transform: translateX(-8px);
}
50% {
opacity: 0.4;
transform: translateX(3px);
}
70% {
opacity: 0.1;
}
80% {
opacity: 0;
}
}
.gt-11__tagline {
font-size: 13px;
letter-spacing: 6px;
color: var(--emerald);
text-transform: uppercase;
opacity: 0;
animation: gt-11-fade-in 0.5s ease 1s both;
}
@keyframes gt-11-fade-in {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 0.7;
transform: translateY(0);
}
}
/* Replay trigger */
.gt-11__replay {
margin-top: 12px;
font-size: 11px;
letter-spacing: 3px;
color: rgba(16,185,129,0.4);
cursor: pointer;
border: none;
background: none;
font-family: inherit;
text-transform: uppercase;
transition: color 0.2s;
padding: 6px 12px;
}
.gt-11__replay:hover {
color: var(--emerald);
}
@media (prefers-reduced-motion: reduce) {
.gt-11__title,
.gt-11__title::before,
.gt-11__title::after,
.gt-11__tagline {
animation: none;
opacity: 1;
}
.gt-11__title::before,
.gt-11__title::after {
display: none;
}
}
```
## JavaScript
```js
(function() {
const btn = document.getElementById('gt-11-replay');
const scene = document.getElementById('gt-11-scene');
if (!btn || !scene) return;
btn.addEventListener('click', function() {
/* Force re-run by cloning node */
const clone = scene.cloneNode(true);
scene.parentNode.replaceChild(clone, scene);
});
})();
```How this works
The main reveal uses a single @keyframes gt-11-reveal-main with animation-fill-mode: both so the starting state (opacity:0, scale(0.85), blur(4px)) is held before the animation begins. The keyframe sweeps through deliberate overshoot (scale(1.04) at 20%), channel-split distortion (offset text-shadows at 20-40%), and a damped settle back to neutral at 100%. This gives a spring-like snap-to-position feel without requiring JavaScript physics libraries.
The two channel pseudo-elements run complementary forwards-fill animations that start at full opacity with maximum displacement and decay to opacity: 0 by the 80% keyframe -- long before the main element finishes settling. The JS replay button clones and replaces the scene node, forcing the browser to restart all CSS animations from their initial state without requiring class toggling.
Make it yours
- Change
animation-durationfrom1.2sto0.6sfor a snappier reveal, or to2sfor a cinematic slow-burn title sequence. - Edit the bezier curve from
cubic-bezier(0.23,1,0.32,1)tocubic-bezier(0.34,1.56,0.64,1)(back-ease) for a springier overshoot. - Swap the channel colours for red and blue to create an RGB print-registration-error aesthetic instead of a green tech reveal.
- Trigger the animation on scroll by wrapping in an
IntersectionObserverand adding the animation class when the element enters the viewport. - Chain multiple headings by adding
animation-delay: 0.4sincrements to each subsequent title element so they cascade into view.
Gotchas — read before shipping
- The DOM-clone replay technique (
cloneNode+replaceChild) does not preserve event listeners attached to child elements -- re-attach them after the clone if needed. animation-fill-mode: bothmeans the element is invisible before the animation fires; if JS is disabled, add anoscriptrule to setopacity: 1; animation: noneas a fallback.- The
filter: blur()at the animation start state triggers a new compositing layer; combined with transform and opacity changes this means four compositor properties are active simultaneously -- test paint timing on mobile.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 80+ | 14+ | 78+ | 80+ |
CSS filter blur in keyframes is supported in all evergreen browsers.