Pop-ups: ils font leur grand retour !

L'objectif de l'initiative Open UI est de permettre aux développeurs de créer plus facilement des expériences utilisateur de qualité. Pour ce faire, nous essayons de résoudre les problèmes les plus problématiques auxquels les développeurs sont confrontés. Nous pouvons y parvenir en fournissant de meilleurs composants et API intégrés à la plate-forme.

Un de ces problèmes concerne les pop-ups, décrits dans Open UI comme « Popovers ».

La réputation de la population populaire s'est longtemps opposée. Cela est en partie dû à la manière dont ils sont créés et déployés. Il s'agit d'un modèle difficile à créer, mais ils peuvent générer une grande valeur ajoutée en dirigeant les internautes vers certaines choses ou en leur faisant connaître le contenu de votre site, surtout s'ils sont utilisés avec bon goût.

La création de fenêtres contextuelles pose souvent deux problèmes majeurs:

  • Assurez-vous de le placer au-dessus du reste de votre contenu, à un endroit approprié.
  • Comment le rendre accessible (compatible avec le clavier, sélectionnable, etc.)

L'API Popover intégrée présente plusieurs objectifs, tous ayant le même objectif global : permettre aux développeurs de créer facilement ce modèle. Voici quelques-uns de ces objectifs:

  • Facilitez l'affichage d'un élément et de ses descendants au-dessus du reste du document.
  • Rendez-le accessible.
  • Ils ne nécessitent pas JavaScript pour la plupart des comportements courants (Light Dismiss, Singleton, empilement, etc.).

Vous pouvez consulter les spécifications complètes des pop-ups sur le site OpenUI.

Compatibilité du navigateur

Où pouvez-vous désormais utiliser l'API Popover intégrée ? Au moment de la rédaction de ce document, cette fonctionnalité est disponible dans Chrome Canary grâce à l'indicateur "Fonctionnalités expérimentales de la plate-forme Web".

Pour activer cet indicateur, ouvrez Chrome Canary et accédez à chrome://flags. Activez ensuite l'indicateur "Fonctionnalités expérimentales de la plate-forme Web".

Il existe également une phase d'évaluation pour les développeurs qui souhaitent tester cette fonctionnalité dans un environnement de production.

Enfin, un polyfill est en cours de développement pour l'API. N'oubliez pas de le consulter à l'adresse github.com/oddbird/popup-polyfill.

Vous pouvez vérifier la compatibilité des pop-up avec:

const supported = HTMLElement.prototype.hasOwnProperty("popover");

Solutions actuelles

Actuellement, que pouvez-vous faire pour promouvoir votre contenu avant tout le reste ? Si votre navigateur le prend en charge, vous pouvez utiliser l'élément "Boîte de dialogue HTML". Vous devez l'utiliser sous forme "modale". Pour cela, JavaScript est nécessaire.

Dialog.showModal();

Des considérations d'accessibilité doivent être prises en compte. Il est recommandé d'utiliser a11y-dialog, par exemple si celui-ci est destiné aux utilisateurs de Safari disposant d'une version antérieure à la version 15.4.

Vous pouvez également utiliser l'une des nombreuses bibliothèques basées sur un pop-up, une alerte ou une info-bulle. Beaucoup de ces méthodes ont tendance à fonctionner de manière similaire.

  • Ajoutez un conteneur au corps pour afficher les pop-overs.
  • Ajustez-le de sorte qu'il se trouve au-dessus de tout le reste.
  • Créez un élément et ajoutez-le au conteneur pour afficher une fenêtre pop-up.
  • Masquez-le en supprimant l'élément pop-over du DOM.

Cela nécessite une dépendance supplémentaire et davantage de décisions pour les développeurs. Il faut également effectuer des recherches pour trouver une offre qui réponde à tous vos besoins. L'API Popover permet de répondre à de nombreux scénarios, y compris aux info-bulles. L'objectif est de couvrir tous ces scénarios courants, ce qui évite aux développeurs d'avoir à prendre une autre décision afin qu'ils puissent se concentrer sur le développement de leurs expériences.

Votre premier pop-up

C'est tout ce dont vous avez besoin.

<div id="my-first-popover" popover>Popover Content!</div>
<button popovertoggletarget="my-first-popover">Toggle Popover</button>

