Ajouter à une liste
Créer une liste
Mettre en surbrillance ligne et colonne au survol d’une table Aujourd’hui, il nous est possible de faire énormément de choses avancés en CSS. Cependant quelque chose qui semble plus ou moins simple n’est pas toujours aussi simple que ce que l’on espérait, voir pas du tout. Le projet sur lequel je travaille affiche énormement de table de données (). Pour certaines d’entre elles, j’aimerais pouvoir mettre en surbrillance la ligne et la colonne qui prolongent cellule que je survole… Il est évident qu’il existe de moches solutions avec Javascript (hum hum), mais il est aussi très simple de le faire avec CSS. Comment cibler une ligne de la table ? Très simplement, en utilisant la pseudo-classe hover sur la ligne ( table-row), on peut changer son background-color. tr:hover { background: antiquewhite; }
Comment cibler une colonne de la table ? Un peu plus compliqué pour cette partie… En Javascript, il est plutôt facile de récupérer l’index de la colonne pour ensuite utiliser CSS et une pseudo-classe :nth-child(), dans toutes les lignes, sélectionner la colonne numéro 3 et lui afficher un background différent. En CSS, en combinant de simple propriétés comme position, overflow et un pseudo-élément ::before, on pourrait s’étendre un peu plus loin que la cellule. Publié par Alsacreations.com
Le mode sombre (dark mode) consiste à adopter des fonds de couleur sombre sur les interfaces utilisateur. Selon Wikipedia, ce mode serait utile pour réduire la fatigue visuelle et la consommation en énergie par rapport aux autres modes d’affichage. Un très grand nombre de personnes en sont adeptes sur leur smartphone, mais également sur leur ordinateur ou tablette. Proposer aux utilisateurs la possibilité d’activer cette fonctionnalité est donc conseillée. Le site de Wikipedia lui-même vient enfin d’annoncer le support du Dark mode pour ses pages de contenus, après de nombreuses années d’attente de ses lecteurs et lectrices. Préférences utilisateur Il est possible d’adapter les thèmes de couleur de son environnement sur l’ensemble de son système d’exploitation, par exemple pour Windows et MacOS :
Windows : Paramètres > Personnalisation > Couleurs > mode Windows par défaut. MacOS : Réglages Système > Apparence > Mode d’apparence. Il est également possible de n’appliquer ce choix qu’au niveau du navigateur web, par exemple :
Dans Firefox : "Réglages > Général > Apparence des sites web" Dans Chrome : "chrome://flags" et chercher "dark mode"
Enfin, en tant que développeur, les Devtools (inspecteur d’élément) de Google Chrome permettent d’émuler le mode sombre / clair via la combinaison de touche "ctrl+shift+p" et chercher "rendering". Les Devtools de Firefox permettent aussi de tester via onglet Inspecteur, dans les boutons-icônes en haut des styles (cf. capture ci-dessous). Couleurs système Les couleurs systèmes représentent une palette de couleurs web proposées par défaut pour les différentes éléments d’interface : couleur de texte, couleur de fond, couleur de lien, couleur de bordure d’un bouton, etc. Ces couleurs sont accessibles (si employées correctement), conformes aux modes de contraste élevé et prêtes à s’adapter automatiquement au mode d’apparence (light et dark mode). Il est même parfaitement possible de les utiliser sous forme de mot-clés en CSS comme les autres couleurs nommées : html { color: CanvasText; background-color: Canvas; } Démo : couleurs système
color-scheme Cette propriété indique au navigateur quel mode d’affichage est souhaité pour un élément donné (light ou dark). Dans l’exemple ci-dessous, on indique que l’élément .formulaire doit obligatoirement s’afficher en mode sombre. Le navigateur ajuste en conséquence les couleurs système, mais aussi les contrôles de formulaires et les scrollbars éventuelles sur cet élément. .formulaire { color-scheme: dark; }
Valeurs de color-scheme
color-scheme: normal; : Le navigateur n’adapte pas les couleurs (valeur par défaut). color-scheme: light; : Le navigateur doit afficher l’élément en mode light. color-scheme: dark; : Le navigateur doit afficher l’élément en mode dark. color-scheme: light dark; : Le navigateur doit afficher l’élément selon les préférences utilisateur.
Exemple concret

Tiens, mais quelle est ma couleur ?


:root { color-scheme: light dark; }
Dans cet exemple, j’indique que l’ensemble du document (:root) doit se conformer aux préférences utilisateur. Sans indiquer de couleurs particulières, ce sont les couleurs système qui s’appliquent et sont autorisées à s’adapter à ces préférences : en mode clair, le document a un fond clair et le titre

