Smart Tooltip System
Tooltips CSS pure qui s'inversent automatiquement au-dessus ou en-dessous, alignés gauche ou droite, dès que le déclencheur frôle un bord du viewport.
Cet effet est gratuit — la catégorie Navigation en contient 36 au total, dont 4 gratuits. Effect.Labs regroupe 811 effets vanilla. Découvrir la catégorie →
Exemples d'usage
| Nom | Statut | Dernière activité | Actions |
|---|---|---|---|
| Sophie Martin | Actif | À l'instant | |
| Lucas Girard | En attente | Il y a 2 h | |
| Emma Leroux | Inactif | Il y a 3 j | |
| Marc Dupont | Actif | Il y a 5 min |
Comment ça marche
Chaque déclencheur (.anchor-tooltip-trigger) est position: relative. Le tooltip (.smart-tooltip) est position: absolute avec bottom: calc(100% + 10px) — il apparaît au-dessus par défaut — et centré horizontalement via left: 50%; transform: translateX(-50%). La flèche est un triangle CSS dessiné par le pseudo-élément ::after : quatre bordures, trois transparentes, une opaque dans la direction du déclencheur.
Quatre classes de surcharge gèrent les variantes positionnelles. .flipped-bottom bascule l'ancre de bottom vers top: calc(100% + 10px) (tooltip en dessous) et retourne la flèche via border-top-color: transparent; border-bottom-color. .flipped-left passe de left: 50% à right: 0; left: auto; transform: none — la flèche se décale à right: 14px. Idem en miroir pour .flipped-right.
L'affichage est piloté par :hover et :focus via transition: opacity 0.2s, transform 0.2s — aucun JS requis pour l'animation. Pour la détection automatique de débordement, un court script (~15 lignes, zéro dépendance) appelle getBoundingClientRect() sur le déclencheur et le conteneur à chaque mouseenter, puis applique la ou les classes .flipped-* appropriées.
Les navigateurs supportant le CSS Anchor Positioning (@position-try + position-try-fallbacks, Chrome 125+) permettent une version entièrement CSS sans script : on déclare des blocs @position-try pour chaque variante et le navigateur choisit automatiquement le premier qui ne déborde pas.
Accessibilité
- prefers-reduced-motion : la transition
opacity 0.2s, transform 0.2sn'est pas désactivée dans le code de base. Ajoutez@media (prefers-reduced-motion: reduce) { .smart-tooltip { transition: none; } }pour les utilisateurs sensibles au mouvement. - Déclenchement au clavier : la règle
.anchor-tooltip-trigger:focus .smart-tooltip { opacity: 1 }est présente dans le CSS — le tooltip s'affiche dès que le bouton reçoit le focus via Tab, sans JS supplémentaire. - Contraste : fond
rgb(30, 27, 75)sur textergb(224, 231, 255)→ ratio ≈ 11,5:1, bien au-delà du seuil WCAG AA (4,5:1). - Les déclencheurs sont des éléments
<button>natifs : focusables, annoncés par les lecteurs d'écran et activables à la touche Espace/Entrée sans ARIA supplémentaire. - Pas d'
aria-describedbydans le code de base : le texte du tooltip n'est pas lu automatiquement par les lecteurs d'écran. Pour les tooltips porteurs d'information critique, ajoutezaria-describedby="id-du-span"sur le bouton et unidsur le<span class="smart-tooltip">.
Compatibilité navigateur
Le positionnement CSS fonctionne dans tous les navigateurs modernes. La détection de débordement via getBoundingClientRect() est universelle. Le mode 100 % CSS natif (position-try-fallbacks) requiert Chrome 125+.
Sans le script de détection, les tooltips s'affichent toujours au-dessus — aucune erreur JS, mais pas d'inversion automatique. Les classes <code>.flipped-*</code> peuvent être appliquées manuellement selon la position connue à la conception.
Le code
Copiez les trois blocs dans votre page. Aucune dépendance.
<div class="anchor-demo">
<div class="tooltip-scene" id="tooltipScene">
<button class="anchor-tooltip-trigger" data-tooltip-pos="top">
Top
<span class="smart-tooltip">Info au-dessus</span>
</button>
<button class="anchor-tooltip-trigger" data-tooltip-pos="top">
Edge
<span class="smart-tooltip">Auto-flip si hors viewport</span>
</button>
<button class="anchor-tooltip-trigger" data-tooltip-pos="top">
Smart
<span class="smart-tooltip">Position adaptative</span>
</button>
</div>
</div>
.anchor-demo {
position: relative;
width: 100%;
height: 220px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.anchor-demo * {
box-sizing: border-box;
}
.tooltip-scene {
display: flex;
gap: 32px;
flex-wrap: wrap;
justify-content: center;
align-items: center;
padding: 20px;
}
.anchor-tooltip-trigger {
position: relative;
padding: 10px 18px;
background: linear-gradient(135deg, rgb(99, 102, 241), rgb(139, 92, 246));
color: rgb(255, 255, 255);
border-width: medium;
border-style: none;
border-color: currentcolor;
border-image: initial;
border-radius: 8px;
font-size: 0.85rem;
font-weight: 600;
cursor: pointer;
font-family: inherit;
}
.anchor-tooltip-trigger .smart-tooltip {
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: calc(100% + 10px);
padding: 8px 14px;
background: rgb(30, 27, 75);
color: rgb(224, 231, 255);
font-size: 0.78rem;
font-weight: 500;
border-radius: 8px;
white-space: nowrap;
pointer-events: none;
opacity: 0;
transition: opacity 0.2s, transform 0.2s;
z-index: 100;
box-shadow: rgba(0, 0, 0, 0.35) 0px 8px 24px;
}
.anchor-tooltip-trigger .smart-tooltip::after {
content: "";
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 100%;
border-width: 6px;
border-style: solid;
border-color: rgb(30, 27, 75) transparent transparent;
border-image: initial;
}
.anchor-tooltip-trigger .smart-tooltip.flipped-bottom {
bottom: auto;
top: calc(100% + 10px);
}
.anchor-tooltip-trigger .smart-tooltip.flipped-bottom::after {
top: auto;
bottom: 100%;
border-top-color: transparent;
border-bottom-color: rgb(30, 27, 75);
}
.anchor-tooltip-trigger .smart-tooltip.flipped-left {
left: auto;
right: 0px;
transform: none;
}
.anchor-tooltip-trigger .smart-tooltip.flipped-left::after {
left: auto;
right: 14px;
transform: none;
}
.anchor-tooltip-trigger .smart-tooltip.flipped-right {
left: 0px;
right: auto;
transform: none;
}
.anchor-tooltip-trigger .smart-tooltip.flipped-right::after {
left: 14px;
right: auto;
transform: none;
}
.anchor-tooltip-trigger:hover .smart-tooltip, .anchor-tooltip-trigger:focus .smart-tooltip {
opacity: 1;
}
// Effet CSS pur — pas de JavaScript nécessaire
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
| background (règle CSS .smart-tooltip) | rgb(30, 27, 75) | Couleur de fond du tooltip — remplacez par votre token dark ou couleur brand. |
| color (règle CSS .smart-tooltip) | rgb(224, 231, 255) | Couleur du texte. Vérifiez le ratio de contraste avec le fond choisi (seuil WCAG AA : 4,5:1). |
| offset (calc(100% + Npx)) | 10px | Espace entre le tooltip et le déclencheur. Augmentez pour plus d'aération, réduisez pour un style dense. |
| transition | opacity 0.2s, transform 0.2s | Durée et propriétés animées à l'affichage/masquage. Réduisez à 0.1s pour un retour plus vif, ou passez à none via media query prefers-reduced-motion. |
| font-size (.smart-tooltip) | 0.78rem | Taille du texte. 0.78rem est lisible sans encombrer — ne pas descendre sous 0.72rem. |
| .flipped-bottom | absent | Classe à ajouter pour afficher le tooltip en-dessous du déclencheur. La flèche s'inverse automatiquement via ::after. |
| .flipped-left / .flipped-right | absent | Classes pour ancrer l'alignement horizontal quand le tooltip déborderait d'un côté du viewport. .flipped-left ancre à droite du déclencheur, .flipped-right ancre à gauche. |
FAQ
Le tooltip est-il vraiment CSS pur ou faut-il du JavaScript ?
L'animation hover/focus et les quatre variantes positionnelles sont 100 % CSS. La détection automatique de débordement — la partie qui choisit la bonne variante au survol — requiert un court script (~15 lignes, zéro dépendance). Sur Chrome 125+, position-try-fallbacks permet de s'en passer entièrement avec un bloc @position-try par variante.
Comment intégrer ce tooltip dans un composant React ou Vue ?
Enveloppez le déclencheur et le span tooltip dans un composant. Dans le handler onMouseEnter, appelez getBoundingClientRect() sur l'élément tooltip et mettez à jour l'état pour appliquer les classes .flipped-*. Le CSS de l'effet s'intègre sans modification — aucun conflit avec les CSS-in-JS tant que les noms de classes restent stables.
Peut-on afficher le tooltip à gauche ou à droite du déclencheur, pas seulement au-dessus ou en-dessous ?
Pas directement avec les classes incluses — celles-ci ajustent l'alignement horizontal mais gardent le tooltip au-dessus ou en-dessous. Pour un positionnement latéral (gauche/droite), ajoutez des règles CSS supplémentaires : par exemple .flipped-side-right { left: calc(100% + 10px); bottom: auto; top: 50%; transform: translateY(-50%); } et la flèche correspondante.