Comment crée-t-on des effets glitch, VHS et de distorsion sur le web ?

Les effets de distorsion abîment volontairement une image ou un titre pour créer une ambiance rétro ou numérique. Les glitchs utilisent des copies décalées découpées avec clip-path et teintées avec text-shadow, les looks CRT et VHS ajoutent des lignes de balayage et du bruit, et les vraies déformations passent par des filtres SVG comme feTurbulence avec feDisplacementMap, ou par WebGL.

Comment choisir, performances et accessibilité
  • Réservez-les aux moments qui portent la marque, comme une page de musique ou de jeu vidéo, une page 404 ou un titre de héros, avec RGB Split, VHS Effect ou CRT Screen, et gardez le texte courant net.
  • Un scintillement rapide peut gêner : limitez l'intensité, ne dépassez jamais trois flashs par seconde et coupez l'animation pour prefers-reduced-motion.
  • RGB Split, Holographic Card, CRT Monitor Effect et Synthwave Scene sont gratuits avec leur code ; les autres effets sont inclus dans Premium.
GLITCH

RGB Split

Séparation chromatique style corruption.

CSS Glitch Text
Voir le code source
HTML
<div class="demo-preview">
  <div class="rgb-split" data-text="GLITCH">GLITCH</div>
</div>
CSS
.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
  box-sizing: border-box
}

.demo-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 280px;
  overflow: hidden;
  position: relative;
  background: rgb(10, 10, 15);
  color: rgb(255, 255, 255);
  font-family: sans-serif;
}

.rgb-split {
  font-size: 3rem;
  font-weight: 900;
  position: relative;
  z-index: 0;
  color: white;
  cursor: pointer;
}

.rgb-split::before,
.rgb-split::after {
  content: attr(data-text);
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.rgb-split::before {
  color: #ff0000;
  z-index: -1;
  animation: rgbShiftR 0.15s infinite;
}

.rgb-split::after {
  color: #00ffff;
  z-index: -1;
  animation: rgbShiftC 0.15s infinite;
}

@keyframes rgbShiftR {

  0%,
  100% {
    transform: translate(-3px, 0);
  }

  50% {
    transform: translate(-5px, 2px);
  }
}

@keyframes rgbShiftC {

  0%,
  100% {
    transform: translate(3px, 0);
  }

  50% {
    transform: translate(5px, -2px);
  }
}
JavaScript
/* CSS pur — aucun JavaScript requis */

VHS Effect

Effet cassette VHS rétro avec scanlines.

CSS Retro Noise

Pixelate Effect

Pixelisation au survol style 8-bit.

CSS JS Retro

Melting Text

Texte qui fond et se déforme.

CSS JS Text

Wave Distortion

Ondulation et torsion du texte.

CSS JS Wave

Noise Overlay

Texture grain animée style film.

CSS Film Texture

CRT Screen

Effet écran cathodique rétro.

CSS CRT Terminal

Glitch Blocks

Blocs de corruption aléatoires.

CSS JS Glitch

Broken Glass

Effet verre brisé avec éclats et fissures.

CSS Overlay Texture

Static Noise

Interférence TV statique style analogique.

CSS JS Canvas
HOLO CARD

Holographic Card

Reflets arc-en-ciel au survol style carte Pokémon.

CSS Hover Premium
Voir le code source
HTML
<div class="demo-preview">
  <div class="holo-card">HOLO CARD</div>
</div>
CSS
.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
  box-sizing: border-box
}

.demo-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 280px;
  overflow: hidden;
  position: relative;
  background: rgb(10, 10, 15);
  color: rgb(255, 255, 255);
  font-family: sans-serif;
}

.holo-card {
  width: 280px;
  height: 180px;
  background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
  border-radius: 16px;
  position: relative;
  overflow: hidden;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 1.25rem;
}

.holo-card::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(125deg,
      transparent 0%,
      rgba(255, 0, 128, 0.3) 15%,
      rgba(0, 255, 255, 0.3) 30%,
      rgba(255, 255, 0, 0.3) 45%,
      rgba(0, 255, 128, 0.3) 60%,
      rgba(128, 0, 255, 0.3) 75%,
      transparent 100%);
  background-size: 200% 200%;
  opacity: 0;
  transition: opacity 0.3s;
  mix-blend-mode: color-dodge;
}

