Alsacreations.com - Apprendre - Archives (février 2024)

Les dernières ressources publiées sur Alsacreations.com

Le: 09 02 2024 à 09:00 Auteur: Raphael

L'arrivée de l'attribut et de l'API HTML popover facilite la gestion de tous les éléments qui doivent s'afficher au-dessus du contenu d'une page Web (fenêtre modale, tooltip, menu déroulant, etc.).

Cette nouvelle fonctionnalité vient s'ajouter à certaines déjà existantes, au point où l'on ne sait plus forcément où donner de la tête entre les éléments dits "Dialog", "Modal", "Popover" ou autres "Overlay".

Tentons de rassembler toutes les caractéristiques globales et techniques de l'ensemble de ces notions afin d'y voir plus clair.

Cet article a pour objectif de poser les bases et de définir les différents termes en jeu. Dans un deuxième temps un article détaillé sera consacré à <dialog> et un autre à popover.

Tableau récapitulatif

Pour bien se rendre compte du nombre de fonctionnalités qui intéragissent, voici d'emblée un tableau récapitulatif des éléments que nous allons couvrir…

popover <dialog>
(modal)
<dialog>
(non modal)
<div role=dialog>
Overlay oui oui oui oui
Modal non oui non non
Inert non oui non non
Top layer oui oui non non
Focus trap non oui oui non
Dismissible echap ou manuel echap echap non
Commentaires Exclusif : ouvrir un popover ferme le précédent Masqué par défaut, visible avec l'attribut open Masqué par défaut, visible avec l'attribut open

Les différentes notions de ce tableau sont détaillées tout au long de cet article de synthèse : popover, <dialog>, overlay, modal, inert, top layer, focus trap, dismissible.

Overlay

Le terme "overlay" ne représente pas véritablement un composant mais une caractéristique. Un élément "overlay" est simplement un élément qui se place au-dessus d'autres éléments dans la page.

Tous les éléments au sein de cette liste sont des overlays :

  • une "fenêtre modale",
  • un menu déroulant,
  • une Tooltip,
  • une boîte de dialogue,
  • un Datepicker,
  • un Dropdown,
  • un Toaster,
  • une notification,
  • un bandeau cookie,
  • etc.

Dans cette même famille nous croiserons les termes de "pop-up" (nouvelle fenêtre au-dessus de la fenêtre actuelle du navigateur) et "pop-in" (élément au-dessus des autres éléments de la page, synonyme de "overlay", donc).

Modal et non-Modal

Selon les spécifications HTML, le terme "modal" ne désigne pas un composant en tant que tel, mais un ensemble de caractéristiques : un élément en overlay peut être "modal" ou "non-modal".

Un élément Modal est le seul à être interactif dans un document, il requiert toute l'attention de l'usager, tout le reste de la page doit être rendu inerte (inert) car aucune autre action ne doit être possible mis à part réagir à cet élément (fermer, accepter, refuser, abandonner, etc.).

Par exemple, un bandeau de recueil de données personnelles doit être consenti par l'utilisateur (obligation légale RGPD) sans quoi il ne devrait pas pouvoir accéder au site. C'est donc un élément de type Modal. Un autre exemple pourrait être celui d'une une modale "login/password" si l'accès au site nécessite une authentification.

Un élément non-Modal, à l'inverse, laisse la possibilité à l'utilisateur de continuer à interagir avec la page. C'est génaralement de cas des éléments tooltip, menu déroulant, dropdown, datepicker, notification, alerte, bandeau cookie.

inert

Un contenu inerte est un contenu avec lequel les utilisatrices et utilisateurs ne peuvent pas interagir. Il n'existe que visuellement, mais ne peut être atteint, cliqué, défilé ni consulté au moyen de technologies d'assistance.

Différentes techniques permettent de rendre une partie de page inerte :

  • L'attribut HTML inert,
  • L'ancienne technique via la combinaison de aria-hidden=true et de tabindex="-1",
  • Un polyfill JavaScript : https://github.com/WICG/inert,
  • L'élément <dialog> (voir cette section pour les détails).

