Prismatic Refraction Card
Une vitre de 340 px posée sur quatre taches de couleur floutées : backdrop-filter blur 18 px + saturate 250 %, deux bordures rouge et cyan décalées jusqu'à ±4,2 px selon le pointeur (l'aberration chromatique), une bande arc-en-ciel translatée jusqu'à ±27 % et un tilt ±10° / ±7°, le tout lissé par une boucle rAF qui s'arrête au repos et se réveille au pointeur ou au clavier. Mesuré : le texte blanc tombe à 1,4–3,9:1 sur le verre.
Vous aurez accès à la démo interactive avec un compte gratuit.
Cet effet fait partie d'Effect.Labs — 811 effets vanilla, une partie gratuite, une partie premium. Cartes comprend 41 effets, dont 6 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
La scène : .prc-scene (width: 100%; aspect-ratio: 16 / 10, border-radius: 14px; overflow: hidden; isolation: isolate; perspective: 1000px, fond #0b1020, curseur crosshair) contient .prc-bg (inset: -14%) et ses quatre .prc-blob — des disques de 46 % de large (#ff2050, #2855ff, #00d4aa, #bf38ff), filter: blur(34px), opacité .88, animés par prc-float sur 20 s (translation ±10 %, échelle .93 à 1.10, décalages 0 / −6 / −13 / −9 s). Ils existent pour que la vitre ait quelque chose à réfracter. .prc-card-wrap (min(72%, 340px), will-change: transform) reçoit le tilt et contient .prc-ca puis .prc-glass.
La vitre : background: linear-gradient(135deg, rgba(255,255,255,.16), .05), bordure 1 px blanche à 22 %, quatre ombres (0 16px 56px .40, un filet clair interne inset 0 1px 1px .56, une pénombre interne inset 0 -2px 10px .20 et un halo vert 0 0 3px rgba(0,255,130,.16)), et backdrop-filter: blur(18px) saturate(250%) brightness(1.06), préfixé -webkit-. ::before = biseau statique (dégradé 128°, blanc .26 → transparent à 65 %) ; ::after = spéculaire radial-gradient(115px 95px at var(--mx) var(--my), blanc .40 → .08 → transparent) en screen. .prc-prism (210 % × 210 %, top/left: -55%) est un dégradé à 108° de sept bandes colorées à 14–22 % d'alpha entre 26 et 70 % de sa largeur, en screen, opacité --prc-prism-opacity (.78) ; l'overflow: hidden de la vitre n'en montre qu'une fenêtre, que le JS déplace.
L'aberration chromatique : .prc-ca (inset: 0; border-radius: 28px) porte ::before, une bordure de 1,8 px rgba(255,32,62,.82) avec halo, translatée de (--prc-ca-x, --prc-ca-y), et ::after, la même en cyan rgba(0,210,255,.82) translatée à l'opposé (calc(var() * -1)). Les deux ont transition: transform .14s ease-out, qui s'ajoute au lissage du JS. Le wrapper reçoit les variables : cax = (lx − .5) × 8,4 → ±4,2 px, cay = (ly − .5) × 4,2 → ±2,1 px. La position de repos IDLE (.66, .34) n'est pas centrée : sans interaction, les franges sont déjà décalées de +1,34 / −0,67 px et la carte inclinée de 3,2° / 2,2°.
Le script lit quatre ids (prcScene, prcWrap, prcGlass, prcPrism) et s'arrête s'il en manque un — une seule carte par page, plus un second jeu d'ids optionnel (…Ex). pointermove sur la scène normalise la position (0 à 1, bornée) ; tick() avance de 7,2 % du chemin par image (95 % en ≈ 40 images, ≈ 670 ms à 60 Hz) et appelle applyCard : rotateX((.5 − ly) × 14) rotateY((lx − .5) × 20) sur le wrapper, variables des franges, --mx/--my en % sur la vitre, translate((lx − .5) × 54%, (ly − .5) × 54%) sur la bande. tick() ne se replanifie que tant que l'écart entre cible et valeur lissée dépasse .0005 sur l'une des deux scènes ; sinon la boucle s'arrête (rafId = 0) et reveiller() la relance au pointermove, au pointerleave et à chaque flèche du clavier — au repos, aucun appel rAF. Au clavier, les flèches déplacent la cible de .16, Échap et Début la recentrent. Aucun écouteur touchmove : pointermove couvre déjà le tactile, et le défilement de la page reste libre. Le fichier livre aussi neuf getElementById pour des curseurs de review (prcIntensity, prcTilt, prcA11y…) et ~105 lignes de CSS pour une carte pricing (.prc-glass--pricing, .prc-price-*, .prc-features, .prc-cta) qu'aucun HTML vendu n'utilise.
Accessibilité
- Contraste insuffisant dans la version fournie — mesuré dans Chromium (texte rendu transparent, pixels échantillonnés sous le texte, trois positions de pointeur et trois instants du cycle des taches) : titre
#fff20 px gras, minimum 1,35:1, médiane 2,6 à 3,05:1, maximum 3,9:1 — sous le seuil de 3:1 du texte large sur la majorité des pixels ; corpsrgba(255,255,255,.88)13,5 px, minimum 1,21:1, médiane ≈ 2,5:1 (seuil 4,5:1). L'ombretext-shadow: 0 1px 12px rgba(0,0,0,.55)ne change pas le minimum (1,57). Correction calculée sur le pixel le plus clair mesuré (rgb(26,249,218)) :.prc-content { background: rgba(8,10,28,.6); padding: 14px 16px; border-radius: 14px }→ titre 6,4:1, corps 5,4:1 (à .55 d'alpha : 5,3 / 4,5). Alternative : assombrir la vitre elle-même (brightness(.7), fondrgba(8,10,28,.5)). - Mouvement réduit : les taches se figent, les transitions des franges disparaissent, le tilt et la bande sont désactivés ; mais
LERPpasse à 1 et le spéculaire suit encore le pointeur — plus d'animation, mais toujours du mouvement. Transparence réduite : vitre opaque#13162e, bande masquée — le texte passe alors à 17,8:1. - Rôles :
.prc-glassporterole="img",tabindex="0"et réagit aux flèches — une image n'est pas interactive : les lecteurs d'écran annoncent une image et l'indication clavier du libellé (vendu en français) ne correspond à rien pour eux. Utilisezrole="group"avec le libellé, ou retireztabindexsi le pilotage clavier n'est pas voulu. - Tactile : aucun écouteur
touchmove, la page défile normalement quand le doigt passe sur la carte ; les Pointer Events (pointermove) pilotent l'effet au doigt, et la scène faitwidth: 100%— la carte occupe toute la largeur du téléphone. Si vous voulez au contraire que le doigt pilote la carte sans faire défiler la page, poseztouch-action: nonesur.prc-scene. - Focus :
.prc-glass:focus-visibledessineoutline: 3px solid rgba(129,140,248,.88)à 4 px. Performance : quatre taches floutées à 34 px en animation permanente et unbackdrop-filterrecalculé à chaque image — lourd sur GPU modeste, même boucle rAF arrêtée (elle ne tourne que pendant le lissage, environ 80 à 100 images après le dernier geste — calculé, ≈ 1,5 s à 60 Hz). Pour alléger, réduisez le flou des taches ou figez-les hors survol.
Compatibilité navigateur
Requiert backdrop-filter (préfixe -webkit- fourni), aspect-ratio, inset, mix-blend-mode, calc() sur variables et les Pointer Events. Aucune bibliothèque.
Sans backdrop-filter (Firefox avant 103), la vitre n'est qu'un dégradé blanc à 16 → 5 % : les taches restent nettes derrière, l'effet verre disparaît, franges et bande arc-en-ciel demeurent. Sans JavaScript, tout reste à la position de repos des variables CSS (franges décalées de 2,5 / 0,8 px, spéculaire à 32 % / 22 %), rien ne suit le pointeur ; les taches continuent de flotter.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
<div class="prc-scene" id="prcScene">
<div class="prc-bg" aria-hidden="true">
<span class="prc-blob prc-blob--1"></span>
<span class="prc-blob prc-blob--2"></span>
<span class="prc-blob prc-blob--3"></span>
<span class="prc-blob prc-blob--4"></span>
</div>
<div class="prc-card-wrap" id="prcWrap">
<div class="prc-ca" aria-hidden="true"></div>
<div class="prc-glass" id="prcGlass" tabindex="0" role="img" aria-label="Carte en verre avec dispersion prismatique — déplacez la souris ou les flèches clavier">
<div class="prc-prism" aria-hidden="true" id="prcPrism"></div>
<div class="prc-content">
<h3 class="prc-title">Prismatic Glass</h3>
<p class="prc-body">Les arêtes décomposent la lumière en rouge et cyan. Déplacez le curseur pour balayer l'arc-en-ciel.</p>
</div>
</div>
</div>
</div>
HTML + CSS + JS complet, prêt à coller — avec des centaines d'effets premium.
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
| CA_SCALE (JS) | 4.2 | Décalage maximal des franges : ±4,2 px en x (× 2), ±2,1 px en y. 8 = prisme appuyé ; 1.5 = subtil. Les deux canaux s'écartent symétriquement. |
| TILT_X / TILT_Y (JS) | 14 / 20 | Amplitude du tilt en degrés (±7° / ±10°). TILT_MULT est un multiplicateur laissé pour un curseur de review — inutile en production. |
| LERP (JS) | 0.072 | Fraction du chemin restant par image. .15 = réactif (~300 ms) ; .04 = lent (1,2 s). Sous prefers-reduced-motion il vaut 1 (instantané). |
| IDLE_X / IDLE_Y (JS) | .66 / .34 | Position de repos (0 à 1) : franges et spéculaire déjà décalés sans interaction, carte inclinée de 3,2° / 2,2°. .5 / .5 = carte parfaitement de face au repos. |
Bande prismatique (CSS — .prc-prism, --prc-prism-opacity) |
sept bandes, opacité .78 | Couleurs à 14–22 % d'alpha entre 26 et 70 % de la largeur de la bande ; course JS ±27 % ((lx − .5) × 54). .4 pour un arc-en-ciel discret ; 0 le supprime sans toucher au HTML. |
| Verre (CSS — .prc-glass backdrop-filter) | blur(18px) saturate(250%) brightness(1.06) | Le saturate à 250 % fait éclater les taches derrière la vitre — c'est lui qui écrase le contraste. saturate(140%) brightness(.8) donne un verre fumé, plus lisible. |
| Taches (CSS — .prc-blob : couleurs, blur 34px, opacité .88, 20 s) | #ff2050, #2855ff, #00d4aa, #bf38ff | La lumière que le verre réfracte. Remplacez par vos couleurs de marque ; sur un fond de page déjà coloré, supprimez .prc-bg — le verre filtre alors ce qui est derrière lui. |
FAQ
prcScene, prcWrap, prcGlass, prcPrism) et prévoit un second jeu codé en dur (prcSceneEx, prcWrapEx, prcGlassEx, prcPrismEx) — l'exemple d'usage de la page catalogue. Pour N cartes, remplacez les getElementById par document.querySelectorAll('.prc-scene').forEach(init) avec scene.querySelector('.prc-card-wrap'), etc., et un état (mx, my, tx, ty) par scène.saturate(250%) qui rend les taches cyan et rose très lumineuses derrière lui. Le remède le moins visible est un scrim sous le seul contenu, rgba(8,10,28,.6) : titre 6,4:1 et corps 5,4:1 sur le pixel le plus clair mesuré. Sinon, ramenez le saturate à 140 % et le brightness à .8.tick() s'arrête d'elle-même : elle ne se replanifie que tant que l'écart entre la cible et la valeur lissée dépasse .0005 (sur la carte principale ou sur l'exemple), puis rafId repasse à 0 et reveiller() la relance au prochain pointermove, pointerleave ou appui sur une flèche — au repos, aucun appel requestAnimationFrame. Ce qui continue de tourner : les quatre taches floutées, animées en CSS sur 20 s, et le backdrop-filter de la vitre, recalculé à chaque image où quelque chose bouge derrière elle. Sous prefers-reduced-motion, les taches se figent (animation: none) et la boucle, LERP à 1, s'arrête dès l'image suivante.