Le 17 octobre dernier, j’animais au devFest Nantes un atelier intitulé « L’Invasion du HTML mutant ».
Un atelier devant par définition impliquer les participants, j’ai fait le choix de créer un mini-jeu en guise de support. C’est un site statique disponible en ligne, open-sourcé sur GitHub — pour que vous puissiez l’améliorer !
Quand je dis statique, c’est statique : le dépôt a une unique dépendance, servor, chargée de fournir un serveur HTTP basique pour travailler en local et servor n’a elle-même aucune dépendance. Le reste n’est que HTML, CSS et JavaScript.
Ça m’a permis de revenir aux fondamentaux, considérablement gagner en efficience ; mais surtout… découvrir tout un tas de trucs et astuces !
En démarrant le jeu, vous commencerez par personnaliser votre personnage. Le seul objectif de cette étape est de découvrir la structure visuelle d’un niveau, en vous permettant de vous impliquer personnellement dans le jeu. Les valeurs choisies seront appliquées dès que possible à tous les personnages du jeu, dans une sorte de représentation en miroir.
Après avoir choisi votre personnage, un niveau d’entraînement vous familiarise avec la mécanique très simple du jeu : une portion de code à compléter et soumettre, exécutée en direct, qui affecte la zone envahie progressivement par des mutants ! Ce code est dans la plupart des niveaux les options passées à un mutationObserver, mais parfois aussi dans la fonction de rappel.
En cas d’échec comme en cas de réussite, une fenêtre modale vous informera. Parlons-en, de cette fenêtre modale !
J’en parlais en 2022 à Paris Web puis au devFest Nantes dans mon sujet « Découvrez " le bon HTML " et économisez du JS et du CSS », l’élément
Dans l’atelier, je m’en sers en plusieurs endroits :
La plupart sont ouvertes programmatiquement, en réaction à un événement. Rien de plus simple : il suffit de récupérer une référence à l’élément
document.querySelector('dialog').showModal();
Une exception toutefois, pour éviter d’ajouter un écouteur d’événement inutile : la fenêtre des règles du jeu est invoquée grâce à un gestionnaire d’événement HTML onclick :
<button type="button" onclick="rules.showModal()">Règles du jeu</button> <dialog> <h5> Aparté : la projection des identifiants HTML en objets globaux </h5> <p>Dans cet exemple, j’invoque l’ouverture de la fenêtre modale avec rules.showModal(), sans avoir défini la variable rules. Comment est-ce possible ? En résumé, tout élément porteur d’un attribut id devient mécaniquement une propriété globale de l’objet window, et devient donc accessible directement par son nom. C’est spécifié sous le joli nom de Named Access on Window Object (en anglais).</p> <p>C’est drôlement pratique, non ? Figurez-vous que c’est aussi un vecteur d’attaque méconnu faisant partie d’un groupe sobrement intitulé DOM clobbering (en anglais). Je vous encourage à parcourir les recommandations de l’OWASP pour mitiger le DOM clobbering (en anglais).</p> <h4> Accessibilité </h4> <p>La méthode showModal() permet d’ouvrir une fenêtre modale, pas une simple boîte de dialogue — en respectant les exigences en matière d’accessibilité : la focus est mécaniquement piégé dedans, la fermeture est possible avec la touche <kbd>Échap</kbd>, etc.</p> <h3> L’arrière-plan </h3> <p>Une fois la fenêtre modale ouverte, on peut s’appliquer à la styler. Là où moult bibliothèques de composants imposent une <div> (voire plusieurs) pour servir d’arrière-plan à la fenêtre, la version native est livrée avec un pseudo-élément ::backdrop qui s’étend naturellement sur tout le viewport et est promue, avec la fenêtre modale, par-dessus le reste de la page dans ce qui est spécifié sous le nom de top layer. <p>Vous n’avez plus qu’à lui appliquer une couleur, une opacité ou que sais-je encore. Dans le jeu, j’ai utilisé une propriété au nom évocateur de backdrop-filter pour appliquer un effet de flou grisé sur l’arrière-plan.<br> </p> <pre class="brush:php;toolbar:false">dialog::backdrop { backdrop-filter: grayscale(50%) blur(.25rem); }
Ne maîtrisant pas le mode de consultation du jeu, j’ai utilisé un peu de CSS moderne pour la largeur de la fenêtre modale afin qu’elle ait une largeur fluide, mais avec des valeurs minimum et maximum.
dialog { max-inline-size: clamp(50vw, 100%, 67.5rem); }
La propriété max-inline-size est la propriété logique correspondant à max-width dans le cas du Français. Et la fonction clamp() est un petit bijou, dont j’abuse déjà copieusement dans chaarts (en anglais) pour obtenir un pseudo-booléen en CSS en fonction d’une valeur, comme expliqué slide 27 de ma conférence « Dessine-moi un graphique (en CSS) » donnée au devFest Nantes 2023, TNT #24 et DevQuest 2024.
J’ai évoqué la capacité de fermer la modale avec la touche Échap, mais l’élément
C’est pourquoi la valeur dialog est ajoutée à la method de soumission d’un formulaire. Elle ne correspond pas à une méthode HTTP comme get ou post, mais bien à un contexte HTML, et permet de fermer directement la fenêtre modale parente. L’utilisation est fort simple :
<form> <p>Et, pour revenir à du HTML à l’ancienne : saviez-vous qu’un bouton à l’autre bout du DOM peut soumettre un formulaire ? Il suffit de lui indiquer le formulaire à soumettre :<br> </p> <pre class="brush:php;toolbar:false"><button form="fermer">Fermer la fenêtre</button>
Et voilà : c’est un bouton de type submit qui soumettra le formulaire avec l’identifiant fermer, qui lui-même fermera la fenêtre de dialogue. C’est beau, non ? Et cet attribut date (au moins) de 2006, dans les spécifications W3C des Web Forms (en anglais) dont les premiers brouillons remontent à 2004..
Pour cet atelier, j’avais besoin de méchants envahisseurs, et de décors. Clairement pas le temps de faire des illustrations à la main, ni les moyens d’acheter des visuels. Une quête sur les internets m’a appris que le type de visuels que je cherchais se nomme les top down tileset, ces petits décors et personnages généralement en 8-bit avec une perspective écrasée.
À force de regarder des visuels en 8-bit, j’ai fini par faire le lien avec une vieille habitude dans mes supports de conférences : les émojis décoratifs en fin de titre. Bon sang, mais c’est bien sûr ! Des émojis !
Les émojis sont formidables. Ce sont des points Unicode, purement textuels, et extrêmement nombreux désormais avec des pelletées de nouveautés dans chaque version d’Unicode. Il y a même des variantes, composées en séquence !
Le meilleur exemple de séquence Unicode à mon avis sont les personnages : le neutre Personne ? peut devenir un homme ? ou une femme ? en y ajoutant le point unicode du genre masculin ♂️ ou féminin ♀️, séparé par une jointure de largeur zéro (zero-width joiner, ).
Pour obtenir un pompier ??, on ajoute simplement un camion de pompier ? à une personne ? ! N’est-ce pas génial, franchement ? Et on peut évidemment y ajouter le genre et le teint.
Ainsi le premier palier permet de personnaliser le genre et le teint du héros.
Le formulaire n’est composé que de deux groupes de bouton radio, chacun ayant une valeur correspondant au point Unicode concerné.
document.querySelector('dialog').showModal();
Et le tour est joué : les utilisateurs de Firefox ne chargeront rien, et les autres téléchargeront une typographie pour afficher la même chose que Firefox. Choisissez mieux votre navigateur, la prochaine fois !
Comme souvent quand je prépare un sujet, je me suis heurté à quelques limites des navigateurs. En l’occurrence, WebKit, le moteur de Safari et Epiphany, a des problèmes avec les variantes de teinte de la Twemoji-COLR. J’ai pu ouvrir un ticket sur leur Bugzilla (en anglais).
Dans la mécanique du jeu, des portions de code sont affichées (pour faire un « code à trous ») et du code est saisi des éléments et
Et pour lire et écrire du code, la coloration syntaxique est drôlement pratique et agréable ! Mais charger un script tel que PrismJS (en anglais) ou highlight.js (en anglais) m’a toujours semblé démesuré pour la valeur ajoutée. Le bloc de code se retrouve charcuté dans le DOM, où des avec des classes plus ou moins lisibles saucissonnent chaque portion de texte en fonction de son rôle syntaxique. C’est carrément indigeste.
Mais au moment où je préparais cet atelier, Heikki Lotvonen a publié un article ahurissant : Font with Built-In Syntax Highlighting (en anglais). C’est à mon sens, une petite révolution : une typographie tirant parti des fonctionnalités OpenType et notamment la table COLR. Fini les tartines de , place à un code lisible et propre !
Si les détails d’implémentation OpenType vous intéressent, je vous encourage à lire l’article. De mon côté, je me suis focalisé sur la personnalisation de la palette, rendues possibles en CSS avec @font-palette-values (sur MDN, en anglais) et la propriété override-colors (sur MDN, en anglais).
Voilà ce que ça donne pour le jeu, dans lequel je profite de l’utilisation de propriétés personnalisées CSS pour la gestion des couleurs :
document.querySelector('dialog').showModal();
Le rendu est pas mal, non ?
Et c’est de la pure amélioration progressive : si votre navigateur ne supporte pas la table COLR, la règle @font-palette-values ou la propriété override-colors, vous aurez juste du texte brut avec la monospace par défaut.
Le dernier point sur lequel je me suis beaucoup amusé, c’est le niveau des aliens. L’émoji alien monster ? ressemble beaucoup, beaucoup, beaucoup aux vaisseaux de Space Invaders. Pour un jeu d’invasion, ça tombe bien.
J’ai donc voulu assumer la référence : arrière-plan noir, animation des envahisseurs qui défilent vers le bas, et… un compteur de score.
Pour ceux qui font du CSS depuis longtemps, vous avez peut-être déjà entendu parler des compteurs CSS. Notre score correspondra simplement au nombre d’aliens présents.
Cependant, si notre compteur commence à 1 et peut monter jusqu’à 100 — et sachant que le jeu original disposait d’un compteur sur cinq chiffres — le rendu ne sera ni élégant ni une belle citation. Heureusement, CSS nous permet de personnaliser le style du compteur avec @counter-style.
Pour obtenir un compteur sur cinq chiffres, affichant des 0 avant la valeur du compteur, voici la déclaration utilisée :
document.querySelector('dialog').showModal();
Là aussi, WebKit est limité : les compteurs CSS ne sont pas incrémentés quand on ajoute des éléments au DOM. C’est Karl Dubost qui a ouvert ce ticket sur Bugzilla (en anglais).
Un autre point saillant pour citer visuellement Space Invaders, ce sont les couleurs vives. L’émoji utilisé vient avec une couleur qu’on ne peut pas surcharger, donc on va devoir l’altérer. Cette technique n’est pas récente, mais extrêmement utile : l’accumulation de filtres CSS pour atteindre la bonne couleur.
C’est un exercice compliqué, et je remercie Barrett Sonntag pour son générateur de filtres pour convertir du noir vers un code héxadécimal (sur CodePen, en anglais). La seule contrainte est de commencer par du noir ce qui se résout facilement en appliquant en premier grayscale(100%) brightness(0%).
<button type="button" onclick="rules.showModal()">Règles du jeu</button> <dialog> <h5> Aparté : la projection des identifiants HTML en objets globaux </h5> <p>Dans cet exemple, j’invoque l’ouverture de la fenêtre modale avec rules.showModal(), sans avoir défini la variable rules. Comment est-ce possible ? En résumé, tout élément porteur d’un attribut id devient mécaniquement une propriété globale de l’objet window, et devient donc accessible directement par son nom. C’est spécifié sous le joli nom de Named Access on Window Object (en anglais).</p> <p>C’est drôlement pratique, non ? Figurez-vous que c’est aussi un vecteur d’attaque méconnu faisant partie d’un groupe sobrement intitulé DOM clobbering (en anglais). Je vous encourage à parcourir les recommandations de l’OWASP pour mitiger le DOM clobbering (en anglais).</p> <h4> Accessibilité </h4> <p>La méthode showModal() permet d’ouvrir une fenêtre modale, pas une simple boîte de dialogue — en respectant les exigences en matière d’accessibilité : la focus est mécaniquement piégé dedans, la fermeture est possible avec la touche <kbd>Échap</kbd>, etc.</p> <h3> L’arrière-plan </h3> <p>Une fois la fenêtre modale ouverte, on peut s’appliquer à la styler. Là où moult bibliothèques de composants imposent une <div> (voire plusieurs) pour servir d’arrière-plan à la fenêtre, la version native est livrée avec un pseudo-élément ::backdrop qui s’étend naturellement sur tout le viewport et est promue, avec la fenêtre modale, par-dessus le reste de la page dans ce qui est spécifié sous le nom de top layer. <p>Vous n’avez plus qu’à lui appliquer une couleur, une opacité ou que sais-je encore. Dans le jeu, j’ai utilisé une propriété au nom évocateur de backdrop-filter pour appliquer un effet de flou grisé sur l’arrière-plan.<br> </p> <pre class="brush:php;toolbar:false">dialog::backdrop { backdrop-filter: grayscale(50%) blur(.25rem); }
C’est verbeux, mais ça fonctionne !
Et dire que je n’ai parlé que de HTML et CSS, pour le moment… Je ne m’étendrai pas autant, mais côté JavaScript, je me suis (un peu trop) amusé avec les Web Components. En résumé :
Dans tout ça, j’ai énormément joué avec les mutationObserver, les intervalles et les minuteurs, les émojis, et la génération de valeurs aléatoires.
Si tout ce fatras vous rend curieux, je vous invite à visiter le dépôt du jeu sur GitHub et à en faire ce que vous voulez !
Et si vous vous lancez dans le jeu, je vous invite à consulter les slides adossés au jeu. En avançant, vous verrez que chaque mutant a son slide. N’avancez pas trop vite, car le slide suivant donne la réponse…
Faites chauffer votre inspecteur !
Cet article fait partie du « Advent of Tech 2024 Onepoint », une série d’articles tech publiés par Onepoint pour patienter jusqu’à Noël.
Voir tous les articles du Advent of Tech 2024.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!