compatibilité de l'attribut inert

Top layer

Top layer est une couche d'empilement au dessus de l'ensemble du document (existe depuis juin 2023). Cette couche n'est pas concernée par z-index ni par overflow: hidden. Les éléments s'empilent dans l'ordre d'apparition dans le Top layer.

Certains éléments sont placés automatiquement par défaut dans le top layer :

  • les éléments en fullscreen API
  • les éléments <dialog> (sauf exceptions)
  • les éléments avec l'attribut popover (sauf exceptions)

::backdrop

Ce pseudo-élement s'applique uniquement aux objets placés dans le top layer. Il permet d'apporter des styles visuels "sous" un overlay en obscurcissant la page par exemple.

/* Cette ombre n'est affichée que si l'élément */
/* est dans le Top layer */
dialog::backdrop {
  background: rgba(0,0,0,0.3);
}

compatibilité du sélecteur ::backdrop

Focus trap

Certains élément nécessitent que la navigation au clavier (touches Tab ou Shift + Tab) ne quitte pas le périmètre du composant : en atteignant le dernier élément focusable, on retourne en boucle au premier élément focusable au sein du composant.

C'est le comportement attendu et souhaité en accessibilité lorsque le composant est "modal" et que tout le reste du document est inerte.

Le focus trap doit toutefois être temporaire et disparaître quand le composant est quitté ou rejeté (dismissed).

Dismissible (jetable)

Certains overlay nécessitent de pouvoir être fermés de manière automatique (via touche echap ou au focus à l'extérieur du composant) et/ou de façon manuelle (en validant un bouton de soumission par exemple). Ce comportement se nomme "Dismissible".

Le menu déroulant sur Alsacréations

Dialog

Un Dialog est un composant de type overlay destiné à apporter une information à un usager et recueillir une interaction de sa part. Les spécifications proposent une API HTMLDialogElement ainsi qu'un élément natif <dialog> qui peut être "Modal" ou "non-Modal".

Le déclenchement se fait via l'API JavaScript :

  • show(): Ouvre le dialog en non-Modal
  • showModal(): Ouvre le dialog en Modal
  • close(): Ferme le dialog et renvoie en option une valeur

Voici un exemple concret :

<dialog id="modale">
  <p>Une modale de type Modal</p>
</dialog>
const modal = document.querySelector("#modale");
modal.showModal();

Les particularités de l'élément <dialog> sont :

  • role=dialog par défaut
  • Masqué par défaut, visible avec l'attribut open
  • Nécessite un nom accessible (aria-label ou aria-labelledby)
  • Focus trap : activé par défaut
  • Jetable (dismiss) via touche echap

Selon son état (Modal ou non-Modal), d'autres caractéristiques s'ajoutent à la liste précédente.

  • Si le <dialog> est "Modal" :

    • Il est placé dans le Top layer,
    • ::backdrop est applicable,
    • Tout le reste du document est rendu automatiquement inert.
  • Si le <dialog> est "non-Modal" :

    • Il n'est pas placé dans le Top layer (donc les règles de stacking context et de z-index s'appliquent),
    • ::backdrop ne s'applique pas,
    • Tout le reste du document est interactif.

Les spécifications d'accessibilité ARIA proposent un attribut role="dialog" pouvant être appliqué sur n'importe quel élément HTML autre que <dialog>, mais sachez que cela implique par défaut :

  • Que l'élement est "non-Modal" (peut le devenir avec aria-modal="true"),
  • Qu'il n'est pas dans le Top layer,
  • Qu'il ne rend pas le reste de page inerte,
  • Qu'il ne crée pas de Focus trap,
  • Qu'il n'est pas Jetable (dismiss) via touche echap.

En outre, sans API JavaScript showModal(), l'élément <dialog> est non-Modal :

<dialog id="dialog" open>
  <p>je suis non-modal</p>
</dialog>

compatibilité de l'élément dialog

:modal

