Afficher une info-bulle lorsque le curseur pointe un élément

Les utilisateurs s'attendent à voir des informations supplémentaires associées sans changer complètement de contexte. Afficher une info-bulle lorsqu'un utilisateur souhaite obtenir plus d'informations peut être utile pour fournir la définition d'un terme, clarifier l'action d'un bouton composé uniquement d'une icône ou fournir des conseils supplémentaires sur un champ de formulaire.

Créer l'info-bulle

Vous pouvez créer un popover avec le comportement requis en ajoutant l'attribut popover="hint" à un élément <div> ou à un autre élément sémantiquement approprié. Lorsque l'utilisateur ouvre l'info-bulle, les autres info-bulles popover="hint" sont masquées, mais pas les info-bulles auto ou manual. Il gère également la fermeture des info-bulles imbriquées.

Il fournit également un comportement de masquage léger. Ainsi, lorsqu'un utilisateur clique ou se concentre en dehors du popover, celui-ci est masqué.

L'élément d'info-bulle doit comporter un attribut id avec une valeur unique :

<!-- MANDATORY: The tooltip container `<div>` must have a `popover` attribute.
     the value of `"hint"` ensures it can be "light dismissed". -->
<div popover="hint" id="tooltip">Tooltip content</div>

Un utilisateur exprime son intérêt pour les informations supplémentaires en pointant sur un élément <a> ou <button>, ou en le sélectionnant. L'élément doit comporter un attribut interestfor correspondant à l'attribut id de l'info-bulle.

<!-- The `interestfor` attribute can be applied to a `<button>` element: -->
<button interestfor="tooltip">Tooltip trigger</button>

<!-- The `interestfor` attribute can also be applied to an `<a>` element: -->
<a interestfor="tooltip" href="">Tooltip trigger</a>

Le déclencheur doit comporter un indicateur visuel pour indiquer que des informations supplémentaires sont disponibles en interagissant avec le déclencheur.

Accessibilité intégrée à interestfor

Lorsque vous utilisez interestfor, le navigateur gère automatiquement la connexion à la technologie d'assistance :

  • Sémantique implicite : une cible avec popover="hint" obtient un rôle minimal implicite de tooltip. NE DÉFINISSEZ PAS role="tooltip" vous-même.
  • Association implicite : le navigateur associe implicitement l'élément source à la cible via aria-describedby lorsque la cible est du texte brut, ou via aria-details lorsque la cible contient du contenu interactif. N'AJOUTEZ PAS aria-describedby ou aria-details au déclencheur.
  • Contenu interactif : étant donné que l'association passe à aria-details si nécessaire, la cible PEUT contenir du contenu interactif (par exemple, un lien dans une "fiche d'intérêt").

Contraintes d'accessibilité (WCAG 1.4.13)

Même si interestfor gère la sémantique ci-dessus, votre implémentation DOIT toujours respecter la règle WCAG 1.4.13 (Contenu au survol ou au focus) :

  • Fermable : les utilisateurs doivent pouvoir fermer l'info-bulle sans déplacer le pointeur ni le focus clavier (par exemple, en appuyant sur la touche Escape). L'attribut popover natif gère automatiquement cette liaison.
  • Survolable : le pointeur doit pouvoir se déplacer sur le contenu de l'info-bulle sans que celle-ci disparaisse. Cela permet aux utilisateurs d'outils d'agrandissement de lire le texte de l'info-bulle en toute sécurité.
  • Persistant : l'info-bulle doit rester visible jusqu'à ce que le déclencheur de survol ou de sélection soit supprimé, que l'utilisateur la ferme explicitement ou que son contenu ne soit plus valide.

Positionner l'info-bulle

L'info-bulle est positionnée à l'aide du positionnement des ancres CSS. Lorsque l'info-bulle est ouverte à l'aide de interestfor, l'élément déclencheur devient automatiquement une ancre implicite pour le popover.

Dans les navigateurs récents compatibles avec le positionnement d'ancrage natif, vous n'avez pas besoin de définir un anchor-name sur le déclencheur ni un position-anchor sur l'info-bulle. Vous pouvez positionner l'info-bulle directement par rapport à son ancrage implicite à l'aide de position-area et gérer le retournement en cas de collision avec position-try-fallbacks :

[popover] {
  /* Implicit anchor from interestfor: no anchor-name or position-anchor needed */
  position-area: top;
  position-try-fallbacks: flip-block;
  margin: unset;
}

Stratégies de remplacement

Créations de remplacement et compatibilité des navigateurs pour les déclencheurs d'intérêt

Les déclencheurs d'intérêt doivent être polyfillés de manière conditionnelle à l'aide du package polyfill interestfor de NPM. Privilégiez le regroupement du polyfill plutôt que l'utilisation du CDN.

OBLIGATOIRE : Détectez la fonctionnalité en vérifiant la propriété interestForElement sur HTMLButtonElement.prototype, et chargez le polyfill uniquement lorsque la compatibilité native est manquante.

