Opent in een nieuw tabblad

CSS-lab · Tekst-effecten

Glitch-tekst

Een klassiek RGB-split glitch-effect: cyaan en magenta kopieën die in korte stoten in plakjes verspringen. Pure CSS met data-text, ::before, ::after en clip-path.

  • Gevorderd
  • Pure CSS
  • MIT-licentie
  • attr()
  • ::before
  • ::after
  • clip-path: inset()
  • mix-blend-mode
HTML
<div class="gt-wrap">
  <p class="gt-kicker">// signaal onderbroken</p>
  <h2 class="gt-glitch" data-text="Storing">Storing</h2>
</div>
CSS
/* Glitch-tekst: RGB-split met clip-path plakjes */
.gt-wrap {
  --ink: #F9F8F6;
  --c1: #00E5FF;
  --c2: #FF2E88;
  --speed: 2.8s;
  --shift: 4px;
  text-align: center;
}

.gt-kicker {
  margin: 0 0 12px;
  font: 600 13px/1 ui-monospace, Menlo, Consolas, monospace;
  letter-spacing: .12em;
  color: var(--c1);
}

.gt-glitch {
  position: relative;
  margin: 0;
  font-family: "Arial Black", "Helvetica Neue", Impact, system-ui, sans-serif;
  font-size: clamp(48px, 11vw, 132px);
  font-weight: 900;
  line-height: 1;
  letter-spacing: -.02em;
  text-transform: uppercase;
  color: var(--ink);
  animation: gt-jitter var(--speed) steps(1, end) infinite;
}

/* Twee kopieën via data-text; lege alt-tekst voor screenreaders */
.gt-glitch::before,
.gt-glitch::after {
  content: attr(data-text);
  content: attr(data-text) / "";
  position: absolute;
  inset: 0;
  clip-path: inset(0 0 100% 0);
  mix-blend-mode: screen;
  pointer-events: none;
}

.gt-glitch::before {
  color: var(--c1);
  animation: gt-slice-a var(--speed) steps(1, end) infinite;
}

.gt-glitch::after {
  color: var(--c2);
  animation: gt-slice-b var(--speed) steps(1, end) infinite;
}

/* Rust tot 55%, dan een korte stoot plakjes */
@keyframes gt-slice-a {
  0%, 55%, 100% { clip-path: inset(0 0 100% 0); transform: translate(0); }
  58% { clip-path: inset(8% 0 64% 0); transform: translate(calc(var(--shift) * -2), 0); }
  62% { clip-path: inset(46% 0 30% 0); transform: translate(var(--shift), 0); }
  66% { clip-path: inset(70% 0 6% 0); transform: translate(calc(var(--shift) * -1), 0); }
  70% { clip-path: inset(20% 0 52% 0); transform: translate(calc(var(--shift) * 2), 0); }
  74% { clip-path: inset(0 0 100% 0); transform: translate(0); }
  86% { clip-path: inset(58% 0 22% 0); transform: translate(calc(var(--shift) * -1.5), 0); }
  89% { clip-path: inset(0 0 100% 0); transform: translate(0); }
}

@keyframes gt-slice-b {
  0%, 57%, 100% { clip-path: inset(0 0 100% 0); transform: translate(0); }
  59% { clip-path: inset(60% 0 18% 0); transform: translate(calc(var(--shift) * 2), 0); }
  63% { clip-path: inset(12% 0 70% 0); transform: translate(calc(var(--shift) * -1), 0); }
  67% { clip-path: inset(36% 0 40% 0); transform: translate(calc(var(--shift) * 1.5), 0); }
  71% { clip-path: inset(80% 0 2% 0); transform: translate(calc(var(--shift) * -2), 0); }
  75% { clip-path: inset(0 0 100% 0); transform: translate(0); }
  87% { clip-path: inset(28% 0 50% 0); transform: translate(calc(var(--shift) * 1.5), 0); }
  90% { clip-path: inset(0 0 100% 0); transform: translate(0); }
}

/* De kop zelf schokt mee */
@keyframes gt-jitter {
  0%, 57%, 76%, 100% { transform: none; }
  60% { transform: skewX(-8deg) translateX(-2px); }
  65% { transform: skewX(4deg); }
  70% { transform: translateX(3px); }
}

/* Geen beweging: een stille kleurverschuiving blijft over */
@media (prefers-reduced-motion: reduce) {
  .gt-glitch,
  .gt-glitch::before,
  .gt-glitch::after { animation: none; }
  .gt-glitch::before { clip-path: none; transform: translateX(-2px); opacity: .7; }
  .gt-glitch::after { clip-path: none; transform: translateX(2px); opacity: .7; }
}

Wat het is en waar je het gebruikt

Dit glitch-effect laat een kop eruitzien alsof het signaal heel even wegvalt. Het grootste deel van de tijd staat de tekst rustig. Dan volgt een korte stoot waarin een cyaan en een magenta kopie in horizontale plakjes verspringen en de kop zelf even schokt. Die afwisseling tussen rust en storing maakt het effect sterker dan een glitch die non-stop doorgaat.

Gebruik het voor een 404-pagina, een campagne met een tech- of muziekthema, een gaming-site of als blikvanger in een donkere sectie. Houd het bij één kop per scherm: een glitch werkt alleen zolang het een uitzondering is.

Zo werkt het

  • Kopieën via data-text: de kop heeft een attribuut data-text met dezelfde tekst. ::before en ::after tonen die tekst met content: attr(data-text) en liggen met inset: 0 precies over het origineel.
  • Kleurscheiding: de pseudo-elementen krijgen var(--c1) en var(--c2) en mix-blend-mode: screen. Op een donkere achtergrond mengen ze zich als echte RGB-kanalen.
  • Plakjes: clip-path: inset() toont telkens maar een horizontale strook. In de keyframes gt-slice-a en gt-slice-b verspringt die strook samen met een translate. Buiten de stoot staat de clip op inset(0 0 100% 0), dus onzichtbaar.
  • Harde sprongen: de timing steps(1, end) zorgt dat er niets vloeiend overgaat: elke keyframe springt direct, precies zoals een digitale storing.
  • Schok: de kop zelf krijgt gt-jitter met een korte skewX, synchroon met de plakjes.

Aanpassen

De variabelen staan op .gt-wrap:

  • --c1 en --c2: de twee kanaalkleuren. Probeer acid lime en violet voor een merkversie.
  • --ink: de kleur van de hoofdtekst.
  • --speed: de lengte van één cyclus, inclusief de rustpauze.
  • --shift: hoe ver de plakjes uitschieten.

Vergeet niet om data-text aan te passen als je de tekst verandert, anders tonen de kopieën iets anders dan het origineel.

Toegankelijkheid en browsersupport

Gegenereerde content kan door sommige screenreaders worden voorgelezen, waardoor de kop drie keer klinkt. Daarom gebruiken we de nieuwere syntax content: attr(data-text) / "", die een lege alternatieve tekst meegeeft. Browsers die dat nog niet kennen, vallen terug op de regel erboven. Snelle, flitsende beweging kan hinderlijk zijn. Met prefers-reduced-motion: reduce stopt alle animatie en blijft er een stille, lichte kleurverschuiving over. De stoten zijn kort en er flitst niets van licht naar donker over het hele scherm. clip-path: inset() en mix-blend-mode werken in alle actuele browsers.

Verder lezen

Een glitch past perfect in een rauwe, eerlijke stijl. Lees meer in ons artikel over brutalistisch webdesign. Wil je zulke effecten doordacht inzetten op je eigen site, bekijk dan interactief webdesign en animaties.