Cartes✨ Premium

Stacked to Spread

Six cartes CSS passent d'une pile légèrement inclinée à une grille 3×2 avec un rebond élastique cubic-bezier — bascule d'état au clic, zéro moteur d'animation JS.

CSSTransformElastic

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

🎈

① Galerie de médias — Vignettes en pile ou déployées en grille

QuandL'utilisateur bascule entre une vue compacte (pile) et une vue d'ensemble (grille) d'une galerie photo, d'une collection ou d'un catalogue de produits.
PourquoiLa pile donne un aperçu élégant en peu d'espace ; le déploiement révèle les six vignettes en un seul geste avec un rebond satisfaisant. L'effet supporte le regard sur le contenu plutôt que sur lui-même.
RéglagesCartes 80×110 px (format portrait), background-image pour les vignettes à la place des dégradés, transition à 0,45 s pour une réponse plus vive.
🎊

② Section bento — Fonctionnalités SaaS révélées en grille 3×2

QuandLa landing page dévoile ses fonctionnalités-clés : les cartes s'affichent d'abord en pile mystérieuse, puis se déploient au scroll ou au clic sur « Découvrir ».
PourquoiLa pile capte l'attention et crée de l'attente ; le déploiement élastique en grille révèle d'un seul geste six bénéfices produit — plus mémorable qu'une liste statique.
RéglagesCartes 110×80 px (paysage), icône SVG + titre dans chaque carte, déclenchement à l'entrée dans le viewport via IntersectionObserver avec 300 ms de délai.

③ Interface de jeu — Main de cartes cachée puis révélée

QuandUn jeu de cartes numérique (quiz, draft, poker simplifié) montre d'abord la main dos visible, puis l'étale sur la table après le clic « Révéler ».
PourquoiLa grille 3×2 reproduit naturellement la disposition d'une main étalée ; le rebond cubic-bezier ajoute un caractère physique plus engageant qu'un simple fondu.
RéglagesCartes 60×90 px (format à jouer), dos uniformes en pile, faces individualisées en spread, bouton « Révéler / Cacher » à la place de Stack/Spread.

Comment ça marche

Six éléments .stack-card sont positionnés en position: absolute à l'intérieur d'un conteneur .stacked-spread-wrapper en position: relative; height: 160px. La logique d'état repose entièrement sur deux classes CSS.stacked et .spread — appliquées au conteneur. Aucun moteur d'animation JS n'est impliqué : tout le mouvement vient des transitions CSS déclarées sur les cartes.

En mode .stacked, chaque carte reçoit via :nth-child un transform: translate(Xpx, Ypx) rotate(Ndeg) de quelques pixels et degrés, simulant une pile posée à la main avec de légères imperfections (de 2 px/2° à 5 px/4° selon la position). En mode .spread, les six cartes se dispersent sur trois colonnes et deux rangées : translateX(−70px) · translate(0) · translateX(+70px) et translateY(−30px) / translateY(+40px).

La transition élastique est déclarée une seule fois sur .stack-card : transition: .6s cubic-bezier(.34, 1.56, .64, 1). La valeur y1 = 1,56, supérieure à 1, fait dépasser les cartes leur cible avant de revenir en place — c'est l'overshoot qui produit le rebond de type spring. Les six cartes démarrent depuis des positions différentes et arrivent toutes à destination au même instant, créant un effet de déploiement en éventail.

La fonction setStackMode(el, mode) orchestre le basculement : elle retire .stacked/.spread du wrapper ciblé par l'id fixe stackDemo, ajoute la nouvelle classe, et synchronise l'état .active sur les boutons toggle. Déclarée globalement, elle peut être appelée depuis n'importe quel déclencheur — clic, hover, scroll ou événement métier.

Accessibilité

  • prefers-reduced-motion : absent du code — aucune règle @media (prefers-reduced-motion: reduce) n'est incluse. Les transitions élastiques s'exécutent même si l'utilisateur a activé cette préférence système. Ajoutez @media (prefers-reduced-motion: reduce) { .stack-card { transition: none } } si votre contexte le requiert.
  • Les boutons Stack et Spread sont des <button> natifs — focusables au clavier (Tab), activables à Entrée et Espace, sans aucun JS supplémentaire.
  • Aucun attribut ARIA n'est présent sur le wrapper ou les cartes. Si les cartes portent du contenu sémantique (images, liens), ajoutez role="group" et aria-label sur .stacked-spread-wrapper, et un alt sur chaque image.
  • Le contraste des textes dans les cartes dépend entièrement du contenu que vous y placez — l'effet lui-même n'impose aucun texte visible dans les cartes.
  • Aucun piège de focus n'est introduit : le toggle ne déplace pas le focus et les cartes restent dans l'ordre naturel du DOM.