<script type="module">
  if (!HTMLButtonElement.prototype.hasOwnProperty("interestForElement")) {
    // CDN link only used for example, prefer bundling.
    await import("https://unpkg.com/interestfor@latest");
  }
</script>

Mises en garde concernant les polyfills CSS

Lorsque vous utilisez le polyfill, l'API CSS change légèrement pour compenser l'absence de compatibilité native avec les pseudo-classes et les propriétés :

  • Pseudo-classes : le polyfill ne peut pas définir de vraies pseudo-classes :interest-source et :interest-target. Il applique donc les classes .interest-source et .interest-target à la place. OBLIGATOIRE : Combinez-les avec :is() pour prendre en charge les états natifs et polyfilled.
/* Styles to apply when the effect is being previewed */
:is(:interest-source, .interest-source) { /* ... */ }
:is(:interest-target, .interest-target) { /* ... */ }
  • Propriétés CSS : pour interest-delay, interest-delay-start et interest-delay-end, le polyfill nécessite l'utilisation de variables CSS, car il ne peut pas lire directement les propriétés personnalisées dans tous les navigateurs.
/* Adjust the start and end delay for interest invokers */
[interestfor] {
  --interest-delay-start: 0.2s;
  interest-delay-start: var(--interest-delay-start);
  --interest-delay-end: 0.1s;
  interest-delay-end: var(--interest-delay-end);
}

Solutions de remplacement et compatibilité des navigateurs pour Popover

L'API Popover est principalement une amélioration progressive, mais ses comportements déterminants (promotion de la couche supérieure, fermeture par clic en dehors de l'élément et appel de popovertarget) n'ont pas d'équivalent CSS uniquement. Les anciens navigateurs ont besoin d'un polyfill ou d'un remplacement manuel si vous préférez ne pas en fournir.

Polyfill : pour que l'attribut popover soit compatible avec les anciens navigateurs, chargez @oddbird/popover-polyfill de manière conditionnelle. OBLIGATOIRE : Détectez la fonctionnalité en vérifiant la propriété popover sur HTMLElement.prototype, et chargez le polyfill uniquement lorsque la compatibilité native est manquante. Ne le chargez PAS de manière inconditionnelle.

Avec un bundler ou une carte d'importation :

// MANDATORY: Feature detect 'popover' on HTMLElement.prototype.
if (!("popover" in HTMLElement.prototype)) {
  import("@oddbird/popover-polyfill");
}

Sans bundler, importez depuis un CDN dans un <script type="module"> :

<script type="module">
  if (!("popover" in HTMLElement.prototype)) {
    import("https://unpkg.com/@oddbird/popover-polyfill@latest/dist/popover.min.js");
  }
</script>

Mise en garde concernant l'application de styles : le polyfill ne peut pas définir la véritable pseudo-classe :popover-open. Il applique donc une classe .\:popover-open à la place. OBLIGATOIRE : Combinez les deux avec :is() ou :where(), sinon les navigateurs qui ne disposent pas de :popover-open ignorent l'intégralité de la règle :

[popover]:is(:popover-open, .\:popover-open) {
  display: block;
}

Vous pouvez également utiliser position: fixed pour une solution de remplacement sans polyfill et calculer manuellement les coordonnées via getBoundingClientRect(), ou vous appuyer sur le positionnement par défaut avec inset: auto si cela convient à votre cas d'utilisation.

popover-polyfill n'ajoute pas de polyfill au comportement de l'indice dans les navigateurs compatibles avec popover, mais pas avec popover="hint". Pour ces navigateurs, une info-bulle ouverte via le focus peut rester ouverte lorsqu'une deuxième info-bulle est ouverte via le survol.

Pour prendre en charge les navigateurs sans positionnement d'ancrage, vous pouvez utiliser le polyfill @oddbird/css-anchor-positioning. Vous pouvez également utiliser @supports pour spécifier une position de remplacement.

Lorsque vous utilisez le polyfill @oddbird/css-anchor-positioning pour la compatibilité avec les anciens navigateurs, sachez qu'il n'est pas compatible avec les ancres implicites ni avec position-area sur les popovers. Définissez explicitement un anchor-name sur le déclencheur, définissez position-anchor sur le popover et positionnez-le à l'aide des fonctions d'encart anchor() au lieu de position-area :

<!-- MANDATORY: Conditionally install the anchor positioning polyfill -->
<script type="module">
  if (!("anchorName" in document.documentElement.style)) {
    await import("https://unpkg.com/@oddbird/css-anchor-positioning");
  }
</script>
button[interestfor="tooltip-attrs"] {
  /* MANDATORY: Each trigger and popover pair must have a unique anchor name, referenced by `anchor-name` on the trigger and `position-anchor` on the popover. */
  anchor-name: --tooltip-attrs;
}
#tooltip-attrs {
  position-anchor: --tooltip-attrs;
  /* If using the anchor positioning polyfill with a popover, DO use `anchor()` functions, and not `position-area. */
  top: anchor(bottom);
  left: anchor(right);
  margin: unset;
}