Tabs Animated
Un indicateur pill gradient glisse entre les onglets via translateX — sélection au clic, panneaux avec fadeIn de 0,3 s, zéro dépendance externe.
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. Navigation comprend 36 effets, dont 4 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
L'indicateur glissant est un <div class="tab-indicator"> positionné en absolute dans le header position: relative. Sa largeur est calc(33.333% - 2.67px) — exactement un tiers du conteneur, les boutons étant en flex: 1 1 0%. Il porte un dégradé linear-gradient(135deg, #6366f1, #8b5cf6) et un border-radius: 8px.
Le déplacement repose sur une seule instruction JS : indicator.style.transform = 'translateX(' + 100 * index + '%)'. La valeur 100 % correspond à 100 % de la largeur de l'indicateur lui-même — soit exactement la largeur d'un onglet. Le navigateur interpole le mouvement via transition: transform .3s cubic-bezier(.4, 0, .2, 1) (courbe Material Design), sans aucun calcul de coordonnées absolues.
Au changement d'onglet, classList.toggle('active', bool) coche le bouton et le panneau correspondants et décoche les autres. Le panneau actif bascule de display: none à display: block et déclenche l'animation CSS fadeIn (opacité 0→1, translateY 10→0 px, durée 0,3 s). La couleur des boutons inactifs transite de rgba(255,255,255,.6) vers #fff sur transition: color .3s.
Les boutons en flex: 1 1 0% occupent tous strictement la même largeur quelle que soit la longueur du label — l'indicateur atterrit toujours juste sous le bon onglet sans calcul supplémentaire. La fonction switchTab(n) est exposée dans la portée globale et peut être appelée programmatiquement depuis n'importe quel script extérieur.
Accessibilité
- prefers-reduced-motion absent — le code ne contient pas de media query
prefers-reduced-motion: la transition de l'indicateur et le fadeIn s'exécutent même si l'OS demande à réduire le mouvement. À ajouter manuellement :@media (prefers-reduced-motion: reduce) { .tab-indicator, .tab-panel { transition: none; animation: none; } }. - Les onglets sont des
<button>natifs — focusables au clavier (Tab / Shift+Tab) et annoncés par les lecteurs d'écran sans configuration supplémentaire. - Pas de rôles ARIA du pattern Tabs (
role="tablist",role="tab",aria-selected,role="tabpanel",aria-controls) — à ajouter si la conformité WCAG 1.3.1 est requise. - Les panneaux non actifs sont masqués par
display: none— retirés de l'arbre d'accessibilité nativement, sansaria-hiddenexplicite. - Contraste du texte actif :
#fffsur le gradient indigo (#6366f1) — ratio > 4,5:1, conforme WCAG AA.
Compatibilité navigateur
CSS transition, transform, flexbox et linear-gradient — supportés dans tous les navigateurs modernes. Zéro dépendance externe.
Sans JS, les onglets restent visibles mais l'indicateur ne glisse pas et les panneaux ne basculent pas — l'onglet Accueil reste affiché en statique. Sans support <code>flexbox</code>, les boutons s'empilent verticalement mais restent fonctionnels.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
<div class="tabs-container">
<div class="tabs-header">
<div class="tab-indicator" id="tabIndicator"></div>
<button class="tab-btn active" onclick="switchTab(0)">Onglet 1</button>
<button class="tab-btn" onclick="switchTab(1)">Onglet 2</button>
<button class="tab-btn" onclick="switchTab(2)">Onglet 3</button>
</div>
<div class="tabs-content">
<div class="tab-panel active" data-tab="0">Contenu de l'onglet 1</div>
<div class="tab-panel" data-tab="1">Contenu de l'onglet 2</div>
<div class="tab-panel" data-tab="2">Contenu de l'onglet 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 (CSS :root) | #6366f1 | Couleur d'accent utilisée par .tab-btn.active { color } — modifiez dans :root ou sur .tabs-container pour un scope plus étroit. |
| .tab-indicator background | linear-gradient(135deg, #6366f1, #8b5cf6) | Gradient de l'indicateur pill — remplacez par une couleur unie (#3b82f6) ou votre palette brand. |
| .tab-indicator transition | transform .3s cubic-bezier(.4,0,.2,1) | Durée et easing du glissement — .15s ease pour une réponse data immédiate, .5s ease-in-out pour une animation éditoriale plus douce. |
| .tabs-container max-width | 350px | Largeur maximale du bloc — supprimez ou passez à 100% pour une barre full-width dans un layout fluide. |
| .tab-btn color (inactif) | rgba(255,255,255,.6) | Opacité du texte des onglets inactifs — augmentez à rgba(255,255,255,.85) pour plus de lisibilité sur fond clair. |
| .tab-panel animation | fadeIn .3s ease | Animation du contenu au basculement — raccourcissez à fadeIn .1s ease pour un affichage quasi-instantané, ou supprimez animation pour un simple swap. |
| switchTab(n) — JS global | — | Appel programmatique pour changer d'onglet sans clic — switchTab(2) active le 3ᵉ onglet. Déclenchez depuis un timer, un événement métier ou un lien externe. |
FAQ
width: calc(33.333% - 2.67px) par calc(100% / N - gap) (ex. calc(25% - 3px) pour 4 onglets). Dans les appels JS, le décalage reste translateX(100 * index %) — il n'y a rien d'autre à modifier côté logique.flex: 1 1 0% : ils partagent la largeur du conteneur à parts strictement égales, indépendamment du texte. L'indicateur hérite de cette largeur fixe et atterrit toujours exactement sous le bon onglet.onclick="switchTab(n)" inline par onClick={() => switchTab(n)} et déclenchez switchTab(defaultTab) dans un useEffect(() => {}, []) côté client. Dans Vue, utilisez @click="switchTab(n)" et mounted() { switchTab(0); }. L'effet ne touche pas au DOM en dehors de son conteneur.