Mais que se passe-t-il ici ?

  • Vous n'avez pas besoin de placer l'élément pop-over dans un conteneur ou quoi que ce soit, car il est masqué par défaut.
  • Vous n'avez pas besoin d'écrire de code JavaScript pour l'afficher. Cette opération est gérée par l'attribut popovertoggletarget.
  • Lorsqu'elle apparaît, elle est promue dans la couche supérieure. Cela signifie qu'elle est placée au-dessus de document dans la fenêtre d'affichage. Vous n'avez pas besoin de gérer z-index ni de vous soucier de l'emplacement de votre pop-over dans le DOM. Elle peut être imbriquée en profondeur dans le DOM, avec des ancêtres coupés. Vous pouvez également identifier les éléments qui se trouvent actuellement dans la couche supérieure à l'aide des outils de développement. Pour en savoir plus sur la couche supérieure, consultez cet article.

GIF montrant la compatibilité de la couche supérieure des outils de développement

  • L'option "Light Dismiss" est disponible immédiatement. Cela signifie que vous pouvez fermer le pop-up avec un signal de fermeture, par exemple en cliquant en dehors de celui-ci, en accédant à un autre élément au clavier ou en appuyant sur la touche Esc. Rouvrez-la et essayez-la !

Qu'est-ce que le pop-over offre d'autre ? Poussons l'exemple plus loin. Envisagez cette démonstration avec du contenu sur la page.

Ce bouton d'action flottant a une position fixe avec une z-index élevée.

.fab {
  position: fixed;
  z-index: 99999;
}

Le contenu de la fenêtre contextuelle est imbriqué dans le DOM, mais lorsque vous l'ouvrez, il est placé au-dessus de cet élément de position fixe. Vous n'avez pas besoin de définir des styles.

Vous remarquerez peut-être également que le pop-over contient désormais un pseudo-élément ::backdrop. Tous les éléments qui se trouvent dans la couche supérieure obtiennent un pseudo-élément ::backdrop stylisé. Cet exemple définit le style de ::backdrop avec une couleur d'arrière-plan alpha réduite et un filtre d'arrière-plan, ce qui floute le contenu sous-jacent.

Appliquer un style à un pop-up

Tournons maintenant notre attention vers le style du pop-up. Par défaut, une fenêtre contextuelle a une position fixe et une marge intérieure est appliquée. Il comporte également display: none. Vous pouvez remplacer cela pour afficher un pop-up. Mais, cela ne le promouvoirait pas dans la couche supérieure.

[popover] { display: block; }

Quelle que soit la façon dont vous promouvez votre pop-up, une fois que vous l'aurez placé sur la couche supérieure, vous devrez peut-être la disposer ou la positionner. Vous ne pouvez pas cibler la couche supérieure et faire quelque chose comme

:open {
  display: grid;
  place-items: center;
}

Par défaut, un pop-up s'affiche au centre de la fenêtre d'affichage avec margin: auto. Toutefois, dans certains cas, il se peut que vous souhaitiez être explicite sur votre positionnement. Exemple :

[popover] {
  top: 50%;
  left: 50%;
  translate: -50%;
}

Si vous souhaitez disposer le contenu dans votre pop-over à l'aide d'une grille CSS ou d'une Flexbox, il peut être judicieux de l'encapsuler dans un élément. Sinon, vous devez déclarer une règle distincte qui modifie display une fois que le pop-up se trouve dans la couche supérieure. Si vous le définissez par défaut, il s'affichera par défaut, ignorant display: none.

[popover]:open {
 display: flex;
}

Si vous avez essayé cette démo, vous remarquerez que le pop-up effectue une transition. Vous pouvez effectuer une transition entre les fenêtres contextuelles à l'aide du pseudo-sélecteur :open. Le pseudo-sélecteur :open correspond aux pop-overs qui s'affichent (et donc dans la couche supérieure).

Cet exemple utilise une propriété personnalisée pour effectuer la transition. Vous pouvez également appliquer une transition au ::backdrop du pop-up.

[popover] {
  --hide: 1;
  transition: transform 0.2s;
  transform: translateY(calc(var(--hide) * -100vh))
            scale(calc(1 - var(--hide)));
}