.holo-card::after {
  content: '';
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(0deg,
      transparent,
      transparent 2px,
      rgba(255, 255, 255, 0.03) 2px,
      rgba(255, 255, 255, 0.03) 4px);
}

.holo-card:hover::before {
  opacity: 1;
  animation: holoShift 3s linear infinite;
}

@keyframes holoShift {
  0% {
    background-position: 0% 0%;
  }

  100% {
    background-position: 200% 200%;
  }
}
JavaScript
/* CSS pur — aucun JavaScript requis */

Iridescent Surface

Surface changeante style nacre ou bulle de savon.

CSS Animation Organic

Prismatic Text

Texte avec aberration chromatique et dispersion.

CSS Text Glitch

Chrome Reflection

Surface métallique chromée avec reflet.

CSS Metal Shine

Oil Slick

Effet flaque d'huile avec reflets multicolores.

CSS Organic Blur

Hologram Projection

Projection holographique flottante avec scanlines.

CSS Sci-Fi Float

Rainbow Refraction

Lumière réfractée à travers un prisme.

CSS Rainbow Spin

Crystal Effect

Gemme cristalline avec reflets internes.

CSS 3D Luxury

Holographic Badge

Badge autocollant avec effet foil holographique rotatif.

CSS Badge Foil

Laser Beam

Faisceau laser animé avec réfraction arc-en-ciel.

CSS Animation Sci-Fi
> SYSTEM BOOT OK
> LOADING DATA...
> READY_

CRT Monitor Effect

Effet moniteur CRT avec scanlines, courbure d'écran et lueur phosphore verte.

CSS Pseudo-elements Retro
Voir le code source
HTML
<div class="demo-preview">
  <div class="crt-monitor">
    <div class="crt-content">
      <span>> SYSTEM BOOT OK</span><br>
      <span>> LOADING DATA...</span><br>
      <span>> READY_</span>
    </div>
  </div>
</div>
CSS
.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
  box-sizing: border-box
}

.demo-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 280px;
  overflow: hidden;
  position: relative;
  background: rgb(10, 10, 15);
  color: rgb(255, 255, 255);
  font-family: sans-serif;
}

.crt-monitor {
  background: #0a0a0a;
  border: 8px solid #2a2a2a;
  border-radius: 20px;
  padding: 24px;
  position: relative;
  overflow: hidden;
  width: 280px;
  min-height: 160px;
  box-shadow: inset 0 0 60px rgba(0, 255, 0, 0.1), 0 0 20px rgba(0, 0, 0, 0.5);
}

.crt-monitor::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: repeating-linear-gradient(0deg,
      transparent,
      transparent 2px,
      rgba(0, 0, 0, 0.15) 2px,
      rgba(0, 0, 0, 0.15) 4px);
  pointer-events: none;
  z-index: 2;
}

.crt-monitor::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: radial-gradient(ellipse at center, transparent 60%, rgba(0, 0, 0, 0.5) 100%);
  pointer-events: none;
  z-index: 3;
}

.crt-content {
  color: #33ff33;
  font-family: 'Courier New', monospace;
  font-size: 14px;
  line-height: 1.6;
  text-shadow: 0 0 8px rgba(51, 255, 51, 0.6);
  position: relative;
  z-index: 1;
}

.crt-content span {
  animation: crtFlicker 4s infinite;
}

@keyframes crtFlicker {

  0%,
  100% {
    opacity: 1;
  }

  92% {
    opacity: 1;
  }

  93% {
    opacity: 0.7;
  }

  94% {
    opacity: 1;
  }

  96% {
    opacity: 0.8;
  }

  97% {
    opacity: 1;
  }
}
JavaScript
/* CSS pur — aucun JavaScript requis */

VHS Tracking

Distorsion de tracking VHS animée avec déplacement horizontal et bleeding couleur.

CSS Animation VHS

ASCII Art Renderer

Texte affiché en caractères ASCII avec police monospace et look terminal vert sur noir.

CSS Monospace Terminal

Pixel Dissolve

Élément qui se pixelise et se dissout au survol avec transition par étapes CSS.

CSS Hover Filter

LED Matrix Display

Texte rendu en afficheur LED dot-matrix avec lueur rouge et grille de points.

CSS Text-shadow LED

