Actus

Les dernières actualités d'Alsacreations.com
  • La règle @starting-style est une règle conditionnelle (at-rule) qui permet de définir l'état initial d'un élément avant qu'une transition ou une animation ne commence. Cette fonctionnalité comble un vide important dans le système d'animations CSS, en permettant de définir explicitement les propriétés d'un élément au moment où il apparaît dans le DOM, plutôt que d'utiliser les valeurs par défaut du navigateur.

    Syntaxe de base

    @starting-style {
      /* Sélecteurs et propriétés qui définissent l'état initial */
      selecteur {
        propriete: valeur;
      }
    }
    

    Cette règle s'applique uniquement aux éléments qui :

    1. Viennent d'être insérés dans le DOM.
    2. Ont des propriétés CSS qui peuvent faire l'objet d'une transition.

    Imbrication (nesting)

    @starting-style peut être imbriqué directement à l'intérieur d'un bloc de sélecteur, ce qui permet une syntaxe plus concise et mieux organisée :

    .element {
      opacity: 1;
      transition: opacity 0.5s ease;
    
      @starting-style {
        opacity: 0;
      }
    }
    

    Cette approche imbriquée est particulièrement utile lorsqu'on travaille avec plusieurs sélecteurs qui partagent des animations similaires, car elle maintient les états initiaux et finaux proches les uns des autres dans le code.

    Cas d'utilisation courants

    La règle @starting-style répond à un problème de longue date dans le développement web : comment créer des animations d'apparition naturelles sans recourir à des techniques complexes ou à JavaScript ? Voici les principaux scénarios où cette fonctionnalité brille particulièrement :

    1. Animations d'entrée fluides

    Sans @starting-style, lorsqu'un élément est ajouté au DOM avec une opacité de 1 et une transition, il apparaît instantanément puis reste statique (car il est déjà à son état final). Avec @starting-style, il devient possible de spécifier qu'il doit commencer avec une opacité de 0 et appliquer une transition vers 1.

    Ce cas d'utilisation est particulièrement pratique pour les notifications, les toasts, les modales et autres éléments qui doivent apparaître de façon élégante sans perturber l'expérience utilisateur.

    2. Animations de positionnements

    Particulièrement utile pour les animations impliquant des changements de positionnement, de taille ou de disposition qui nécessitent un point de départ spécifique.

    Par exemple, pour les listes d'éléments chargés dynamiquement ou les grilles réorganisées après un filtrage, @starting-style permet de définir précisément la position initiale, créant ainsi un effet de mouvement fluide depuis cet état vers l'état final.

    3. Effets d'apparition personnalisés

    Permet de créer des effets d'entrée élégants sans avoir recours à JavaScript ou à des astuces CSS complexes.

    Cela inclut des animations combinant plusieurs propriétés comme l'opacité, la rotation, le redimensionnement et le déplacement. Ces animations multiaxiales étaient auparavant difficiles à implémenter de manière purement déclarative en CSS, nécessitant souvent des contournements ou des frameworks.

    4. Menus et sous-menus

    L'animation des menus déroulants ou des sous-menus bénéficie grandement de @starting-style, permettant de définir précisément le point d'origine de l'expansion (depuis le haut, le bas ou le côté) et d'autres propriétés visuelles pour une transition naturelle.

    Avantages

    La règle @starting-style présente de nombreux bénéfices par rapport aux approches traditionnelles d'animation d'entrée. Ces avantages touchent aussi bien l'expérience de développement que les performances et la maintenance du code :

    1. Déclaratif et simple : Définit clairement l'état initial sans JavaScript. Cette approche purement CSS permet d'exprimer l'intention directement dans les feuilles de style sans ajouter de logique supplémentaire côté client. La syntaxe est intuitive et s'intègre parfaitement dans le workflow existant des développeurs front-end.

    2. Performance : Optimisé par le navigateur pour de meilleures animations. Étant implémenté nativement par les navigateurs, @starting-style peut bénéficier d'optimisations internes que les solutions JavaScript ne peuvent pas atteindre. Les animations sont plus fluides et consomment moins de ressources, particulièrement important sur les appareils mobiles… Même si, soyons francs, nous allons plutôt éviter les animations sur mobile.

    3. Cohérence : Évite les sauts ou comportements inattendus lors de l'apparition d'éléments. Sans cette règle, les éléments peuvent apparaître brusquement avant que les transitions ne commencent, créant une expérience visuelle dégradée. @starting-style garantit que les éléments commencent leur vie dans le DOM avec l'état visuel exact que vous avez défini.

    4. Lisibilité du code : Avec la syntaxe imbriquée, les états initiaux et finaux sont déclarés à proximité l'un de l'autre, rendant le code plus compréhensible et plus facile à maintenir.

    Inconvénients

    Malgré ses nombreux avantages, @starting-style présente certaines limitations qu'il est important de considérer avant de l'intégrer dans vos projets. Ces inconvénients sont principalement liés à sa nouveauté et à sa portée d'application limitée :

    1. Support navigateur : Fonctionnalité récente qui n'est pas encore prise en charge par tous les navigateurs. Ce point est crucial pour les applications web devant fonctionner sur un large éventail de navigateurs, y compris des versions plus anciennes. Vous devrez prévoir des solutions de repli pour garantir une expérience acceptable pour tous les utilisateurs. Ce point est détaillé un peu plus loin.

    2. Cas d'usage limités : Ne s'applique qu'aux éléments nouvellement insérés dans le DOM. Cette règle n'a aucun effet sur les éléments existants ou lorsque vous modifiez des propriétés sur des éléments déjà présents. Il s'agit vraiment d'une solution spécialisée pour les animations d'entrée, pas pour les animations générales.

    3. Débogage : Peut être difficile à déboguer car l'état n'est visible que brièvement pendant l'insertion dans le DOM. Les outils de développement actuels ne sont pas toujours adaptés pour inspecter ces états transitoires, ce qui peut compliquer le processus de mise au point des animations. Ceci dit, rien ne vous empêche d'augmenter artificiellement la durée de l'animation pour la tester.

    4. Complexité potentielle : Peut rendre le code CSS moins prévisible si utilisé de manière excessive. Comme avec toute technique d'animation, il est facile d'en faire trop en créant des interfaces trop animées qui peuvent distraire ou fatiguer les utilisateurs. Une utilisation judicieuse reste nécessaire.

    Exemples pratiques

    Exemple 1 : Fondu à l'apparition

    .fade-in {
      opacity: 1;
      transition: opacity 0.5s ease-in-out;
    
      @starting-style {
        opacity: 0;
      }
    }
    

    Exemple 2 : Animation d'entrée avec translation

    .slide-in {
      translate: 0;
      transition: translate 0.8s ease-out;
    
      @starting-style {
        translate: -100% 0;
      }
    }
    

    Exemple 3 : Animation combinée

    .fancy-entrance {
      opacity: 1;
      scale: 1;
      rotate: 0deg;
      transition: 
        opacity 0.5s ease-out, 
        scale 0.7s cubic-bezier(0.175, 0.885, 0.32, 1.275),
        rotate 0.7s cubic-bezier(0.175, 0.885, 0.32, 1.275);
    
      @starting-style {
        opacity: 0;
        scale: 0.6;
        rotate: -10deg;
      }
    }
    

    Démo interactive

    Voici le code HTML et CSS pour une démo simple que vous pouvez tester :

    Voir la démo

    Compatibilité des navigateurs

    La règle @starting-style est encore en développement, même si son support est déjà relativement universel :

    Vérifiez toujours la compatibilité actuelle sur Can I Use avant d'utiliser cette fonctionnalité en production. Par exemple, notez que Firefox n'accepte pas cette fonctionnalité lorsqu'appliquée à display: none.

    Alternatives pour les navigateurs non supportés

    Pour garantir une expérience utilisateur cohérente sur tous les navigateurs, y compris ceux qui ne prennent pas encore en charge @starting-style, plusieurs approches peuvent être envisagées :

    1. Utiliser @supports pour la détection de fonctionnalités : Cette règle conditionnelle vous permet de fournir différentes implémentations selon la prise en charge des fonctionnalités par le navigateur :
    @supports at-rule(@starting-style) {
      /* Styles si @starting-style est supporté */
    }
    

    Seul petit souci : la fonction at-rule() dans @supports est relativement récente et sa compatibilité est beaucoup trop limitée actuellement.

    1. Approche progressive : Une méthode fiable consiste simplement à laisser les navigateurs ignorer silencieusement la règle qu'ils ne comprennent pas :
    /* Style de base qui fonctionne partout */
    .element {
      opacity: 1;
      transition: opacity 0.5s ease;
    }
    
    /* Les navigateurs qui ne comprennent pas `@starting-style` ignoreront cette règle */
    .element {
      @starting-style {
        opacity: 0;
      }
    }
    
    1. Utiliser des classes JavaScript pour gérer les transitions d'entrée :
    const element = document.createElement("div");
    element.className = "element element-entering";
    container.appendChild(element);
    
    // Retirer la classe après une frame pour déclencher la transition
    requestAnimationFrame(() => {
      requestAnimationFrame(() => {
        element.classList.remove("element-entering");
      });
    });
    
    1. Frameworks JavaScript et leurs systèmes de transition : Si vous utilisez déjà un framework, tirez parti de ses capacités intégrées d'animation :
    • Vue.js et son composant <Transition> : Vue propose un système élégant pour gérer les animations d'entrée/sortie.
    • React avec des bibliothèques comme react-transition-group ou framer-motion.
    • Angular avec son système d'animation.
    • Bibliothèques légères comme Alpine.js ou HTMX qui proposent également des solutions pour les animations d'entrée.
    • Bibliothèques spécialisées comme GSAP.

    Ces solutions de frameworks offrent l'avantage d'une compatibilité étendue et sont souvent accompagnées de fonctionnalités supplémentaires comme la gestion des animations lors de la suppression d'éléments (ce que @starting-style ne gère pas).

    La meilleure approche consiste souvent à combiner plusieurs de ces techniques, en commençant par une expérience de base fonctionnelle pour tous les utilisateurs, puis en améliorant progressivement l'interface pour les navigateurs qui prennent en charge les fonctionnalités modernes comme @starting-style.

    Conclusion

    La règle @starting-style représente une avancée significative pour les animations CSS, en simplifiant grandement la création d'animations d'entrée fluides. Même si son support n'est pas encore universel, elle offre une solution élégante et performante pour les animations d'apparition qui étaient auparavant difficiles à implémenter en CSS pur.

    Cette fonctionnalité s'inscrit dans l'évolution continue du CSS vers des capacités d'animation et de mise en page de plus en plus puissantes et déclaratives, réduisant notre dépendance à JavaScript pour des effets visuels sophistiqués.

    Retrouvez l'intégralité de ce tutoriel en ligne sur Alsacreations.com

  • Dans la création de maquettes graphiques, l'accessibilité ne doit pas être une étape supplémentaire en fin de projet, mais une considération intégrée dès les premières phases de conception. Travailler sur Figma avec une approche “accessibility-first” permet d'assurer une expérience inclusive pour tous les utilisateurs et utilisatrices, tout en facilitant l'intégration et la collaboration entre designers et développeurs.

    Pourquoi intégrer l’accessibilité web dès la conception des maquettes graphiques ?

    • Cela améliore l'expérience utilisateur : une conception inclusive bénéficie à toutes les personnes utilisant le site ou le service, dont les personnes en situation de handicap. En optimisant la lisibilité, la navigation et l'ergonomie des interfaces, on améliore l'expérience pour des profils variés comme les personnes âgées, ou encore celles et ceux naviguant dans des environnements contraignants (faible luminosité, forte exposition au bruit, etc.).
    • Cela permet d’anticiper les contraintes techniques, d’aligner les attentes et d’éviter des malentendus en phase d’intégration : un travail collaboratif bien structuré assure une mise en œuvre plus fluide et efficace des bonnes pratiques d’accessibilité.
    • À la création d’un UI Kit (kit d'interface utilisateur), cela permet de fournir une base standardisée et conforme aux RGAA (Référentiel général d'amélioration de l'accessibilité) : on garantit tout le long de la conception que chaque composant respecte les bonnes pratiques d’accessibilité (contrastes suffisants, espaces suffisant autour des éléments cliquables, typographie lisible etc…).
    • Cela permet de réduire les coûts et les itérations : corriger un problème d'accessibilité en phase de conception est bien moins coûteux que de devoir refondre une interface une fois en production.

    Bonnes pratiques pour concevoir des maquettes accessibles sur Figma

    Contraste et couleurs

    Un mini Kit UI sur Figma qui utilise le plugin Color Contrast Checker WCAG

    • Utiliser des plugins comme “Color Contrast Checker WCAG 2.1” pour vérifier le respect des ratios de contraste (WCAG 2.1 AA : 4.5:1 pour le texte normal, 3:1 pour les grands textes). Cela permet de définir une palette de couleurs respectant les standards WCAG (Web content accessibility guidelines) pour garantir une lisibilité optimale.

    • Éviter de transmettre de l'information uniquement par la couleur (ex : ajouter des icônes, des motifs ou des textes explicites).

    • Vérifier que les couleurs utilisées dans les composants d’interface et les éléments graphiques porteurs d’informations sont suffisamment contrastées.

    Typographie et hiérarchie visuelle

    • Privilégier une taille de texte minimale de 16 pixels sur desktop pour assurer une bonne lisibilité.
    • Une bonne pratique serait d'interdire les typographies de type Calligraphie, Déstructuré, OldSchool etc… Il faut privilégier des typographies avec des caractères bien distinguables intégrant nativement plusieurs styles (gras, italique…) : exemple -> Atkinson Hyperlegible, Luciole, Gill Sans…
    • Préférer une structure visuelle claire de l'information avec des niveaux de titres cohérents (passage brutal d’un titre de niveau 1 à un titre de niveau 4, par exemple). ; ceci permet de simplifier la navigation dans la page.

    Composants et interactions accessibles

    • Penser à l’état focus pour tous les composants. Le focus est un indicateur visuel qui montre quel élément interactif (bouton, lien, champ de formulaire) est actuellement sélectionné, par exemple via la navigation clavier. Il est essentiel pour les utilisateurs naviguant sans souris et doit être suffisamment visible avec un contraste marqué et une bordure ou un effet distinctif.
    • Tous les champs de formulaire doivent avoir une étiquette pertinente.
    • Concevoir des boutons avec des zones cliquables d'au moins 44 x 44 pixels.
    • Ajouter des libellés clairs et explicites (pour les boutons ou liens par exemple, il faut éviter "Cliquez ici").

    Conclusion

    Intégrer l'accessibilité dès les maquettes sur Figma est une approche essentielle pour garantir une expérience utilisateur de qualité et englober un maximum de personnes . En appliquant les bonnes pratiques d’accessibilité dès la phase de conception, on assure une meilleure lisibilité, une navigation fluide et des interactions accessibles à tous et toutes, y compris aux personnes en situation de handicap. Cela permet d’anticiper les besoins d’un large éventail d’utilisateurs et garantir que chaque interface soit non seulement fonctionnelle, mais aussi agréable et intuitive à utiliser.

    L’accessibilité ne doit pas être perçue comme une contrainte, mais comme un levier pour un design inclusif, garantissant une expérience optimale pour toutes et tous.

    Publié par Alsacreations.com

  • La notion d'origine est un concept fondamental dans le développement web, en particulier pour la sécurité et la gestion des ressources. Elle est essentielle pour comprendre comment les navigateurs appliquent des politiques de sécurité comme la politique de même origine (Same-Origin Policy) et donc comment ils doivent se comporter lorsqu'une requête HTTP demande un fichier qui n'est pas exactement au même "emplacement" que la page web qui émet cette requête.

    HTTP étant le protocole à la base du web, il a évolué depuis ses premières versions pour se perfectionner et ajouter des notions de sécurité qui n'étaient pas établies dès ses débuts car nous n'avions pas à disposition des technologies et API aussi avancées qu'aujourd'hui pour construire des applications.

    Schéma simplifié d'une requête cross-origin

    La notion de CORS (Cross-Origin Resource Sharing) entre alors en jeu, souvent pour développer à l'aide d'API qu'on interroge avec des requêtes en front et la méthode fetch() ou l'antique AJAX (alias XMLHttpRequest). C'est d'ailleurs dans le standard Fetch du WhatWG que nous retrouvons ces extensions au protocole HTTP, supportées depuis au moins 2014 et remplaçant efficacement JSONP.

    Spécification Fetch sur WhatWG

    Dans le cas présent, ce n'est pas le serveur qui va autoriser ou bloquer l'accès à une ressource mais bien le navigateur, en fonction de l'origine et des éventuels en-têtes HTTP renvoyés par le serveur... principalement pour empêcher les attaques CSRF (Cross-Site Request Forgery) et à limiter l'accès aux ressources sensibles d'un site web par des scripts exécutés depuis une autre origine.

    Sans CORS, un site malveillant pourrait charger une page de votre banque en arrière-plan et récupérer des données sensibles via une requête AJAX ou fetch, voire effectuer une requête malveillante (ex: déclencher un virement).

    Qu'est-ce qu'une origine ?

    Une origine (ou origin en anglais) est définie par trois composants principaux :

    1. Protocole (Scheme) : Le protocole utilisé, surtout http ou https puisqu'on fait du web.
    2. Nom de domaine (Host ou Hostname) : Le nom de domaine du site web, par exemple www.kiwipedia.fr.
    3. Port : Le numéro de port, par exemple 80 pour HTTP ou 443 pour HTTPS.

    Deux adresses ou plus précisément URLs (Uniform Resource Locator) ont la même origine si elles partagent ces 3 composants : le même protocole, le même nom de domaine et le même port.

    Une origine

    Exemples

    • http://www.kiwipedia.fr/page1.html et http://www.kiwipedia.fr/page2.html ont la même origine (facile !).
    • http://www.kiwipedia.fr et https://www.kiwipedia.fr ont des origines différentes (différents protocoles).
    • http://www.kiwipedia.fr et http://kiwipedia.fr ont des origines différentes (différents noms de domaine / sous-domaine).
    • http://www.kiwipedia.fr et http://www.kiwipedia.fr:8080 ont des origines différentes (différents ports).

    Politique de même origine (Same-Origin Policy)

    La politique de même origine est une mesure de sécurité importante, restreignant la manière dont les documents ou scripts d'une origine peuvent interagir avec les ressources d'une autre origine.

    👉 Ce qui est permis par défaut :

    • Une page peut librement interagir avec une autre page de la même origine.
    • Les requêtes fetch ou AJAX peuvent être effectuées vers la même origine sans restriction.

    👉 Ce qui est restreint :

    • Les requêtes asynchrones (XHR, fetch) vers une origine différente sont bloquées par défaut (sauf si CORS est configuré).
    • L'accès aux cookies, au stockage local et aux autres données sensibles est limité à la même origine.

    CORS (Cross-Origin Resource Sharing)

    Pour permettre des interactions entre différentes origines, les serveurs peuvent utiliser CORS qui est un mécanisme permettant à un serveur d'indiquer les origines autorisées à accéder à ses ressources. Cela se fait via des en-têtes HTTP spécifiques dont la plus connue est Access-Control-Allow-Origin.

    Preflight 🛫

    Une requête Preflight est une mesure de sécurité qui protège les utilisateurs contre les attaques CSRF et assure que seules les requêtes autorisées puissent être exécutées. Elle est déclenchée si la requête :

    • Utilise une méthode HTTP autre que GET, POST ou HEAD (comme PUT, DELETE, PATCH).
    • Contient des en-têtes personnalisés (Authorization, X-Custom-Header, etc.).
    • Utilise un Content-Type autre que application/x-www-form-urlencoded, multipart/form-data, ou text/plain.

    Le navigateur va donc envoyer une requête HTTP "CORS Preflight" avant une requête principale lorsqu'une requête vers une autre origine est effectuée. Elle a pour but de vérifier si la requête principale est autorisée.

    Schéma de fonctionnement requête CORS Preflight

    1️⃣ Le navigateur envoie une requête HTTP OPTIONS : elle ne contient aucune donnée sensible (cookies, tokens, etc.) et inclut plusieurs en-têtes spécifiques pour demander les permissions au serveur.

    OPTIONS /api/ HTTP/1.1
    Origin: https://www.alsacreations.com
    Access-Control-Request-Method: POST
    Access-Control-Request-Headers: Content-Type, Authorization
    

    2️⃣ Le serveur répond poliment avec les en-têtes CORS :

    HTTP/1.1 204 No Content
    Access-Control-Allow-Origin: https://www.alsacreations.com
    Access-Control-Allow-Methods: POST
    Access-Control-Allow-Headers: Content-Type, Authorization
    Access-Control-Max-Age: 3600
    
    • Si le serveur accepte la requête, il renvoie une réponse avec les en-têtes CORS (Access-Control-Allow-*).
    • Si les règles CORS du serveur ne permettent pas la requête principale, le navigateur bloque la requête.

    Pour autoriser toutes les origines, on peut utiliser le joker Access-Control-Allow-Origin: * ce qui rend la ressource de facto "publique". Par contre il n'est pas possible d'indiquer une suite d'origines (de domaines) différents. Pour contourner cette limitation, on peut utiliser un langage back-end ou un proxy qui renverra la valeur appropriée en fonction de la provenance de la première requête.

    Exemple de configuration pour Apache

    Pour configurer CORS dans Apache, vous pouvez utiliser le module mod_headers pour définir les en-têtes nécessaires ; il est la plupart du temps activé par défaut. Voici un exemple de configuration :

    <VirtualHost *:80>
        DocumentRoot /var/www/kiwipedia.fr
        ServerName www.kiwipedia.fr
    
        <Directory /var/www/kiwipedia.fr>
            Options Indexes FollowSymLinks
            AllowOverride All
            Require all granted
        </Directory>
    
        # Configuration CORS
        <IfModule mod_headers.c>
            Header set Access-Control-Allow-Origin "https://www.alsacreations.com"
            Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
            Header set Access-Control-Allow-Headers "Content-Type"
        </IfModule>
    </VirtualHost>
    

    Ceci peut aussi être placé dans un fichier .htaccess à la racine de votre projet.

    • Access-Control-Allow-Origin : Spécifie l'origine autorisée à accéder aux ressources. Vous pouvez utiliser * pour autoriser toutes les origines, mais cela n'est pas recommandé pour des raisons de sécurité.
    • Access-Control-Allow-Methods : Méthodes HTTP autorisées pour les requêtes CORS.
    • Access-Control-Allow-Headers : En-têtes HTTP autorisés dans les requêtes CORS.

    Exemple de configuration pour Nginx

    Dans Nginx, vous pouvez ajouter les en-têtes nécessaires dans votre bloc de configuration server. Voici un exemple :

    server {
        listen 80;
        server_name www.kiwipedia.fr;
    
        root /var/www/kiwipedia.fr;
        index index.html index.htm;
    
        location / {
            try_files $uri $uri/ =404;
    
            # Configuration CORS
            add_header 'Access-Control-Allow-Origin' 'https://www.alsacreations.com';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'Content-Type';
    
            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Max-Age' 1728000;
                add_header 'Content-Type' 'text/plain charset=UTF-8';
                add_header 'Content-Length' 0;
                return 204;
            }
        }
    }
    

    Situations délicates et erreurs

    Si l'origine (origin) n'est pas correctement configurée, vous pouvez rencontrer plusieurs types d'erreurs qui seront rapidement visibles dans la console du navigateur

    Console affichant une erreur CORS

    ...et qui peuvent être inspectées dans l'onglet "Réseau" (ou Network).

    Devtools affichant une erreur CORS

    Elles seront principalement liées à la politique de même origine (Same-Origin Policy) et aux configurations CORS (Cross-Origin Resource Sharing). Voici quelques erreurs courantes et les cas où elles peuvent se produire :

    Erreurs CORS

    Access to XMLHttpRequest at 'URL' from origin 'ORIGIN' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

    Cette erreur (la plus courante) se produit lorsque le serveur ne renvoie pas l'en-tête Access-Control-Allow-Origin nécessaire pour autoriser les requêtes provenant d'une origine différente. Cela peut se produire lors de requêtes XHR ou fetch. Dans ce cas il suffira d'ajouter correctement l'en-tête attendu pour débloquer la situation.

    Access to XMLHttpRequest at 'URL' from origin 'ORIGIN' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.

    Cette erreur se produit lorsque vous essayez d'inclure des informations d'identification (comme des cookies ou des en-têtes d'autorisation) dans une requête CORS, mais que le serveur utilise * comme valeur pour Access-Control-Allow-Origin. Pour inclure des informations d'identification, le serveur doit spécifier explicitement l'origine autorisée.

    Access to XMLHttpRequest at 'URL' from origin 'ORIGIN' has been blocked by CORS policy: Method 'METHOD' is not allowed.

    Cette erreur se produit lorsque la méthode HTTP utilisée dans la requête (par exemple, POST, PUT) n'est pas autorisée par le serveur. Le serveur doit inclure cette méthode dans l'en-tête Access-Control-Allow-Methods.

    Erreurs liées à la politique de même origine

    Blocked a frame with origin "ORIGIN" from accessing a cross-origin frame.

    Cette erreur se produit lorsque du code JavaScript d'une page tente d'accéder au contenu d'une iframe provenant d'une origine différente. La politique de même origine empêche cet accès pour des raisons de sécurité (parce que les iframes c'est bien pratique, mais il y a des failles tout de même...)

    Uncaught DOMException: Blocked a frame with origin "ORIGIN" from accessing a cross-origin frame.

    Similaire à l'erreur précédente, cela peut se produire lors de tentatives d'accès à des objets DOM dans une iframe provenant d'une origine différente (on a déjà dit que les iframes c'est pratique, mais... ?)

    Erreurs liées aux cookies et au stockage local

    Failed to read the 'localStorage' property from 'Window': Access is denied for this document.

    Celle-ci est un peu plus "logique" : elle se produit si une page tente d'accéder à localStorage depuis une origine différente, ce qui est interdit, également pour des raisons de sécurité. En général si on s'y prend bien, on ne devrait pas la rencontrer souvent.

    Tester ?

    Si vous devez contourner ces contraintes lorsque vous développez, soit pour tester la configuration avant/après, soit parce que vous n'avez pas encore eu l'occasion d'ajouter les bons en-têtes HTTP, sachez qu'il existe des extensions navigateur qui permettent d'ignorer ces politiques de sécurité par exemple CORS Everywhere sous Firefox. Évidemment il faudra penser à revenir à la situation normale ensuite ;)

    Publié par Alsacreations.com

  • PHPStan est un outil d’analyse statique de code PHP assez simple à utiliser.

    Si vous développez des petits ou moyens projets, par exemple des sites WordPress cela peut vous aider à augmenter la qualité de votre code et détecter les bugs.

    Capture d'écran du site PHPStan

    Ainsi PHPStan va :

    • 📁 analyser la globalité ou un dossier spécifique (ex : votre thème WordPress)
    • 🐛 repérer les erreurs potentielles, les avertissements, les bugs
    • 📰 écrire le résultat dans un fichier de log

    Le log va ressembler à ceci :

    ------ ----------------------------------------------------------------------------------
      Line   wwww/functions.php                                                               
     ------ ----------------------------------------------------------------------------------
      :10    Access to an undefined property object::$ID.
      :77    Variable $wp_query might not be defined.  
      :377   Function add_wiki_link() has no return type specified.                           
      :379   Parameter #5 $callback of function add_menu expects callable(): mixed, '' given. 
     ------ ----------------------------------------------------------------------------------
    

    Selon votre niveau de connaissance de PHP, ces retours peuvent sembler obscurs, mais on s'y retrouve vite avec un peu d'entraînement.

    D'où vient ce nom ? de PHP Static Analysis !

    Wow ! Mindblown !

    Qu'est-ce que l’analyse statique ?

    L’analyse statique consiste à examiner le code source, sans le lancer, pour identifier sur ~10 niveaux (dans le cas de PHPStan) :

    • les erreurs
    • les incohérences de typage
    • les problèmes potentiels de logique
    • plein d’autres trucs

    Concrètement : variables qui n’existent pas, fonctions déclarées avec 2 arguments mais appelées avec 3, etc.

    On peut aussi s’en servir pour s’assurer par avance de la compatibilité avec une version upgradée de PHP.

    Encore un outil de plus ? Oui et non : s’il est intégré par défaut dès le début d'un projet et qu’on connaît la commande, cela permet de gagner du temps en repérant/comprenant un bug potentiel durant / à la fin du développement.

    Installation

    Avec composer, c'est assez rapide : composer require --dev phpstan/phpstan, ce qui l'ajoute aux dépendances de développement dans composer.json :

      "require-dev": {
        "phpstan/phpstan": "^1.12"
      },
    

    Ainsi on pourra lancer vendor/bin/phpstan analyse public/themes >phpstan.log et lire les contenus du fichier log.

    On peut aussi ajouter un script dans composer.json :

      "scripts": {
        "phpstan": "phpstan analyse --memory-limit 1024M >phpstan.log"
      }
    

    Ce qui permettra de le lancer plus aisément avec composer phpstan.

    Configuration

    On ajoute un fichier phpstan.neon qui va contenir des paramètres basiques :

    • scanDirectories: permet de prendre connaissance des déclarations PHP existantes
    • scanFiles : permet de connaître des variables déjà définies
    • level : niveau d'exigeance
    • paths: liste des chemins réellement analysés

    Exemple concret pour un projet WordPress

    parameters:
        scanDirectories:
          - public/wordpress
          - public/plugins
          - public/mu-plugins
        scanFiles: # permet de connaître des variables custom
          - public/wp-config.php
        level: max
        paths:
          - public/themes
    

    On pourra aussi ajouter des règles à ignorer (les plus inoffensives évidemment) lorsqu'on le nombre de lignes relevées est trop important et qu'on ne peut pas tout ré-adapter dans un framework qui ne satisferait pas pleinement PHPStan.

        ignoreErrors:
          - '#Cannot access offset .*#'
          - '#Cannot access property .*#'
          - '#Parameter .* of echo cannot be converted to string#'
          - '#Parameter .* function .* expects .* mixed given#'
          - '#While loop condition is always true#'
          - '#code above always terminates#'
    

    Autres outils ?

    Ce n'est pas le seul de sa catégorie, il existe aussi

    Pas mal non ?

    Un éléphant cool avec des lunettes de soleil pixellisées

    Publié par Alsacreations.com

  • Les animations liées au scroll (ou scroll-driven animations) constituent une nouvelle fonctionnalité CSS permettant de synchroniser des animations avec le défilement d'une page ou d'un conteneur. Cette solution native vient remplacer efficacement les scripts JavaScript habituels, avec une meilleure performance et une implémentation simplifiée de manière générale.

    Apparition d'un bouton "scroll-to-top" lors du scroll de page. Source : Codepen

    Syntaxe de base

    Une animation liée au scroll n'en reste pas moins une animation au sens CSS du terme, elle nécessite donc un @keyframes et une propriété animation comme toute animation CSS classique. Ce sont les propriétés complémentaires animation-timeline et animation-range qui différencient ce type d'animation des autres.

    @keyframes monAnimation {
      /* ici un scénario d'animation */
    }
    .element {
      animation: monAnimation linear auto both; /* Définit l'animation dans son ensemble */
      animation-timeline: scroll(); /* Définit le défilement comme référent */
      animation-range: 0 100%; /* Définit la plage de défilement pour l'animation */
    }
    

    Types d'animations possibles

    La spécification CSS "Scroll-Driven Animations" définit deux modes d'animations, qui diffèrent par le moment auquel l'animation se déclenche :

    • Animation basée sur le scroll (Scroll Timeline) : L'animation se déclenche quand l'utilisateur scrolle au sein d'un conteneur défilable (ou la page entière)
    • Animation basée sur la vue (View Timeline) : L'animation se déclenche quand l'élément entre et sort de la vue d'un conteneur défilable (ou la page entière)

    1. Animation basée sur le scroll (Scroll Timeline)

    /* Animation liée au scroll du conteneur */
    .element {
      animation-timeline: scroll();
    }
    

    La fonction scroll() accepte deux paramètres optionnels :

    • Le conteneur scrollable de référence : nearest (le plus proche, valeur par défaut), root (le document entier), self (l'élément lui-même s'il est scrollable)
    • L'axe de défilement : block (vertical, valeur par défaut), inline (horizontal), y (vertical), x (horizontal)
    Animation de l'entête du site bretzel.alsacreations.com (animation de type "scroll")

    2. Animation basée sur la vue (View Timeline)

    .element {
      /* Animation liée à la vue du conteneur */
      animation-timeline: view();
    }
    

    La fonction view() n'accepte qu'un seul paramètre optionnel : celui de l'axe de défilement : block (vertical, valeur par défaut), inline (horizontal), y (vertical), x (horizontal).

    Navigation du site goetter.fr lorsque chaque section entre dans le viewport (animation de type "view()")

    Dans le détail : animation-range

    La propriété animation-range définit les points de début et de fin de l'animation par rapport au défilement. Elle accepte plusieurs formats de valeurs :

    1. Mots-clés de position

    .element {
      animation-range: entry cover; /* Du moment où l'élément entre dans la vue jusqu'à ce qu'il soit entièrement visible */
      animation-range: cover exit; /* Du moment où l'élément est entièrement visible jusqu'à ce qu'il sorte de la vue */
      animation-range: entry exit; /* Du moment où l'élément entre dans la vue jusqu'à ce qu'il en sorte */
    }
    

    2. Mots-clés avec pourcentages

    .element {
      /* L'animation commence quand 25% de l'élément est visible et se termine quand il est couvert à 75% */
      animation-range: entry 25% cover 75%;
    
      /* L'animation commence quand l'élément est visible à 50% et se termine quand il sort de la vue */
      animation-range: cover 50% exit;
    }
    

    L'excellent outil View Timeline Ranges Visualizer permet de bien se représenter visuellement les différents mots-clés cover, contain, entry, exit, etc.

    3. Valeurs absolues

    .element {
      /* Définit le début à 0% du scroll et la fin à 100% */
      animation-range: 0% 100%;
    
      /* Animation sur une portion spécifique du scroll */
      animation-range: 100px 700px;
    }
    

    Dans le détail : linear auto both

    Les valeurs linear, auto et both sont généralement recommandées pour les scroll-driven animations :

    animation: monAnimation linear auto both;
    
    • Le mot-clé linear assure une progression constante et prévisible liée au scroll et évite les accélérations/décélérations qui peuvent créer des effets indésirables,
    • Le mot-clé auto est nécessaire car il remplace la durée traditionnelle en secondes (valeur 0 par défaut) ici inutile,
    • Le mot-clé both est recommandé car il combine les effets de forwards et backwards et maintient l'état final de l'animation même si l'utilisateur arrête de scroller.

    Animation basée sur un référent personnalisé

    Les scroll-timelines personnalisées permettent de lier une animation au défilement d'un conteneur spécifique plutôt qu'au plus proche ou de la page entière.

    ⚠️ Attention : l'élément animé doit être un descendant du conteneur avec le scroll-timeline-name.

    /* Définition du conteneur avec scroll */
    .scroll-container {
      overflow-y: auto; /* scroll obligatoire sur le conteneur */
      scroll-timeline-name: --nom-du-conteneur; /* nom donné au référent */
     ...;
    }
    
    /* Éléments animés en fonction du scroll du conteneur */
    .animated-element {
      animation: slideIn linear auto both;
      animation-timeline: --nom-du-conteneur; /* lié au conteneur référent */
     ...;
    }
    

    Support navigateurs et enrichissement progressif

    Les animations liées au scroll en CSS sont encore en développement et ne sont pas supportées par tous les navigateurs. Pour assurer une expérience dégradée élégante sur les navigateurs ne reconnaissant pas les scroll-driven animations, @supports est la solution :

    /* Animation déclenchée uniquement si supportée */
    @supports (animation-timeline: scroll()) {
      .element {
        opacity: 0;
        animation: fadeIn linear auto both;
        animation-timeline: scroll();
        animation-range: entry 50% cover 50%;
      }
    }
    

    Un exemple concret : une barre de progression animée au scroll

    Barre de progression de lecture lors du défilement de la page. Source : Codepen
    <div class="progress">
      <div class="progress-bar"></div>
    </div>
    
    .progress-bar {
      --progress-color: hotpink;
      --progress-size: 40px;
      position: fixed;
      top: 0;
      width: 100%;
      height: var(--progress-size);
      background: var(--progress-color);
    }
    
    @supports (animation-timeline: scroll()) {
      .progress-bar {
        animation: scale linear auto both;
        animation-timeline: scroll(root);
        animation-range: 0 100%;
      }
      @keyframes scale {
        from {
          scale: 0 1;
        }
        to {
          scale: 1 1;
        }
      }
    }
    

    Accessibilité

    Dans certaines conditions, les animations ne sont pas toujours les bienvenues. C'est le cas notamment pour les personnes souffrant de troubles liés au mouvement ou à l'attention. Il est donc impératif de respecter les préférences d'accessibilité de l'utilisateur et c'est là qu'intervient le média CSS prefers-reduced-motion.

    La valeur reduce s'assure de ne pas déclencher d'animation lorsqu'elle n'est pas souhaitée :

    @media (prefers-reduced-motion: reduce) {
      .animated-element {
        animation: none;
      }
    }
    

    Performances

    Pour des raisons relativement évidentes, toute animation à l'écran peut se révéler coûteuse en performance. Il est donc important de suivre quelques bonnes pratiques :

    .animation-optimisee {
      will-change: transform;
      animation: slide linear auto both;
      animation-timeline: scroll();
    }
    

    Quelques démos et cas pratiques

    Parmi la foule de démos trouvées sur les internets, voici un petit panel pour aller encore plus loin et se faire une idée des possibilités offertes par cette nouvelle spécification CSS :

    Conclusion

    Les animations liées au scroll en CSS représentent une avancée majeure pour les animations web, offrant une solution à la fois native et performante pour concevoir des expériences interactives liées au défilement. Bien que le support navigateur soit encore en développement, cette technologie est promise à un bel avenir et mérite d'être considérée pour les projets modernes, à condition d'observer quelques recommandations utiles telles que la prise en compte de l'accessibilité et de la performance.

    Publié par Alsacreations.com

  • Il a toujours été complexe de définir avec précision un niveau de support navigateur dans les projets web, d'autant plus avec la variété des plateformes (mobile, desktop) et malgré la concentration du marché autour d'un nombre réduit de moteurs.

    Navigateurs web

    D'un côté car de multiples langages entrent en jeu pour l'intégration (interprétation/reconnaissance des balises HTML et des propriétés CSS), développements (syntaxe JavaScript et API utilisables, version de HTTP, protocoles et en-têtes). D'un autre côté car avec les mises à jour constantes de toutes parts, cette grille de lecture est changeante, entre le début et la fin d'un projet, si tant est qu'il y ait une fin.

    L'approche par dégradation gracieuse qui a été définie comme une bonne pratique pour ne pas exclure un public non-technophile, bien que très appréciable sur le papier, n'est plus toujours applicable tant la dépendance à des frameworks tout-en-un impose déjà de reconnaître toute une panoplie de fonctionnalités et ne plus permettre de se reposer sur une version dégradée, voire brute d'un site ou d'une application web.

    Les plus gros acteurs du web qui ne manquent pourtant pas de moyens et d'un public très large, ont progressivement abandonné les alternatives statiques minimalistes qui pouvaient exister. Nous avons bien plus tendance à vouloir exploiter les derniers outils à la mode, quitte à laisser des personnes sur le bord des autoroutes de l'information, là où par le passé il fallait bien plus faire attention au support des anciens navigateurs.

    Un peu de transpilation

    Des solutions existent pour automatiser et faciliter l'interprétation de code récent sur d'anciennes plateformes.

    En CSS, si une propriété récente n'est pas reconnue, la mise en page ou l'apparence sera dégradée mais cela ne devrait pas empêcher la consultation et l'usage (en théorie) ; on utilise aussi autoprefixer pour éviter d'écrire des préfixes vendeurs, mais cela devrait disparaître à terme.

    En JavaScript, on a longtemps transpilé, par exemple avec l'aide de Babel du code ECMAScript très récent vers des versions rétro-compatibles, utilisant des syntaxes plus communes, cela se passe en général bien ; par contre si une API ou fonctionnalité native du navigateur est absente c'est plus problématique et il faut passer par un fallback, un shim, un polyfill, c'est-à-dire un bout de code plus ou moins conséquent qui va tenter de reproduire plus ou moins fidèlement ce que le navigateur ne reconnaît pas tout seul.

    En HTML étant donné la relative stabilité des balises et les solutions de repli possibles jusqu'à l'interprétation du contenu en texte brut, la question se pose moins... en théorie : deux éléments largement reconnus comme <details> et <summary> ont provoqué des tourments pour les lecteurs d'écran, Voiceover iOS ne reconnaissant pas le rôle de bouton de summary. Désormais au tour de <dialog> et popover : il y a de nouveaux éléments censés simplifier et remplacer des implémentations ARIA imparfaites mais les navigateurs et/ou lecteurs d'écran ne suivent pas ce rythme (et/ou leur spécification d'ailleurs).

    Browserslist

    Dans le seul aspect technique, une bibliothèque a aidé jusqu'à présent : Browserslist permet dans un fichier de configuration ou directement dans package.json de définir par des mots simples quelle "quantité" du marché des navigateurs on souhaite cibler. Par exemple > 0.5%, last 5 versions, not dead indiquera aux autres outils de compilation (Babel, Autoprefixer, Postcss...) sur quelles instructions se reposer pour satisfaire cette exigence de rétro-compatibilité.

    Le site va nous permettre d'obtenir un tableau très détaillé des versions et une estimation de la population globale qui répondra à cette condition.

    Capture d'écran de Browserslist

    CanIUse

    Vous connaissez Can I use et ses nombreux tableaux, que l'on peut affiner par zone géographique, par usage et par date. Avant de lancer un nouveau développement on pourra consulter l'une ou l'autre fonctionnalité, mais malheureusement pas toutes, cela devient tentaculaire.

    Can i use webp

    Approche par version de navigateur (avant)

    Exemple de formule : "Support de Firefox 37, d'Internet Explorer 11, et Chrome 42".

    Durant de nombreuses années, les navigateurs ont connu des progrès moins fluides, moins granulaires et plus espacés dans le temps, car les mises à jour automatiques n'étaient pas la règle : il était humainement possible de suivre l'évolution des versions et d'avoir en tête les nouveautés apportées, par exemple entre Internet Explorer 5 et 6.

    Désormais, avec des numérotations de versions qui se comptent en dizaines et un rythme de sorties qui se compte en semaines imposé par les équipes de Chromium, puis Firefox, puis Safari (WebKit), il devient difficile de définir avec précision un tableau de support pour un projet d'autant plus que les API envisagées deviennent de plus en plus complexes pour transformer le web en plateforme complète de développement. Si certaines entreprises choisissent la "stabilité" de Firefox ESR (Extended Support Release) pour bloquer les fonctionnalités à une certaine version, cela reste marginal.

    Notons l'initiative de Simon Willison qui a codé un outil permettant d'obtenir un historique plus détaillé du support déjà affiché par la documentation MDN avec MDN timelines.

    Approche par ancienneté relative

    Formule possible : "Support optimal des navigateurs desktop jusqu'à 2 ans et en mode dégradé jusqu'à 5 ans, support des navigateurs mobiles jusqu'à 3 ans".

    Avec notre écosystème mouvant, on peut s'orienter vers un support mesuré à l'ancienneté des navigateurs. On ne mesure plus le nombre de versions écoulées mais le temps. Cela a l'avantage d'être souple et cela peut sembler "toujours à jour" quoiqu'il arrive... mais concrètement on sera toujours dans une zone approximative au fur et à mesure de la durée de vie d'un projet : faut-il mesurer par rapport à la date de démarrage des développements, ou de mise en ligne définitive ? Quid du paysage technique dans 6 mois, 1 an et plus.

    Approche par baseline

    Avec toutes ces difficultés et l'impossibilité de suivre exhaustivement les versions et leur immense tableau de support, la plus récente vision est le pragmatisme (et optimisme ?) : Baseline définit deux statuts :

    Intitulé Logo Définition
    Nouveauté disponible Baseline new la fonctionnalité est compatible avec tous les principaux navigateurs : elle est interopérable.
    Disponibilité générale Baseline widely 30 mois se sont écoulés depuis la nouvelle date d'interopérabilité. Cette fonctionnalité peut être utilisée par la plupart des sites
    Disponibilité limitée Baseline limited C'est trop récent, peu ou pas supporté.

    On retrouve un tableau aussi très fourni grâce à Web Platform Status, à l'initiative de l'équipe de Chrome. Il faut les comprendre, les nouveautés s'enchaînent plus vite qu'il n'est possible à un humain de les suivre et à Google d'abandonner des produits.

    Tableau baseline

    C'est probablement ce qui fait le plus sens à l'heure actuelle, avec un repère temporel par année (baseline 2023, 2024, 2025...) et un niveau de confiance affiché pour les développeuses et développeurs bien plus compréhensible pour la question "est-ce que je peux utiliser ce truc, ou est-ce que ça va casser ?".

    On retrouve aussi Baseline sur MDN

    MDN Baseline

    ...et sur CanIUse.

    Can I use baseline

    Cet alignement entre équipes de développement de moteurs, documentations et toutes les personnes qui font du web en général a le mérite d'être plus abordable.

    Mais alors on fait quoi de Baseline ?

    Baseline widely

    Avec une fonctionnalité annoncée en "Disponibilité générale" : on peut assez bien prendre une décision, on sait qu'elle est intéropérable depuis un moment ayant permis à la majorité des internautes d'effectuer les mises à jour nécessaires... n'est-ce pas ? Mais rien ne le garantit, comme toujours un pourcentage non négligeable de personnes seront contraintes pour des raisons de moyens ou d'outils, et rien ne garantit non plus que l'on soit irréprochable du côté des outils d'accessibilité.

    👉 On peut décider d'utiliser la fonctionnalité pour un projet qui démarre, ou qui se met à jour dès à présent, avec toutefois un point d'attention à prévoir une solution de repli si son absence est bloquante pour un pourcentage significatif d'internautes.

    Baseline limited

    Avec une fonctionnalité annoncée en "Disponibilité limitée" : c'est assez évident, un ou plusieurs moteurs de navigateurs n'en sont pas équipés (ou les versions de Chromium sont trop fraîches), une majorité d'internautes n'y auront pas accès.

    👉 On évite d'y toucher.

    Baseline new

    Avec une fonctionnalité annoncée en "Nouveauté disponible" : c'est plus délicat. Depuis quand est-elle disponible, pour qui, et quel est le délai qui court (pour les 30 mois), vient-il de démarrer ou est-on proches de passer en statut "Disponibilité générale" ? C'est pourquoi https://webstatus.dev/ précise des dates (lorsqu'on coche les bonnes options) :

    Web Platform Status fonctionnalités avec dates

    Par exemple appearance nouveau en 2022 est passé en "disponibilité générale" en septembre 2024. La media query prefers-contrast obtiendra le même sésame en décembre 2024, tandis que pour forced-colors ce sera en mars 2025.

    🤷 Au cas par cas ?

    Prenons quelques exemples (à la date de publication) :

    Fonctionnalité Statut Date d'annonce / disponibilité prévue Part de la population en France/Europe
    Attribut HTML inert Baseline new avril 2023 / octobre 2025 95%
    backdrop-filter Baseline new septembre 2024 / mars 2027 98%
    requestVideoFrameCallback Baseline new octobre 2024 / avril 2027 98%
    WebUSB Baseline limited aucune précision* 75%

    On notera donc des étrangetés dans le pragmatisme qui devrait faire sens : accent-color est reconnu partout mais encore noté "Limité" ; requestVideoFrameCallback ne devrait accéder à "Disponibilité générale" qu'en 2027 mais est déjà implémenté en réalité par tous les moteurs actuels ; le vénérable zoom n'a été listé qu'à partir de mai 2024, etc.

    Alors, "ça dépend" ?

    Oui. Des dates en question, de l'importance des technologies à supporter et de leur caractère bloquant ou non-bloquant. Les étiquettes proposées par l'approche baseline sont intéressantes et pratiques : d'un coup d'oeil on peut se faire une première idée et échanger dans des termes simples avec des collègues ou des clients. Mais dans la réalité, on ne sera pas épargnés par les tableaux de supports, les projections temporelles et les pourcentages divers. C'est notre métier, chacun saura prendre les bonnes décisions ;)

    Publié par Alsacreations.com

  • Les import maps sont une fonctionnalité moderne de JavaScript qui permet de contrôler comment le navigateur résout les imports de modules.

    Vous avez sûrement déjà rencontré dans vos projets des modules JavaScript, aussi appelés ESM (EcmaScript Modules) qui induisent un découpage des portions de code et de données. C'est très pratique, avec certains fichiers - en général fournis par une bibliothèque - qui exportent des fonctions, tableaux, objets, etc. pour les mettre à la disposition d'autres fichiers - en général les vôtres - qui les importent.

    On sait aussi que depuis quelques années de tels scripts peuvent être chargés dans le navigateur à l'aide de la balise script équipée de l'attribut type="module".

    Que sont les import maps ?

    Une déclaration d'import map pourrait être la suivante à l'aide de la nouvelle valeur type="importmap".

    <script type="importmap">
    {
        "imports": {
            "logger": "/js/logger.js",
            "tools/": "/js/tools/",
            "lodash": "https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"
        }
    }
    </script>
    

    On peut constater qu'il s'agit d'un objet, contenant une clé "imports", elle même définissant une correspondance entre des noms courts et des chemins longs.

    On peut aussi faire appel à un beau fichier JSON contenant cette "carte", ce qui semblera plus propre que de les déclarer inline dans le corps de la page.

    <script type="importmap" src="/map.json">
    

    Avantages

    Cela a pour but de :

    • Simplifier la gestion des dépendances dans le navigateur.
    • Permettre d'utiliser des noms simples plutôt que des chemins complets.
    • Éviter d'avoir à spécifier les versions dans chaque import.

    Ainsi on pourra écrire ensuite

    import _ from 'lodash';
    
    // Import depuis un chemin local
    import { log } from 'logger';
    
    // Import via un préfixe
    import { maFonction } from 'tools/malib.js';
    

    On améliore la lisibilité et on peut plus facilement changer les versions et les chemins réels vers les dépendances.

    Il y a quelques petites limitations : les projets d'envergure avec des frameworks et des outils de compilation tels que Vite, viennent déjà avec des solutions de résolution de modules. Certaines fonctionnalités qui optimisent le développement et le poids des ressources (hot reloading, tree shaking) ne sont pas disponibles. C'est pourquoi on s'en servira plutôt pour du prototypage rapide, des petites démonstrations techniques ou des projets qui ne passent pas par des frameworks évolués.

    L'attribut type="importmap" est supporté par tous les navigateurs actuels et considéré comme faisant partie de la baseline 2023.

    Publié par Alsacreations.com

  • Mermaid est un langage qui permet de créer des diagrammes dynamiques directement dans des fichiers Markdown c'est à dire en mode texte.

    Il est très utile pour représenter visuellement des concepts complexes sous forme de graphiques, schémas, diagrammes (comme des diagrammes de flux, des organigrammes, des graphiques Gantt, etc.) dans un format simple et lisible.

    Un beau schéma vaut mille mots de markdown.

    Mermaid s'intègre directement avec des plateformes et outils de documentation comme GitHub, GitLab, Docusaurus, MkDocs, ou Jekyll. Ainsi on peut inclure des diagrammes légers dans des fichiers README ou des wikis sans avoir besoin de les exporter en images.... images qui seront souvent non modifiables par les autres personnes participant à un projet car elles n'auront pas les sources tandis qu'avec Mermaid la source de l'image sera dans le document.

    Le résultat étant généré à la volée en SVG (vectoriel) il s'adaptera à la résolution sans difficulté ainsi qu'à la préférence de thème, clair ou sombre (dark mode).

    Exemples

    La syntaxe de mermaid est assez basique, mais efficace.

    graph TD;
        A-->B;
        A-->C;
        B-->D;
        C-->D;
    

    La première ligne définit le type de diagramme et les suivantes la logique que l'on souhaite écrire. Remarquez qu'il n'y a pas d'instruction de positionnement de bloc, on s'attache juste à décrire les relations, et la bibliothèque JavaScript se charge du reste en transformant ce texte en un beau schéma.

    Graphique en mermaid

    On peut même générer des flux Git. 🤓

    gitGraph
        commit
        commit
        branch develop
        checkout develop
        commit
        commit
        checkout main
        merge develop
        commit
        commit
    

    Mermaid git

    Voici un diagramme de séquence bien complexe à dessiner, et pourtant simple à écrire en texte.

    sequenceDiagram
        Gitlab->>Gitlab: reçoit un Push sur main
        Gitlab->>Runner: Lance un runner
        Runner->>Serveur: Connexion SSH
        Runner->>Serveur: Envoie les instructions shell du job
        Serveur-->>Gitlab: Connexion SSH vers Gitlab
        Serveur-->>Gitlab: git pull
        Gitlab-->>Serveur: Fichiers
        Runner->>Gitlab: Retourne les logs
        Note over Runner, Serveur: Fin
    

    Voici le rendu sur GitHub avec en bonus quelques boutons pour zoomer, se déplacer, copier, etc.

    Mermaid séquence sur GitHub

    Avantages

    • C'est du texte.
    • C'est modifiable.
    • C'est versionnable.
    • C'est adapté aux wikis.
    • C'est multi-plateforme.
    • C'est compris par GitHub et GitLab.

    Inconvénients

    • Il faut a priori connaître sa syntaxe (encore une autre...) (mais... des outils existent)

    Support par GitHub et GitLab

    Les deux plateformes les plus répandues de versionnement de code source supportent nativement Mermaid, ce qui est un grand avantage pour documenter vos projets, vos fichiers README.md de manière compréhensible et remplacer de longues explications de texte par des schémas limpides.

    Documentation de GitHub

    Mermaid expliqué sur GitHub

    Documentation de GitLab

    Mermaid expliqué sur GitHub

    Documentation officielle

    La documentation de Mermaid est très bien conçue et vous permet rapidement de cerner tout ce que permet la bibliothèque

    Documentation de mermaid

    Éditeurs en ligne

    Pour faciliter les opérations, des éditeurs en ligne très bien conçus vous permettent de partir de modèles et de vous adapter progressivement à la syntaxe avec un aperçu du résultat.

    • Mermaid Live Editor - gratuit, très souple, affichage plein écran et quelques options de mise en forme.

    Mermaid Live Editor

    Il permet aussi le partage par URL c'est-à-dire d'encoder le contenu dans l'adresse et de la diffuser pour retrouver le schéma d'origine, par exemple pour le résultat ci-dessus :

    https://mermaid.live/edit#pako:eNo1T8tOxDAM_BUr5-4P9IDUBwcQW0A9tnuwErON2CTFSYBV0w_iO_gxslvWkqXxaGZsL0I6RaIUbyf3JSfkMFrIVQ1d_A4H2O3ukpyIc8OJPChn7e9PBmThsX_uEtSboR6ql4erHpqNaYd5mvfnShlttyC8QO0DU7qJmmXZI2ts6wI88SdFhv71aV3_z7gGJibvXWSZ9_qAQX9E8gnuh6btDiAKYYgNapXfWC6-UYSJDI2izFAhv49itGvWYQyuP1spysCRCsEuHqfbEGeFgVqNR0azkesfwYJfFw
    

    Mermaid Editor

    Génère des rendus en ASCII art (ou dans un Terminal).

    $ cat test.mermaid
    graph LR
    A --> B & C
    B --> C & D
    D --> C
    
    $ mermaid-ascii --file test.mermaid
    +---+     +---+     +---+
    |   |     |   |     |   |
    | A |---->| B |---->| D |
    |   |     |   |     |   |
    +---+     +---+     +---+
      |         |         |
      |         |         |
      |         |         |
      |         |         |
      |         v         |
      |       +---+       |
      |       |   |       |
      ------->| C |<-------
              |   |
              +---+
    

    Pimp my mermaid

    Mermaid est un projet open source, ce qui signifie qu'il est possible de l'étendre ou de le modifier pour des besoins spécifiques si nécessaire.

    Enfin, on peut avoir accès à des thèmes de couleur

    • par défaut - pour tous les diagrammes.
    • neutre - idéal pour les documents en noir et blanc qui seront imprimés.
    • sombre - convient bien aux éléments de couleur sombre ou au mode sombre.
    • forêt - avec des nuances de vert.
    • base - le seul thème qui peut être modifié

    Bref, c'est rudement pratique, on le prend en main facilement et vous serez fiers de pouvoir documenter vos projets, wiki, issues avec de beaux schémas compréhensibles.

    Publié par Alsacreations.com

  • Tout le monde connaît désormamis le terme "URL" pour désigner une adresse sur le web. Bien que certains navigateurs tentent de la simplifier au maximum dans la barre de navigation (et peut être un jour de l'invisibiliser), elle revêt une importance capitale pour savoir où on est, et où on va.

    URI URN URL

    Première chose à savoir : URL et URN sont des sous-types d'URI.

    URI

    L'URI (Uniform Resource Identifier) est le terme le plus général qui englobe à la fois URL et URN : c'est une chaîne de caractères qui identifie de manière unique une ressource. Cela peut se faire par l'emplacement de la ressource, son nom, ou les deux.

    Un chemin de fichier local pourrait donner une bonne idée d'URI :

    file:///C:/Documents/Dossier/image.png
    

    Dans cet exemple :

    • Le schéma est file (on comprend donc que la ressource est locale).
    • Le séparateur :// (que l'on retrouve également dans les URLs) distingue le schéma de l'adresse, c'est une convention admise partout, mais ici nous sommes dans un cas particulier : en général les // précèdent un nom d'hôte, nom de domaine, adresse IP or ici nous sommes en local donc il n'y en a pas, c'est pourquoi on peut voir directement trois slash à la suite ///.
    • L'adresse (locale) vers la ressource est donc /C:/Users/Utilisateur/Documents/monfichier.txt c'est-à-dire à peu près un chemin que vous pouvez écrire de manière traditionnelle sur un système d'exploitation Windows.

    URN

    L'URN (Uniform Resource Name) est un type d'URI, identifiant une ressource par son nom dans un espace de noms particulier. Ici on ne spécifie pas comment accéder à la ressource (pas de protocole par exemple) mais seulement son identité, qui en théorie devrait être unique et persistante, indépendemment d'un endroit de stockage (contrairement à une URL).

    Par exemple un numéro d'ISBN (International Standard Book Number) qui identifie de manière unique un livre peut être écrite sous forme d'URN.

    urn:isbn:978-2-212-67683-9
    

    On peut également écrire un numéro de téléphone.

    urn:tel:+33123456789
    

    Ou encore un UUID (Universally Unique IDentifier) qui est très utilisé en développement, ou pour donner des identifiants à des ressources matérielles.

    urn:uuid:123e4567-e89b-12d3-a456-426614174000
    

    Dans ces exemples

    • Les séparateurs sont des :
    • On préfixe par urn
    • On ajoute le protocole/schéma.
    • On termine par l'identifiant de la ressource.

    URL

    L'URL quant à elle sert évidemment d'adresse pour chaque page web, fichier quelconque sur Internet et plus particulièrement sur le web même si ce n'est pas le seul protocole qui l'exploite.

    Par exemple on peut écrire une URL pour une adresse FTP (File Transfer Protocol) - qui d'ailleurs à une époque pouvait être reconnue et exploitée par la plupart des navigateurs :

    ftp://login:password@ftp.schnapsgpt.com:21/dossier/image.png
    

    On reconnaît les mêmes principes que précédemment avec le schéma (protocole), les sépararateurs divers :, @, / et l'ajout ici d'informations d'identifications pour accéder à la ressource login:password ainsi que le port 21.

    Dans le cas d'une URL pour le web, nous retrouverons le protocole http ou https (sécurisé d'une certaine façon).

    https://www.alsacreations.com/article/lire/1930-URL-URI-URN-quelles-differences.html
    

    Ces adresses apportent des avantages :

    • Elles reflètent souvent la structure hiérarchique d'un site web pour comprendre l'organisation du contenu (si on a bien fait le travail de structuration).
    • Elles permettent le partage par lien, universel entre des milliers d'applications, même sur mobile.
    • Elles permettent d'identifier la source d'une information par le nom de domaine... sauf si des personnes fourbes réservent un nom avec des caractères internationaux/Unicode très similaires, soit une attaque homographe pour faire pointer vers un autre site non moins fourbe.

    En bonus, de belles URLs sont exploitées par les robots des moteurs de recherche (coucou Googlebot) pour mieux comprendre et indexer les pages web: bien pensées elles peuvent améliorer le référencement d'un site.

    D'où vient l'URL ?

    L'invention de l'URL est attribuée à Tim Berners-Lee (encore lui !) l'inventeur de bien des composants essentiels du web : HTML, le premier navigateur, le premier serveur (pour lui répondre), et le protocole HTTP. Rien que ça.

    Cet adressage date donc des années 1990 lorsque Tim développait ses projets au CERN à Genève. Il souhaitait pouvoir fournir un adressage des documents et autres ressources sur le réseau informatique qu'il était en train de créer. Au fur et à mesure, le concept a été amélioré par l'IETF (Internet Engineering Task Force).

    En savoir bien plus

    Écoutez l'épisode Disséquons une URL, première partie de l'excellent Carré, Petit, Utile : Le programme radio des gens du numérique.

    L'URL est un standard décrit par la RFC 1738, précisée dans le cas des liens mailto par la RFC 2368... complétée par la RFC 2396 sur les URI, puis par la RFC 3986 l'élargissant encore plus aux URI, ainsi que la RFC 8089 sur les noms locaux de fichiers, et ainsi de suite.

    Publié par Alsacreations.com

  • Nous n'avons pas fini d'entendre parler de les LLM (grands modèles de langages) et de l'Intelligence Artificielle. Outre les sytèmes en ligne (souvent payants) il est possible d'interroger un modèle local (gratuitement) par l'intermédiaire d'un peu de JavaScript.

    Pour ceci nous utiliserons :

    Ollama

    Ollama

    Ollama est une application disponible pour Linux, macOS, Windows qui sert d'interface de gestion de LLM. Voyons la comme une sorte de Docker qui ira piocher dans un catalogue d'images disponibles en ligne, faciles à télécharger et à exécuter en une seule instruction ou presque en précisant bien le nom du modèle souhaité.

    Les commandes essentielles après avoir téléchargé et installé Ollama :

    • ollama list liste les modèles déjà téléchargés
    • ollama pull <modèle> télécharge un nouveau LLM
    • ollama run <modèle> exécute
    • ollama stop <modèle> met fin à l'exécution
    • ollama rm <modèle> supprime

    Pour l'occasion, nous utiliserons llama 3.2

    ollama pull llama3.2
    

    Pour préciser une autre version du modèle avec nombre de paramètres (comprenez complexité et poids) différent, on pourra par exemple indiquer ollama pull llama3.2:1b pour 1B soit un milliard de paramètres.

    Jusque-là si tout va bien, nous pouvons d'ores et déjà discuter en mode texte brut par un ollama run llama3.2.

    Package JavaScript Ollama

    Cette bibliothèque nous permet d'aller interroger Ollama installé localement en définissant le modèle, le message à lui envoyer et en traitant la réponse. De manière très basique on peut se servir de console.log mais ce n'est pas très intéressant car bloquant jusqu'à obtenir la totalité de la réponse ; la promptitude du modèle dépendra aussi de la puissance de votre machine et de votre mémoire vive disponible.

    À l'aide d'un environnement Node.js (déjà installé n'est-ce pas ?), nous pouvons poursuivre.

    1. Créer un dossier quelconque 📁 pour notre projet.

    2. Installer la dépendnace avec npm install --save ollama (ou avec pnpm)

    npm install ollama

    1. Écrire un petit script kiwi.mjs pour importer ollama et appeler chat() afin de lancer la discussion
    import ollama from 'ollama'
    
    const response = await ollama.chat({
      model: 'llama3.2',
      messages: [{ role: 'user', content: 'Quelle est la recette du cake au kiwi ?' }],
    })
    // ⚠️ Ceci peut prendre beaucoup de temps car on attend la réponse complète
    console.log(response.message.content)
    

    Il suffira de l'exécuter en ligne de commande avec node kiwi.mjs.

    Exécution d'ollama dans le terminal

    Pour streamer la réponse, c'est-à-dire la restituer au fur et à mesure de l'ajout de mots par le LLM, on peut se servir de l'alternative en activant l'option stream.

    import ollama from 'ollama'
    
    const message = { role: 'user', content: 'Quelle est la recette du cake au kiwi ?' }
    const response = await ollama.chat({ model: 'llama3.2', messages: [message], stream: true })
    for await (const part of response) {
      process.stdout.write(part.message.content)
    }
    

    Un bon nombre d'autres paramètres et méthodes existent dans cette interface, il suffira de consulter la documentation pour les découvrir.

    Et en application web ?

    C'est possible ! Une page interrogera le modèle via ollama :

    Architecture d'application web utilisant l'IA

    Pour transformer le tout en une petite application web utilisable dans le navigateur...

    1. Nous ajoutons express
    npm install --save express
    

    Ce qui va permettre de construire un couple client/serveur minimaliste avec deux fichiers :

    • server.mjs, qui sera à l'écoute des messages
    • public/index.html, qui contiendra un formulaire et affichera le résultat

    Les explications sont fournies par des commentaires dans le code source suivant, à vous de jouer en vous l'appropriant.

    1. Fichier server.mjs
    import express from 'express';
    import ollama from 'ollama';
    
    const app = express(); // Instance d'Express
    const port = 3000; // Port à l'écoute
    
    app.use(express.json());
    
    // On sert le dossier public en statique, dans lequel on place notre page index.html
    app.use(express.static('public'));
    
    // On accepte les requêtes POST vers /chat
    app.post('/chat', async (req, res) => {
      // Notre message sera envoyé dans le corps de la requête (body)
      const message = { role: 'user', content: req.body.content };
    
      // La réponse provenant du LLM est une promesse
      const response = await ollama.chat({ model: 'llama3.2', messages: [message], stream: true });
    
      // La réponse envoyée à la page web dispose d'en-têtes HTTP
      //... permettant de faire persister la connexion
      res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
      });
    
      // Pour toute portion de réponse reçue, on la stream
      for await (const part of response) {
        res.write(`data: ${JSON.stringify(part.message)}\n\n`);
      }
    
      res.end();
    });
    
    // On écoute sur le port configuré
    app.listen(port, () => {
      console.log(`Serveur en écoute : http://localhost:${port}`);
    });
    
    1. Page public/index.html correspondante :
    <!doctype html>
    <html lang="fr">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>KiwIA</title>
        <style>
        /* à personnaliser selon vos envies */
        body { font-family: system-ui; background: #222; color: #fff; padding: 2rem; }
        #chat, [type=submit] { padding: 1rem; border-radius: 0.5rem; border: 1px solid #ccc; margin: 1rem 0; background: inherit; color: inherit; }
        #chat { min-width: 20rem; font-size: inherit; }
        #reponse { text-align: left; line-height: 2; }
        </style>
    </head>
    <body>
    <h1>Chat KiwIA 🥝</h1>
    
    <form>
        <input type="text" id="chat" placeholder="Votre message...">
        <button type="submit">Envoyer</button>
    </form>
    <div id="reponse"></div>
    
    <script>
        const form = document.querySelector('form');
        const input = document.querySelector('#chat');
        const resultat = document.querySelector('#reponse');
    
        // À la validation du formulaire
        form.addEventListener('submit', async (e) => {
            e.preventDefault();
    
            // On récupère le contenu du message
            const content = input.value.trim();
            if (!content) return; // Si c'est vide on arrête là
    
            // Petit message d'attente
            resultat.textContent = 'Un instant et je suis à vous...';
            // On vide le champ d'entrée
            input.value = '';
    
            try {
                // Requête asynchrone en POST vers /chat
                const response = await fetch('/chat', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    // Corps de la requête en JSON
                    body: JSON.stringify({ content }),
                });
    
                resultat.textContent = '';
    
                // On instancie une interface ReadableStream
                const reader = response.body.getReader();
                const decoder = new TextDecoder();
    
                // Tant qu'on a du contenu...
                while (true) {
                    const { done, value } = await reader.read(); // On lit
                    if (done) break;
    
                    const lines = decoder.decode(value).split('\n');
    
                    // On itère sur la réponse reçue pour alimenter le résultat
                    for (const line of lines) {
                        if (line.startsWith('data: ')) {
                            const data = JSON.parse(line.slice(6));
                            resultat.textContent += data.content;
                        }
                    }
                }
            } catch (error) {
                console.error('Error:', error);
                resultat.textContent = 'Une erreur est survenue.';
            }
        });
    </script>
    
    </body>
    </html>
    
    1. On lance le tout grâce à node server.mjs et on consulte l'adresse indiquée dans le navigateur pour atteindre la page HTML qui affiche le formulaire.

    On peut perfectionner le rendu en mettant en page le message renvoyé sous forme de markdown (mais cela dépend du modèle interrogé) plutôt que de l'afficher en texte brut.

    Perspectives

    On peut voir que construire une application web sollicitant un LLM est tout à fait envisageable avec les technologies d'aujourd'hui et les standards déjà en place (HTML/CSS, JavaScript, fetch, Streams API, etc). À partir de là tout est possible pour imaginer élaborer des interfaces qui vont dialoguer en texte clair ou par d'autres moyens plus subtiles, et réagir en conséquence. Vous pouvez aussi briefer votre LLM en amont et lui donner des instructions ou un contexte de réponse, voire en construire un nouveau (avec l'instruction FROM de Ollama).

    Pour pousser l'horizon encore plus loin, faire tourner des LLM dans le navigateur lui-même est possible grâce à WebGPU (voir une démo ici : Qwen-2.5 on WebGPU sur Huggingface) avec une performance tout à fait honorable.

    Les concepteurs de navigateurs préparent des interfaces aisées d'accès en JavaScript pour interroger un modèle local, tels que Google avec l'IA Gemini intégrée dans Chrome. Nous n'avons pas fini d'en entendre parler.

    Retrouvez l'intégralité de ce tutoriel en ligne sur Alsacreations.com

  • Les variables CSS ont révolutionné la manière de gérer les styles dans le développement web.

    Si vous en avez assez de répéter les mêmes valeurs CSS partout dans votre code, alors cet article est fait pour vous !

    Vous allez découvrir ici comment les utiliser efficacement, pourquoi elles sont si pratiques et comment elles se comparent aux solutions comme Sass et LESS.

    Allons-y !

    Qu'est-ce qu'une variable CSS ?

    Une variable CSS (aussi appelée "propriété personnalisée") est un moyen de stocker des valeurs réutilisables dans votre feuille de style.

    Imaginez-la comme une boîte où vous pouvez ranger une couleur, une taille de police ou n'importe quelle autre valeur CSS, puis la réutiliser où vous le souhaitez.

    Comment déclarer et utiliser des variables CSS ?

    Déclarer une variable CSS

    Les variables CSS sont généralement définies au sein du sélecteur :root.

    Ce sélecteur représente le niveau le plus élevé de votre document et les variables ainsi définies seront accessibles partout dans votre fichier CSS.

    :root { 
      --main-color: #3498db;
      --font-size: 16px;
    }
    

    Dans cet exemple, deux variables sont créées : --main-color et --font-size.

    Elles sont définies respectivement avec une couleur et une taille de police.

    Utiliser une variable CSS

    Pour utiliser une variable, vous devez appeler la fonction var().

    Celle-ci prend le nom de la variable en argument et l'injecte dans les propriétés CSS que vous souhaitez modifier.

    body {
      background-color: var(--main-color);
      font-size: var(--font-size);
    }
    

    Ici, var(--main-color) applique la couleur principale définie à l'arrière-plan du body, tandis que var(--font-size) ajuste la taille du texte.

    Variables CSS avec des valeurs de secours

    Vous pouvez également fournir une valeur de secours (fallback) à une variable CSS.

    C'est utile au cas où la variable ne serait pas définie ou si le navigateur ne la supportait pas.

    body {
      color: var(--text-color, #333);
    }
    

    Dans cet exemple, si la variable --text-color n'est pas définie, la couleur par défaut #333 sera appliquée.

    Réutilisation dans différents éléments

    Les variables CSS peuvent être réutilisées sur plusieurs éléments.

    h1 {
      color: var(--main-color);
    }
    
    p {
      border-color: var(--main-color);
    }
    

    En utilisant la même variable sur différents éléments (comme h1 et p), vous assurez une cohérence visuelle tout en simplifiant les modifications futures.

    Nous reviendrons justement sur les raisons d'utiliser les variables CSS dans la section suivante.

    Modifier une variable CSS pour des sections précises

    L'un des aspects les plus puissants des variables CSS est qu'elles peuvent être redéfinies localement pour des sections spécifiques de votre page.

    Vous n'êtes pas limité à une seule valeur globale.

    Par exemple, si vous souhaitez changer la couleur principale dans une certaine section de votre site, vous pouvez le faire en redéfinissant la variable uniquement pour cette partie.

    .section-1 { 
      --main-color: #d32f2c;
    }
    
    .section-2 { 
      --main-color: #3fcef2; 
    }
    

    Ensuite, dans vos styles, vous utilisez toujours var(--main-color) comme d'habitude, mais la valeur s'adaptera en fonction de la section où elle est utilisée :

    .section-1 h1 { 
      color: var(--main-color); /* Couleur rouge */
    }
    
    .section-2 h1 {
      color: var(--main-color); /* Couleur cyan */ 
    }
    

    Grâce à cette flexibilité, vous pouvez facilement adapter le design de différentes sections de votre page sans devoir réécrire tout votre code CSS.

    Pourquoi utiliser les variables CSS ?

    Maintenant que vous savez comment créer et utiliser les variables CSS, vous en voyez tout le potentiel et la puissance.

    Je tiens toutefois à souligner pourquoi, selon moi, elles sont indispensables dans la création de styles CSS.

    Centralisation des styles

    Plutôt que de répéter les mêmes valeurs partout dans votre code, les variables CSS vous permettent de centraliser des éléments récurrents comme les couleurs, les polices ou les espacements.

    Ainsi, si vous devez modifier une valeur, vous n'avez qu'à la changer à un seul endroit, et l'ensemble de votre site sera mis à jour.

    Un vrai gain de temps, surtout pour les projets de grande envergure.

    Faciliter la maintenance

    Les variables CSS améliorent considérablement la lisibilité et la maintenance de votre code.

    Par exemple, au lieu de chercher chaque occurrence d'une couleur pour la changer, vous modifiez simplement la valeur de la variable.

    C'est également très pratique si vous travaillez en équipe : chacun peut rapidement comprendre et ajuster les styles sans risquer d'oublier une valeur cachée quelque part dans le CSS.

    Thématisation simplifiée

    Si vous souhaitez proposer plusieurs thèmes de couleur ou de design pour un site, les variables CSS sont parfaites pour cela.

    Vous pouvez déclarer différentes valeurs pour vos variables en fonction du thème sélectionné, et tout bascule automatiquement sans effort supplémentaire, ouvrant ainsi la porte à des interfaces utilisateur facilement personnalisables.

    J'aborderai ce sujet plus en profondeur un peu plus loin dans l'article.

    Compatibilité et flexibilité

    Les variables CSS sont compatibles avec la plupart des navigateurs modernes, ce qui signifie que vous pouvez les utiliser dès maintenant dans vos projets sans vous soucier des problèmes de compatibilité.

    Les variables CSS sont un atout majeur pour tout développeur souhaitant optimiser son flux de travail, réduire les erreurs et créer des designs évolutifs.

    Elles apportent une réponse simple et élégante à la complexité croissante des feuilles de style dans les projets modernes.

    Variables CSS et préprocesseurs (Sass, LESS) (Comparaison)

    Les variables CSS et les préprocesseurs comme Sass et LESS permettent tous deux de gérer des valeurs réutilisables dans vos styles, mais ils présentent des différences majeures.

    Support natif vs compilation

    Les variables CSS sont directement comprises par les navigateurs modernes.

    Pas besoin de compiler quoi que ce soit : vous les déclarez dans votre CSS et elles fonctionnent immédiatement.

    En revanche, avec Sass et LESS, il faut compiler le code pour obtenir un fichier CSS utilisable.

    Flexibilité en temps réel

    Les variables CSS peuvent également être modifiées en temps réel, par exemple via JavaScript, ce qui les rend parfaites pour des thèmes dynamiques ou des interactions utilisateur.

    document.documentElement.style.setProperty('--primary-color', '#e74c3c');
    

    En comparaison, avec Sass et LESS, les variables sont statiques : une fois le code compilé, vous ne pouvez plus modifier ces valeurs sans recompiler les fichiers.

    Quand utiliser les variables CSS ou un préprocesseur

    Je vous conseille d'utiliser uniquement un fichier CSS avec des variables CSS pour des pages statiques ou de petite envergure, car elles suffisent amplement dans ces cas-là.

    Mais pour des projets plus vastes et structurés, l'utilisation d'un préprocesseur reste souvent plus intéressante.

    Heureusement, il est possible de combiner les deux approches en utilisant des variables CSS au sein même de vos fichiers Sass ou LESS, ce qui permet de profiter du meilleur des deux mondes : la flexibilité des variables CSS et la puissance des préprocesseurs.

    Gestion des thèmes avec les variables CSS

    Que vous souhaitiez implémenter un mode clair et un mode sombre, ou bien proposer plusieurs variations de couleurs, les variables CSS vous permettent de gérer cela efficacement sans réécrire l'intégralité de votre feuille de style.

    Déclaration des variables globales

    Tout commence par la déclaration de vos variables globales dans le sélecteur :root.

    :root {
      --primary-color: #3498db;
      --background-color: #ffffff;
      --text-color: #333333;
    }
    

    Ces variables peuvent ensuite être utilisées dans vos styles réguliers.

    body {
      background-color: var(--background-color);
      color: var(--text-color);
    }
    
    button {
      background-color: var(--primary-color);
    }
    

    Changer de thème via la redéfinition des variables

    Pour appliquer un thème alternatif, comme un mode sombre, il suffit de redéfinir les valeurs des variables CSS dans une classe spécifique, par exemple .dark-theme.

    .dark-theme {
      --primary-color: #e74c3c;
      --background-color: #2c3e50;
      --text-color: #ecf0f1;
    }
    

    Ensuite, vous pouvez appliquer cette classe au niveau du body ou d'une autre balise englobante dans votre HTML, et tous les styles qui utilisent ces variables seront mis à jour automatiquement, sans avoir à dupliquer votre code CSS.

    body.dark-theme {
      background-color: var(--background-color);
      color: var(--text-color);
    }
    

    Gestion multi-thèmes facile

    Vous pouvez créer autant de thèmes que nécessaire, en modifiant simplement les valeurs de ces variables CSS pour chaque classe de thème.

    Par exemple, si vous souhaitez ajouter un thème clair, vous définissez simplement une autre classe avec des valeurs différentes :

    .light-theme {
      --primary-color: #3498db;
      --background-color: #ffffff;
      --text-color: #333333;
    }
    

    Cela vous permet de basculer entre plusieurs thèmes très facilement, uniquement en changeant la classe appliquée sur l'élément racine.

    Pour aller plus loin dans la gestion des thèmes, vous pouvez consulter cet article sur les modes d'apparence Light mode et Dark mode.

    Bonnes pratiques pour l'utilisation des variables CSS

    L'utilisation des variables CSS est un excellent moyen de rendre votre code plus propre, maintenable et flexible.

    Toutefois, pour en tirer le meilleur parti, il est essentiel de suivre quelques bonnes pratiques.

    Voici quelques conseils pour utiliser les variables CSS de manière optimale.

    Déclarez vos variables dans :root

    Comme mentionné précédemment, pour maximiser la portée de vos variables, il est conseillé de les déclarer dans le sélecteur :root.

    Ainsi, elles seront accessibles dans tout le document et pourront être réutilisées partout.

    :root {
      --primary-color: #3498db;
      --font-size-base: 16px;
    }
    

    Utilisez des noms de variables explicites

    Choisir des noms de variables clairs et explicites est essentiel pour rendre votre code facile à comprendre et à maintenir.

    Par exemple, préférez --primary-color plutôt que --color1, ce qui permet à quiconque lit votre code de comprendre immédiatement à quoi correspond la variable.

    :root {
      --primary-color: #3498db;
      --secondary-color: #2ecc71;
      --font-size-large: 24px;
    }
    

    Des noms explicites facilitent également les ajustements futurs.

    Utilisez des variables pour les valeurs répétitives

    Les variables CSS sont particulièrement utiles pour les valeurs que vous utilisez fréquemment, comme les couleurs, les tailles de police, ou les espacements.

    :root {
      --spacing-unit: 16px;
    }
    
    .container {
      padding: var(--spacing-unit);
    }
    
    .card {
      margin-bottom: var(--spacing-unit);
    }
    

    Regroupez vos variables par type

    Pour une meilleure organisation, regroupez vos variables par type, comme les couleurs, les tailles de police ou les espacements. Cela vous permettra de structurer votre fichier CSS de manière plus lisible et d'y revenir plus facilement pour faire des modifications.

    :root {
      /* Couleurs */
      --primary-color: #3498db;
      --secondary-color: #2ecc71;
    
      /* Tailles de police */
      --font-size-base: 16px;
      --font-size-large: 24px;
    
      /* Espacements */
      --spacing-small: 8px;
      --spacing-medium: 16px;
      --spacing-large: 32px;
    }
    

    Préparez des valeurs de secours

    Il est toujours recommandé de fournir une valeur de secours dans vos déclarations var(), surtout si vous travaillez avec des variables CSS qui pourraient ne pas être définies dans certains contextes.

    button {
      background-color: var(--primary-color, #3498db);
    }
    

    Dans cet exemple, si --primary-color n'est pas définie, la valeur #3498db sera utilisée à la place.

    Limitez l'utilisation excessive de variables

    Bien que les variables CSS soient très utiles, il est important de ne pas en abuser.

    Évitez de créer une variable pour chaque petite valeur.

    Concentrez-vous sur les éléments qui sont susceptibles de changer ou qui sont utilisés fréquemment à travers votre code.

    Trop de variables peuvent rendre votre fichier CSS difficile à gérer.

    Conclusion

    Les variables CSS ont véritablement transformé la manière de gérer les styles dans le développement web moderne.

    Elles apportent une flexibilité et une simplicité inégalées, permettant de centraliser et de modifier des valeurs globales sans dupliquer le code.

    Que ce soit pour la gestion des couleurs, des tailles de police, ou même pour des thèmes dynamiques, elles offrent un moyen puissant de rendre votre CSS plus maintenable.

    Retrouvez l'intégralité de ce tutoriel en ligne sur Alsacreations.com

  • Ah les carrousels… Fonctionnalité souvent demandée par les clients, car c’est dynamique, ça bouge, c’est fun etc. Mais en avez-vous réellement besoin pour votre site ?

    Un carrousel, c’est quoi ?

    De manière générale, la plupart des carrousels contiennent plusieurs diapositives (avec des images, vidéos ou autre) qui défilent lorsqu’on clique sur une flèche de navigation ou une pagination.

    Cela permet aux utilisateurs et utilisatrices de maximiser la densité de l'information sans avoir à faire défiler les pages. Pratique non ? Oui, mais… Des études ont montré que la plupart des personnes ont tendance à ignorer les carrousels. Nous allons voir pourquoi.

    Les carrousels sont très peu utilisés

    Selon les recherches d'Erik Runyon, directeur technique des communications marketing à l'Université de Notre Dame, les carrousels affichent un taux de clic relativement faible. En ayant fait l’étude sur le site même de l’Université avec un carrousel statique (qui ne défile pas automatiquement), 84 % des clics ont été effectués sur les articles en position 1, le reste étant réparti assez équitablement entre les quatre autres (~4 % chacun).

    graphique sur le pourcentage de cliques sur un carrousel à 5 diapositives

    En revanche, sur les carrousels automatiques, le taux de clic est plus élevé que sur les autres diapositives.

    Une autre étude a été réalisée par Rashika Tasnim Keya en janvier 2022, étudiante à l’Université de Design de ICT, proposant aux internautes deux même sites e-commerce, mais qui affichent des produits différemments ; le premier site sans carousel, et le deuxième site avec carrousels pour faire défiler les nombreux produits.

    Analyse graphique sur les carrousels

    Selon le graphique ci-dessus, une des questions posées aux internautes était de savoir s’ils trouvaient facilement les produits sur le site internet. Le site sans carrousel à remporté le plus de votes sur la réponse “Fortement d’accord”, alors que le site avec carrousels a remporté la réponse “Modéré”.

    L’analyse a montré que la plupart des utilisateurs ont déclaré que l'interface sans carrousel était plus compréhensible que l'interface avec les carrousels. En effet, l’interface était plus claire, et leur recherche d'articles ou de produits a été plus précise et plus rapide que sur le site avec les carrousels.

    On peut noter que l'expérience utilisateur est significativement différente selon l’interface avec ou sans carrousel, et que les personnes ont tendance à réaliser leur objectif plus facilement avec des composants simples d'utilisation.

    Pourquoi éviter les Carrousels ?

    • Ils sont souvent plus difficiles à gérer et peuvent donner des résultats inattendus sur les appareils et les navigateurs plus anciens.
    • En 2023, Google a également indiqué clairement que l'accent devait être mis sur la vitesse et l'amélioration de l'expérience utilisateur grâce à la facilité d'utilisation. Les carrousels ne s'inscrivent absolument pas dans ce plan.
    • Les carrousels ne sont pas simples à utiliser. Selon le World Wide Web Consortium (W3C), le carrousel doit suivre ou mettre en œuvre certaines lignes directrices afin de le rendre accessible à toutes et tous.
    • Pour les carrousels automatiques, chaque personne a besoin d'un temps différent pour lire l'ensemble du contenu du carrousel. Si c'est trop rapide, les personnes sont frustrées, et si c'est trop lent, elles le sont également, en particulier pour les personnes qui ont des problèmes de motricité et qui ont du mal à cliquer sur un élément avant qu'il ne soit enlevé.

    Mais si vous insistez…

    Si nous prenons l’exemple d’un site e-commerce, l'objectif de l'internaute est de trouver des informations sur les produits, de comparer différentes gammes de produits et de prendre une décision d'achat. Cela signifie que l'utilité du carrousel dépend du contexte de l'utilisateur. L'utilisateur est donc plus susceptible d’utiliser les carrousels.

    Mais étant donné que les utilisateurs sont moins enclins à cliquer sur les flèches pour afficher la diapositive suivante, il peut être plus efficace de changer automatiquement de diapositive après un certain temps ou de leur montrer des diapositives d'une page différente lorsqu'ils reviennent sur votre site. À noter cependant qu’au niveau de l’accessibilité, une diapositive automatique doit comporter obligatoirement un système de mise en pause et de relance du défilement.

    Selon les règles du cerveau de John Medina, la vision prime sur les autres sens. Toutefois, un grand nombre de diapositives ne constitue pas un bon carrousel, car une injection excessive d'images visuelles entraîne une charge cognitive. Par conséquent, cinq diapositives ou moins, adaptées à la mémoire à court terme, amélioreront l'expérience de l'utilisateur. Il faut également faire attention à placer les flèches de manière intuitive. Les utilisateurs préfèrent naviguer d'une manière qui leur est familière en raison de leur expérience passée.

    Pour conclure

    En conclusion, bien que les carrousels puissent sembler attrayants et dynamiques, leur efficacité est souvent remise en question. Les études montrent que ces éléments interactifs captent rarement l'attention des utilisateurs et peuvent même nuire à l'expérience utilisateur en compliquant la navigation et en augmentant la charge cognitive. De plus, les défis techniques liés à l'accessibilité et à la compatibilité multiplateforme rendent leur mise en œuvre complexe.

    Ainsi, il est essentiel de bien réfléchir à leur utilité réelle dans le contexte spécifique de votre site. Si vous décidez tout de même d'opter pour un carrousel, il est crucial de l'utiliser de manière réfléchie, en prenant en compte les meilleures pratiques pour garantir une expérience utilisateur fluide et accessible.

    Liens et ressouces utiles pour intégrer des carrousels accessibles :

    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.

    modes d'apparence sur MacOS

    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).

    devtools de Firefox

    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;
    }
    

    Couleurs système usuelles

    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

    <h1>Tiens, mais quelle est ma couleur ?</h1>
    
    :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 <h1> est de couleur sombre; et inversement en mode sombre.

    la propriété color-scheme

    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:

    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 bouton switch en action

    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 :

    1. On vérifie si le choix de thème était déjà mémorisé en localStorage.
    2. Sinon on vérifie les préférences utilisateur du système.
    3. Puis on crée ou modifie l'attribut data-theme-preference sur <html> (valeur "light" ou "dark").
    4. Et on mémorise le choix en localStorage.
    5. 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.

    Pixels bretzels 100e édition

    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 ✌️

    Les sponsors

    L'évènement est généreusement soutenu par de super sponsors :

    sponsors Pixels et Bretzels

    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é à <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énéralement le 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