est de couleur sombre; et inversement en mode sombre. Compatibilité de color-scheme : https://caniuse.com/mdn-css_properties_color-scheme Conclusion : appliquer color-scheme: light dark; est un bon début pour toute page qui souhaite s’adapter au mode d’apparence, mais cette fonctionnalité n’agit que sur les Couleurs Système (et de l’interface du navigateur) donc c’est plutôt limité en terme de design. @media (prefers-color-scheme: …) La requête prefers-color-scheme est un critère des spécifications Media Query permettant de détecter le Mode d’apparence de l’utilisateur (celui défini via ses préférences système et/ou son navigateur). Cette fonctionnalité permet d’aller un cran plus loin que color-scheme en appliquant des palettes de couleurs totalement personnalisées et adaptées au choix (au système, plus précisément) de nos visiteurs. Nous détectons si l’OS ou le navigateur est configuré en mode sombre de cette manière : @media (prefers-color-scheme: dark) { /* ici des styles prévus pour Dark Mode */ }
Concrètement, cela pourrait se traduire ainsi pour nos pages web : :root { --color-primary: pink; --color-primary--darkmode: hotpink; @media (prefers-color-scheme: light) { --color-base: var(--color-primary); } @media (prefers-color-scheme: dark) { --color-base: var(--color-primary--darkmode); } }
Dans l’extrait ci-dessus :
Notre palette de couleurs est composée de --color-primary et --color-primary--darkmode Si le mode d’apparence est clair alors --color-base vaut --color-primary Si le mode d’apparence est sombre alors --color-base vaut --color-primary--darkmode
Nos différents composants bénéficieront par conséquent d’une couleur --color-base dont la valeur s’adaptera automatiquement à la configuration du système, par exemple : .card { color: var(--color-base); }
La vidéo ci-dessous illustre la mise en oeuvre de la media query prefers-color-scheme: Mise en oeuvre de la media query prefers-color-scheme
Compatibilité de @media (prefers-color-scheme: …) : https://caniuse.com/prefers-color-scheme light-dark() Cette valeur-fonction accepte deux paramètres de couleurs et renvoie l’une ou l’autre selon les préférences utilisateur (OS ou navigateur). .card { color: light-dark(pink, hotpink); }
Autre exemple : :root { color-scheme: light dark; --primary-color: light-dark(#fff, hotpink); --primary-background: light-dark(hotpink, #fff); } body { color: var(--primary-color); background-color: var(--primary-background); }
Compatibilité de light-dark() : https://caniuse.com/mdn-css_types_color_light-dark Switch Un Switch est un composant de type "interrupteur". Il va au-delà de ce que proposent les spécifications CSS évoquées jusqu’alors, puisqu’il permet à l’internaute de choisir le thème de couleur qu’il préfère lorsqu’il visite votre site en particulier, indépendamment de ses préférences utilisateur dans son système d’exploitation. Un design totalement inclusif devrait proposer ce genre de fonctionnalités pour tenter d’atteindre la meilleure expérience possible pour tous les usagers de votre site. Les contraintes et le processus ne sont pas si simples :
Le thème doit s’adapter par défaut aux préférences utilisateur (OS ou navigateur). L’utilisateur devrait aussi pouvoir choisir de changer de thème pour votre site, malgré ses préférences utilisateur. Ce choix spécifique pour ce site doit être mémorisé pour toutes les pages et pour une prochaine visite.
Voici un exemple de Switch accessible sur Codepen : https://codepen.io/alsacreations/pen/ExBPExE Le déroulé des événements lors du clic/touch sur le bouton est celui-ci :
On vérifie si le choix de thème était déjà mémorisé en localStorage. Sinon on vérifie les préférences utilisateur du système. Puis on crée ou modifie l’attribut data-theme-preference sur (valeur "light" ou "dark"). Et on mémorise le choix en localStorage. Enfin, on passe l’attribut aria-pressed du bouton à "pressed".
Le test pour connaître le choix de l’utilisateur porte sur l’attribut data-theme-preference, on s’en servira ainsi côté CSS : .card { color: pink; } [data-theme-preference="dark"] .card { color: hotpink; }
Ou en syntaxe imbriquée : .card { color: pink; [data-theme-preference="dark"] & { color: hotpink; } }
Conclusion Offrir une expérience d’environnement sombre et clair est de plus en plus courant et recommandé, rien que pour le confort de tous les usagers. Cependant, techniquement, rien n’est vraiment magique car les contraintes sont nombreuses et les solutions sont toutes partielles. Au final, le meilleur compromis semble être un Switch , assemblage de spécifications CSS et de JavaScript pour l’accessibilité et la mémorisation des choix utilisateur. Publié par Alsacreations.com

Les années passent, Pixels & Bretzels 🥨 se renouvelle (qui d’entre vous utilise encore le nom « WdStr » ?), mais garde le même cap : continuer de vous proposer régulièrement des conférences et rencontres, que ce soit dans votre cœur de métier ou pour vous faire prendre conscience de nouvelles problématiques. Pour fêter cette 100e édition, Pixels & Bretzels pose ses octets chez Alsacréations. Il y aura des quiz et des lots à vous faire gagner ! ✨ Même si cela fait longtemps que vous n’êtes pas venu·e à l’un de nos événements, rejoignez-nous. Comment s’inscrire ? Via le site HelloAsso avec le lien suivant : trop fort je m’inscris à Pixels & Bretzels 100e édition 3 bonnes raisons de nous rejoindre :
Venez profiter d’une ambiance festive Sortez la tête de vos projets et retrouvez la communauté Tentez de gagner un lot !
Lieu et horaire Le mardi 19 mars 2024 à 19h chez Alsacréations 10 place du Temple Neuf 67000 Strasbourg Nous avons hâte de vous y retrouver ✌️ Publié par Alsacreations.com
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é à 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 (modal) (non modal)
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, , 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 (voir cette section pour les détails). 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 (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); } 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". 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 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 :

Une modale de type Modal


const modal = document.querySelector("#modale"); modal.showModal();
Les particularités de l’élément 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 est "Modal" :
Il est placé dans le Top layer, ::backdrop est applicable, Tout le reste du document est rendu automatiquement inert. Si le 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 , 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 est non-Modal :

je suis non-modal

:modal La pseudo-classe :modal s’applique à tous les éléments à l’état Modal (par exemple un ouvert avec l’API showModal()). #modale:modal { background: hotpink; } popover Un popover est un overlay composé d’un attribut popover associé à un déclencheur :
Choucroute et Saucisses de Strasbourg !

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 (
, valeur par défaut si omise) : c’est le comportement idéal pour tooltip, menu déroulant, dropdown, datepicker, manual dismiss (
) : parfait pour des notifications ou des alertes. :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 { /*...*/ } 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 , popover ou une simple
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
https://hidde.blog/dialog-modal-popover-differences/ https://blog.logrocket.com/comparing-popover-api-dialog-element/ https://open-ui.org/components/popover.research.explainer/ https://adrianroselli.com/2023/05/brief-note-on-popovers-with-dialogs.html Publié par Alsacreations.com
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. 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. 👉 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é. 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 :
Le voici optimisé avec moins de précision sur les coordonnées, et un résultat visuel semblable : 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 ) 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 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
La pseudo-classe :has() réalise le fantasme historique de pouvoir enfin "cibler le parent" en CSS… mais elle fait bien plus que ça !
:has() est une pseudo-classe CSS issue des spécifications "Selectors level 4" où elle est décrite comme "sélecteur relationnel". Le sélecteur :has() cible un élément en relation avec la liste d’arguments qu’il contient au sein de ses parenthèses. Cela permet de cibler un parent ou ancêtre, mais également un frère précédent dans le DOM. Commençons justement par une énumération d’exemples de ce qu’est capable de réaliser :has()… Quelques exemples simples Je cible l’élément à condition qu’il contienne un descendant  : a:has(img) { }
Je cible l’élément
à condition qu’il contienne un enfant direct  : a:has(> img) { }
Je cible n’importe quel élément du DOM à condition qu’il contienne un descendant  : :has(img) { }
Je cible l’élément
Aujourd’hui, il nous est possible de faire énormément de choses avancés en CSS. Cependant quelque chose qui semble ± simple n’est pas toujours aussi simple que ce que l’on espère, voir pas du tout. Le projet sur lequel je travaille affiche énormément de table de données (
). Pour certaines d’entre elles, j’aimerais pouvoir mettre en surbrillance la ligne et la colonne de la cellule que je survole… Il est évident qu’il existe de moches solutions avec Javascript (hum hum), mais il est aussi très simple de le faire avec CSS (codepen). Comment cibler une ligne de la table ? Très simplement, en utilisant la pseudo-classe hover sur la ligne ( table-row), on peut changer son background-color. tr:hover { background: antiquewhite; }
Comment cibler une colonne de la table ? Un peu plus compliqué pour cette partie… En Javascript, il est plutôt facile de récupérer l’index de la colonne pour ensuite utiliser CSS et une pseudo-classe :nth-child(). Pour toutes les lignes, sélectionner la colonne numéro 4, et lui afficher un background différent. En CSS, on ne peut pas connaître son index (à l’exception de first et last), remonter la structure et ensuite réappliquer plus loin. Par contre, en combinant de simple propriétés comme position, overflow et un pseudo-élément ::before, on pourrait créer l’illusion en s’étendant verticalement un peu plus loin que la cellule. td { position: relative; &:hover::before { content: ""; position: absolute; inset: -100vh 0; /* https://developer.mozilla.org/fr/docs/Web/CSS/inset */ background: antiquewhite; z-index: -1; /* On positione le pseudo-élément en arrière plan */ } }
Avec inset: -100vh 0 (équivalent à top: -100vh; right: 0; bottom: -100vh; left: 0;), on va prendre la largeur de la cellule et s’étendre en hauteur. Maintenant, nous avons bien une surbrillance qui se fait sur les deux axes. Il y a cependant notre colonne qui s’étend un peu trop. En ajoutant un simple overflow: hidden sur notre table, on contiendra tout ça. Voir le résultat Publié par Alsacreations.com
Aujourd’hui, il nous est possible de faire énormément de choses avancés en CSS. Cependant quelque chose qui semble plus ou moins simple n’est pas toujours aussi simple que ce que l’on espérait, voir pas du tout. Le projet sur lequel je travaille affiche énormement de table de données (
). Pour certaines d’entre elles, j’aimerais pouvoir mettre en surbrillance la ligne et la colonne qui prolongent cellule que je survole… Il est évident qu’il existe de moches solutions avec Javascript (hum hum), mais il est aussi très simple de le faire avec CSS (codepen). Comment cibler une ligne de la table ? Très simplement, en utilisant la pseudo-classe hover sur la ligne ( table-row), on peut changer son background-color. tr:hover { background: antiquewhite; }
Comment cibler une colonne de la table ? Un peu plus compliqué pour cette partie… En Javascript, il est plutôt facile de récupérer l’index de la colonne pour ensuite utiliser CSS et une pseudo-classe :nth-child(), dans toutes les lignes, sélectionner la colonne numéro 4 et lui afficher un background différent. En CSS, on ne peut pas connaître son index (à l’exception de first et last), remonter la structure et réappliquer plus loin. Par contre, en combinant de simple propriétés comme position, overflow et un pseudo-élément ::before, on pourrait créer l’illusion en s’étendant un peu plus loin que la cellule. td { position: relative; &:hover::before { content: ""; position: absolute; inset: -100vh 0; /* https://developer.mozilla.org/fr/docs/Web/CSS/inset */ background: antiquewhite; z-index: -1; /* On positione le pseudo-élément en arrière plan */ } }
Avec inset: -100vh 0 (équivalent à top: -100vh; right: 0; bottom: -100vh; left: 0;), on va prendre la largeur de la cellule et s’étendre en hauteur. Maintenant, nous avons bien une surbrillance qui se fait sur les deux axes. Il y a cependant notre colonne qui s’étend un peu trop. En ajoutant un simple overflow: hidden sur notre table, on contiendra tout ça. Pour voir le résultat: codepen Retrouvez l’intégralité de ce tutoriel en ligne sur Alsacreations.com
Le format SVG peut paraître parfois un peu intimidant, et l’associer à des transitions ou des animations CSS semble encore plus audacieux pour bon nombre de personnes. Cependant, dans certains cas, l’alchimie entre SVG et CSS est aussi bénéfique qu’extrêmement simple à mettre en oeuvre. Dans ce tutoriel, nous allons suivre étape par étape comment animer un bouton burger simple avec SVG et CSS. Quels outils ? La liste des outils nécessaires pour atteindre nos objectifs est particulièrement réduite puisqu’un simple éditeur de code fait le job (n’importe lequel fait l’affaire, Visual Studio Code étant mon choix personnel). Pour aller plus loin, et en guise de bonus, on peut également piocher :
Un éditeur SVG en ligne (parce que ça peut toujours servir) Des recommendations concernant l’accessibilité des SVG (au hasard les Guidelines Alsacréations) Un éditeur de courbes de Bezier (pour des animations originales)
SVG c’est quoi ? En trois mots, voici comment résumer SVG :
SVG est un format graphique vectoriel (composé de tracés et de courbes) Il est développé et maintenu depuis 1999 par le W3C (standard officiel, open source) Il est conçu en XML (compatible HTML) (on peut le créer et le lire avec un simple éditeur de texte)
1. Produire le burger bouton en SVG Si l’on y regarde de plus près, une "icône Burger" c’est bêtement trois rectangles horizontaux espacés et avec des coins arrondis. Notre éditeur de code préféré est amplement suffisant pour s’aquitter de la tâche de dessiner des rectangles : on va tout d’abord dessiner un élément SVG vide avec une fenêtre de "100 x 100". C’est une dimension purement indicative car tout est proportionnel et adaptable en SVG.
.burger-icon { width: 200px; height: 200px; /* taille du SVG */ border: 2px dotted #ddd; /* bordure = simple repère */ } Le tracé de notre premier rectangle est un jeu d’enfant aussi : l’élément SVG rect est fait pour ça, attribuons-lui des coordonnées (x=0 et y=0) ainsi qu’une largeur de "100" et une hauteur de "20". Vous aurez compris qu’à partir d’un premier rectangle, il n’est pas difficile de produire les deux suivants. Et voilà ! Pour ce qui est des coins arrondis, là aussi SVG a tout prévu sous la forme de l’attribut rx, à qui une valeur de "5" semble tout à fait parfaite. Le résultat est bluffant et on se rend compte de la puissance insoupçonnée d’un éditeur de code. Plus sérieusement, ce n’était vraiment pas compliqué, non ? Par contre, ce qui est vraiment dommage c’est de répéter les mêmes choses plusieurs fois… Mais justement, il se trouve que… la plupart des attributs SVG existent également sous forme de propriétés CSS ! Voici par conséquent comment nous allons pouvoir améliorer notre code actuel :
rect { x: 0; rx: 5px; width: 100px; height: 20px; } .rect-1 { y: 0; } .rect-2 { y: 40px; } .rect-3 { y: 80px; }
Autre avantage loin d’être anodin, ces propriétés CSS-SVG ont la bonne idée d’être animables : on peut par exemple effectuer une transition sur la propriété… y ! rect { ... transition: y 1s; } .rect-1:hover { y: 15px; } 2. Préparer le SVG et le rendre accessible Nous allons à présent nous atteler à transformer notre icône SVG en un véritable "bouton Burger", fonctionnel et accessible. Pour ce faire, on commence par placer le SVG dans un
Notre icône SVG est considérée comme purement décorative, car c’est le bouton qui portera l’information. Nous veillons à lui appliquer les attributs suivants :
Un attribut aria-hidden="true" Un attribut focusable="false" pour éviter de naviguer au sein du SVG. Aucun élément ni <desc> ni d’attribut title, aria-label, aria-labelledby, ni role="img"<br />... <svg class="burger-icon" aria-hidden="true" focusable="false" viewBox="0 0 100 100"> </svg> ...<br />Le bouton, quant à lui, nécessite les éléments suivants :<br />Un nom accessible (via aria-label ou un texte masqué à la ".sr-only") En option, et selon les cas de figure, un attribut aria-controls pour lier à la cible et un attribut aria-expanded pour signaler l’état du bouton. Dans notre cas, ce n’est pas néessaire.<br /><button class="burger-button" aria-label="Menu" data-expanded="false"> ... </button><br />Voici le script JavaScript destiné à gérer l’interaction et la mise à jour des attributs data-, et déclencher l’animation de l’icône : (function () { function toggleNav() { // Define targets const button = document.querySelector(’.burger-button’); const target = document.querySelector(’#navigation’); button.addEventListener(’click’, () => { const currentState = target.getAttribute("data-state"); if (!currentState || currentState === "closed") { target.setAttribute("data-state", "opened"); button.setAttribute("data-expanded", "true"); } else { target.setAttribute("data-state", "closed"); button.setAttribute("data-expanded", "false"); } }); } // end toggleNav() toggleNav(); }()); Pouquoi JavaScript ? Très sincèrement parce que c’est son job de déclencher des actions au clic et de modifier des classes ou des attibuts en conséquence. Cette mission aurait été réalisable en CSS au moyen de cases à cocher mais, ne nous mentons pas, c’est un peu de la bidouille.<br />3. Les étapes de l’animation Pour être très précis, nous n’allons pas employer une "animation" pour nos effets, mais une combinaison de trois "transitions", qui se révèleront amplement suffisantes pour notre besoin.<br />Voici le scénario étape par étape qui doit se réaliser :<br />L’action de clic ou de touch sur l’élément button doit déclencher une série de trois transitions; La transition 1 consiste en un déplacement vertical de .rect-1 et .rect-3 qui se rejoignent au centre du SVG; La transition 2 consiste à faire disparaître .rect-2 qui traîne dans nos pattes. En terme de timing, cette transition doit se dérouler en même temps que la transition 1; La transition 3 se compose d’une rotation de 45 degrés de .rect-1 et .rect-3 et doit de déclencher juste après les transitions précédentes).<br />Transition 1 et 2 : "translate" et "opacity" La propriété transitionest appliquée sur l’élément à l’état initial (hors événement) afin d’assurer une transition au retour lorsque l’événement est quitté. /* transition sur la propriété y et opacity, durée 0.3s */ rect { transition: y 0.3s, opacity 0.3s; } /* coordonnées y initiales */ .rect-1 { y: 0; } .rect-2 { y: 40px; } .rect-3 { y: 80px; }<br />Au clic, le bouton passe en data-expanded "true" et on déplace verticalement deux rectangles au centre et on masque le 3e rectangle central. [data-expanded="true"] .rect-1 { y: 40px; } [data-expanded="true"] .rect-2 { opacity: 0; } [data-expanded="true"] .rect-3 { y: 40px; }<br />Transition 3 : "rotate" Aux deux transitions précédentes, on ajoute une transition sur la propriété rotate sans oublier de la faire débuter après un léger délai. /* on attend un delai de 0.3s avant de commencer rotate */ rect { transition: y 0.3s, opacity 0.3s, rotate 0.3s 0.3s; }<br />Au clic, les trois transitions se déclenchent. [data-expanded="true"] .rect-1 { y: 40px; rotate: 45deg; } [data-expanded="true"] .rect-2 { opacity: 0; } [data-expanded="true"] .rect-3 { y: 40px; rotate: -45deg; } ⚠️ J’imagine que cela ne vous a pas échappé : tout se passe très bien à l’aller, mais malheureusement pas au retour. L’explication provient du fait que la transition se déroule dans le sens inverse au retour et que la rotation se déclenche trop tôt. Il va nous falloir une transition différente à l’aller et au retour et gérer des délais différents entre la transition et la rotation. /* transition au retour (quand on perd le clic) */ /* on attend un delai de 0.3s avant de commencer y */ rect { transition: y 0.3s 0.3s, opacity 0.3s, rotate 0.3s; }<br />/* transition à l’aller (quand on clique) */ /* on attend un delai de 0.3s avant de commencer rotate */ [data-expanded="true"] rect { transition: y 0.3s, opacity 0.3s, rotate 0.3s 0.3s; } Grâce à cette adaptation subtile, notre effet fonctionne parfaitement à l’aller et au retour lors de l’interaction. Pour finir en beauté, le truc en plus consiste en une petite accélération sous forme de cubic-bezier pour un effet de "rebond". [data-expanded="true"] rect { transition: y 0.3s, opacity 0.3s, rotate 0.3s 0.3s cubic-bezier(.55,-0.65,0,2.32); } CSS final Voici les styles CSS complets de ce tutoriel. Notez qu’ils prennent en compte les préférences utilisateur grâce au media query prefers-reduced-motion : si la personne a choisi dans ses réglages système de réduire les animations, celles-ci ne seront tout simplement pas déclenchées. Pour voir le résultat et aller plus loin, une petite collection CodePen de boutons burger animés a été rassemblée à cette adresse : https://codepen.io/collection/VYqwJK .rect-1 { y: 0; } .rect-2 { y: 40px; } .rect-3 { y: 80px; } [data-expanded="true"] .rect-1 { y: 40px; rotate: 45deg; } [data-expanded="true"] .rect-2 { opacity: 0; } [data-expanded="true"] .rect-3 { y: 40px; rotate: -45deg; } /* transitions si acceptées */ @media (prefers-reduced-motion: no-preference) { rect { transition: y 0.3s 0.3s, opacity 0.3s, rotate 0.3s; } [data-expanded="true"] rect { transition: y 0.3s, opacity 0.3s, rotate 0.3s 0.3s cubic-bezier(.55,-0.65,0,2.32); } } Retrouvez l’intégralité de ce tutoriel en ligne sur Alsacreations.com</div> <div style="height:20px;"> </div> <div class="timeline-thumbnail" title="Animer un bouton burger simple avec SVG et CSS" > <div class="timeline-thumbnail-content" style="background-image: url(https://feedbot.net/storage/thumbnails/2023_12/1b9392230da6166d97e929c0d06e3cd4-2bb58e10e10418b365be670dfe51b0f8.jpg);"> <a href="https://www.alsacreations.com/tuto/lire/1921-Animer-un-bouton-burger-simple-avec-SVG-et-CSS.html" target="_blank" style="display:block; width:100%; height:100%;"></a> </div> <div class="timeline-title"> <a href="https://www.alsacreations.com/tuto/lire/1921-Animer-un-bouton-burger-simple-avec-SVG-et-CSS.html" target="_blank" style="text-decoration: none;"><span style="color:var(--feedbot-gray); font-size: 12px; text-transform: uppercase;">www.alsacreations.com</span><br /><span style="color: var(--feedbot-title); font-weight: bold; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;">Animer un bouton burger simple avec SVG et CSS</span></a> </div> </div> <div style="position:relative; display: block; height: 28px;"> <div class="timeline-buttons-left"> <form class="timeline-buttons share_371959"> <input type="hidden" name="article_id" value="371959"> <input type="hidden" name="feed_id" value="376"> <input type="hidden" name="site_id" value="172"> <input type="hidden" name="messagetitle" value="Animer un bouton burger simple avec SVG et CSS"> <input type="hidden" name="message" value="« Le format SVG peut paraître parfois un peu intimidant, et l’associer à des transitions ou des animations CSS semble encore plus audacieux pour bon nombre de personnes.Cependant, dans certains cas, l’alchimie entre SVG et CSS est aussi bénéfique qu’extrêmement simple à mettre en oeuvre. Dans ce tutoriel, nous allons suivre étape par étape comment animer un bouton burger simple avec SVG et CSS. Quels outils ?La liste des outils… »"> <input type="hidden" name="url" value="https://www.alsacreations.com/tuto/lire/1921-Animer-un-bouton-burger-simple-avec-SVG-et-CSS.html"> <input type="hidden" name="peertubeid" value=""> <input type="hidden" name="youtubeid" value=""> <input type="hidden" name="thumbnail" value="https://feedbot.net/storage/thumbnails/2023_12/1b9392230da6166d97e929c0d06e3cd4-2bb58e10e10418b365be670dfe51b0f8.jpg"> <button onclick="share(371959)" class="timeline-buttons" title="SHARE"> <i class="fa fa-retweet" aria-hidden="true" style="margin-right: 5px;"></i> SHARE</span> </button> </form> <form class="timeline-buttons unshare_371959" style="display: none;"> <input type="hidden" name="action" value="delete_status"> <input type="hidden" name="article_id" value="371959"> <input type="hidden" name="status_id" value=""> <button onclick="unshare(371959)" type="submit" class="timeline-buttons" title="SHARED : 19/12/2023 01:37" style="color:var(--feedbot-purple);"> <i class="fa fa-retweet" aria-hidden="true" style="margin-right: 5px;"></i> SHARED</span> </button> </form> </div> <div class="timeline-buttons-right"> <form class="timeline-buttons bookmark_371959" class="timeline-buttons-div"> <input type="hidden" name="action" value="bookmark"> <input type="hidden" name="article_id" value="371959"> <input type="hidden" name="feed_id" value="376"> <input type="hidden" name="site_id" value="172"> <button onclick="bookmark(371959)" class="timeline-buttons" title="READ_LATER"> <i class="fa fa-bookmark" aria-hidden="true" style="margin-right: 5px;"></i> READ_LATER </button> </form> <form class="timeline-buttons unbookmark_371959" style="display:none;" class="timeline-buttons-div"> <input type="hidden" name="action" value="delete_bookmark"> <input type="hidden" name="article_id" value="371959"> <button onclick="unbookmark(371959)" class="timeline-buttons" title="READ_LATER" style="color:red;"> <i class="fa fa-bookmark" aria-hidden="true" style="margin-right: 5px;"></i> READ_LATER </button> </form> </div> </div></div> <div class="content-home" style="padding-top: 15px; padding-bottom: 0px;" id="1701692316"> <div style="height:75px;"> <form action="https://feedbot.net" class="follow-button subscribe_376" method="post" title="SUBSCRIBE_TO Alsacreations.com - Actualités"> <button type="submit"><i class="fa fa-rss" aria-hidden="true"></i></button> </form> <div style="width: 60px; aspect-ratio: 1 / 1; background-image: url(https://feedbot.net/storage/icons/505d4634449bab300618b607328ae6c0aac872de.png); background-size: cover; background-position: center; border-radius: 50%; float:left; overflow: hidden;"> <a href="https://feedbot.net/feed/376" style="display:block; width:100%; height:100%;"></a> </div> <div style="margin-left: 74px; padding-top: 13px; line-height: 16px;"> <a href="https://feedbot.net/feed/376" style="color:var(--feedbot-title); font-weight: bold; text-decoration: none; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;">Alsacreations.com - Actualités</a> <a href="https://feedbot.net/feed/376/351196" style="font-size: 12px; text-decoration: none; color: var(--feedbot-text);">04/12/2023 01:18</a> </div> </div> <div class="description" data-article-id="351196" id="description-351196">Article rédigé suite à un stage d’observation dans l’équipe d’Alsacréations Lorsque l’on consulte un site web, nous pouvons tous voir le code source (avec ctrl + U » ou en faisant un clic droit puis inspecter). Quelques sites en profitent pour dissimuler des easter eggs le plus souvent sous la forme d’ascii art ou de messages à demi-cachés, que ce soit en HTML, JavaScript, ou CSS. Ces messages sont soit des petits clins d’oeil à destination d’autres personnes curieuses ou pratiquant le développement web, soit intentionnels pour mentionner des liens vers des pages de recrutement, des avertissements ou des ressources variées. Voyons quelques exemples de différentes natures, en mettant de côté ceux qu’affichent les moteurs de recherche tels que Google avec des mots clés spécifiques (ex: cherchez "anagramme" ou "Askew"). HTML Mozilla a placé dans son code un "godzilla" crachant du feu sur le logo, assorti d’un message : Bonjour, enchanté ! Intéressé d’avoir un impact direct sur des centaines de millions d’utilisateurs ? Rejoins Mozilla, et viens faire partie de la communauté qui aide à construire un meilleur avenir pour le web. Visitez … pour en apprendre plus sur les emplois disponibles. Visitez … pour plus de façons de s’impliquer et aider à supporter Mozilla _.-~-. 7’’ Q.. _7 (_ _7 _/ _q. / _7 . ___ /VVvv-’_ . 7/ / /~- \_\ ’-._ .-’ / // ./ ( /-~-/||’=.__ ’::. ’-~’’ { ___ / // ./{ V V-~-~| || __’’_ ’:::. ’’~-~.___.-’’ _/ // / {_ / { / VV/-~-~-|/ .’__’. ’. ’:: _ _ _ ’’. / /~~~~||VVV/ / ) _ __ ___ ___ ___(_) | | __ _ .::’ / (~-~-~\.-’ / ’ ::::. | ’_ ` _ / _ \_ / | | |/ _` | :::’ /.. /..\__/ ’ ’::: | | | | | | (_) / /| | | | (_| | ::’ vVVv vVVv ’: |_| |_| |_|\___/___|_|_|_|\__,_| ’’ Hi there, nice to meet you! Interested in having a direct impact on hundreds of millions of users? Join Mozilla, and become part of a global community that’s helping to build a brighter future for the Web. Visit https://www.mozilla.org/careers to learn about our current job openings. Visit https://www.mozilla.org/contribute for more ways to get involved and help support Mozilla.<br />Sur la page d’accueil de Amazon, vous trouverez tout en bas de la page de code, un canard qui dit Meow. Sympa non ? .__(.)< (MEOW) \___) ~~~~~~~~~~~~~~~~~~<br />Sur theoatmeal se cache un gigantesque ptérodactyle, à vous de le trouver. Vous pourrez également trouver le logo de l’Université du Michigan dans leur code source : <!-- MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMM MMMMMMMMMMMMMMMMM MMMMMMMMM MMMMMMMM MMMMMMMMMMMMMMM MMMMMMMMM MMMMMMMM MMMMMMMMMMM MMMMMMMMM MMMMMMMM MMMMMMMMM MMMMMMMMM MMMMMMMM MMMMMMM MMMMMMMMM MMMMMMMMMMMM MMMMM MMMMMMMMMMMM MMMMMMMMMMMM MMM MMMMMMMMMMMM MMMMMMMMMMMM V MMMMMMMMMMMM MMMMMMMMMMMM MMMMMMMMMMMM MMMMMMMMMMMM ^ ^ MMMMMMMMMMMM MMMMMMMMMMMM MM MM MMMMMMMMMMMM MMMMMMMMMMMM MMMM MMMM MMMMMMMMMMMM MMMMMMMMMMMM MMMMM MMMMM MMMMMMMMMMMM MMMMMMMMMMMM MMMMMM MMMMMM MMMMMMMMMMMM MMMMMMMM MMMM MMMM MMMMMMMMM MMMMMMMM MMMMMVMMMMM MMMMMMMMM MMMMMMMM MMMMMMMMMMM MMMMMMMMM MMMMMMMM MMMMMMMMMMM MMMMMMMMM MMMMMMMM MMMMMMMMMMM MMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM --><br />Quelques marques comme KitKat ou Coca-Cola avaient aussi opté pour cet art caché, mais les ont supprimés depuis des refontes récentes. Si vous souhaitez vous aussi ajouter un easter egg tel quel dans votre code, il y a une manière très simple de le faire : utiliser les commentaires HTML entre <!-- et finissant par -->. Tout ce qui est placé entre n’est pas interprété par le navigateur. Vous trouverez aussi de nombreux sites vous permettant de générer de l’art avec les caractères. Code Konami Le Code Konami quant à lui correspond à une combinaison de touches successives, venant initialement d’un code de triche de jeu vidéo : « Haut Haut Bas Bas Gauche Droite Gauche Droite B A ». Vous pouvez essayer cette commande sur :<br />Le site de Ldlc : La page va se retourner La page du billet de 10 dollars de la Banque du Canada : l’hymne national survient avec une pluie de billets La page 404 de Discord : Un jeu snake va se lancer Un petit script konami-js vous premet de l’ajouter facilement. robots.txt, humans.txt Les fichiers robots.txt sont connus pour être placés à la racine d’un site pour interdire le référencement de certaines portions aux robots d’indexation. Ces derniers peuvent contenir des commentaires, donc de l’ascii art. Notez par exemple celui de alsacreations.com ;) Plus récemment pensés, les fichiers humans.txt décrivent les personnes "humaines" ayant contribué à un projet et sont un espace totalement libre pour y dissimuler (aussi) des easter eggs. Par exemple :<br />Celui de Google basique mais efficace Celui de html5boilerplate.com Celui de Discord très artistique ..-:oo-. .:oo/:-. -oooooooooooooooooooooo. __ ___ -oooooooooooooooooooooooo. OOOOOOOOO:-. `MM` _.._ _.._ _.._ ____ _ _. OOO. -oooooooooooooooooooooooooo. OOOOOOOOOOOo: -/ooo-ooo. -/OOOOOO/. :/OOOOOO:. OOOO.oOo: .:oOOOO-.OOO. `ooooooo/--/oooooo:--/ooooooo OOOO `OOOO `OooI `ooo:. ` /oOO/```-:..oOOO-``OOO: OOOO/` ``.oOOO/```OOO. :oooooo- :oooo- :oooooo- OOOO .OOOo `OOOI `-OOOOOOo.`OOOO. -OOO: .OOOo OOOO. -OOOO` /OOO. ooooooo:- -/oooo:- -/oooooo/ OOOOooooOooo- `OOOI ._ `]OO/ :OOOOoooOO.`OOOOOooOOOO- OOOO. `/OOOOooOOOOO. ooooooooo//oooooooo//ooooooooo OOOOOOOOO:-` `OOOI `:OOoOO:-` `-:OOOO:-` `-:OOOO:-` OOOO. `-:OOO:-`OOO. ooooooo/ooooooooooooo//oooooo/ `.:ooooo/``.------.`.oooo/:. `.-:` .:-.` https://discord.com/company<br />Console La console JavaScript du navigateur peut révéler des messages, une fois ouverte (par F12 ou Ctrl+Shift+I). C’est un outil typique à destination des développeuses et développeurs, on y retrouve non seulement des erreurs ;) mais aussi parfois des messages de bienvenue ou encore d’avertissement comme Discord qui est assez explicite : À vous ! Prenez quelques instants pour ajouter à vos projets et sites ces petits messages cachés. Et précisez en commentaires si vous connaissez d’autres sites avec de telles astuces ! Publié par Alsacreations.com</div> <div style="height:20px;"> </div> <div class="timeline-thumbnail" title="Les easter eggs sur le web" > <div class="timeline-thumbnail-content" style="background-image: url(https://feedbot.net/storage/thumbnails/2023_12/5075ae534764ddbb1ab2313745a1b434-f8b79e6c83af44996cf408a9f5debcec.jpg);"> <a href="https://www.alsacreations.com/actu/lire/1917-Les-easter-eggs-sur-le-web.html" target="_blank" style="display:block; width:100%; height:100%;"></a> </div> <div class="timeline-title"> <a href="https://www.alsacreations.com/actu/lire/1917-Les-easter-eggs-sur-le-web.html" target="_blank" style="text-decoration: none;"><span style="color:var(--feedbot-gray); font-size: 12px; text-transform: uppercase;">www.alsacreations.com</span><br /><span style="color: var(--feedbot-title); font-weight: bold; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;">Les easter eggs sur le web</span></a> </div> </div> <div style="position:relative; display: block; height: 28px;"> <div class="timeline-buttons-left"> <form class="timeline-buttons share_351196"> <input type="hidden" name="article_id" value="351196"> <input type="hidden" name="feed_id" value="376"> <input type="hidden" name="site_id" value="172"> <input type="hidden" name="messagetitle" value="Les easter eggs sur le web"> <input type="hidden" name="message" value="« Article rédigé suite à un stage d’observation dans l’équipe d’AlsacréationsLorsque l’on consulte un site web, nous pouvons tous voir le code source (avec ctrl + U” ou en faisant un clic droit puis inspecter).Quelques sites en profitent pour dissimuler des easter eggs le plus souvent sous la forme d’ascii art ou de messages à demi-cachés, que ce soit en HTML, JavaScript, ou CSS. Ces messages sont soit des petits clins… »"> <input type="hidden" name="url" value="https://www.alsacreations.com/actu/lire/1917-Les-easter-eggs-sur-le-web.html"> <input type="hidden" name="peertubeid" value=""> <input type="hidden" name="youtubeid" value=""> <input type="hidden" name="thumbnail" value="https://feedbot.net/storage/thumbnails/2023_12/5075ae534764ddbb1ab2313745a1b434-f8b79e6c83af44996cf408a9f5debcec.jpg"> <button onclick="share(351196)" class="timeline-buttons" title="SHARE"> <i class="fa fa-retweet" aria-hidden="true" style="margin-right: 5px;"></i> SHARE</span> </button> </form> <form class="timeline-buttons unshare_351196" style="display: none;"> <input type="hidden" name="action" value="delete_status"> <input type="hidden" name="article_id" value="351196"> <input type="hidden" name="status_id" value=""> <button onclick="unshare(351196)" type="submit" class="timeline-buttons" title="SHARED : 04/12/2023 01:18" style="color:var(--feedbot-purple);"> <i class="fa fa-retweet" aria-hidden="true" style="margin-right: 5px;"></i> SHARED</span> </button> </form> </div> <div class="timeline-buttons-right"> <form class="timeline-buttons bookmark_351196" class="timeline-buttons-div"> <input type="hidden" name="action" value="bookmark"> <input type="hidden" name="article_id" value="351196"> <input type="hidden" name="feed_id" value="376"> <input type="hidden" name="site_id" value="172"> <button onclick="bookmark(351196)" class="timeline-buttons" title="READ_LATER"> <i class="fa fa-bookmark" aria-hidden="true" style="margin-right: 5px;"></i> READ_LATER </button> </form> <form class="timeline-buttons unbookmark_351196" style="display:none;" class="timeline-buttons-div"> <input type="hidden" name="action" value="delete_bookmark"> <input type="hidden" name="article_id" value="351196"> <button onclick="unbookmark(351196)" class="timeline-buttons" title="READ_LATER" style="color:red;"> <i class="fa fa-bookmark" aria-hidden="true" style="margin-right: 5px;"></i> READ_LATER </button> </form> </div> </div></div> </div> <div class="widget-home"> <div class="widget-home-content small_screens_hide" style="margin-top: 20px; text-align: center;"> <h4 style="font-size:20px; margin-bottom: 20px; color:var(--feedbot-title);">ENJOY_USING Feedbot ?</h4> <p style="margin-bottom: 20px;">FUNDING</p> <script src="https://liberapay.com/raph/widgets/button.js"></script> <noscript><a href="https://liberapay.com/raph/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a></noscript> </div><div class="footer small_screens_hide">COPYRIGHT <a href="https://tooter.social/@raph" target="_blank" rel="me">Raph <i class="fa fa-mastodon" aria-hidden="true"></i></a><br /> Logo by <a href="https://maous.fr/" target="_blank">Maous <img src="https://feedbot.net/assets/maous.png" style="width:22px; margin-bottom:6px; vertical-align: middle;"/></a></div> </div> </div> <script> var isActive = false; var page = "single-feed"; var feed_id = "376"; var search = ""; $(window).scroll(function(){ get_sticky_position($(".widget-home")); }); $(window).on("resize", function(){ get_sticky_position($(".widget-home")); $("#post-data").find('.description:not([data-expanded]').each(function(){ linesCount(this); }); }); function linesCount($elem){ var article_id = $($elem).attr("data-article-id"); var lineHeight = parseFloat($($elem).css('line-height')); var elementHeight = $($elem)[0].scrollHeight; var lineCount = Math.floor(elementHeight / lineHeight); var read_more_elem = $(".read-more[data-article-id=" + article_id + "]").length; if(lineCount > 5){ $($elem).addClass("description-short"); if(read_more_elem == 0){ $($elem).addClass("description-short"); $(`<div class="read-more" data-article-id="` + article_id + `" style="width:100%; font-weight: bold; text-align: center; margin-top: 10px; cursor: pointer;">READ_MORE</div>`).insertAfter($elem); } } else{ $($elem).removeClass("description-short"); $(".read-more[data-article-id=" + article_id + "]").remove(); } } $(document).on("click", ".read-more", function(){ var article_id = $(this).attr("data-article-id"); $(".description[data-article-id=" + article_id + "]").removeClass("description-short"); $(".description[data-article-id=" + article_id + "]").attr("data-expanded", "true"); $(this).remove(); }); $(function(){ $("#post-data").find('.description').each(function(){ linesCount(this); $(this).attr('data-loaded', 'true'); }); }); get_sticky_position($(".widget-home")); </script> </section> <script type="text/javascript"> // Mobile Safari in standalone mode if(("standalone" in window.navigator) && window.navigator.standalone){ // If you want to prevent remote links in standalone web apps opening Mobile Safari, change 'remotes' to true var noddy, remotes = false; document.addEventListener('click', function(event) { noddy = event.target; // Bubble up until we hit link or top HTML element. Warning: BODY element is not compulsory so better to stop on HTML while(noddy.nodeName !== "A" && noddy.nodeName !== "HTML"){ noddy = noddy.parentNode; } if('href' in noddy && noddy.href.indexOf('http') !== -1 && (noddy.href.indexOf(document.location.host) !== -1 || remotes)){ event.preventDefault(); document.location.href = noddy.href; } },false); } </script> <script type="text/javascript"> // Get the button: let mybutton = document.getElementById("myBtn"); // When the user scrolls down 20px from the top of the document, show the button window.onscroll = function() {scrollFunction()}; function scrollFunction() { if(document.body.scrollTop > 5000 || document.documentElement.scrollTop > 5000){ mybutton.style.display = "block"; } else{ mybutton.style.display = "none"; } } // When the user clicks on the button, scroll to the top of the document function topFunction(){ $('html, body').animate({ scrollTop: 0 }, 'medium'); } </script> </body> </html>