Footnote Popover
Des marqueurs de référence superscripts affichent une bulle de contenu positionnée au-dessus du marqueur, animée en opacité et en scale — pur CSS, zéro JavaScript.
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'effet repose entièrement sur CSS, sans ligne de JavaScript. Chaque marqueur .fn-ref est un badge inline-flex en position: relative, et son popover .fn-popover est un enfant en position: absolute avec bottom: calc(100% + 10px) — ce qui l'ancre exactement 10 px au-dessus du badge, centré horizontalement via left: 50%; transform: translateX(-50%).
La visibilité est pilotée par le sélecteur de descendant .fn-ref:hover .fn-popover : au repos, le popover a opacity: 0, transform: translateX(-50%) scale(0.95) et pointer-events: none ; au survol, il passe à opacity: 1, scale(1) et pointer-events: auto — la double transition CSS (opacity .2s, transform .2s) produit l'entrée en fondu-scale sans RAF ni JS.
La flèche pointant vers le marqueur est dessinée par le pseudo-élément .fn-popover::after avec la technique border trick : un carré nul dont les bords forment un triangle isocèle (border-color: #1e1b4b transparent transparent), posé en top: 100% et centré. Le fond du popover (#1e1b4b) et la couleur du triangle sont identiques, ce qui aligne visuellement la flèche au fond.
Le badge reçoit un fond rgba(99,102,241,.2) passant à rgba(99,102,241,.4) au survol (transition: background .2s), et est en vertical-align: super pour s'insérer naturellement dans le flux de texte comme un exposant. Le popover est déclaré pointer-events: none au repos pour éviter les conflits de survol sur les zones adjacentes.
Accessibilité
- prefers-reduced-motion absent : le code ne déclare pas de bloc
@media (prefers-reduced-motion: reduce)— les transitions CSS d'opacité et de scale s'exécutent même si l'OS signale une préférence de mouvement réduit. À ajouter si déployé sur un site grand public. - Interaction au clavier non couverte : le popover n'est déclenché que par
:hoverCSS — les utilisateurs naviguant au clavier (Tab) ne voient pas le contenu. Pour couvrir le clavier, il faut ajoutertabindex="0"sur.fn-refet utiliser le sélecteur:focus-within. - Aucun attribut
aria-présent sur les marqueurs ou les popovers — le contenu des notes est invisible pour les lecteurs d'écran. Ajouterrole="button",aria-describedbyouaria-haspopupsi le contenu est essentiel. - Contraste texte : la couleur du texte du popover (
#c7d2fesur fond#1e1b4b) dépasse le ratio WCAG AA de 4,5:1 — le texte secondaire reste lisible. - Le badge (
#818cf8surrgba(99,102,241,.2)) est décoratif (numéro court) ; son fond translucide sous-passe le ratio AA, mais le chiffre seul ne constitue pas un contenu critique.
Compatibilité navigateur
L'effet n'utilise que des sélecteurs CSS2/CSS3 et des transitions — aucun polyfill requis.
Si les transitions CSS ne sont pas supportées, le popover s'affiche et se masque de façon instantanée au survol — aucune erreur, le contenu reste accessible.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
<div class="anchor-demo">
<div class="footnote-scene">
<div class="footnote-text">
Texte avec référence
<span class="fn-ref">1
<span class="fn-popover">
<span class="fn-num">[1]</span> Contenu de la note.
</span>
</span>
suite du texte.
</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 |
|---|---|---|
| .fn-popover { width } | 220px | Largeur de la bulle — augmentez pour des notes longues, réduisez pour des définitions courtes. Valeur recommandée : 180–300px. |
| .fn-popover { bottom } | calc(100% + 10px) | Décalage vertical entre le bas du popover et le haut du badge. Augmentez l'offset (ex. 14px) si votre fonte est grande et que les popovers se chevauchent. |
| .fn-popover (background) | #1e1b4b | Couleur de fond de la bulle. Doit correspondre à la couleur du triangle ::after pour éviter le décalage visuel. |
| .fn-popover::after (border-color) | #1e1b4b transparent transparent | Couleur du triangle pointant vers le badge — maintenez-la identique au fond du popover. |
| .fn-ref (background / hover background) | rgba(99,102,241,.2) / .4 | Fond du badge au repos et au survol. Ajustez l'opacité ou la couleur pour s'adapter à votre palette brand. |
| .fn-popover (transition) | opacity .2s, transform .2s | Durée et courbe des animations d'entrée/sortie. Passez à .15s pour une apparition plus vive, ou .3s ease-in-out pour un fondu plus doux. |
| .fn-popover (font-size) | .72rem | Taille de la police du contenu du popover. Garde le texte discret — ne pas dépasser .85rem pour rester dans la hiérarchie typographique. |
| .fn-ref { transform: scale } | scale(0.95) → scale(1) | Amplitude de l'animation de grossissement à l'entrée. Réduisez à scale(0.98) pour un effet plus subtil, ou supprimez la propriété transform pour désactiver l'animation scale. |
FAQ
tabindex="0" sur chaque .fn-ref et complétez le sélecteur CSS : .fn-ref:hover .fn-popover, .fn-ref:focus-within .fn-popover { opacity: 1; transform: translateX(-50%) scale(1); pointer-events: auto; }. Pour les lecteurs d'écran, ajoutez role="button" sur .fn-ref et aria-describedby pointant vers l'id du popover.left: 50%; transform: translateX(-50%) par right: 0; transform: translateX(0) (ou left: 0 selon le bord), et déplacez la flèche ::after en conséquence via left: auto; right: 8px. Pour une gestion automatique, un attribut data-popover-side="left|right" piloté par un court script JS suffit.position: absolute est rogné par tout ancêtre avec overflow: hidden ou overflow: clip. La solution la plus simple est de passer le conteneur à overflow: visible. Si ce n'est pas possible (ex. carrousel, tableau à défilement), déplacez le popover hors du flux via position: fixed et repositionnez-le avec JavaScript depuis les coordonnées getBoundingClientRect() du badge.