Compatibilité navigateur

Nécessite CSS transition, transform et sélecteurs :nth-child — supportés dans tous les navigateurs modernes depuis 2014. Zéro dépendance externe.

Chrome 88+✓ Complet
Firefox 87+✓ Complet
Safari 15+✓ Complet
Edge 88+✓ Complet
Mobile iOS✓ Touch OK
Android Chrome✓ Complet

Sans support CSS transition (navigateurs < 2014), les cartes sautent instantanément d'un état à l'autre sans animation — la mise en page reste correcte. Aucune erreur JS n'est levée.

Le code

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

index.html — structure
<div class="morph-toggle-group">
  <button class="morph-toggle active" onclick="setStackMode(this, 'stacked')">Stack</button>
  <button class="morph-toggle" onclick="setStackMode(this, 'spread')">Spread</button>
</div>
<div class="stacked-spread-wrapper stacked" id="stackDemo">
  <div class="stack-card">1</div>
  <div class="stack-card">2</div>
  <div class="stack-card">3</div>
  <div class="stack-card">4</div>
  <div class="stack-card">5</div>
  <div class="stack-card">6</div>
</div>
🔒 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
.stack-card (width / height) 60 px × 80 px Dimensions de chaque carte. Modifiez directement les propriétés CSS — les offsets de pile et de grille sont en px absolus, à recalculer si vous changez fortement la taille.
transition (.stack-card) .6s cubic-bezier(.34, 1.56, .64, 1) Durée et courbe d'animation. Remplacez y1 (1,56) par une valeur ≤ 1 pour supprimer le rebond, ou montez à 1,8–2,2 pour un overshoot plus prononcé.
Spread colonnes (translateX) −70 px · 0 · +70 px Écartement horizontal de la grille 3×2. Ajustez les translateX dans les règles .spread .stack-card:nth-child(n) pour resserrer ou élargir les colonnes.
Spread rangées (translateY) −30 px · +40 px Espacement vertical entre les deux rangées. Modifiez les translateY des six règles nth-child en mode .spread.
Stack offsets (nth-child) 2–5 px · 2–4° Imperfection visuelle de la pile. Chaque carte a un translate et un rotate propres. Montez les valeurs pour une pile plus désordonnée, ramenez-les à zéro pour un empilement parfait.
.stack-card:nth-child(n) background Dégradé indigo→violet→rose→rouge→ambre Couleur individuelle de chaque carte. Remplacez le dégradé par une couleur unie, une background-image ou votre propre gradient brand.
CSS var --radius-md 0.5rem Rayon d'arrondi des cartes. Modifiez la variable sur :root pour passer de rectangles nets (0) à des cartes plus arrondies (1rem+).
setStackMode(el, mode) Fonction globale — appelez-la depuis n'importe quel événement. Pour déclencher sans référence au bouton toggle, basculez les classes directement : document.getElementById('stackDemo').classList.replace('stacked','spread').

FAQ

Oui. Ajoutez ou supprimez des .stack-card dans le wrapper. Pour la pile, ajoutez des règles :nth-child avec de petits décalages. Pour la grille, calculez de nouveaux translate selon le nombre de colonnes et de lignes voulu — il n'y a aucune logique JS à adapter, seulement du CSS.
La fonction setStackMode cible l'id fixe 'stackDemo'. Pour plusieurs instances, donnez à chaque wrapper un id différent et créez une fonction de toggle par instance — ou factorisez en passant l'id en paramètre : function toggleStack(el, mode, id) { var w = document.getElementById(id); w.classList.remove('stacked','spread'); w.classList.add(mode); }.
Basculez les classes directement sur le wrapper : const w = document.getElementById('stackDemo'); w.classList.remove('stacked'); w.classList.add('spread');. Encapsulez dans un IntersectionObserver, un setInterval ou le callback de votre événement selon votre déclencheur.