[popover]::backdrop {
  transition: opacity 0.2s;
  opacity: calc(1 - var(--hide, 1));
}


[popover]:open::backdrop  {
  --hide: 0;
}

Nous vous conseillons de regrouper les transitions et les animations sous une requête média pour le mouvement. Cela peut également vous aider à respecter votre timing. En effet, vous ne pouvez pas partager de valeurs entre popover et ::backdrop via une propriété personnalisée.

@media(prefers-reduced-motion: no-preference) {
  [popover] { transition: transform 0.2s; }
  [popover]::backdrop { transition: opacity 0.2s; }
}

Jusqu'à présent, vous avez vu l'utilisation de popovertoggletarget pour afficher un pop-up. Pour l'ignorer, nous allons utiliser l'option "Light Ignorer". Toutefois, vous pouvez également utiliser les attributs popovershowtarget et popoverhidetarget. Ajoutons un bouton à un pop-over qui le masque et modifions le bouton d'activation pour qu'il utilise popovershowtarget.

<div id="code-popover" popover>
  <button popoverhidetarget="code-popover">Hide Code</button>
</div>
<button popovershowtarget="code-popover">Reveal Code</button>

Comme indiqué précédemment, l'API Popover va bien au-delà de la notion historique de pop-up. Vous pouvez créer des applications pour tous les types de scénarios : notifications, menus, info-bulles, etc.

Certains de ces scénarios nécessitent des modèles d'interaction différents. Interactions (par exemple, lorsque l'utilisateur passe le curseur) L'utilisation d'un attribut popoverhovertarget a été testée, mais elle n'est pas encore implémentée.

<div popoverhovertarget="hover-popover">Hover for Code</div>

