Scroll✨ Premium

Card Stack

Cinq cartes de 80 px en position: sticky, épinglées de 10 px en 10 px dans un bloc de 280 px : chacune entre par une animation pilotée par view() — opacité 0 → 1, translateY 40 → 0, scale .92 → 1 sur 64 px de défilement — puis reste sous la suivante, son bord de 10 px visible. CSS seul, zéro JavaScript, course de 720 px.

CSSStackSticky

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

Historique de transactions dans un relevé bancaire — chaque opération entre en fondu et reste en bord de pile — Card Stack exemple 1

① Historique de transactions dans un relevé bancaire — chaque opération entre en fondu et reste en bord de pile

QuandApplication de gestion financière personnelle : sous l'en-tête du compte (solde, mois, filtre), le relevé de septembre est une liste d'opérations — libellé, date, catégorie, montant — que le client fait défiler ; chaque ligne apparaît en fondu-échelle à son entrée puis s'épingle sous la suivante.
PourquoiChaque opération arrive seule — fondu et échelle sur 51 px de défilement, la suivante un pas de 76 px plus loin — puis se range sous celle qui la suit, son bord de 10 px visible : la pile sous l'en-tête grandit d'une bande par ligne parcourue, et sa hauteur dit au client où il en est dans le mois, sans compteur ni pagination ; revenir en arrière ressort les lignes une à une, entières. Slide In Cards (fx-0562) ferait entrer chaque ligne aussi, une fois par la gauche, une fois par la droite, puis la laisserait sortir par le haut du bloc : rien ne s'accumule, l'entrée seule ne dit pas combien d'opérations sont passées.
RéglagesFond clair : cartes blanches bordées (#e2e5ea, ombre à 8 %) et texte sombre à la place des dégradés, largeur 100 %, 64 px de haut, 12 px d'écart (pas de 76 px). Six cartes au lieu de cinq : règle :nth-child(6) { top: 60px } ajoutée. Bloc de 270 px sous un en-tête de 90 px, plateau de 660 px (course 390) ; animation-range et état de départ conservés — mesuré : la sixième ligne entre entre 128 et 178 px et s'épingle à 336. Montants positifs en vert #15803d (5:1 sur blanc).
Résultats de bilan nutritionnel — un indicateur à la fois, les valeurs lues restent sous les yeux — Card Stack exemple 2

② Résultats de bilan nutritionnel — un indicateur à la fois, les valeurs lues restent sous les yeux

QuandApplication de santé, écran de résultats d'un bilan de la journée : protéines, glucides, lipides, fibres, vitamine D — cinq cartes avec la valeur mesurée, l'objectif et un verdict, qui se révèlent l'une après l'autre en défilant.
PourquoiLe décalage de 10 px garde chaque indicateur visible en bord de pile sous le suivant : la lecture est ordonnée et les valeurs déjà lues restent à portée d'œil — Fade Up (fx-0535) les laisserait sortir du cadre une fois lues. Un mur de cinq chiffres devient une séquence, sans onglets ni pagination.
RéglagesMécanique du code vendu intacte (sticky à 10 → 50 px, entry entry 80%, état de départ) ; cartes de 84 px et 16 px d'écart (pas de 100 px), un dégradé par nutriment (indigo, ambre, rose, vert, cyan) dont la seconde couleur est assombrie pour tenir 5:1 avec le texte blanc, contenu en deux colonnes (nom + objectif, valeur de 21 px + verdict). Bloc de 296 px sous un en-tête de 64 px, plateau de 700 px (course 404) — mesuré : quatrième carte de 26 à 92 px, cinquième de 126 à 192, pile complète à 370.
Journal de bord d'un projet de construction — les entrées de la semaine s'empilent dans l'ordre chronologique — Card Stack exemple 3

③ Journal de bord d'un projet de construction — les entrées de la semaine s'empilent dans l'ordre chronologique

QuandOutil de gestion de chantier : le journal de la semaine 39 liste cinq entrées datées — réunion de chantier, livraison béton, inspection, incident, livraison — que le chef de projet parcourt en défilant ; chaque carte apparaît à son tour et s'ajoute à la pile.
PourquoiL'ordre chronologique est imposé par le défilement, une entrée après l'autre, sans la ligne verticale ni les repères de Timeline Scroll (fx-0582) : les cartes sont autonomes, chacune porte sa date et son type, et la barre colorée de gauche suffit à typer l'événement. Le journal reste une simple liste de div, à générer côté serveur sans structure de frise.
RéglagesCartes plates #1f2937 bordées, barre gauche de 4 px colorée par type (réunion ambre, livraison cyan, inspection vert, incident rouge), 88 px de haut, 14 px d'écart (pas de 102 px), numéro d'entrée à droite. Bloc de 302 px sous un en-tête de 58 px, plateau de 720 px (course 418) ; sticky et animation-range inchangés — mesuré : quatrième carte de 22 à 92 px, cinquième de 124 à 194, épinglées à 282 et 374.

Comment ça marche

Le HTML vendu tient en quatre niveaux : le cadre .demo-preview (flex centré, min-height: 300px, position: relative, fond #0a0a0f, texte blanc, box-sizing: border-box pour tout ce qu'il contient), le bloc défilant .sdc-scroll-container (100% × 280px, overflow-y: auto, scroll-behavior: smooth, barre de 4 px stylée par ::-webkit-scrollbar), le plateau .ss-cardstack-content (1000 px de haut, padding: 20px 12px) et cinq .ss-cardstack-card : 90 % de large, 80 px de haut, margin: 0 auto 16px, border-radius: 12px, flex centré, texte blanc de 13,6 px en graisse 700, ombre 0 4px 20px rgba(0,0,0,.3), un dégradé à 135° par carte (#4f46e5 → #6366f1 pour la première, #ec4899 → #f472b6 pour la cinquième). Le pas vertical vaut 96 px : les cartes commencent à 20, 116, 212, 308 et 404 px du haut du plateau, et la course mesure 1000 − 280 = 720 px. Sous le bloc, le span.sdc-scroll-hint « Scrollez ↓ » (absolu, 8 px du bas du cadre, 10,4 px, blanc à 30 %) pulse entre .3 et .7 toutes les 2 s. Le champ JavaScript est vide ; aucune variable CSS du site, aucune erreur console.

L'entrée est une animation CSS dont le temps est le défilement. La règle de base pose l'état de départ — opacity: 0; transform: translateY(40px) scale(.92) — et la @keyframes ssCardStack ne contient qu'une image to (opacity: 1; transform: translateY(0) scale(1)). animation-timeline: view() crée une timeline de vue anonyme : le scroller est l'ancêtre défilant le plus proche, .sdc-scroll-container, et la progression suit la position de la carte dans ses 280 px. animation-range: entry entry 80% (forme courte de entry 0% entry 80%) borne l'animation à l'entrée : 0 % quand le haut de la carte touche le bord bas du bloc, 100 % quand elle y est entrée tout entière ; 80 % d'une carte de 80 px, c'est 64 px de défilement pour tout le fondu. animation-duration: auto, linear et animation-fill-mode: both font le reste : avant la plage, l'état de départ ; après, l'état final — dans les deux sens (mesuré : revenir à 0 rend aux cartes 4 et 5 leur opacité 0). Mesuré dans Chromium 151, page vierge : la carte 4 va de 0 à 1 entre 28 et 92 px de défilement (.031 à 30, .5 à 60, .969 à 90), la carte 5 entre 124 et 188 (.563 à 160). Les trois premières sont déjà à 1 au repos : leur plage d'entrée est passée avant le début de la course (première question de la FAQ).

L'empilement est du position: sticky pur, avec un top qui croît de 10 px par carte (:nth-child(1) à 10 px … :nth-child(5) à 50 px). Une carte s'épingle quand sa position normale passe sous son top : à 10, 96, 182, 268 et 354 px de défilement. Les suivantes, plus tardives dans le DOM, se peignent par-dessus : chaque carte laisse voir 10 px de la précédente, et la pile occupe de 10 à 130 px du bloc. L'entrée et l'épinglage ne se chevauchent jamais — la carte 4 finit son fondu à 92 px et s'épingle à 268. Le bloc conteneur du sticky est le plateau : ses 1000 px gardent les cinq cartes collées jusqu'au bout, mais la pile est complète à 354 px et les 366 px restants ne changent plus rien.

Accessibilité

  • prefers-reduced-motion absent du code : mesuré sous émulation, rien ne change — les cartes 4 et 5 restent à opacity: 0 tant qu'on n'a pas défilé jusqu'à elles, comme sans la préférence, et l'indice pulse toujours. Le fondu est piloté par le lecteur (aucun mouvement sans son geste), ce qui le range parmi les animations déclenchées par l'interaction (WCAG 2.3.3). Pour un repli à plat, ajoutez @media (prefers-reduced-motion: reduce) { .ss-cardstack-card { animation: none; opacity: 1; transform: none } .sdc-scroll-hint { animation: none } } : les cinq cartes sont visibles d'emblée et s'empilent sans fondu — ce que voit déjà Firefox.
  • Clavier : mesuré, Tab donne le focus au bloc sans tabindex dans Chromium (flèche bas 40 px, PageDown 285, Fin 720) et dans Firefox (51, 303, 720) ; WebKit ne focalise pas un bloc défilant sans tabindex="0" — ajoutez-le sur .sdc-scroll-container, avec un aria-label et un style :focus-visible. Sur écran tactile, le geste doit commencer dans le bloc ; overscroll-behavior: contain évite d'entraîner la page en bout de course.
  • Contraste (texte blanc de 13,6 px en graisse 700, seuil 4,5:1) : 6,3 → 4,5:1 sur la première carte, puis 4,5 → 3,0 (deuxième), 4,2 → 2,7 (troisième), 3,5 → 2,5 (quatrième) et 3,5 → 2,7 (cinquième) : quatre cartes sur cinq passent sous le seuil sur leur moitié claire. Assombrissez la seconde couleur de chaque dégradé (#4338ca, #6d28d9, #a21caf, #be185d tiennent 6:1 et plus avec du blanc) ou posez le texte sur un fond uni. L'indice à 30 % vaut 2,6:1 : décoratif, aria-hidden="true".
  • Lecteurs d'écran et contenu recouvert : les cinq cartes sont des div lus dans l'ordre du DOM ; opacity: 0 ne retire rien de l'arbre d'accessibilité, un lecteur d'écran lit donc les cinq d'un coup. Si les cartes portent une information, prenez ul/li ou article avec un titre. Visuellement, une carte épinglée n'est plus lisible que sur ses 10 px de bord : seul le retour en arrière la découvre (le sticky se défait dans l'autre sens, mesuré) — prévoyez-le si vos cartes sont des données et non des étapes. L'indice « Scrollez ↓ » est écrit en dur en français.

Compatibilité navigateur

CSS seul, zéro dépendance, zéro JavaScript : animation-timeline: view(), animation-range et animation-duration: auto (animations pilotées par le défilement), position: sticky, overflow-y, dégradés, @keyframes. Les animations pilotées par le défilement existent dans Chrome et Edge depuis la version 115, dans Safari et iOS depuis la version 26 (mesuré dans WebKit 26.5 : mêmes valeurs qu'en Chromium) ; Firefox ne les gère dans aucune version. Mesuré dans Firefox 153 : animation-timeline et animation-duration: auto sont ignorés, la durée calculée tombe à 0 s et l'animation, en fill-mode: both, se pose sur son image to dès le chargement — les cinq cartes sont visibles à pleine opacité, sans fondu ni glissement, et s'empilent exactement comme ailleurs (10, 20, 30, 40, 50 px en fin de course). Rien n'est perdu, seule l'entrée manque. Le code ne contient pas de bloc @supports : l'état final sert de repli.

Chrome 115+✓ Complet
Edge 115+✓ Complet
Safari 26+✓ Complet (mesuré dans WebKit 26.5)
Firefox✓ Aucune version — cartes visibles d'emblée, empilement sans fondu (mesuré dans Firefox 153)
iOS Safari 26+✓ Complet (défilement tactile du bloc)
Android Chrome 115+✓ Complet

Là où animation-timeline manque (Firefox, Chrome avant 115, Safari avant 26) : cartes à plat, opacité 1, sans translation ni échelle, empilement sticky identique. Un navigateur sans position: sticky ferait défiler les cartes comme une liste ordinaire. Sans le cadre .demo-preview, l'indice « Scrollez ↓ » perd son ancre et tombe au bas de la page : retirez le span ou donnez position: relative à votre propre cadre.

Le code

Structure HTML à coller dans votre page (le CSS + JS sont inclus avec Premium) :

index.html — structure
<div class="demo-preview">
  <div class="sdc-scroll-container">
    <div class="ss-cardstack-content">
      <div class="ss-cardstack-card">…</div>
      <div class="ss-cardstack-card">…</div>
      <div class="ss-cardstack-card">…</div>
      <div class="ss-cardstack-card">…</div>
      <div class="ss-cardstack-card">…</div>
    </div>
  </div>
  <span class="sdc-scroll-hint">…</span>
</div>
Débloquer le code complet — 9,90 € HT/mois

Le code complet HTML + CSS + JS de Card Stack, 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éfautEffet
Nombre de cartes et décalage (HTML + CSS — :nth-child(n) { top }) 5 cartes, top 10 → 50 px par pas de 10 Le pas est le bord visible de chaque carte sous la suivante. Une sixième carte n'a ni fond ni top propre (elle prend top: 10px et un fond transparent) : ajoutez :nth-child(6) { top: 60px; background: … }. Un pas de 6 px serre la pile, 16 px laisse lire un début de titre sur chaque bord.
Plage d'entrée (CSS — animation-range: entry entry 80%) entry 0 % → entry 80 % (64 px de défilement pour 80 px de carte) entry entry 100% étire le fondu sur toute l'entrée (80 px) ; entry 20% entry 100% retarde le départ ; cover 0% cover 40% continue après l'entrée complète. La plage se lit en pourcentage de la hauteur de la carte : plus la carte est haute, plus le fondu dure. La courbe linear colle au geste ; ease-out fait apparaître vite puis poser lentement.
État de départ (CSS — règle de base opacity: 0; transform: translateY(40px) scale(.92)) invisible, 40 px plus bas, 92 % La @keyframes ne contient que l'image to : le départ est celui de la règle de base, c'est là qu'on le règle. translateY(16px) scale(.98) donne une entrée discrète ; opacity: .4 laisse deviner la carte avant son entrée.
Hauteur du plateau et du bloc (CSS — .ss-cardstack-content { height: 1000px }, .sdc-scroll-container { height: 280px }) 1000 px / 280 px (course 720, pile complète à 354) La course vaut plateau − bloc ; la pile est complète à 354 px (dernière carte épinglée), au-delà rien ne change. Un plateau de 640 px (course 360) finit juste après ; si le nombre de cartes varie, passez en height: auto avec un padding-bottom égal à la hauteur du bloc. Le bloc de 280 px décide combien de cartes sont déjà visibles au repos (trois ici).
Taille et écart des cartes (CSS — height: 80px, width: 90%, margin: 0 auto 16px) 80 px, 90 %, 16 px (pas de 96 px) Le pas règle le rythme des épinglages : une carte tous les 96 px de défilement. Les cartes sont des boîtes flex centrées avec un seul texte ; pour une ligne date / libellé / montant, passez justify-content: space-between et un padding horizontal — le sticky et l'animation ne dépendent pas du contenu.
Couleurs (CSS — :nth-child(n) { background: linear-gradient(135deg, …) }) 5 dégradés de l'indigo au rose, texte blanc Chaque carte porte son fond ; la pile se lit par ces bandes de 10 px, gardez des couleurs distinctes d'une carte à l'autre. Le texte blanc de 13,6 px ne tient 4,5:1 que sur la première carte : assombrissez la seconde couleur ou passez à des cartes unies (blanches bordées sur fond clair, comme la première scène).
Défilement doux et indice (CSS — scroll-behavior: smooth, .sdc-scroll-hint) smooth / « Scrollez ↓ » pulsant 2 s smooth n'agit que sur les positions posées par script (mesuré : scrollTop = 720 se relit 0 et arrive en 420 ms environ dans Chromium, 540 dans Firefox, 200 dans WebKit) — auto si un bouton pilote le bloc. L'indice est un reste du catalogue : français en dur, ancré au cadre .demo-preview ; pour vous en passer, retirez le span et la @keyframes sdcHintPulse.

FAQ

Parce que leur plage d'entrée est derrière le point de départ. entry court de l'instant où le haut de la carte touche le bord bas du bloc à celui où elle y est entrée entière ; au repos, les cartes 1 et 2 (20 → 100 et 116 → 196 px) sont entières dans les 280 px du bloc, et la troisième (212 → 292) n'a que 12 px dehors : sa plage entry 0% → 80% va de −68 à −4 px de défilement, déjà passée, et fill-mode: both lui applique l'image finale. Mesuré : au repos, opacité 1 sur les trois, 0 sur les cartes 4 et 5, qui entrent entre 28 et 92 px puis 124 et 188. Pour que toutes entrent en fondu, décalez-les sous le bord bas — padding-top: 280px sur le plateau, la course commence alors par un écran vide — ou réduisez le bloc sous le pas : 90 px ne montrent que la première carte.
Franchement : c'est la même technique avec d'autres réglages, pas un autre effet — même position: sticky, même view() avec entry entry 80%, même état de départ (40 px plus bas, 92 %), même pas de 10 px, zéro JavaScript des deux côtés. Les écarts se lisent dans les deux codes : fx-0568 pose des cartes de 90 px à 85 % (80 px à 90 % ici), les épingle de 30 à 70 px (10 à 50 ici), remplace le plateau fixe de 1000 px par deux espaceurs — 40 px avant la première carte, 120 px après la dernière — et donne à son bloc height: 100% et un padding de 20 px, au lieu d'un bloc de 280 px dont le padding est porté par le plateau. Mesuré dans Chromium, les deux dans un bloc de 280 px : fx-0568 défile sur 450 px, montre deux cartes au repos (la troisième à 11 %), épingle à 10, 106, 202, 298 et 394 px et sa pile occupe 50 → 180 px, le padding du bloc s'ajoutant au top de chaque carte ; Card Stack défile sur 720 px, montre trois cartes, épingle à 10, 96, 182, 268 et 354 px, pile de 10 à 130 px. Règle d'usage : partez de Card Stack, et ne reprenez de fx-0568 que ses espaceurs si le nombre de cartes varie — le plateau suit alors le contenu, à condition que l'espaceur final remplisse ce qui reste du bloc sous la dernière carte épinglée : 100 px dans un bloc de 280 (les 120 px de fx-0568 suffisent), 220 dans un bloc de 400 — mesuré, avec 120 px la dernière carte s'arrête à 154 px et ne s'épingle jamais. Hauteur, largeur et top de départ sont des valeurs à changer, pas une raison de choisir l'un ou l'autre.
Oui, et le code n'a presque rien à changer : view() prend l'ancêtre défilant le plus proche, donc le document si vous retirez overflow-y: auto du bloc (ou le bloc lui-même), et position: sticky s'épingle alors par rapport à la fenêtre. Remplacez le plateau de 1000 px par vos sections, avec assez de contenu après la dernière carte pour qu'elle ait le temps de s'épingler (sa position normale moins son top). Le pas de 10 px devient petit sur un grand écran : 24 à 32 px laissent lire le titre de chaque carte recouverte. Un en-tête fixe s'ajoute au top de chaque carte, sinon il la couvre ; l'indice, ancré au cadre, passerait en position: fixed. Firefox y voit la même pile, sans fondu.