Navigation✨ Premium

Floating Indicator

Une pill indicatrice glisse sous l'onglet actif — position et largeur lues en temps réel via getBoundingClientRect(), interpolées par une cubic-bezier(0.44, 0, 0.56, 1).

JSNavSmooth

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

Navigation principale d'une app SaaS — Floating Indicator exemple 1

① Navigation principale d'une app SaaS

QuandEn tête d'une page produit ou d'un espace client avec 3 à 5 sections (Overview, Features, Pricing) où l'utilisateur navigue fréquemment.
PourquoiLa pill glissante signale l'onglet actif sans jamais quitter le conteneur — plus élégant qu'un soulignement classique sur un fond sombre, et le halo violet renforce l'identité brand.
Réglages--primary: #6366f1, --radius-lg: 0.75rem, padding interne 6 px, 3 items.
Onglets de métriques dans un dashboard analytics — Floating Indicator exemple 2

② Onglets de métriques dans un dashboard analytics

QuandDans un dashboard avec des vues permutables (Trafic, Conversions, Revenus, Coûts) que l'utilisateur bascule régulièrement lors de ses analyses.
PourquoiLa glissade fluide maintient la continuité visuelle lors des changements de vue fréquents et réduit la désorientation — l'animation montre clairement que l'état a changé.
Réglages--primary: #10b981 (vert brand), --bg-card: #0f172a, transition .35s cubic-bezier(.44, 0, .56, 1), 4 items.
Filtres de catégories sur un blog ou un catalogue — Floating Indicator exemple 3

③ Filtres de catégories sur un blog ou un catalogue

QuandSur une page listant des articles ou des produits filtrés par catégorie (Tous, Design, Dev, Marketing) sans rechargement de page.
PourquoiL'indicateur donne un retour visuel immédiat sur le filtre actif ; la dilatation simultanée de la pill lors du passage d'un label court à un long rend la sélection perceptible même sur des items rapprochés.
Réglages--radius-lg: 2rem (pill ronde), --primary: #f59e0b, font-size: .85rem, 4 items.

Comment ça marche

L'indicateur (.floating-nav-indicator) est un <div> positionné en absolute à l'intérieur du conteneur .floating-nav (en relative). Il apparaît visuellement sous les labels grâce à un z-index: 1 sur les items. Sa couleur est un dégradé linéaire 135° de #6366f1 à #8b5cf6, complété par un halo box-shadow violet à 40 % d'opacité. Au chargement, le JS le positionne immédiatement sous le premier onglet sans transition visible.

Au clic sur un item, l'effet appelle getBoundingClientRect() sur l'item et sur le conteneur nav, puis calcule un décalage relatif en soustrayant les deux valeurs de left. Il écrit ensuite style.width et style.left sur l'indicateur. La mesure est faite en temps réel à chaque clic, ce qui rend l'effet insensible aux variations de largeur des labels — un label court vers un long produit une dilatation-glissade simultanée des deux propriétés.

Le CSS prend le relais via transition: .4s cubic-bezier(.44, 0, .56, 1) sur .floating-nav-indicator. Cette courbe est une ease-in-out légèrement plus vive que la courbe CSS native (ease-in-out = cubic-bezier(.42, 0, .58, 1)), ce qui donne à la pill une sensation de masse nette sans traîner. Les deux propriétés animées (left et width) déclenchent le layout à chaque frame — pour des perfs GPU-only, elles peuvent être remplacées par transform: translateX() + scaleX().

Accessibilité

  • prefers-reduced-motion : non géré dans ce code — la transition CSS reste active même si l'OS demande à réduire le mouvement. Correctif minimal : @media (prefers-reduced-motion: reduce) { .floating-nav-indicator { transition: none } }.
  • Les items sont des <span> non focusables nativement — la nav n'est pas atteignable au clavier. Pour la conformité WCAG 2.1.1, remplacez-les par des <button> ou ajoutez tabindex="0" avec un listener keydown sur Enter/Space.
  • Aucun rôle sémantique sur le conteneur — ajoutez role="tablist" sur .floating-nav et role="tab" + aria-selected="true/false" sur chaque item pour une conformité lecteur d'écran complète.
  • Contraste texte inactif (#a1a1aa sur #12121a) : ratio ≈ 7,2:1 — WCAG AA et AAA ✓.
  • Contraste texte actif (#ffffff sur le gradient #6366f1→#8b5cf6) : ratio ≈ 4,3:1 — légèrement en dessous du seuil AA de 4,5:1 pour le texte normal de taille standard.

Compatibilité navigateur

Utilise getBoundingClientRect() et les transitions CSS — disponibles dans tous les navigateurs modernes sans polyfill.

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

Sans JS, l'indicateur reste sur sa position initiale définie en HTML et aucune erreur n'est levée — la nav reste lisible mais statique.

Le code

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

index.html — structure
<div class="floating-nav" id="floatingNav">
  <div class="floating-nav-indicator" id="floatingIndicator"></div>
  <span class="floating-nav-item active" data-index="0">Onglet 1</span>
  <span class="floating-nav-item" data-index="1">Onglet 2</span>
  <span class="floating-nav-item" data-index="2">Onglet 3</span>
</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
--primary #6366f1 Couleur de départ du dégradé de la pill. Remplacez par votre couleur brand — la fin du dégradé (#8b5cf6) est codée en dur dans le CSS de .floating-nav-indicator.
--bg-card #12121a Fond du conteneur de navigation flottant.
--text-secondary #a1a1aa Couleur des labels inactifs. Assurez un ratio ≥ 4,5:1 avec votre couleur de fond.
--radius-lg 0.75rem Border-radius du conteneur nav et de la pill. Montez à 2rem pour une pill entièrement ronde.
--border rgba(255,255,255,0.08) Bordure du conteneur flottant — ajustez l'opacité pour l'effacer ou l'accentuer.
transition (.floating-nav-indicator) .4s cubic-bezier(.44, 0, .56, 1) Durée et courbe de la glissade. Passez à .25s ease pour une réponse plus nerveuse, ou .6s pour un effet plus ample.
padding (.floating-nav) 6px Espace interne entre la bordure du conteneur et les items — change la marge autour de la pill.
box-shadow (.floating-nav-indicator) rgba(99,102,241,.4) 0 4px 15px Halo lumineux sous la pill. Changez la couleur et l'intensité selon votre palette.

FAQ

Le positionnement repose sur getBoundingClientRect(), qui lit les coordonnées au moment du clic. Si la fenêtre est redimensionnée ensuite, aucun recalcul n'est déclenché. Ajoutez window.addEventListener('resize', () => m(activeItem))activeItem est l'item actuellement marqué .active — ou utilisez un ResizeObserver sur le conteneur pour une réactivité plus précise.
Le code original cible les IDs uniques floatingNav et floatingIndicator dans un IIFE. Pour plusieurs instances, extrayez la logique en une fonction réutilisable : function initFloatingNav(navEl, indicatorEl) { const items = navEl.querySelectorAll('.floating-nav-item'); /* … */ } et appelez-la pour chaque paire, en passant les éléments directement plutôt que des IDs.
Oui. Le code actuel anime left et width, deux propriétés qui provoquent un relayout. Pour une animation 100 % compositeur, remplacez l'indicateur par un élément de largeur 100 % et animez transform: translateX(offsetPx) scaleX(ratio) avec transform-origin: left — le navigateur composite la transformation sans toucher au layout. Le calcul du décalage et du ratio reste à faire en JS avec getBoundingClientRect().