Scroll✨ Premium

Parallax Layers

Un cadre de 280 px qui défile sur 620 px, un seul écouteur scroll et six écritures de style par événement : halo de fond remonté de 60 px et grossi ×1,5, trois formes tournées de 180°, mot grossi ×1,8 et fondu à 50 % — sauf que les deux couches avant sont en position: absolute et quittent le cadre avant 26 % de la course.

CSSJavaScriptParallaxe

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. Scroll comprend 70 effets, dont 12 gratuits. Découvrir la catégorie →

3 exemples d'usage

Carte des vins d'un restaurant gastronomique — la bouteille qu'on tourne pour lire l'étiquette — Parallax Layers exemple 1

① Carte des vins d'un restaurant gastronomique — la bouteille qu'on tourne pour lire l'étiquette

QuandPage « carte des vins » d'un restaurant : un cadre par cru, fond de cave, médaillon de l'étiquette, nom du vin en avant-plan, millésime et prix en marge.
PourquoiLa rotation de la couche médiane évoque le geste réel de tourner une bouteille pour lire son étiquette — aucun autre effet de la catégorie ne produit ce mouvement rotatif sur une couche distincte de la translation de fond. Le fond de cave défile lentement avec un léger zoom, le médaillon tourne de 180° comme pour être lu de l'autre côté, et le nom du cru grossit avant de s'effacer pour laisser place au millésime suivant.
RéglagesCadre de 540 × 360 : .parallax-viewport et les trois couches à 360 px, .parallax-scroll-space à 600 px (course de 240 px) passé en display: grid, les trois couches en grid-area: 1 / 1; position: sticky; top: 0 pour rester dans le cadre jusqu'aux 180° ; disque de fond remplacé par la cave (540 × 360, sans blur), médaillon de 120 px dans le .plx-element de la médiane, mot en Georgia 28 px, dégradé or → crème. JS inchangé.
Carte du système solaire dans un cours de physique en ligne — l'orbite encodée dans l'effet — Parallax Layers exemple 2

② Carte du système solaire dans un cours de physique en ligne — l'orbite encodée dans l'effet

QuandFigure interactive d'un chapitre sur le mouvement orbital : fond étoilé, soleil au centre de l'anneau d'orbite, planète sur l'anneau, nom de l'astre et distance en avant-plan.
PourquoiLes trois vitesses différentes combinées à la rotation de la couche médiane reproduisent le mouvement orbital sans CSS supplémentaire — la mécanique de l'effet encode directement la physique à enseigner, là où un simple parallaxe bi-couche ne ferait que décorer. Le fond étoilé défile lentement, la planète parcourt une demi-orbite autour du soleil (180°), le nom de l'astre et sa distance grossissent puis s'effacent au fil du scroll.
RéglagesMêmes réglages de cadre (360 px, course 240 px, couches collantes superposées). Fond : champ d'étoiles en radial-gradient multiples dans .plx-element (le zoom ×1,5 devient un rapprochement). Médiane : anneau d'orbite de 170 px avec le soleil centré (invariant par rotation) et la planète sur l'anneau ; rotate(180·e deg) devient une demi-révolution. Avant-plan : « Mars · 228 M km » en 26 px.
Fiche de segment dans un outil d'entraînement cycliste — contexte, effort et résultat en un seul geste — Parallax Layers exemple 3

③ Fiche de segment dans un outil d'entraînement cycliste — contexte, effort et résultat en un seul geste

QuandFiche d'un segment chronométré dans un outil d'analyse de performance : photo du col en fond, arc chronométrique, chrono du record, nom et profil du segment en marge.
PourquoiLa combinaison simultanée translate + rotate + scale + opacity sur trois couches condense trois informations (contexte, effort, résultat) en une seule interaction scroll — une superposition statique aurait nécessité des onglets ou des tooltips. Le col défile lentement en fond, l'arc chronométrique tourne sur la couche médiane, le chrono du record grossit et s'estompe au premier plan.
RéglagesMêmes réglages de cadre. Fond : ciel d'aube et deux crêtes en clip-path: polygon() à l'intérieur de .plx-element. Médiane : anneau de 140 px en conic-gradient (arc de 270°, douze graduations) masqué en couronne, aiguille de 2 px — la rotation de 180° se lit comme une aiguille de chrono. Avant-plan : « 12:47 » en chiffres à chasse fixe 40 px, dégradé menthe → cyan, fondu à 50 % à la butée.

Comment ça marche

