Card Morph
La carte grossit au clic via une courbe back-ease-out, masque son aperçu et révèle son contenu par un fondu-scale — elle se referme d'un clic extérieur.
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
Un gestionnaire de clic sur .card-morph-expand appelle classList.toggle('expanded'). Un second listener sur document détecte les clics extérieurs et retire la classe expanded automatiquement — pas de bouton de fermeture nécessaire.
L'animation est pilotée par une transition CSS : transition: .5s cubic-bezier(.175, .885, .32, 1.275). Cette courbe back ease-out produit un léger dépassement puis un retour élastique au scale(1.1) final, sans une ligne de JavaScript d'animation. Une ombre portée violette apparaît simultanément via box-shadow.
L'échange de contenu repose sur deux couches empilées en position: absolute; inset: 0. La couche aperçu (.card-preview) passe à opacity: 0 en 0,3 s. La couche contenu (.card-full-content) part de opacity: 0; transform: scale(.9) et rejoint opacity: 1; transform: scale(1) en 0,4 s, créant un surgissement centré.
Aucun requestAnimationFrame n'est utilisé : l'effet est 100 % CSS transitions sur bascule de classe. La .card-morph-expand porte overflow: hidden — le contenu ne déborde jamais hors des arrondis, même à scale(1.1).
Accessibilité
- prefers-reduced-motion absent : le code ne contient pas de media query
prefers-reduced-motion— les transitions scale et opacity s'exécutent toujours, même si l'OS demande à réduire le mouvement. À ajouter manuellement si nécessaire. - L'élément cliquable est une
<div>sansrole="button"ni gestionnairekeydown— inaccessible au clavier (Tab ne la sélectionne pas, Entrée/Espace n'ont pas d'effet). - Pas d'attribut
aria-expanded: les lecteurs d'écran ne sont pas informés de l'état ouvert/fermé. - Le texte secondaire (
--text-muted: #8b8b93) sur fond#12121aatteint un ratio de contraste d'environ 4,7:1 — conforme WCAG AA (≥ 4,5:1). - La cible de clic (280 × 180 px par défaut) dépasse largement les 44 × 44 px recommandés par WCAG 2.5.5.
Compatibilité navigateur
Nécessite CSS transitions et classList — supportés dans tous les navigateurs modernes depuis 2017. Zéro dépendance externe.
Sans JS, la carte reste dans son état initial (aperçu visible). Les styles CSS sont autonomes — aucun flash ni mise en page brisée.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
<div class="demo-preview">
<div class="card-demo card-morph-expand" id="morphExpandCard">
<div class="card-preview">
<div class="card-preview-icon">
<!-- Icône SVG 24×24 -->
</div>
<span>Cliquez</span>
</div>
<div class="card-full-content">
<h5>Titre du contenu révélé</h5>
<p>Description détaillée affichée à l'expand.</p>
</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 |
|---|---|---|
| --bg-card | #12121a | Couleur de fond de la carte — remplacer par n'importe quelle couleur de votre design system. |
| --radius-xl | 1rem | Rayon d'arrondi des coins — 0.5rem pour un look card, 1.5rem pour un look pill. |
| --border | rgba(255,255,255,0.08) | Couleur du bord de la carte au repos — augmentez l'opacité pour un contour plus visible sur fonds clairs. |
| --text-primary | #ffffff | Couleur du titre dans le contenu révélé. |
| --text-muted | #8b8b93 | Couleur du texte secondaire dans le contenu révélé (ratio WCAG AA ≈ 4,7:1 sur --bg-card par défaut). |
| transition: .5s cubic-bezier(.175,.885,.32,1.275) | .5s back-ease-out | Durée et courbe de l'expansion — .3s ease-out pour un rendu plus direct, .7s pour un effet plus théâtral. |
| transform: scale(1.1) | scale(1.1) | Amplitude d'expansion dans .card-morph-expand.expanded — scale(1.05) pour discret, scale(1.2) pour dramatique. |
| box-shadow | rgba(99,102,241,.3) 0 25px 50px | Couleur et portée de l'ombre au survol — changez la couleur RGBA pour correspondre à votre accent brand. |
| linear-gradient(135deg,#6366f1,#8b5cf6) | indigo→violet | Dégradé de l'icône ronde dans .card-preview-icon — remplacez par vos couleurs brand ou une image de fond. |
FAQ
morphExpandCard — une seule instance. Pour plusieurs cartes, remplacez le getElementById par une boucle : document.querySelectorAll('.card-morph-expand').forEach(card => { card.addEventListener('click', () => card.classList.toggle('expanded')); }); et ajoutez document.addEventListener('click', e => document.querySelectorAll('.card-morph-expand').forEach(c => { if (!c.contains(e.target)) c.classList.remove('expanded'); })).<div> cliquable n'est pas focusable nativement. Deux correctifs : remplacez-la par un <button type="button" class="card-morph-expand"> (focusable, Entrée/Espace activent le clic), ou ajoutez tabindex="0" sur la div et un listener keydown qui appelle classList.toggle('expanded') sur Enter et Space. Mettez également aria-expanded à jour par JS..card-morph-expand définissez transition: transform .35s ease-in, box-shadow .35s ease-in (fermeture rapide), puis dans .card-morph-expand.expanded surchargez avec transition: transform .5s cubic-bezier(.175,.885,.32,1.275), box-shadow .5s ease-out (ouverture élastique). CSS applique la règle active au moment de la transition.