Retro Terminal

Terminal vert sur noir avec animation de frappe, curseur clignotant et scanlines CRT.

CSS Animation Terminal

Gameboy Palette

Contenu rendu dans la palette 4 nuances de vert du Gameboy avec filtre CSS.

CSS Filter Gameboy

Dot Matrix Printer

Texte apparaissant ligne par ligne comme imprimé par une imprimante matricielle.

CSS Animation Print

Windows 95 UI Kit

Boutons et fenêtre avec bordures biseautées 3D authentiques style Win95.

CSS Borders Win95
RETRO

Synthwave Scene

Scène rétro animée avec grille en perspective, soleil néon et palette rose/cyan/violet.

CSS Animation Synthwave
Voir le code source
HTML
<div class="demo-preview">
  <div class="synthwave-scene">
    <div class="synthwave-stars">
      <span></span><span></span><span></span><span></span>
      <span></span><span></span><span></span><span></span>
    </div>
    <div class="synthwave-sun"></div>
    <div class="synthwave-text">RETRO</div>
    <div class="synthwave-grid"></div>
  </div>
</div>
CSS
.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
  box-sizing: border-box
}

.demo-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 280px;
  overflow: hidden;
  position: relative;
  background: rgb(10, 10, 15);
  color: rgb(255, 255, 255);
  font-family: sans-serif;
}

