Tab Content Morph
Panneau d'onglets CSS pur : les panneaux permutent par un crossfade opacity et un glissement translateY+scale synchronisés — morphing fluide en 0,5 s, zéro librairie.
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
Tous les panneaux sont empilés via position: absolute; inset: 0 dans un conteneur relatif. À l'état inactif, chaque panneau porte opacity: 0 et transform: translateY(10px) scale(.95) : invisible, décalé de 10 px vers le bas et légèrement rétréci. La classe .active le ramène à opacity: 1; transform: translateY(0) scale(1) — c'est la combinaison crossfade + glissement vertical qui définit le morphing.
La transition repose sur une seule règle CSS : transition: .5s cubic-bezier(.4, 0, .2, 1) (la courbe Material Design « ease-out »). Quand switchTab() déplace la classe .active, le panneau sortant fond et glisse vers le bas pendant que le panneau entrant monte et grossit simultanément — les deux transitions s'exécutent en parallèle sur la même couche GPU, sans aucun reflow du document.
La fonction switchTab(index, btn) est déclarée dans une IIFE. Elle retire .active de tous les boutons via querySelectorAll('.tab-morph-btn') et de tous les panneaux via querySelectorAll('#tabMorphContent .tab-morph-panel'), puis pose la classe sur le bouton cliqué et sur le panneau d'indice correspondant. Les panneaux inactifs ont pointer-events: none : aucune interaction involontaire avec du contenu masqué.
Limite : switchTab est déclarée à l'intérieur de l'IIFE et n'est pas exposée dans window ; les attributs onclick du HTML ne la trouvent pas en contexte global. Pour une utilisation multi-instance ou programmatique, redéfinissez window.switchTab en scopant les sélecteurs sur le .tab-morph-wrapper parent du bouton cliqué (voir section Personnalisation et FAQ).
Accessibilité
- prefers-reduced-motion : absent — le code ne contient aucune détection de cette préférence OS ; la transition de 0,5 s s'exécute toujours, y compris pour les utilisateurs sensibles au mouvement.
- Les déclencheurs sont des
<button>natifs : focusables au clavier par défaut, activables à la touche Entrée ou Espace. - Le patron ARIA tabs est absent : ni
role="tablist", nirole="tab"sur les boutons, nirole="tabpanel"niaria-selected— les lecteurs d'écran ne perçoivent pas la relation onglet/panneau. - Les panneaux inactifs ont
pointer-events: none: aucune interaction involontaire avec du contenu masqué. - Contraste du texte des boutons inactifs (
#a5b4fcsur fond#0a0a0f) : ratio ≈ 5,1:1, niveau WCAG AA atteint.
Compatibilité navigateur
L'effet repose uniquement sur des transitions CSS et querySelectorAll — disponibles dans tous les navigateurs depuis 2016. Zéro dépendance externe.
Sans support des transitions CSS, les panneaux permutent instantanément (sans morphing) mais la navigation par onglets reste entièrement fonctionnelle — aucune erreur JS.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
<div class="tab-morph-wrapper">
<div class="tab-morph-nav">
<button class="tab-morph-btn active" onclick="switchTab(0, this)">Onglet 1</button>
<button class="tab-morph-btn" onclick="switchTab(1, this)">Onglet 2</button>
<button class="tab-morph-btn" onclick="switchTab(2, this)">Onglet 3</button>
</div>
<div class="tab-morph-content" id="tabMorphContent">
<div class="tab-morph-panel active"><!-- Contenu 1 --></div>
<div class="tab-morph-panel"><!-- Contenu 2 --></div>
<div class="tab-morph-panel"><!-- Contenu 3 --></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 |
|---|---|---|
| --primary | #6366f1 | Variable CSS racine : couleur d'accent du bouton actif (background + border-color). Remplacez par la couleur brand pour intégrer l'effet dans votre design system. |
| .tab-morph-panel { transition } | 0.5s cubic-bezier(.4, 0, .2, 1) | Durée et courbe du morphing. Essayez 0,3 s pour un rendu vif, 0,7 s pour un enchaînement cinématique. La courbe ease-out est celle de Material Design. |
| translateY(10px) dans .tab-morph-panel | 10px | Amplitude verticale du glissement d'entrée. Réduisez à 4 px pour un déplacement quasi imperceptible, montez à 20 px pour un effet de profondeur plus marqué. |
| scale(.95) dans .tab-morph-panel | 0.95 | Facteur d'échelle du panneau inactif. Descendez à 0,90 pour accentuer le zoom avant d'entrée, remplacez par 1 pour supprimer l'effet de scale. |
| .tab-morph-content { min-height } | 80px | Hauteur minimale du conteneur de panneaux. Ajustez à la hauteur du panneau le plus grand pour éviter le saut de mise en page quand les panneaux ont des contenus de tailles très différentes. |
| .tab-morph-btn { padding } | 6px 14px | Taille des zones de clic. Augmentez le padding pour respecter la cible tactile minimum de 44 × 44 px recommandée par WCAG 2.5.5. |
| window.switchTab(index, btn) | — | Redéfinissez cette fonction pour la rendre accessible globalement et scopée par instance (btn.closest('.tab-morph-wrapper')) — indispensable pour plusieurs instances sur la même page ou pour déclencher un changement d'onglet programmatiquement. |
FAQ
switchTab interroge querySelectorAll('.tab-morph-btn') sans contrainte de portée — plusieurs instances se perturbent mutuellement. Pour en avoir plusieurs, redéfinissez window.switchTab en scopant les sélecteurs sur le wrapper parent : var w = btn.closest('.tab-morph-wrapper'); w.querySelectorAll('.tab-morph-btn').forEach(…). Chaque instance est alors totalement indépendante.<button class="tab-morph-btn" onclick="switchTab(3, this)">Onglet 4</button> dans .tab-morph-nav et <div class="tab-morph-panel">…</div> dans .tab-morph-content. L'index passé à switchTab correspond à la position du panneau (0-based). Aucune modification du CSS n'est nécessaire — la transition s'applique automatiquement à tout élément .tab-morph-panel.@media (prefers-reduced-motion: reduce) { .tab-morph-panel { transition: none; } }. Les panneaux permutent alors instantanément sans animation — fonctionnel et respectueux des utilisateurs sensibles au mouvement.