Anatomie : .parallax-viewport#parallax-scroll est le conteneur défilant — width: 100%, height: 280px, overflow: hidden auto, barre WebKit de 4 px stylée. Il contient .parallax-scroll-space, un bloc de 900 px en position: relative : la course est de 900 − 280 = 620 px. Trois couches y vivent. #plx-bg (.st-parallax-layer : position: sticky; top: 0, 280 px, flex centré, pointer-events: none, z-index: 1) porte un .plx-element de 200 px, disque radial-gradient(rgba(99,102,241,.15), transparent 70%) sous filter: blur(20px) — mesuré en fin de course, son point le plus clair vaut rgb(20,21,40) sur #0a0a0f, à peine une lueur. #plx-mid (position: absolute; top: 0, 280 px, z-index: 2) aligne dans un .plx-element flex à gap: 12px trois .plx-shape de 40 px : un losange (bordure 2 px violet à 40 %, rayon 8 px, rotate(45deg)), un cercle (bordure rose à 40 %) et un triangle (clip-path: polygon(50% 0, 0 100%, 100% 100%), cyan à 20 %). #plx-fg (absolu aussi, z-index: 3) centre un span.plx-text « PARALLAXE » en 1,4 rem gras 800 — 135 × 25 px mesurés —, dégradé #a855f7 → #ec4899 découpé par background: … text et -webkit-text-fill-color: transparent. Sous le tout, .scroll-hint-label « Scrollez pour explorer » : absolu, 8 px du bas, 0,65 rem, blanc à 30 %, opacité qui pulse de .3 à .7 toutes les 2 s (pulseHint).

Le JavaScript tient en un écouteur scroll sur le conteneur, sans requestAnimationFrame, sans lissage. À chaque événement il lit l = scrollTop et e = l / (scrollHeight − clientHeight) — la progression de 0 à 1 sur les 620 px — puis écrit six styles en ligne, tous linéaires : le disque de fond reçoit translateY(−60·e px) scale(1 + .5·e) ; la couche médiane translateY(−.3·l px) et ses trois formes rotate(180·e deg) ; la couche avant translateY(−.6·l px), le mot scale(1 + .8·e) et opacity: 1 − .5·e. Mesuré à la molette dans Chromium, à 300 px (e = 0,484) : fond −29 px / ×1,24, médiane −90 px, rotation 87°, avant −180 px, mot ×1,39 à 76 % d'opacité ; en butée : −60 px / ×1,5, −186 px, 180°, −372 px, ×1,8 à 50 %. Aucune inertie : chaque valeur est exactement proportionnelle au défilement et revient sur ses pas quand on remonte. Chaque événement coûte quatre querySelector et six écritures de style ; l'écouteur n'est jamais retiré.

La géométrie contredit la promesse des « trois vitesses ». Seule la couche de fond est sticky ; la médiane et l'avant-plan sont position: absolute; top: 0 dans l'espace qui défile : elles montent déjà à la vitesse du contenu, et la translation négative s'y ajoute — 1,3× et 1,6× le défilement, vers le haut. Mesuré : le mot sort du cadre à 100 px de course (e = 0,16, à peine ×1,13 et 92 % d'opacité), les trois formes à 160 px (e = 0,26, 46° de rotation). Sur les 620 px, 520 ne montrent plus que la lueur collante qui glisse de 60 px. Les 180°, le ×1,8 et le fondu à 50 % s'exécutent hors champ. Deux indices d'un code remanié : .parallax-viewport est déclaré deux fois, d'abord position: sticky; top: 0 puis position: relative — la première règle est morte —, et la classe .st-parallax-layer (le collant) n'est posée que sur le fond. Pour une parallaxe à trois couches sur toute la course, il faut les rendre toutes collantes et superposées, et réduire les deux translations (cf. FAQ) ; le reste du script ne change pas.

