Layered Parallax
Cinq calques absolus dans une section de 900 px, chacun sur sa propre trajectoire animation-timeline: scroll() : fond en scale 1 → 1,3, formes en translateY 60 → −80 px et rotation −5° → +10°, anneaux 40 → −60 px et +5° → −8°, titre 20 → −20 px et opacité ,7 → 1, points 80 → −100 px. CSS pur, zéro script, course de 620 px.
Mis à jour le
Cet effet fait partie d'Effect.Labs — 811 effets vanilla, une partie gratuite, une partie premium. Scroll comprend 70 effets, dont 12 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
Quatre niveaux dans le HTML vendu : le cadre .demo-preview (flex centré, min-height: 300px, position: relative, fond #0a0a0f), la boîte .sdc-scroll-container (100% × 280px, overflow-y: auto, scroll-behavior: smooth, barre de 4 px via ::-webkit-scrollbar), la section .ss-parallax-content (900 px, position: relative, overflow: clip, dégradé 135° #0f0f23 → #1a1a3e) et cinq .ss-parallax-layer en position: absolute; inset: 0. Calque 1 : deux halos radiaux, violet à 30 % 40 % et cyan à 70 % 60 %. Calque 2 : huit .ss-parallax-shape en flex-wrap centré — carré de 45 px, rond de 35 px sur les positions paires, pilule de 55 × 30 sur les multiples de 3, opacités ,5 / ,4 / ,35, dégradés violet → magenta et cyan → violet. Calque 3 : cinq .ss-parallax-ring, cercles à bordure de 2 px, 60 px cyan et 40 px violet en alternance. Calque 4 (z-index: 2) : un titre de 20,8 px graisse 800 et un sous-titre de 12 px blanc à 60 %, textes écrits en dur (« Parallax Layers », « Chaque couche se deplace a une vitesse differente », sans accents). Calque 5 : douze .ss-parallax-dot de 8, 12 et 6 px. Sous la boîte, span.sdc-scroll-hint « Scrollez ↓ », absolu à 8 px du bas du cadre, 10,4 px, pulsation ,3 ↔ ,7 en 2 s. Champ JavaScript vide. Course : 900 − 280 = 620 px, identique à 1 264 et 374 px de large (mesuré).
Cinq @keyframes (ssPlx1 à ssPlx5), un par calque, chacun rattaché par animation-timeline: scroll(), animation-duration: auto, animation-range: normal, linear, animation-fill-mode: none. scroll() équivaut à scroll(nearest block) : la timeline suit le conteneur de défilement le plus proche — la boîte de 280 px — et la progression vaut scrollTop ÷ 620. Mesuré dans Chromium à 0 / 310 / 620 px : fond scale 1 / 1,15 / 1,3 (le calque de 1 264 × 900 px devient 1 643 × 1 170, rogné par overflow: clip) ; formes translateY 60 / −10 / −80 px et rotate −5° / 2,5° / 10° ; anneaux 40 / −10 / −60 px et 5° / −1,5° / −8° ; titre 20 / 0 / −20 px et opacité ,7 / ,85 / 1 ; points 80 / −10 / −100 px. En bout de course l'animation se déclare finished mais reste appliquée (scale(1.3) relu à 620 px). Pour 620 px de molette, cinq vitesses apparentes : le fond 620 px (il grossit, il ne monte pas), le titre 660, les anneaux 720, les formes 760, les points 800. Les deux rotations opposées tournent des calques de toute la largeur autour de leur centre : la première forme, à 280 px à gauche du centre, monte de 209 px (140 de translation + 69 de rotation) quand la huitième, à droite, ne monte que de 73 ; pour les anneaux c'est l'inverse, 69 px à gauche et 133 à droite. Cette torsion croisée fait la profondeur, davantage que les vitesses.
Livré avec overflow: hidden sur la section, l'effet était inerte : hidden fait de la section un conteneur de défilement à course nulle, et scroll() s'y rattachait — mesuré sur l'original, timeline.source = .ss-parallax-content, currentTime null, cinq calques à transform: none de 0 à 620 px. overflow: clip rogne pareil sans créer de conteneur de défilement : la timeline remonte à .sdc-scroll-container. C'est la seule ligne changée. Pas d'id, pas de script : collé deux fois, chaque copie suit sa propre boîte (mesuré : première au repos à translateY(80px), seconde en bout de course à −100). Le titre, à 449 px du haut de la section au repos, n'entre dans la fenêtre de 280 px qu'à scrollTop 160 et en sort à 440 : centré à mi-course, invisible au repos.
Accessibilité
- prefers-reduced-motion absent du code : mesuré sous émulation, rien ne change — scale 1,3, −100 px et 10° en bout de course, indice qui pulse. Le mouvement suit le geste du lecteur, mais WCAG 2.3.3 vise aussi les animations déclenchées par l'interaction : ajoutez
@media (prefers-reduced-motion: reduce) { .ss-parallax-layer { animation: none } .sdc-scroll-hint { animation: none } .sdc-scroll-container { scroll-behavior: auto } }. Les cinq calques se figent alors à leur état de base (transform: none, opacité 1) — exactement ce que voit Firefox, tout reste lisible. - Clavier : mesuré sur le code vendu, Tab donne le focus à la boîte sans
tabindexdans Chromium 151 comme dans Firefox 153 ; flèche bas avance de 40 px dans Chromium (6,5 % de la course) et de 51 dans Firefox, Page suivante va à 285 et 303, Fin à 620 — dans Firefox la boîte défile au clavier mais les calques restent à plat (voir Compatibilité). WebKit 26.5 ne focalise pas la boîte sanstabindex="0": Tab reste sur la page, flèches et Fin sans effet ; avec l'attribut, 40, 280 et 620. Ajoutez-le sur.sdc-scroll-container, avec unaria-labelet un style:focus-visible. Au doigt, le geste doit commencer dans les 280 px ;overscroll-behavior: containévite d'entraîner la page en butée. - Contraste : le titre blanc de 20,8 px vaut 16,7 à 18,9:1 sur le dégradé, encore 11:1 à son entrée dans la fenêtre (calque à 78 % d'opacité). Le sous-titre blanc à 60 % dans un calque à ,7 tombe à 4,0:1 au repos — mais il n'est pas visible au repos : 4,7:1 quand il entre (scrollTop 160), 5,3:1 au centre, 6,0:1 à la sortie, tenu de peu pour 12 px. Ne descendez pas l'opacité de départ de
ssPlx4sous ,7 si le sous-titre porte une information. L'indice à 30 % vaut 2,6:1 : décoratif,aria-hidden="true". - Lecteurs d'écran : formes, anneaux et points sont des
divvides, rien n'est annoncé ; le titre et le sous-titre sont lus dans l'ordre du DOM, la position de défilement n'y change rien. Posezaria-hidden="true"sur les calques 1, 2, 3 et 5, et donnez au calque 4 un vrai niveau de titre (h2/h3) si la section ouvre une page. Les deux textes vendus sont en français sans accents : à remplacer.
Compatibilité navigateur
CSS seul : animation-timeline: scroll(), animation-duration: auto, animation-range, overflow: clip, flexbox, dégradés, transforms 2D. Zéro JavaScript, zéro dépendance. Les animations pilotées par le défilement existent dans Chrome et Edge 115+, Safari et iOS 26 ; Firefox ne les exécute dans aucune version. Mesuré dans le Firefox de Playwright, page vierge : CSS.supports('animation-timeline: scroll()') renvoie faux, animation-duration: auto aussi — la durée retombe à 0 s et, avec animation-fill-mode: none, les cinq calques restent à leur état de base : transform: none, opacité 1, relus à 0, 155, 310, 465 et 620 px. Un visiteur Firefox voit une section fixe de 900 px qui défile dans la boîte de 280 : halos, formes, anneaux, titre (visible de scrollTop 150 à 450 environ), points — sans parallaxe, rien de caché, rien hors cadre, rien de superposé. Aucun bloc @supports dans le code : l'état de base est déjà le repli à plat.
Avant Chrome/Edge 115 et Safari 26, même état que dans Firefox : les déclarations animation-timeline et animation-duration: auto sont ignorées, les calques restent à plat et la section défile. overflow: clip est inconnu avant Chrome 90, Firefox 81 et Safari 16 : la déclaration tombe, la section passe en overflow: visible, mais rien n'y déborde puisque rien n'y est animé (calques en inset: 0). Sans le cadre .demo-preview, l'indice « Scrollez ↓ » perd son ancre (position: absolute) et tombe au bas de la page : retirez-le ou gardez un parent en position: relative.
Le code
Structure HTML à coller dans votre page (le CSS + JS sont inclus avec Premium) :
<div class="demo-preview">
<div class="sdc-scroll-container">
<div class="ss-parallax-content">
<div class="ss-parallax-layer ss-parallax-layer-1"></div>
<div class="ss-parallax-layer ss-parallax-layer-2">
<div class="ss-parallax-shape"></div> ×8
</div>
<div class="ss-parallax-layer ss-parallax-layer-3">
<div class="ss-parallax-ring"></div> ×5
</div>
<div class="ss-parallax-layer ss-parallax-layer-4">
<div>
<div class="ss-parallax-title">…</div>
<div class="ss-parallax-subtitle">…</div>
</div>
</div>
<div class="ss-parallax-layer ss-parallax-layer-5">
<div class="ss-parallax-dot"></div> ×12
</div>
</div>
</div>
<span class="sdc-scroll-hint">…</span>
</div>
Le code complet HTML + CSS + JS de Layered Parallax, prêt à coller — et les 811 effets. Ou 299 € une fois, accès à vie.
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
Course (CSS — .ss-parallax-content { height: 900px }, .sdc-scroll-container { height: 280px }) |
620 px | La progression vaut scrollTop ÷ (hauteur de la section − hauteur de la boîte) : toutes les amplitudes se jouent sur cette course. 1 500 px de section = 1 220 px de course, parallaxe plus lente ; 400 px = 120 px, très vif (mesuré 180 px en scène 3). La boîte peut prendre la hauteur de votre mise en page, ou disparaître : sans boîte, scroll() suit la page. |
Amplitudes (CSS — @keyframes ssPlx1 à ssPlx5) |
scale 1 → 1,3 · 60 → −80 px et −5° → 10° · 40 → −60 px et 5° → −8° · 20 → −20 px et ,7 → 1 · 80 → −100 px | Chaque calque a ses deux images-clés : changez une valeur, sa vitesse relative change. Les rotations tournent tout le calque autour de son centre : à 10°, un point à 600 px du centre bouge de 104 px — sur une section large, réduisez-les à 3–5° ou les formes des bords sortent du cadre (rognées par overflow: clip). |
Fond (CSS — .ss-parallax-content { background }, .ss-parallax-layer-1 { background }) |
dégradé 135° #0f0f23 → #1a1a3e, deux halos violet et cyan | Le calque 1 ne porte que les halos et grossit de 1 à 1,3 : à 1,3 il déborde de 190 px de chaque côté, rogné. Le cadre .demo-preview reste #0a0a0f derrière la boîte : alignez-le sur votre page si elle est claire. Les trois scènes en font une palette chaude, une néon et une marine. |
Formes, anneaux, points (CSS — .ss-parallax-shape, -ring, -dot et leurs :nth-child) |
8 formes (45, 35 et 55 × 30 px), 5 anneaux (60/40 px), 12 points (8/12/6 px) | Trois règles :nth-child(2n), (3n) et (5n) varient tailles et couleurs — la sixième forme est à la fois 2n et 3n, la règle 3n écrite après l'emporte. Ajoutez ou retirez des div, aucun compte n'est imposé ; la disposition est un flex-wrap centré (gap 30, 20 et 20 px) : flex-direction: column et un margin-left par élément donnent des barres empilées (scène 2). |
Titre (HTML + CSS — .ss-parallax-title, .ss-parallax-subtitle, .ss-parallax-layer-4) |
« Parallax Layers » 20,8 px graisse 800, sous-titre 12 px à 60 %, centré à 449 px du haut | Le calque 4 est un flex centré : au repos, le titre est hors de la fenêtre de 280 px, visible seulement entre 160 et 440 px de défilement. Pour un titre lisible d'emblée, align-items: flex-start; padding-top (scènes 1 et 3) ou une section plus courte. L'opacité ,7 → 1 est dans ssPlx4. |
Indice « Scrollez ↓ » (HTML + CSS — .sdc-scroll-hint, @keyframes sdcHintPulse) |
8 px du bas du cadre, 10,4 px, 30 → 70 % en 2 s | Absolu par rapport au cadre .demo-preview (position: relative) : sans le cadre, il tombe au bas de la page. Décoratif et en français : retirez le span, la keyframe part avec lui. |
Barre et lissage (CSS — .sdc-scroll-container) |
barre de 4 px violette (WebKit), scroll-behavior: smooth |
::-webkit-scrollbar n'existe pas dans Firefox (barre native) ; scrollbar-width: thin et scrollbar-color couvrent tous les moteurs. Le smooth n'agit que sur les positions posées par script ou par ancre : passez en auto si un bouton pilote la boîte. |
Timeline (CSS — animation-timeline: scroll(), animation-range: normal) |
défileur le plus proche, axe bloc, course entière | scroll(root) suit la page au lieu de la boîte ; une timeline nommée (scroll-timeline: --plx y sur la boîte, animation-timeline: --plx sur les calques) rattache l'effet à un défileur précis même si un ancêtre intermédiaire est overflow: auto ou hidden — le piège qui rendait le code inerte avant réparation. animation-range: 0 50% joue toute l'amplitude sur la première moitié de la course. |
FAQ
scroll() sans argument prend le conteneur de défilement le plus proche, et qu'un overflow: hidden en est un — programmable, à course nulle. Tel qu'il était vendu, chaque calque suivait donc la section elle-même : timeline inactive, cinq calques à transform: none quelle que soit la position, et la même règle rendait la démo du catalogue immobile. overflow: clip rogne à l'identique mais n'est pas un conteneur de défilement : la timeline remonte à la boîte de 280 px. Pour le vérifier chez vous, dans la console : document.querySelector('.ss-parallax-layer-5').getAnimations()[0].timeline.source doit renvoyer .sdc-scroll-container (ou html si vous avez retiré la boîte), et getComputedStyle(…).transform doit changer entre le haut et le bas de la course. Si vous enveloppez l'effet dans un bloc à overflow: hidden ou auto plus proche que le vrai défileur, le même piège se referme : passez ce bloc en clip ou nommez la timeline (voir « Timeline » dans les réglages).animation-timeline: scroll() — mais fx-0548 n'anime que des translations verticales : trois halos radiaux (translateY 40 → −60 px), huit points (20 → −40) et deux textes centrés, « PARALLAX » en 35 px et une légende (30 → −80 et 15 → −30, autour d'un translate(-50%, -50%)). Quatre keyframes, quatre vitesses, pas de rotation, pas d'échelle, pas d'opacité. fx-0592 en ajoute deux dimensions : deux rotations de signe opposé qui tordent le calque des formes et celui des anneaux en sens contraire (la gauche des formes monte de 209 px, la droite de 73 ; les anneaux font l'inverse), un fond qui grossit de 30 % et un titre qui émerge de ,7 à 1 — sur trois familles d'éléments (8 formes en trois variantes, 5 anneaux, 12 points) au lieu de halos et de points. Choisissez fx-0548 pour un glissement sobre à quatre plans ; fx-0592 quand vous voulez la torsion et le zoom du fond, ou des volumes typés (barres, pilules, anneaux) à recolorer. Les deux jumeaux au catalogue, Parallax Layers CSS et Parallax CSS (fx-0557, trois cercles flous), portent la même section en overflow: hidden : le même contrôle en console vaut pour eux..sdc-scroll-container en height: auto; overflow: visible) : scroll() remonte au défileur de la page et la progression court sur toute la hauteur du document — les calques bougent aussi quand la section n'est pas à l'écran, ce qui gaspille l'amplitude. Remplacez plutôt scroll() par view() sur les cinq calques : mesuré dans une fenêtre de 800 px avec la section posée après 1 000 px de contenu, la progression est à 0 % quand le haut de la section touche le bas de la fenêtre, 47 % quand elle en occupe le haut (scale(1.14)), 100 % quand son bas sort par le haut — 1 700 px de course ; hors de cette plage l'animation ne s'applique plus (fill-mode: none), sans effet visible puisque la section est hors champ. Gardez overflow: clip sur la section. La variante épinglée des scènes 1 et 3 (position: sticky; top: 0 sur la section, contenu qui monte dessus) fonctionne aussi dans la page : la section ne bouge plus, seuls ses calques glissent.