.synthwave-scene {
  width: 300px;
  height: 200px;
  background: linear-gradient(180deg, #0a001a 0%, #1a0033 30%, #2d004d 50%, #ff006e 51%, #ff006e 52%, #0a001a 52%);
  border-radius: 12px;
  position: relative;
  overflow: hidden;
}

.synthwave-sun {
  position: absolute;
  width: 80px;
  height: 80px;
  background: linear-gradient(180deg, #ff9900, #ff006e, #cc00ff);
  border-radius: 50%;
  top: 20%;
  left: 50%;
  transform: translateX(-50%);
  box-shadow: 0 0 40px #ff006e, 0 0 80px #ff006e66;
  clip-path: polygon(0 0, 100% 0, 100% 40%, 0 40%, 0 45%, 100% 45%, 100% 55%, 0 55%, 0 60%, 100% 60%, 100% 100%, 0 100%);
}

.synthwave-grid {
  position: absolute;
  bottom: 0;
  left: -50%;
  width: 200%;
  height: 48%;
  background:
    linear-gradient(90deg, transparent 0%, rgba(255, 0, 110, 0.3) 49.5%, #ff006e 50%, rgba(255, 0, 110, 0.3) 50.5%, transparent 100%),
    repeating-linear-gradient(90deg, transparent, transparent calc(10% - 1px), rgba(255, 0, 110, 0.4) calc(10% - 1px), rgba(255, 0, 110, 0.4) 10%),
    repeating-linear-gradient(0deg, transparent, transparent 20px, rgba(255, 0, 110, 0.3) 20px, rgba(255, 0, 110, 0.3) 21px);
  transform: perspective(200px) rotateX(60deg);
  transform-origin: center top;
  animation: synthGrid 2s linear infinite;
}

.synthwave-text {
  position: absolute;
  top: 8%;
  width: 100%;
  text-align: center;
  font-family: 'Inter', sans-serif;
  font-weight: 900;
  font-size: 20px;
  letter-spacing: 4px;
  text-transform: uppercase;
  background: linear-gradient(180deg, #00ffff, #ff00ff);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  filter: drop-shadow(0 0 10px #ff00ff) drop-shadow(0 0 20px #00ffff);
}

.synthwave-stars {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 52%;
  overflow: hidden;
}

.synthwave-stars span {
  position: absolute;
  width: 2px;
  height: 2px;
  background: #fff;
  border-radius: 50%;
  animation: twinkle 3s ease-in-out infinite;
}

.synthwave-stars span:nth-child(1) {
  top: 10%;
  left: 15%;
  animation-delay: 0s;
}

.synthwave-stars span:nth-child(2) {
  top: 20%;
  left: 75%;
  animation-delay: 0.7s;
}

.synthwave-stars span:nth-child(3) {
  top: 5%;
  left: 45%;
  animation-delay: 1.2s;
}

.synthwave-stars span:nth-child(4) {
  top: 30%;
  left: 85%;
  animation-delay: 0.3s;
}

.synthwave-stars span:nth-child(5) {
  top: 8%;
  left: 60%;
  animation-delay: 1.8s;
}

.synthwave-stars span:nth-child(6) {
  top: 25%;
  left: 25%;
  animation-delay: 2.1s;
}

.synthwave-stars span:nth-child(7) {
  top: 15%;
  left: 90%;
  animation-delay: 0.9s;
}

.synthwave-stars span:nth-child(8) {
  top: 35%;
  left: 10%;
  animation-delay: 1.5s;
}

@keyframes synthGrid {
  0% {
    background-position-y: 0px;
  }

  100% {
    background-position-y: 21px;
  }
}

@keyframes twinkle {

  0%,
  100% {
    opacity: 0.3;
  }

  50% {
    opacity: 1;
  }
}
JavaScript
/* CSS pur — aucun JavaScript requis */

Cursed Blood Goo

Du sang liquide en metaballs : il goutte, fusionne, coule et s'accumule en flaque. Le curseur transporte un glob qui projette des gouttelettes et aspire le sang alentour. Couleur personnalisable (slime, encre, lave…).

💡 Idéal pour : hero Halloween gore, page 404 « qui saigne », intro de film/horreur, header d'événement, fond de section premium, écran de chargement.

Canvas Metaballs Liquide Gratuit
Voir le code source
HTML
<div class="demo-preview">
  <div class="goo-scene" data-goo data-color="#c81e2d">
    <canvas class="goo-canvas"></canvas>
    <div class="goo-hint" aria-hidden="true">Balaye le sang…</div>
  </div>
</div>
CSS
.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
  box-sizing: border-box
}

.demo-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 200px;
  position: relative;
  background: rgb(10, 10, 15);
  color: rgb(255, 255, 255);
  font-family: sans-serif;
}

.goo-scene {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 10;
  border-radius: 14px;
  overflow: hidden;
  isolation: isolate;
  background: #0b0406;
  cursor: crosshair;
}

.goo-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  filter: blur(7px) contrast(16);
}

.goo-hint {
  position: absolute;
  bottom: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  font-size: 12px;
  color: #ff5a5a;
  opacity: .6;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .goo-scene {
    cursor: auto;
  }
}
JavaScript
(function() {
  /* ============================================================
     JS scopé (IIFE) — Cursed Blood Goo (fx-0803)
     Metaballs de sang sur chaque [data-goo]
  ============================================================ */
  (function() {
    var reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    var MAX = 130;

    document.querySelectorAll('[data-goo]').forEach(function(scene) {
      var canvas = scene.querySelector('.goo-canvas');
      var ctx = canvas.getContext('2d');
      var color = scene.dataset.color || '#c81e2d';
      var dpr = Math.min(devicePixelRatio || 1, 2);
      var W, H, drops = [],
        pool = 0,
        frame = 0;
      var mx = -999,
        my = -999,
        on = false,
        bx = -999,
        by = -999,
        pmx = -999,
        pmy = -999;

      function resize() {
        W = canvas.width = scene.clientWidth * dpr;
        H = canvas.height = scene.clientHeight * dpr;
      }
      resize();
      window.addEventListener('resize', resize);

      scene.addEventListener('pointermove', function(e) {
        var r = scene.getBoundingClientRect();
        mx = (e.clientX - r.left) * dpr;
        my = (e.clientY - r.top) * dpr;
        on = true;
      });
      scene.addEventListener('pointerleave', function() {
        on = false;
        mx = my = -999;
      });

      function blob(x, y, r) {
        ctx.beginPath();
        ctx.arc(x, y, r, 0, 6.2832);
        ctx.fill();
      }

      function render() {
        ctx.fillStyle = '#0b0406';
        ctx.fillRect(0, 0, W, H);
        ctx.fillStyle = color;
        // flaque (surface ondulée)
        var surf = H - pool;
        ctx.beginPath();
        ctx.moveTo(0, H + 2);
        ctx.lineTo(0, surf);
        for (var x = 0; x <= W; x += 18 * dpr) ctx.lineTo(x, surf + Math.sin(x * 0.012 + frame * 0.05) * 6 * dpr);
        ctx.lineTo(W, H + 2);
        ctx.closePath();
        ctx.fill();
        // gouttes
        for (var i = 0; i < drops.length; i++) blob(drops[i].x, drops[i].y, drops[i].r);
        // glob du curseur
        if (on && bx > -500) blob(bx, by, 34 * dpr);
      }

      if (reduceMotion) {
        // scène figée : flaque + quelques gouttes au repos
        pool = H * 0.22;
        for (var i = 0; i < 9; i++) drops.push({
          x: (0.12 + Math.random() * 0.76) * W,
          y: (0.2 + Math.random() * 0.45) * H,
          r: (12 + Math.random() * 14) * dpr
        });
        render();
        return;
      }

      (function loop() {
        requestAnimationFrame(loop);
        frame++;
        // dégoulinade depuis le haut
        if (frame % 11 === 0 && drops.length < MAX) drops.push({
          x: Math.random() * W,
          y: -12 * dpr,
          vx: (Math.random() - 0.5) * 0.5,
          vy: 1 + Math.random() * 1.4,
          r: (9 + Math.random() * 9) * dpr
        });
        var floorY = H - pool;
        for (var i = drops.length - 1; i >= 0; i--) {
          var d = drops[i];
          d.vy += 0.28 * dpr;
          d.vx *= 0.99;
          d.x += d.vx;
          d.y += d.vy;
          if (on) {
            var ax = mx - d.x,
              ay = my - d.y,
              dist = Math.hypot(ax, ay);
            if (dist < 150 * dpr && dist > 1) {
              var f = (1 - dist / (150 * dpr)) * 0.7;
              d.vx += ax / dist * f;
              d.vy += ay / dist * f;
            }
          }
          if (d.y + d.r * 0.4 >= floorY) {
            pool = Math.min(H * 0.5, pool + (d.r * d.r) / W * 0.8);
            drops.splice(i, 1);
            continue;
          }
          if (d.x < -40 * dpr || d.x > W + 40 * dpr) drops.splice(i, 1);
        }
        pool = Math.max(0, pool - 0.14 * dpr); // la flaque s'écoule lentement → équilibre
        if (on) {
          bx += (mx - bx) * 0.3;
          by += (my - by) * 0.3;
          var sp = Math.hypot(mx - pmx, my - pmy);
          if (sp > 13 * dpr && drops.length < MAX) drops.push({
            x: bx + (Math.random() - 0.5) * 22 * dpr,
            y: by + (Math.random() - 0.5) * 22 * dpr,
            vx: (mx - pmx) * 0.07,
            vy: (my - pmy) * 0.07 + 1,
            r: (6 + Math.random() * 6) * dpr
          });
        }
        pmx = mx;
        pmy = my;
        render();
      })();
    });
  })();
})();

Questions fréquentes

Comment créer un effet glitch en CSS ? +

L'effet glitch utilise des pseudo-éléments (::before, ::after) positionnés en absolu avec des clip-path animés. Chaque pseudo-élément montre une copie décalée du texte avec des couleurs différentes (rouge, cyan). L'animation déplace les clip-path de manière saccadée.

Qu'est-ce que le displacement mapping en CSS ? +

Le displacement mapping déforme une image en utilisant une carte de déplacement (une image en niveaux de gris). En CSS, on simule cet effet avec SVG filters (feTurbulence + feDisplacementMap). En JavaScript, on utilise WebGL ou canvas.

Les effets de distortion sont-ils accessibles ? +

Les effets de distortion peuvent poser des problèmes d'accessibilité pour les personnes épileptiques ou sensibles aux mouvements. Respectez toujours prefers-reduced-motion et évitez les clignotements rapides (plus de 3 flashs par seconde, règle WCAG 2.3.1).

Quel est l'effet de distortion le plus performant ? +

Les effets CSS purs (glitch avec clip-path, noise avec background-image) sont les plus légers. Les effets canvas/WebGL (displacement, pixelisation) sont plus lourds mais plus spectaculaires. Utilisez requestAnimationFrame et pausez hors viewport.

Comment appliquer un effet de distortion à une image ? +

Utilisez un filtre SVG avec feTurbulence pour générer du bruit, puis feDisplacementMap pour déformer l'image. Appliquez le filtre avec CSS filter: url(#monFiltre). Animez l'attribut baseFrequency du feTurbulence pour un effet dynamique.