Accessibilité

  • prefers-reduced-motion absent du code. Mesuré sous reduce : pulseHint tourne toujours et, à 300 px de défilement, la médiane est tournée de 87° et le mot grossi ×1,39. Une parallaxe est le cas typique de WCAG 2.3.3 (animation déclenchée par l'interaction). Conditionnez l'ajout de l'écouteur à !matchMedia('(prefers-reduced-motion: reduce)').matches — les couches restent alors à leur position de repos, un repli honnête — et ajoutez @media (prefers-reduced-motion: reduce) { .scroll-hint-label { animation: none } }.
  • Le repère « Scrollez pour explorer » est codé en français, en 10,4 px, blanc à 30 % sous une opacité qui pulse : contraste calculé de 1,22:1 à 1,83:1 sur #0a0a0f (2,62:1 sans la pulsation), loin des 4,5:1. Il est aussi positionné par rapport au wrapper .demo-preview : collé sans lui, mesuré dans une fenêtre de 600 px, il tombe à y = 579 alors que le conteneur finit à y = 400. Soit vous en faites une consigne lisible (14 px, blanc à 70 %), soit vous le passez en aria-hidden="true" et mettez la consigne dans l'aria-label du conteneur.
  • Clavier et lecteurs d'écran. Le conteneur overflow: auto n'a aucun enfant focalisable : Chrome 130+ et Firefox le rendent focalisable au Tab (les flèches défilent, l'effet suit), Safari non — posez tabindex="0", role="region" et un aria-label. Le mot « PARALLAXE » est un vrai texte, lu par les lecteurs d'écran ; les formes sont des div vides, muettes. Si les couches sont décoratives, aria-hidden="true" sur .parallax-scroll-space évite d'annoncer un mot isolé dans une zone qui défile pour rien.
  • Contraste des couches. Le mot : #a855f7 4,99:1 et #ec4899 5,6:1 sur #0a0a0f au repos (22 px gras : seuil 3:1 en grand texte, tenu), mais 2,05:1 à 2,15:1 à 50 % d'opacité en fin de course, et 3,96:1 / 3,53:1 sur fond blanc. Les formes, décoratives (seuil 3:1), sont sous le seuil : bordures à 40 % = 1,70:1 et 1,76:1, triangle à 20 % = 1,45:1 ; montez les alphas à .8 si elles doivent se voir. Le halo de fond est à 1,14:1 : invisible sur un fond clair.

Compatibilité navigateur

Requiert ES2015 (const, fonctions fléchées, gabarits de chaîne), position: sticky, clip-path: polygon(), filter: blur(), la syntaxe à deux valeurs overflow: hidden auto et le mot-clé text dans le raccourci background — c'est lui qui fixe le seuil Chrome. Aucune bibliothèque, aucune variable CSS, aucune animation-timeline : la parallaxe est calculée en JavaScript sur l'événement scroll, elle fonctionne donc dans Firefox, contrairement aux cinq autres parallaxes de la catégorie (fx-0538, fx-0548, fx-0557, fx-0573, fx-0592), pilotées au défilement en CSS natif — mesuré dans Firefox 153 : CSS.supports('animation-timeline: scroll()') répond faux et fx-0548 n'y bouge pas, quand fx-0576 y tourne de 73° après une molette de 300 unités. Mêmes transformations, même dégradé de texte et même triangle mesurés dans WebKit.

Chrome 120+✓ Complet
Firefox 61+✓ Complet
Safari 14+✓ Complet
Edge 120+✓ Complet
Mobile iOS 14+✓ Complet (défilement au doigt, événements scroll pendant l'inertie)
Android Chrome 120+✓ Complet

Sans JavaScript, la zone défile mais rien ne se transforme : la lueur reste collée, les formes et le mot montent avec le contenu et sortent du cadre. Chrome et Edge antérieurs à 120 (décembre 2023) rejettent text dans le raccourci background : la déclaration entière tombe et, avec -webkit-text-fill-color: transparent, le mot est invisible — ajoutez -webkit-background-clip: text à côté. Sans clip-path (Safari avant 13.1 sans préfixe), le triangle est un carré cyan.

Le code

Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :

index.html — structure
<div class="parallax-viewport" id="parallax-scroll">
  <div class="parallax-scroll-space">
    <div class="st-parallax-layer parallax-bg-layer" id="plx-bg">
      <div class="plx-element"></div>
    </div>
    <div class="parallax-mid-layer" id="plx-mid">
      <div class="plx-element">
        <div class="plx-shape"></div>
        <div class="plx-shape"></div>
        <div class="plx-shape"></div>
      </div>
    </div>
    <div class="parallax-fg-layer" id="plx-fg">
      <span class="plx-text">PARALLAXE</span>
    </div>
  </div>
</div>
<span class="scroll-hint-label">Scrollez pour explorer</span>
🔒 Débloquer le code complet — à partir de 2,99 € le 1er mois

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éfautEffet
Course (CSS — .parallax-scroll-space height 900px) 900 px, soit 620 px de course pour un cadre de 280 px e est normalisé : les amplitudes (−60 px, 180°, ×1,8) sont atteintes en butée quelle que soit la hauteur ; allonger la course ralentit tout. Mais −.3·l et −.6·l sont en pixels absolus : à 1 500 px de course, la médiane monte de 450 px.
Hauteur du cadre (CSS — .parallax-viewport, .st-parallax-layer, .parallax-mid-layer, .parallax-fg-layer : 280px) 280 px, quatre fois Les quatre valeurs changent ensemble : les couches sont dimensionnées à la main, pas en height: 100%. Le wrapper .demo-preview impose en plus min-height: 300px.
Fond (JS — translateY(${-60*e}px) scale(${1+.5*e})) −60 px et ×1,5 en butée Amplitude du glissement et du zoom du disque de fond. −120 / 1 pour un fond qui monte sans grossir. Le disque de 200 px flouté à 20 px reste quasi invisible (1,14:1) : montez l'alpha du dégradé de .15 à .4 pour qu'on le voie.
Couche médiane (JS — translateY(${-.3*l}px) et rotate(${180*e}deg)) −0,3 px par pixel défilé, 180° en butée La translation s'ajoute au défilement naturel de la couche (absolue) : 1,3× au total. 360 pour un tour complet ; 0 pour une couche qui ne fait que glisser. Les trois formes tournent comme un bloc autour du centre de .plx-element.
Avant-plan (JS — translateY(${-.6*l}px), scale(${1+.8*e}), opacity = 1 − .5*e) −0,6 px par pixel, ×1,8 et 50 % en butée 1 − e pour un mot qui disparaît complètement ; 1 + 2·e pour un zoom de titre. C'est le span entier qui grossit, pas la police : le texte reste net.
Superposition des couches (CSS — .parallax-mid-layer, .parallax-fg-layer : position absolute) absolues dans l'espace défilant (sortie du cadre à 100 et 160 px) Pour une parallaxe sur toute la course : .parallax-scroll-space { display: grid } et, sur les trois couches, grid-area: 1 / 1; position: sticky; top: 0 ; puis −.15·l et −.2·l dans le script. Mesuré ainsi sur 280 px et 620 px de course : formes et mot visibles jusqu'en butée (le mot à 86 %). Avec le collant seul, le mot sort encore à 310 px.
Couleurs (CSS — halo rgba(99,102,241,.15), bordures .4, dégradé #a855f7 → #ec4899) indigo / violet, rose, cyan / violet → rose Le dégradé du mot est découpé par background: … text : ajoutez -webkit-background-clip: text pour Chrome et Edge antérieurs à 120, sinon le mot y est transparent. Sur fond clair, le mot tient 3,96:1 / 3,53:1 : assombrissez vers #7e22ce → #be185d.
Repère (HTML — .scroll-hint-label) « Scrollez pour explorer », 10,4 px, blanc à 30 %, pulse 2 s Texte à traduire ou à retirer ; il dépend du position: relative de .demo-preview. Sous prefers-reduced-motion, coupez pulseHint.

FAQ

C'est ce que fait le code vendu, mesuré : le mot quitte le cadre à 100 px de course sur 620 (16 %), les trois formes à 160 px (26 %). Seul #plx-bg porte la classe .st-parallax-layer (position: sticky) ; #plx-mid et #plx-fg sont position: absolute; top: 0 à l'intérieur de .parallax-scroll-space, qui défile. Elles montent donc à la vitesse du contenu, plus leur translation (−.3·l, −.6·l) : 1,3× et 1,6× le défilement. Les 180° de rotation, le ×1,8 et le fondu se jouent hors champ. Correctif en trois règles et deux nombres : .parallax-scroll-space { display: grid }, sur les trois couches grid-area: 1 / 1; position: sticky; top: 0 — elles se superposent dans la même cellule et restent collées pendant toute la course, seules les translations du script les déplacent —, puis −.15·l et −.2·l à la place de −.3 et −.6. Mesuré avec ces réglages : formes et mot visibles jusqu'en butée. Avec le collant seul et les facteurs d'origine, le mot sort encore à 310 px (−372 px en butée pour un cadre de 280).
Le moteur. Ces trois-là (comme Parallax fx-0538 et Parallax CSS fx-0557) sont pilotés par animation-timeline: scroll() ou une scroll-timeline nommée : zéro JavaScript, mais rien ne bouge dans Firefox — mesuré dans Firefox 153, CSS.supports('animation-timeline: scroll()') répond faux et les couches de fx-0548 gardent transform: none après défilement — et l'amplitude est figée dans des @keyframes. Ici, un écouteur scroll calcule chaque valeur : l'effet tourne dans Firefox (73° après une molette de 300 unités) et chaque facteur est un nombre dans le script. Côté mouvement : fx-0548, fx-0557 et fx-0573 ne font que translater ; fx-0592 combine translation, scale(1 → 1.3), des rotations de ±5 à 10° et une opacité de .7 à 1 sur cinq couches ; fx-0576 est le seul à tourner une couche de 180° et à faire grossir puis fondre l'avant-plan (×1,8, 50 %). Et le seul dont deux couches sur trois sortent du cadre avant le tiers de la course — voir la question précédente.
Le script n'est pas encapsulé : quatre const au niveau du script (parallaxScroll, plxBg, plxMid, plxFg), sans IIFE, et quatre getElementById — une seule instance possible. Mesuré : le second collage lève cette erreur de syntaxe et le second bloc ne s'exécute pas (le premier, déjà lancé, continue). Pour plusieurs instances : enveloppez le script dans (() => { … })() ou, mieux, remplacez les ids par des classes et bouclez sur document.querySelectorAll('.parallax-viewport'), chaque instance cherchant ses couches par querySelector dans son propre conteneur ; les ids du HTML deviennent inutiles. Le garde parallaxScroll && plxBg && … de l'original ne protège que d'un HTML absent, pas d'un doublon.