La pseudo-classe :modal s'applique à tous les éléments à l'état Modal (par exemple un <dialog> ouvert avec l'API showModal()).

#modale:modal {
  background: hotpink;
}

compatibilité du sélecteur :modal

popover

Un popover est un overlay composé d'un attribut popover associé à un déclencheur :

<button popovertarget="tooltip">Ouvrir la tooltip</button>
<div popover id="tooltip">Choucroute et Saucisses de Strasbourg&nbsp;!</div>

Les particularités d'un élément pourvu d'un attribut popover sont :

  • L'élément est "non-Modal",
  • Il est placé dans le Top layer,
  • ::backdrop est applicable,
  • Aucun role spécifique ne lui est affecté. Le choix dépend du type de composant (role="alert" par exemple),
  • Jetable (dismiss) via touche echap par défaut,
  • Exclusif : il peut y en avoir plusieurs dans la page mais un seul dans l'état déployé à la fois.

Le comportement dismissible (jetable) dépend de la valeur associée à l'attribut popover :

  • light dismiss (<div popover=auto>, valeur par défaut si omise) : c'est le comportement idéal pour tooltip, menu déroulant, dropdown, datepicker,
  • manual dismiss (<div popover=manual>) : parfait pour des notifications ou des alertes.

compatibilité de l'attribut popover

:popover-open