L'idée est de pointer sur un élément pour afficher la cible. Ce comportement peut être configuré via les propriétés CSS. Ces propriétés CSS définissent la fenêtre de temps nécessaire au survol d'un élément auquel un pop-up réagit. Le comportement par défaut testé affichait un pop-up après un 0.5s explicite de :hover. Ensuite, il faudrait fermer légèrement la fenêtre ou ouvrir une autre fenêtre contextuelle pour la fermer (plus d'informations à ce sujet prochainement). Cela est dû au fait que la durée de masquage du pop-up a été définie sur Infinity.

En attendant, vous pouvez utiliser JavaScript pour émuler cette fonctionnalité.

let hoverTimer;
const HOVER_TRIGGERS = document.querySelectorAll("[popoverhovertarget]");
const tearDown = () => {
  if (hoverTimer) clearTimeout(hoverTimer);
};
HOVER_TRIGGERS.forEach((trigger) => {
  const popover = document.querySelector(
    `#${trigger.getAttribute("popoverhovertarget")}`
  );
  trigger.addEventListener("pointerenter", () => {
    hoverTimer = setTimeout(() => {
      if (!popover.matches(":open")) popover.showPopOver();
    }, 500);
    trigger.addEventListener("pointerleave", tearDown);
  });
});

Définir une fenêtre de survol explicite présente l'avantage de garantir que l'action de l'utilisateur est intentionnelle (par exemple, un utilisateur passe son pointeur sur une cible). Nous ne voulons pas afficher le pop-up, sauf si c'est volontaire.

Essayez cette démonstration en passant la souris sur la cible avec la fenêtre définie sur 0.5s.


Avant d'examiner des cas d'utilisation courants et des exemples, examinons plusieurs choses.


Types de pop-over

Nous avons abordé le comportement des interactions non-JavaScript. Mais qu'en est-il du comportement des fenêtres pop-over dans son ensemble ? Que faire si vous ne voulez pas que l'option "Ignorer la lumière" soit activée ? Ou voulez-vous appliquer un modèle Singleton à vos pop-overs ?

L'API Popover vous permet de spécifier trois types de pop-up dont le comportement est différent.

[popover=auto]/[popover]:

  • Prise en charge de l'imbrication. Cela ne signifie pas seulement que les éléments sont imbriqués dans le DOM. La définition d'un pop-over ancestral est un élément qui est :
    • liés par la position DOM (enfant).
    • en déclenchant des attributs sur des éléments enfants tels que popovertoggletarget, popovershowtarget, etc.
    • associée par l'attribut anchor (API CSS Anchoring en cours de développement).
  • Lumière ignorée.
  • L'ouverture permet de fermer les autres fenêtres pop-up qui ne sont pas des fenêtres pop-over ancestrales. Jouez avec la démonstration ci-dessous qui montre le fonctionnement de l'imbrication avec les pop-overs ancêtres. Découvrez en quoi le fait de remplacer certaines instances popoverhidetarget/popovershowtarget par popovertoggletarget change la donne.
  • Si l'un d'eux est ignoré, l'application Light ignore toutes les autres. En revanche, si l'utilisateur en ignore une dans la pile, seules celles qui se trouvent au-dessus dans la pile sont ignorées.

[popover=manual]:

  • Ne ferme pas les autres fenêtres pop-up.
  • Voyant éteint.
  • Nécessite une fermeture explicite via un élément déclencheur ou JavaScript.

API JavaScript

Si vous avez besoin de mieux contrôler les pop-overs, vous pouvez utiliser JavaScript. Vous obtenez à la fois une méthode showPopover et une méthode hidePopover. Vous avez également des événements popovershow et popoverhide à écouter:

Afficher un pop-up js popoverElement.showPopover() Masquer un pop-up:

popoverElement.hidePopover()

Attendez qu'un pop-over s'affiche:

popoverElement.addEventListener('popovershow', doSomethingWhenPopoverShows)

Attendez qu'un pop-over s'affiche et annulez l'affichage:

popoverElement.addEventListener('popovershow',event => {
  event.preventDefault();
  console.warn(‘We blocked a popover from being shown’);
})

Attendez qu'un pop-over soit masqué:

popoverElement.addEventListener('popoverhide', doSomethingWhenPopoverHides)

Vous ne pouvez pas annuler un pop-up masqué:

popoverElement.addEventListener('popoverhide',event => {
  event.preventDefault();
  console.warn("You aren't allowed to cancel the hiding of a popover");
})

Vérifiez si un pop-up se trouve dans la couche supérieure:

popoverElement.matches(':open')

Cela permet de bénéficier d'une puissance supplémentaire pour des scénarios moins courants. Par exemple, vous pouvez afficher un pop-up après une période d'inactivité.

Cette démonstration contient des pop-ups avec des pop-ups audibles. Nous avons donc besoin de JavaScript pour lire le contenu audio. Lors d'un clic, nous masquons le pop-up, l'audio est lu, puis nous l'affichons de nouveau.

Accessibilité

L'accessibilité est au premier plan de la réflexion avec l'API Popover. Les mappages d'accessibilité associent le pop-over à son élément déclencheur, si nécessaire. Cela signifie que vous n'avez pas besoin de déclarer les attributs aria-* tels que aria-haspopup, si vous utilisez l'un des attributs de déclenchement tels que popovertoggletarget.

Pour gérer la mise au point, vous pouvez utiliser l'attribut "autofocus" afin de sélectionner un élément dans un pop-up. C'est la même chose que pour une boîte de dialogue, mais la différence se produit lors du retour de la mise au point, en raison d'un léger abandon. Dans la plupart des cas, la fermeture d'un pop-up rétablit l'élément précédemment sélectionné. Toutefois, le curseur est placé sur un élément sur lequel l'utilisateur a cliqué lorsqu'il est fermé pour une occasion légère, s'il peut le faire. Consultez la section sur la gestion des sélections dans la vidéo explicative.

Vous devez ouvrir cette version de démonstration en plein écran pour qu'elle fonctionne.

Dans cette démonstration, l'élément ciblé prend un contour vert. Essayez de naviguer avec la touche de tabulation dans l'interface avec le clavier. Notez où le curseur est renvoyé à la fermeture d'un pop-up. Vous remarquerez peut-être également que si vous avez sélectionné la touche de tabulation, le pop-over s'est fermé. C'est ce qui se passe grâce à la conception. Bien que les fenêtres pop-up permettent de gérer le focus, ils ne pimentent pas l'attention. De plus, la navigation au clavier identifie un signal de fermeture lorsque le curseur sort du pop-up.

Ancrage (en cours de développement)

Lorsqu'il s'agit de fenêtres pop-up, il est difficile de s'adapter à l'ancrage de l'élément sur son déclencheur. Par exemple, si une info-bulle est configurée pour s'afficher au-dessus de son déclencheur, mais que le document fait l'objet d'un défilement. Cette info-bulle risque d'être tronquée par la fenêtre d'affichage. Il existe actuellement des solutions JavaScript pour gérer ce problème, comme l'UI flottante. Ils repositionneront l'info-bulle pour que vous puissiez empêcher cela et se baser sur l'ordre de positionnement souhaité.

Mais nous voulons que vous puissiez définir cela avec vos styles. Une API associée est en cours de développement en plus de l'API Popover pour résoudre ce problème. L'API CSS Anchor Positioning (Positionnement de l'ancrage CSS) vous permet de partager la connexion d'éléments avec d'autres éléments, en repositionnant ces éléments afin qu'ils ne soient pas tronqués par la fenêtre d'affichage.

Cette démonstration utilise l'API d'ancrage dans son état actuel. La position du bateau dépend de celle de l'ancre dans la fenêtre d'affichage.

Voici un extrait du code CSS utilisé pour cette démonstration. JavaScript n'est pas nécessaire.

.anchor {
  --anchor-name: --anchor;
}
.anchored {
  position: absolute;
  position-fallback: --compass;
}
@position-fallback --compass {
  @try {
    bottom: anchor(--anchor top);
    left: anchor(--anchor right);
  }
  @try {
    top: anchor(--anchor bottom);
    left: anchor(--anchor right);
  }
}

Consultez les spécifications ici. Il y aura également un polyfill pour cette API.

Exemples

Maintenant que vous connaissez les avantages de Popover et comment, penchons-nous sur quelques exemples.

Notifications

Cette démonstration affiche une notification "Copier dans le presse-papiers".

  • Fuseau horaire : [popover=manual].
  • Pop-over showPopover affiché en cas d'action
  • Après un délai avant expiration de 2000ms, masquez-le avec hidePopover.

Toasts

Cette démonstration utilise la couche supérieure pour afficher des notifications de type toast.

  • Un pop-up de type manual fait office de conteneur.
  • Les nouvelles notifications sont ajoutées au pop-up, qui s'affiche.
  • Elles sont supprimées du DOM via l'API Web Animations lors d'un clic.
  • S'il n'y a pas de toasts à afficher, le pop-over est masqué.

Menu imbriqué

Cette démonstration montre le fonctionnement d'un menu de navigation imbriqué.

  • Utilisez [popover=auto], car il autorise les pop-overs imbriqués.
  • Utilisez autofocus sur le premier lien de chaque liste déroulante pour naviguer au clavier.
  • C'est un candidat idéal pour l'API CSS Anchoring. Toutefois, pour cette démonstration, vous pouvez utiliser un peu de JavaScript pour mettre à jour les positions à l'aide de propriétés personnalisées.
const ANCHOR = (anchor, anchored) => () => {
  const { top, bottom, left, right } = anchor.getBoundingClientRect();
  anchored.style.setProperty("--top", top);
  anchored.style.setProperty("--right", right);
  anchored.style.setProperty("--bottom", bottom);
  anchored.style.setProperty("--left", left);
};

PRODUCTS_MENU.addEventListener("popovershow", ANCHOR(PRODUCT_TARGET, PRODUCTS_MENU));

N'oubliez pas que cette version de démonstration utilise autofocus. Vous devez donc l'ouvrir en plein écran pour que vous puissiez naviguer au clavier.

Fenêtre pop-up multimédia

Cette démonstration vous montre comment faire apparaître des contenus multimédias.

  • Utilise [popover=auto] pour ignorer légèrement.
  • JavaScript écoute l'événement play de la vidéo et la fait apparaître.
  • L'événement popoverhide dans les pop-ups met la vidéo en pause.

Pop-overs de style wiki

Cette démonstration montre comment créer des info-bulles de contenu intégré contenant des contenus multimédias.

  • Fuseau horaire : [popover=auto]. En montrer l'un masque les autres parce qu'ils ne sont pas ancêtres.
  • Affiché sur pointerenter avec JavaScript.
  • Un autre candidat idéal pour l'API CSS Anchoring.

Cette démonstration crée un panneau de navigation à l'aide d'un pop-up.

  • Utilise [popover=auto] pour ignorer légèrement.
  • Utilise autofocus pour sélectionner le premier élément de navigation.

Gérer les arrière-plans

Cette démonstration vous montre comment gérer les arrière-plans pour plusieurs pop-overs dans lesquels vous ne souhaitez qu'un seul ::backdrop visible.

  • Utilisez JavaScript pour gérer la liste des fenêtres pop-up visibles.
  • Appliquez un nom de classe dans le pop-up inférieur de la couche supérieure.

Pop-over personnalisé du curseur

Cette démonstration montre comment utiliser popover pour promouvoir un canvas sur la couche supérieure et l'utiliser pour afficher un curseur personnalisé.

  • Passage de canvas au niveau de la couche supérieure avec showPopover et [popover=manual].
  • Lorsque d'autres pop-ups sont ouverts, masquez et affichez le pop-up canvas pour vous assurer qu'il se trouve en haut.

Pop-over de la feuille d'action

Cette démonstration montre comment utiliser un pop-up comme feuille d'action.

  • Afficher le pop-over par défaut, remplaçant display.
  • La feuille d'action est ouverte avec le déclencheur de pop-over.
  • Lorsque le pop-over s'affiche, il est placé dans la couche supérieure et traduit en vue.
  • Vous pouvez utiliser Light Dismiss pour le renvoyer.

Fenêtre pop-up d'activation du clavier

Cette démonstration montre comment utiliser le pop-over pour l'interface utilisateur de style palette de commandes.

  • Appuyez sur Cmd+J pour afficher la fenêtre pop-up.
  • Le input est sélectionné avec autofocus.
  • La boîte combinée est un deuxième popover placé sous l'entrée principale.
  • Si le menu déroulant n'est pas présent, la palette se ferme.
  • Un autre candidat pour l'API Anchoring

Pop-over temporisé

Cette démonstration montre un pop-up d'inactivité après quatre secondes. Modèle d'UI souvent utilisé dans les applications qui contiennent des informations sécurisées sur un utilisateur pour afficher une fenêtre modale de déconnexion.

  • Utilisez JavaScript pour afficher le pop-up après une période d'inactivité.
  • Lors du pop-up, réinitialisez le minuteur.

Éco. d'écran

Comme pour la démo précédente, vous pouvez ajouter une touche de fantaisie à votre site et ajouter un économiseur d'écran.

  • Utilisez JavaScript pour afficher le pop-up après une période d'inactivité.
  • Fermer le voyant pour masquer et réinitialiser le minuteur.

Suivi du signe d'insertion

Cette démonstration montre comment faire suivre un caret d'entrée dans un pop-up.

  • Afficher le pop-over en fonction de la sélection, de l'événement de touche ou de la saisie de caractères spéciaux
  • Utilisez JavaScript pour mettre à jour la position du pop-up avec des propriétés personnalisées de portée.
  • Cette approche nécessite une réflexion approfondie concernant le contenu montré et l'accessibilité.
  • On le retrouve souvent dans l'UI d'édition de texte et dans les applications où vous pouvez ajouter des tags.

Menu du bouton d'action flottant

Cette démonstration montre comment utiliser le pop-over pour implémenter un menu de boutons d'action flottants sans JavaScript.

  • Promouvez un pop-up de type manual avec la méthode showPopover. Il s'agit du bouton principal.
  • Le menu est un autre pop-over qui est la cible du bouton principal.
  • Le menu est ouvert avec popovertoggletarget.
  • Appuyez sur autofocus pour sélectionner le premier élément de menu affiché.
  • L'option Light Ignorer ferme le menu.
  • La rotation de l'icône utilise :has(). Pour en savoir plus sur :has(), consultez cet article.

Et voilà !

Il s'agit donc d'une introduction au pop-over, que nous présenterons plus tard dans le cadre de l'initiative "Open UI". Utilisé de façon judicieuse, il s'agira d'un complément fantastique à la plate-forme Web.

N'oubliez pas de consulter la section Ouvrir l'interface utilisateur. L'explication contextuelle est mise à jour à mesure que l'API évolue. Voici la collection où se trouvent toutes les démonstrations.

Merci de nous avoir contactés !


Photo par Madison Oren, publiée sur Unsplash