Effets Visuels & Distortions
Distortion, holographique, CRT, VHS, glitch et rétro digital.
Mis à jour le
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.
RGB Split
Séparation chromatique style corruption.
Voir le code source
<div class="demo-preview">
<div class="rgb-split" data-text="GLITCH">GLITCH</div>
</div>.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);
}
}/* CSS pur — aucun JavaScript requis */VHS Effect
Effet cassette VHS rétro avec scanlines.
Pixelate Effect
Pixelisation au survol style 8-bit.
Melting Text
Texte qui fond et se déforme.
Wave Distortion
Ondulation et torsion du texte.
Noise Overlay
Texture grain animée style film.
CRT Screen
Effet écran cathodique rétro.
Glitch Blocks
Blocs de corruption aléatoires.
Broken Glass
Effet verre brisé avec éclats et fissures.
Static Noise
Interférence TV statique style analogique.
Holographic Card
Reflets arc-en-ciel au survol style carte Pokémon.
Voir le code source
<div class="demo-preview">
<div class="holo-card">HOLO CARD</div>
</div>.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%;
}
}/* CSS pur — aucun JavaScript requis */Iridescent Surface
Surface changeante style nacre ou bulle de savon.
Prismatic Text
Texte avec aberration chromatique et dispersion.
Chrome Reflection
Surface métallique chromée avec reflet.
Oil Slick
Effet flaque d'huile avec reflets multicolores.
Hologram Projection
Projection holographique flottante avec scanlines.
Rainbow Refraction
Lumière réfractée à travers un prisme.
Crystal Effect
Gemme cristalline avec reflets internes.
Holographic Badge
Badge autocollant avec effet foil holographique rotatif.
Laser Beam
Faisceau laser animé avec réfraction arc-en-ciel.
> LOADING DATA...
> READY_
CRT Monitor Effect
Effet moniteur CRT avec scanlines, courbure d'écran et lueur phosphore verte.
Voir le code source
<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>.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;
}
}/* CSS pur — aucun JavaScript requis */VHS Tracking
Distorsion de tracking VHS animée avec déplacement horizontal et bleeding couleur.
ASCII Art Renderer
Texte affiché en caractères ASCII avec police monospace et look terminal vert sur noir.
Pixel Dissolve
Élément qui se pixelise et se dissout au survol avec transition par étapes CSS.
LED Matrix Display
Texte rendu en afficheur LED dot-matrix avec lueur rouge et grille de points.
Retro Terminal
Terminal vert sur noir avec animation de frappe, curseur clignotant et scanlines CRT.
Gameboy Palette
Contenu rendu dans la palette 4 nuances de vert du Gameboy avec filtre CSS.
Dot Matrix Printer
Texte apparaissant ligne par ligne comme imprimé par une imprimante matricielle.
Windows 95 UI Kit
Boutons et fenêtre avec bordures biseautées 3D authentiques style Win95.
Synthwave Scene
Scène rétro animée avec grille en perspective, soleil néon et palette rose/cyan/violet.
Voir le code source
<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>.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;
}
}/* 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.
Voir le code source
<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>.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;
}
}(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();
})();
});
})();
})();