La pseudo-classe CSS :popover-open représente un élément popover (c'est-à-dire un élément avec un attribut popover) qui est dans l'état ouvert.

:popover-open {
  /*...*/
}

compatibilité du sélecteur :popover-open

OK alors quand est-ce qu'on utilise quoi ?

Le nombre de possibilités offertes par les spécifications ne facilite pas le choix lorsqu'il s'agit d'intégrer un composant qui doit se placer au-dessus d'un contenu.

Entre les modales, les menus déroulants, les boîtes de dialogues et autres bandeaux d'alerte, il n'est guère aisé de piocher parmi <dialog>, popover ou une simple <div> en position abolute dopée avec JavaScript.

Les réponses aux deux questions suivantes sont déterminantes dans votre choix final :

  • L'utilisateur a-t-il le droit d'ignorer ce composant ?
    (si non, alors il s'agit sans aucun doute d'un élément "Modal" car tout le reste de la page doit devenir inert)
  • Le visuel attendu est-il une "modale" avec backdrop obscurci ?
    (si oui, là aussi nous aurons recours à un élément de type "Modal")

J'espère avoir éclairci la plupart des points d'ombres (même s'il en demeure sans doute) de ce vaste sujet des différents overlays. Pour finir, voici quelques articles de référence absolument indispensables pour en savoir plus.

Ressources

Publié par Alsacreations.com

Le: 01 02 2024 à 09:00 Auteur: Rodolphe

Les images SVG sont désormais omniprésentes sur le web : illustrations, schémas, décoration, icônes, ce format vectoriel se prête bien à toutes sortes de formes simples car il est léger et étirable à l'infini produisant un beau résultat sur les écrans à forte densité de pixel (hdpi, retina...).

Si l'on peut en produire "à la main" à l'aide d'un éditeur de code, car il s'agit avant tout de XML, les images SVG sont souvent générées par des programmes de dessin/webdesign tels que Figma, Illustrator, Inkscape et divers. Ces programmes ne vont pas nécessairement réduire au maximum le poids de l'image, même si cela tend à s'améliorer. Ils n'hésiteront pas à ajouter des métadonnées inutiles ou des instructions de code superflues, provenant de la façon dont a été élaborée l'image (calques, précision des formes et des tracés).

Ainsi Figma proposera une petite fonctionnalité d'export bien pratique et rapide pour copier une forme ou un groupe en tant que code SVG. Celui-ci pourra être inclus de manière inline au code HTML.

Figma : copier en tant que SVG

La performance étant cruciale, et scrutée par les outils d'analyse, les robots d'indexation, il est courant de devoir faire attention non seulement au poids des images bitmap (jpeg, png, webp, avif) mais aussi à SVG, avec d'autres techniques compte tenu de sa spécificité vectorielle.

Optimisons

S'il y a quelques années, il fallait se pencher manuellement sur l'optimisation du code SVG, désormais bon nombre d'outils remplissent 99% des objectifs. La plupart étant listés par CSS Tricks : Tools for Optimizing SVG.

🤖 Pour un traitement automatisé, on pourra prévoir dans un workflow de pojet web d'intégrer svgo durant un processus de compilation ou simplement en ligne de commande. En voici un exemple via Nodejs mais cette bibliothèque se retrouve dans d'autres situations (extension Sketch, Visual Studio Code, SublimeText, Atom... plugin postCSS, Gulp, Webpack, etc.).

pnpm add -g svgo
# Des images sélectionnées
svgo image1.svg image2.svg -o image1.min.svg image2.min.svg
# Tout un dossier (récursif)
svgo -f images/svg/icons/src -o images/svg/icons/dist

🎨 Pour un export depuis Figma, on passe par une extension de la communauté Advanced SVG Export qui embarque l'algorithme de SVGO et dont les paramètres sont configurables.

Extension export SVG pour Figma

👉 Pour un traitement image par image quelle que soit la source, utilisons le fameux SVGOMG, version humainement graphique de SVGO, qui acceptera soit un fichier soit un copier-coller direct (encore plus pratique), puis affichera l'aperçu et la possibilité de ré-exporter ou re-copier le code source amélioré.

SVGOMG en action

Si la plupart des options par défaut conviennent, détaillons celles qui rejoignent les principales techniques à retenir lorsqu'on intervient manuellement sur du SVG :

  • Baisser la précision : les coordonnées sont stockées dans un espace à 2 dimensions, vectoriel, et souvent avec une précision excessive. Inutile de manipuler et stocker des chiffres à 5 décimales si finalement à l'écran il s'agit de les arrondir au demi-pixel. Cette option produit de bons résultats sur des formes très complexes lorsque des chemins "longs" comprennent beaucoup de coordonnées et que l'on peut simplifier les courbes.

Exemple de chemin avec trop de précision :

<path d="M24 18.55C26.2 17.45 27.5 16.15 28 14.55C28.6 12.65 27.8 10.55 25.8 8.34996C24.1 6.34996 22.3 5.64996 20.5 6.14996C19 6.54996 17.6 7.84996 16.3 9.84996C15.2 11.55 14.3 13.65 13.7 15.75C13.1 17.85 13 19.35 13.3 20.25C14.2 20.55 15.6 20.55 17.8 20.25C20.1 20.15 22.2 19.55 24 18.55ZM12 9.44996C13.1 7.24996 13.4 5.44996 12.8 3.94996C12.1 2.04996 10.3 0.849963 7.40002 0.249963C4.90002 -0.350037 3.00002 0.149963 1.90002 1.64996C1.00002 2.84996 0.500025 4.64996 0.700025 7.14996C0.800025 9.24996 1.30002 11.35 2.20002 13.55C3.00002 15.55 3.70003 16.85 4.50003 17.45C5.40003 17.25 6.60003 16.25 8.10003 14.75C9.90003 12.95 11.1 11.25 12 9.44996ZM25.6 33.75C28 34.15 29.8 33.85 31.1 32.85C32.6 31.65 33.2 29.55 32.9 26.55C32.7 23.95 31.6 22.45 29.9 21.75C28.4 21.25 26.6 21.45 24.3 22.35C22.4 23.15 20.5 24.25 18.8 25.65C17.1 27.05 16.1 28.15 15.9 29.15C16.5 29.85 17.6 30.75 19.5 31.75C21.6 32.85 23.6 33.55 25.6 33.75Z" fill="#ACC737"/>

Le voici optimisé avec moins de précision sur les coordonnées, et un résultat visuel semblable :

<path d="M24 18.6c2.2-1.2 3.5-2.5 4-4 .6-2-.2-4-2.2-6.3-1.7-2-3.5-2.7-5.3-2.2-1.5.4-2.9 1.7-4.2 3.7-1.1 1.8-2 3.8-2.6 6-.6 2-.7 3.6-.4 4.4.9.4 2.3.4 4.5 0a14 14 0 0 0 6.2-1.6ZM12 9.4c1.1-2.2 1.4-4 .8-5.5C12.1 2 10.3 1 7.4.2 4.9-.4 3 .2 1.9 1.6 1 2.8.5 4.6.7 7.1c.1 2.1.6 4.3 1.5 6.5.8 2 1.5 3.3 2.3 3.8.9-.1 2.1-1.1 3.6-2.6A20 20 0 0 0 12 9.3Zm13.6 24.4c2.4.4 4.2 0 5.5-1 1.5-1.1 2.1-3.2 1.8-6.2-.2-2.7-1.3-4.2-3-4.9-1.5-.4-3.3-.3-5.6.7-1.9.8-3.8 1.9-5.5 3.3-1.7 1.4-2.7 2.4-2.9 3.4.6.8 1.7 1.6 3.6 2.6 2.1 1.2 4.1 1.8 6.1 2Z" fill="#ACC737"/>
  • Supprimer les informations inutiles : commentaires <!-- --> dans le code source, métadonnées de l'éditeur d'image qui aime y laisser sa trace, et même éléments cachés (hidden) : tout ce qui ne se "voit" de toute façon pas en production, et ignoré par le navigateur.
  • Supprimer les informations XML : à l'origine SVG a été construit sur XML qui induit des contraintes : un doctype, des namespaces le cas échéant... si ces éléments sont absents les navigateurs s'en accomodent. Par exemple l'attribut xmlns n'est pas nécessaire si le code SVG est inline dans le code HTML.
  • Fusionner les informations, minifier les couleurs : notamment de style, les classes et valeurs ne sont pas toujours générées intelligemment, il s'agit alors de mutualiser les styles communs plutôt que de se reposer uniquement sur des attributs style="" (ex : 2 carrés verts auront les mêmes propriétés) pour gagner de la place. En revanche l'option merge paths peut empêcher de conserver tous les tracés individuels pour agir sur chacun : cela dépendra beaucoup des règles externes CSS et du code JavaScript qui pourrait interagir avec le SVG attendu. Si vous écrivez des propriétés de style qui doivent s'appliquer sur un élément en particulier, nommé par une classe, et que cette classe est retirée, cela n'aura plus d'effet.
  • Supprimer les éléments ou attributs SVG en excès : en plus du code inutile lorsqu'il s'agit d'éléments ou attributs vides, on constate souvent une imbrication de groupes (balise <g>) qui ne sont pas nécessaires au-delà de l'édition, il faut juste faire attention à préserver l'ordre de superposition des formes.
  • Appliquer les transformations : les coordonnées initiales d'une forme peuvent être complétées, modifiées et transformées à la volée par des propriétés d'échelle, de déplacement, de rotation, autant les appliquer directement dans le fichier sur ces mêmes coordonnées.
  • Remplacer des balises par d'autres : toute forme simple (cercle, carré, rectangle) existe en tant que balise SVG mais peut aussi être décrite par un chemin générique <path> avec des coordonnées minimales.
  • Minifier le code et/ou le remettre en forme (Prettify) : supprimer les espaces inutiles, joindre les lignes, ou les réindenter correctement, c'est toujours un compromis entre lisibilité humaine et gain de quelques octets côté réseau.

Si vous examinez toutes les options listées par SVGOMG, vous imaginerez aisément tout ce qui peut être entrepris pour alléger une image SVG. Pour constater les effets avant/après sur le code source, consultez l'onglet Markup et activez/désactivez l'option Show original.

Une opération toutefois devra nécessiter une vérification et intervention manuelle : si votre SVG contient des images bitmap (non vectorielles), ce qui est tout à fait possible pour des effets non reproductibles en vectoriel (cela se remarquera à son poids global lourd et à la présence de code en base64) alors il faudra étudier la possibilité de les remplacer par de vraies formes simplifiées.

TL;DR ?

Utilisez SVGOMG.

Publié par Alsacreations.com