Vue normale

Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.
À partir d’avant-hierAlsacreations.com - Actualités

Lancement de SchnapsGPT

C'est avec beaucoup d'émotion que nous pouvons dévoiler aujourd'hui SchnapsGPT un agent conversationnel de nouvelle génération issu de nos laboratoires de développement.

Durant des années, nous avons planifié, mis au point et conçu ce projet innovant, construit autour de techniques d'apprentissage supervisé, via l'injection des données collectées via notre autre module Schnapsum, et par renforcement, via l'indexation de nombreuses ressources disponibles sur le web et des flux RSS (Réseaux Sociaux Schnapsiens).

Capture d'écran de SchnapsGPT

Ce prototype, qui marque un tournant dans l'univers des modèles de langage, est disponible dès aujourd'hui sur le web et prochainement via une API pour permettre l'intégration dans des services tiers. Ses facultés de génération de contenu, de compréhension et d'interaction avec les humains vont au-delà de ce que la concurrence a pu proposer jusqu'à présent. C'est en langage naturel que vous pourrez vous adresser à cette intelligence et qu'elle pourra vous répondre également en toute intelligence.

La base de données de SchnapsGPT contient désormais plus de 42 pétaoctets de paramètres, jusqu'à 7 couches OSI et plusieurs dizaines d'entités Unicode. Sa courbe d'apprentissage est exponentielle avec un fine-tuning de qualité effectué par notre équipe expérimentée en protocoles HTTP et clés SSH.

🥝 Essayez dès aujourd'hui SchnapsGPT ! 🥝

SchnapsGPT mascotte

Nous sommes ouverts à toute acquisition ou collaboration si vous représentez un moteur de recherche mondial, une application web de bureautique, ou un VC de la Silicon Valley de Munster. Merci de nous soutenir dans notre monnaie locale, le Stück.

Our goal is to make the world a better place… and don’t be evil

Publié par Alsacreations.com

Navigation Timing API

Navigation Timing API est une interface de programmation qui permet d'accéder à des informations sur les performances de navigation d'un site Web, générées par le navigateur. Cela correspond à peu près aux informations que l'on trouve dans l'onglet Performance des devtools mais avec un accès "programmatique" plutôt que visuel. Ainsi on peut mesurer les temps de chargement et de rendu, non seulement sur son propre poste mais aussi sur celui des internautes et récupérer l'information. Différents événements sont monitorés et retournés en plus du temps de chargement total de la page. Le support est très bon sur tous les navigateurs depuis environ 2014.

☝ En réalité cette API profite d'un interface déjà décrite dans une autre spécification : Performance Timeline qui elle-même étend les pouvoirs déjà offerts par High Resolution Time.

Voici un exemple de code qui utilise l'API Navigation Timing pour mesurer le temps total :

// Récupération de l'objet de performance de navigation
const perf = window.performance;

// Récupération de l'événement de chargement de la page
const loadEvent = perf.timing.loadEventEnd;

// Récupération du temps actuel
const now = perf.now();

// Calcul du temps total de chargement (en millisecondes)
const pageLoadTime = now - loadEvent;

// Affichage du temps total de chargement de la page
console.log("Temps total de chargement : " + pageLoadTime + " ms");

Ici on se concentre sur loadEventEnd mais il existe bien d'autres propriété intéressantes spécifiques à cette API :

  • startTime : temps (en ms) auquel la navigation a commencé, c'est-à-dire lorsque l'internaute a cliqué sur un lien ou saisi une URL dans la barre d'adresse.
  • loadEventStart et loadEventEnd : temps (en ms) auquel l'événement load de la page a été déclenché et s'est terminé.
  • domInteractive : temps (en ms) auquel le navigateur a terminé le parsing du document HTML et a commencé à traiter les scripts et les ressources externes de la page.
  • domContentLoadedEventStart et domContentLoadedEventEnd : temps (en ms) auxquels le navigateur a démarré puis terminé le chargement de la partie "non-bloquante" de la page (c'est-à-dire les éléments qui ne sont pas nécessaires au chargement initial de la page, comme les images et les scripts en mode asynchrone).
  • domComplete : temps (en ms) auquel le navigateur a terminé le chargement de tous les éléments de la page, y compris les ressources bloquantes (comme les scripts JavaScript qui doivent être chargés et exécutés avant que la page soit rendue).

Et des propriété héritées des interfaces déjà mentionnées dans d'autres API :

  • redirectStart et redirectEnd : temps (en ms) auquel la redirection a commencé et s'est terminée, si la navigation a été redirigée vers une autre URL.
  • fetchStart : temps (en ms) auquel la requête HTTP a été envoyée pour récupérer le document HTML de la page.
  • domainLookupStart et domainLookupEnd : temps (en ms) auquel la résolution de nom de domaine a commencé et s'est terminée.
  • connectStart et connectEnd : temps (en ms) auquel la connexion au serveur a commencé et s'est terminée.
  • requestStart : temps (en ms) auquel la requête HTTP pour le document HTML de la page a été envoyée au serveur.
  • responseStart et responseEnd : temps (en ms) auquel la réponse du serveur a été reçue et la réception du document HTML de la page a été terminée.
  • domLoading : temps (en ms) auquel le navigateur a commencé à parser le document HTML de la page.

À noter que certaines clés sont préservées pour raisons de compatibilité avec la version 1 de l'API mais dépréciées dans la dernière à jour.

Ces propriétés associées ensemble peuvent être utilisées pour mesurer différentes étapes du processus de chargement et identifier les goulots d'étranglement à améliorer.

Vous pouvez également examiner tout ceci en entrant window.performance.timing dans la Console du navigateur.

Navigation Timing dans la console

Usage pour statistiques

Voici un exemple de code qui utilise la Navigation Timing API pour mesurer le temps total de chargement d'une page Web et envoyer cette information à une API de statistiques :

// Récupération de l'objet de performance de navigation
const perf = window.performance;

// Récupération de l'événement de chargement de la page
const loadEvent = perf.timing.loadEventEnd;

// Récupération du timing actuel
const now = perf.now();

// Calcul du temps total de chargement (en millisecondes)
const pageLoadTime = now - loadEvent;

// préparation de l'objet à envoyer à l'API de statistiques
const statsData = {
  pageLoadTime: pageLoadTime
};

// envoi des données à l'API de statistiques sous forme JSON
fetch("https://example.com/stats", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify(statsData)
})
  .then(function(response) {
    console.log("Données envoyées à l'API de statistiques :", response);
  })
  .catch(function(error) {
    console.error("Erreur lors de l'envoi des données à l'API de statistiques :", error);
  });

Notez que cet exemple est simplifié et ne prend pas en compte tous les cas possibles par exemple, si la requête à l'API de statistiques échoue (dans ce cas il faudrait traiter l'erreur renvoyée) ou si la page est redirigée avant que les données puissent être envoyées (dans ce cas il faut décider si on ignore ou si on stocke l'information temporairement dans sessionStorage pour tenter un nouvel envoi sur une page suivante).

Publié par Alsacreations.com

Les Web Workers en action

Les web workers sont des threads JavaScript qui permettent de déléguer des tâches longues et/ou intensives en CPU à des processus en arrière-plan, afin d'éviter de bloquer l'interface de l'application web.

Cela signifie que vous pouvez exécuter du code JavaScript qui prend du temps à s'exécuter, comme des calculs complexes, des opérations de traitement de données ou des téléchargements de fichiers, sans perturber la réactivité de votre application et notamment déclencher l'apparition d'un avertissement du navigateur de type Attention : le script ne répond pas, voulez-vous attendre ou l'arrêter ?.

Le support de cette technique est très bon de nos jours avec tous les navigateurs majeurs desktop et mobiles, depuis IE10 inclus et Android 4.4, soit depuis environ 2014. Reportez-vous au tableau Caniuse : Web Workers pour tous les détails.

Pour utiliser un web worker, vous devez créer un fichier JavaScript séparé qui contiendra le code à exécuter en arrière-plan, puis utiliser l'API des web workers pour instancier un web worker à partir de ce fichier et lui envoyer des messages pour lancer des tâches ou obtenir des résultats. Le web worker exécutera le code de manière asynchrone, de sorte que vous pouvez continuer à interagir avec l'application pendant que le code du web worker s'exécute en arrière-plan.

Cas d'usage

On utilise des workers dans les cas suivants (et d'autres) pour éviter de bloquer l'interface :

  • Calculs complexes : Si vous avez besoin de calculer des valeurs complexe qui prennent du temps à s'exécuter, vous pouvez utiliser un web worker pour déléguer ces calculs à un processus en arrière-plan et éviter de bloquer l'interface utilisateur (UI) de l'application.
  • Traitement de données : Si vous avez besoin de traiter de grandes quantités de données qui prennent du temps à s'exécuter, vous pouvez utiliser un web worker pour déléguer ce traitement à un processus en arrière-plan et éviter de surcharger le processeur.
  • Téléchargement de fichiers : Si vous avez besoin de télécharger de gros fichiers qui prennent du temps, vous pouvez utiliser un web worker pour déléguer cette tâche.
  • Animations complexes : Si vous avez besoin d'animations complexes qui prennent du temps à s'exécuter, vous pouvez utiliser un web worker pour déléguer l'exécution de ces animations à un processus en arrière-plan et économiser les ressources.

Une démo vaut mille mots

⚗️ L'exemple le plus parlant peut être retrouvé en ligne : Sorting 50K Array with Bubble Sort.

Capture d'écran d'une démonstration de web worker

Il s'agit d'effectuer un tri sur un tableau par algorithme bubble sort (tri à bulles) avec 2 méthodes : - sans worker : de manière classique, cet exercice bloque l'interface, on peut le voir aux styles figés du bouton, à l'absence de l'animation de la barre de progression, et de réactivité globale. - avec worker : le document principal continue de vivre avec ses états, animations, interactions, sans bloquer durant la réalisation du calcul.

Limitations

Par leur nature, les workers ont des limites.

  1. Ils ne peuvent pas accéder à certaines propriétés de l'objet window, comme window.document, car ils sont exécutés dans un contexte de thread séparé et ne partagent pas le même espace de nomage que le code principal de l'application. Cela également pour éviter des conflits d'accès aux ressources avec les scripts de la page principale.
  2. Ils ne peuvent pas afficher de fenêtres de dialogue ou des boîtes de message, car ils n'ont pas accès aux fonctionnalités de l'interface graphique de l'application.
  3. Ils ne peuvent pas utiliser certains objets de l'API navigation, comme history ou location, car ils n'ont pas accès à la barre d'adresse ou à l'historique de navigation de l'application.
  4. Ils ne peuvent pas interagir directement avec le DOM de la page, car ils n'ont pas accès aux éléments HTML de l'application. Pour mettre à jour le DOM depuis un web worker, vous devez en réalité envoyer un message au processus principal de l'application, qui lui même interviendra.
  5. Ils ne peuvent pas accéder à certaines APIs du navigateur, comme celles qui gèrent les cookies ou les notifications, car elles sont liées à l'interface de l'application, du document, du navigateur.

Initialisation d'un worker

Créez un fichier JavaScript séparé qui contiendra le code à exécuter en arrière-plan. Ce fichier sera appelé "fichier de travail".

Dans votre code principal, utilisez le constructeur Worker() de l'objet Worker pour instancier un web worker à partir du fichier de travail. Cette méthode prend en paramètre le chemin vers le fichier :

const worker = new Worker('path/to/worker.js');

Vous pouvez maintenant envoyer des messages au web worker en utilisant la méthode postMessage() de l'objet Worker, et par la même occasion lancer les opérations :

worker.postMessage({ message: 'Hello, worker!' });

Vous pouvez également définir un gestionnaire d'événements qui sera appelé chaque fois que le web worker envoie un message au code principal en utilisant la méthode addEventListener() de l'objet Worker :

worker.addEventListener('message', (event) => {
  console.log(event.data);
});

Lorsque vous avez fini de travailler avec le web worker, vous pouvez le fermer en utilisant la méthode terminate() :

worker.terminate();

Vous pouvez également utiliser l'API des web workers pour gérer les erreurs et les exceptions qui se produisent dans le code du web worker en définissant des gestionnaires d'événements pour les événements error et messageerror.

Rappelez-vous que le code du fichier de travail est exécuté dans un contexte de thread séparé, de sorte que toutes les variables et fonctions définies dans le fichier de travail ne seront pas disponibles dans le code principal de l'application. Pour communiquer entre le code principal et le web worker, vous devez utiliser l'API des web workers pour envoyer et recevoir des messages.

Exemple concret

Voici un exemple basique mais concret d'utilisation d'un web worker pour effectuer des calculs. Attention les instructions sont présentées de manière minimaliste, il serait plus propre de les réunir dans un objet, une classe, etc. pour ne pas manipuler des variables globales.

On crée un fichier JavaScript séparé qui contiendra le code à exécuter en arrière-plan. Par exemple, le fichier de travail pourrait ressembler à ceci :

// La fonction de calcul complexe
function calculate(data) {
  // Effectuez les calculs complexes ici
  const result = /* résultat des calculs */;
  postMessage(result);
}

// Attendez un message du code principal
onmessage = function(e) {
  // Appelez la fonction de calcul avec les données reçues
  calculate(e.data);
};

Dans votre code principal, utilisez la méthode Worker() pour instancier un web worker à partir du fichier de travail :

const worker = new Worker('worker.js');

Définissez un gestionnaire d'événements qui sera appelé chaque fois que le web worker envoie un message au code principal en utilisant la méthode addEventListener() de l'objet Worker :

worker.addEventListener('message', (event) => {
  console.log(event.data); // Affiche le résultat des calculs
});

Envoyez un message au web worker en utilisant la méthode postMessage() de l'objet Worker et en lui envoyant les données à traiter :

worker.postMessage({ data: /* données à traiter */ });

Le web worker recevra le message et exécutera la fonction de calcul en arrière-plan, en utilisant les données envoyées par le code principal. Lorsque les calculs sont terminés, le web worker enverra un message au code principal avec le résultat, qui sera affiché dans le gestionnaire d'événements défini.

Publié par Alsacreations.com

Deno, le futur de Node ?

Deno est un environnement d'exécution JavaScript et TypeScript qui a été pensé et conçu pour être une alternative à Node.js. Il permet à ce titre d'exécuter du code JavaScript, en-dehors d'un navigateur c'est-à-dire en ligne de commande ou en mode serveur grâce au moteur V8 de Chromium... mais il a été construit avec une série de différences clés par rapport à Node.js.

Le logo de Deno en situation

Un kiwi s'est caché dans cette image, saurez-vous le retrouver ?

Quelles sont les différences ?

Deno a été lancé par le créateur de Node lui-même : Ryan Dahl. Lors d'une conférence JSConf, ce dernier avait exprimé des regrets relatifs à sa première oeuvre qui date (déjà) de 2009. Vous pouvez découvrir ses arguments en vidéo : 10 choses que je regrette à propos de Node.js - Ryan Dahl

Entre autres :

  • Deno a été conçu pour être plus sécurisé que Node.js : son noyau a été écrit en Rust, qui est réputé pour sa robustesse, alors que Node fut conçu en C++. Par ailleurs tous les fichiers et ressources externes sont bloqués par défaut, ce qui signifie que vous devez explicitement autoriser l'accès à ces fichiers et ressources avant de pouvoir y accéder dans votre code. Cela peut aider à prévenir les attaques de type "chemin d'accès transversal" qui sont courantes dans les applications.
  • Deno supporte nativement TypeScript et JavaScript (tandis que Node.js utilise JavaScript bien entendu). TypeScript est un sur-ensemble de JavaScript qui ajoute comme son nom le suggère le typage statique des données, ce qui peut aider à éviter certains types d'erreurs de programmation.
  • Deno met l'accent sur la simplicité et l'uniformité, ce qui se reflète dans sa conception générale : toutes les fonctionnalités sont accessibles à travers un seul module global, plutôt que d'être divisées en différents modules comme c'est le cas dans Node. De plus, Deno inclut toutes les bibliothèques et outils nécessaires à l'exécution de code, vous n'avez donc pas besoin d'installer des packages tiers comme c'est le cas avec Node et npm.
  • Deno souhaite être au plus proche des standards et API natives par exemple il embarque Fetch ou WebStorage... dont une compatibilité avec les navigateurs : avec des ES Modules il n'y a pas besoin de webpack pour que ce soit prêt à l'emploi.

L'import de paquets se fait via URL, ce qui peut sembler initialement étrange mais fait sens dans la philosophie de Deno qui se veut décentralisé. Ce concept est bien expliqué par la documentation : Linking to third party code. Fini node_modules et package.json.

import { assertEquals } from "https://deno.land/std/testing/asserts.ts";

Côté performance, les résultats sont relativement similaires entre Deno et Node car le moteur interne reste V8.

Comment utiliser Deno ?

Avant toute chose, il faut garder à l'esprit que Deno est bien plus récent et que si des gros progrès sont réalisés pour améliorer la stabilité, on manque encore certainement de recul, de retours de bugs, de documentation et d'une communauté aussi importante que celle de Node pour déclarer que l'un peut remplacer l'autre d'un claquement de doigts... même s'il prévoit un module de compatibilité avec Node.

Pour utiliser Deno, vous devez d'abord l'installer en suivant les instructions fournies sur le site web officiel de Deno. Vous pouvez ensuite lancer des exécutions de code avec la commande deno dans le terminal, et vous vous retrouverez avec un environnement habituel où l'on peut entrer des instructions JavaScript et quitter avec close().

Voici un exemple de script Deno simple qui affiche "Hello World" dans la console :

// Fichier hello.js ou hello.ts
console.log("Hello World!");

Pour exécuter ce programme, vous pouvez utiliser la commande deno run :

deno run hello.js

Dès que l'on va tenter d'accéder à des ressources, Deno va demander l'autorisation. Par exemple pour l'accès en écriture à un fichier :

⚠️ Deno requests write access to "hello.log". Grant? [a/y/n/d (a = allow always, y = allow once, n = deny once, d = deny always)]

ou au réseau avec fetch :

⚠️ Deno requests net access to "wikipedia.org". Run again with --allow-net to bypass this prompt. Allow? [y/n (y = yes allow, n = no deny)]

On va pouvoir débloquer ces autorisations avec --allow-write (écriture de fichiers), --allow-net (accès au réseau), --allow-env accès à l'environnemment et --allow-run pour exécuter des sous-processus.

Il existe de nombreuses autres commandes et options que vous pouvez utiliser avec Deno pour exécuter et gérer vos programmes. Pour en savoir plus, consultez la documentation officielle de Deno

Publié par Alsacreations.com

Internationalisation (i18n) ou localisation (l10n) ?

i18n et l10n sont deux acronymes raccourcissant l'écriture de mots initialement anglais, possédant des équivalents français, en retenant leur première lettre (ici "i" ou "l"), leur dernière (ici "n"), et en précisant entre ces deux lettres le nombre de caractères manquants provenant du mot d'origine.

i18n = internationalisation

L10n = localisation

  • i18n signifie internationalisation et se rapporte aux processus de conception et de développement qui peuvent être adaptés pour différentes langues et cultures : le but est de prévoir le code et les ressources pour que le site web (ou l'application) soit adaptable à d'autres langues et cultures.

  • l10n ou L10n pour ne pas confondre le "L" minuscule avec un "I" majuscule, signifie localisation et se réfère aux processus d'adaptation spécifiques à une langue et une culture en tenant compte de la traduction du contenu, de l'adaptation des formats de date et d'heure, de la modification des images et des couleurs pour correspondre aux normes culturelles locales, etc.

Les deux pratiques font partie de la même démarche globale et il existe bon nombre de recommandations, dont des Conseils pratiques sur l’internationalisation du Web du W3C parmi lesquels on peut noter utilisez partout un encodage UTF-8, qui peut sembler évident de nos jours.

Rappel sur la langue dans HTML

Du point de vue de HTML, pensez également à respecter la bonne pratique d'indiquer la langue du document grâce à l'attribut lang sur la balise <html> et à notifier tout changement de langue dans le contenu grâce à ce même attribut et un code ISO 639-1. Cela va affecter non seulement la prononciation d'une synthèse vocale mais aussi le fonctionnement des formulaires avec la correction orthographique.

<!doctype html>
<html lang="fr">
  <body>
    <h1>Cosmogonie</h1>
    <p>Terry Pratchett avait écrit, dans <cite lang="en">Lords and Ladies</cite> :
      <q lang="en">In the beginning there was nothing, which exploded.</q>
    </p>
    <p>Quant à Douglas Adams, l'un des passages célèbres dans 
      <cite>Le Dernier Restaurant avant la fin du monde</cite> reste toujours
      <q lang="en">In the beginning, the universe was created.
      This has made a lot of people very angry and has been widely regarded as a bad move.</q>
    </p>
  </body>
</html>

Localisation

La localisation pourrait se résumer, entre autres, par :

  • La traduction de l'ensemble du contenu du site web (textes, images, boutons, sous-titres des vidéos, etc.) pour s'assurer que le public cible peut comprendre facilement le contenu.
  • L'adaptation des formats de date, de temps, de devise et de mesure selon les normes en vigueur dans le pays. Y compris la présentation des calendriers, des semaines qui ne débutent pas le même jour, voire des week-ends et des périodes de vacances.
  • L'utilisation de couleurs, symboles et d'images qui sont familières ou suffisamment significatives (nous dirons affordantes).
  • L'ajout de fonctionnalités spécifiques pour les utilisateurs du pays, telles que la possibilité de choisir leur fuseau horaire (pour les pays qui recouvrent plusieurs fuseaux) ou leur langue préférée (pour les zones géographiques qui comptent plusieurs langues pratiquées).
  • La prise en compte de contraintes matérielles, par exemple l'agencement des touches du clavier (suivez mon regard dépité si vous avez déjà été confronté à un jeu qui impose les touches W, A, S, D alors que ce n'est pas du tout adapté à la disposition AZERTY).
  • La prise en compte des différences de législations dans le monde (par exemple mentions légales, conditions de vente, affichage des prix avec ou sans taxe, bannières cookies, etc).

On peut donc considérer qu'il s'agit d'une brique à part entière de l'expérience utilisateur (UX), et que cela va également faire partie de certaines stratégies de référencement du contenu (SEO).

Internationalisation

L'internationalisation peut se définir par une préparation au niveau technique de tout ce qui est nécessaire à une localisation.

  • La séparation du contenu et du code, afin que le contenu puisse être facilement modifié et traduit sans avoir à modifier le code de l'application ou du site. En conservant une base de code commune, cela peut permettre une réduction des coûts et des délais de développement pour chaque nouvelle version ou adaptation régionale.
  • L'utilisation de formats de date, d'heure, de devise et de mesure standardisés pour les rendre facilement adaptables au contexte, par des fonctions de mise en forme.
  • L'utilisation de l'Unicode, de polices de caractères qui supportent différentes langues et scripts car certains ensemble de glyphes sont limités aux caractères latins.
  • L'acceptation par les formulaires de formats d'adresses postales (champs différents selon les pays).
  • L'acceptation par les formulaires d'une souplesse dans les numéros de téléphone à travers le monde (c'est bien pour cela que <input type="tel"> n'est pas doté d'une validation native).
  • La possibilité d'écrire de droite à gauche, commme de gauche à droite, avec l'attribut dir et les valeurs rtl (right to left, de droite à gauche) et ltr (left to right, de gauche à droite) soit par exemple <p lang="ar" dir="rtl">شكرا جزيلا</p>... et donc y faire également attention en CSS. Ce qu'on appelle le BiDi pour BiDirectionnel.
  • L'attention accordée à réserver la place pour des mots plus longs dans le design d'interface, parce que "DonaudampfschiffFahrtsgesellschaftskapitän" existe tout autant que "OK".
  • Et enfin la possibilité de changer la langue d'une interface et de préserver cette préférence.

La prise en compte des caractéristiques de chaque région du monde peut aller jusqu'à l'adaptation à la qualité du réseau, de la bande passante ou de la part de marché des navigateurs. En poussant la perfection au maximum, on peut imaginer devoir s'adapter au format A4 et à la fois au format Letter des États-Unis pour l'élaboration d'une feuille de styles print.

Quelques modules pour l'internationalisation

Il existe plusieurs modules populaires en JavaScript bien pratiques.

Intl : Un object natif d'ECMAScript qui est bien supporté et fournit des fonctionnalités telles que le formattage de date avec DateTimeFormat, de temps relatif avec RelativeTimeFormat, de devises et de nombres avec NumberFormat et même de pluriels avec PluralRules.

Moment.js et date-fns : Des bibliothèques populaires pour la manipulation de dates/heures avec des capacités de calcul, de temps relatif, de formattage et de traduction dans de multiples langues grâce à l'apport de la communauté.

i18next : Une bibliothèque pour la gestion des chaînes de texte et des traductions, qui prend en charge les formats de date, de temps, de devise et de nombre, ainsi que des fonctionnalités avancées de gestion des traductions.

FormatJS : Une autre bibliothèque pour la gestion des chaînes de texte et des traductions, qui prend en charge les formats de date, de temps, de devise et de nombre, ainsi que la gestion des plurales et des règles de grammaire spécifiques à chaque langue.

Citons aussi Globalize.js et bien d'autres qui au fil du temps ont été rendues nécessaires par l'absence de fonctionnalités natives et pratiques.

Ce ne sont que des exemples relatifs à JavaScript, pour tout ce qui est CMS et langages back-end, la plupart des solutions embarquent des méthodes prêtes à l'emploi ou des extensions dédiées à cet usage, par exemple Polylang pour WordPress qui remplace désormais avantageusement WPML.

Nous avions déjà abordé le sujet avec :

Lost in Translation - image du film

Pour la traduction de chaînes de texte, de nombreuses applications existent de nos jours y compris pour centraliser et fédérer le travail de plusieurs personnes, mais n'oubliez pas que le travail d'un.e véritable traducteur.rice est irremplaçable notamment pour toutes les raisons et subtilités évoquées précédemment.

Publié par Alsacreations.com

Le nullish coalescing operator en JavaScript

Le Nullish coalescing operator qui s'écrit avec un double point d'interrogation ?? en JavaScript est un opérateur de comparaison qui permet de renvoyer la valeur d'une expression si elle est définie et non nulle, ou sinon de renvoyer une valeur par défaut.

Il est utilisé depuis ECMAScript 2020 pour éviter les erreurs de type undefined lorsqu'on tente d'accéder à des propriétés d'objets ou à des éléments de tableaux qui pourraient ne pas être définis.

On peut le compléter par un caractère = pour obtenir un nullish coalescing assignment, qui pourra servir quant à lui à assigner une valeur si la variable avec laquelle on souhaite l'utiliser (celle qui doit recevoir la valeur, à gauche donc) n'est pas déjà définie.

Par exemple on pourra écrire avec un nullish coalescing operator

// Avec un objet
let fruit = { nom: "Kiwi", vitamine: "C" }
let dessert = fruit.nom ?? "Banane"
// dessert contiendra "Kiwi"

// Avec un tableau
let nombres = [1, 2, undefined, 4, null, 6]
let premierNombre = nombres[0] ?? 0
// premierNombre contiendra 1

...pour éviter d'écrire ceci :

let dessert
let fruit = { nom: "Kiwi", vitamine: "C" }
if(fruit && fruit.nom) {
  dessert = fruit.nom
} else {
  dessert = "Banane"
}

Et pour utiliser un nullish coalescing assignment, on pourra écrire :

// Avec un objet
let fruit = { nom: "Kiwi" }
fruit.vitamine ??= "C"
// fruit.vitamine contiendra "C" car n'était pas définie auparavant

fruit.vitamine ??= "D"
// fruit.vitamine contiendra toujours "C"

// Avec un tableau
let nombres = [1, 2, undefined, 4, null, 6]
nombres[0] ??= 0
// nombres[0] contient alors toujours 1

Il existe aussi l'opérateur de coalescence de faible priorité qui s'écrit avec un double pipe (aussi nommé "barre verticale" ou "tube" en français) ||, mais celui-ci renvoie la première valeur vraie rencontrée, alors que le Nullish coalescing operator ?? renvoie uniquement la première valeur définie et non nulle rencontrée.

Publié par Alsacreations.com

ECMAScript

ECMAScript est un standard de programmation pour les langages de script sur lequel repose... JavaScript. Dans la pratique, le terme JavaScript au sens large recouvre non seulement le noyau du langage (le standard ECMAScript) mais aussi les différentes API qui sont nécessaires pour le faire fonctionner dans un navigateur web, dont le fameux DOM (Document Object Model) lui autorisant à manipuler la représentation des données du document. Il faut également lui adjoindre XMLHttpRequest, WebSockets, WebWorkers, Canvas, fetch, bref tout ce qui fait partie de la plateforme web moderne actuellement.

L'abréviation ECMA provient de l'European Computer Manufacturers Association, organisation à but non lucratif qui développe des standards, au même titre que le W3C pour HTML et CSS. Fait assez rare pour être noté, l'ECMA est basée à Genève, en Suisse et non pas dans la Silicon Valley.

ECMAScript possède plus particulièrement le nom de code ECMA-262. On le retrouve dans des environnements sans navigateur, par exemple dans Node.js qui est en pratique basé sur le moteur V8 de Chromium mais qui fonctionne sans l'aspect de rendu graphique et donc sans DOM. Cela signifie que tout appel à une fonctionnalité ou une API "navigateur" aboutira sur une erreur car elle sera inconnue.

ECMA-262

ECMAScript va définir les essentiels fonctionnant à la fois en front et en back :

  • La syntaxe en général, les mots clés
  • La façon de gérer les erreurs
  • Les types (string, number, boolean, function, object, bigint, undefined, symbol, null...)
  • Les mécanismes d'héritage / prototype
  • Les structures et fonctions incluses (tableaux, mathématiques, JSON...)
  • Les modules
  • D'autres subtilités du langage

Notez également l'existence de TypeScript dont nous avons déjà parlé, super-set de JavaScript qui implémente notamment le typage.

Qui conçoit EcmaScript ?

ECMAScript est conçu et maintenu par le Technical Committee 39 (TC39), un comité de normalisation composé de représentants de différentes entreprises et organisations du monde du web. Le TC39 travaille en étroite collaboration avec les principaux acteurs notamment développeurs de navigateurs web, pour élaborer et mettre à jour le standard en fonction des besoins. Le but est de s'assurer qu'ECMAScript reste un standard de programmation pertinent.

Quelles sont les principales versions et évolutions d'EcmaScript ?

ECMAScript a connu de nombreuses versions et évolutions depuis sa création en 1996. Les versions initiales d'ECMAScript sont les suivantes :

  • ECMAScript 1 : première version d'ECMAScript publiée en 1996.
  • ECMAScript 2 : publication en 1998, avec des corrections de bogues et des améliorations mineures par rapport à la première version.
  • ECMAScript 3 : publication en 1999, avec l'ajout de nouvelles fonctionnalités telles que les expressions régulières et les try/catch pour la gestion des exceptions.
  • ECMAScript 4 : projet avorté en 2008, qui visait à ajouter de nouvelles fonctionnalités pour améliorer la programmation orientée objet dans ECMAScript.
  • ECMAScript 5 : publication en 2009, avec l'ajout de fonctionnalités telles que la gestion des propriétés d'objet et la compatibilité avec les objets JSON.

S'en est suivie une période de stagnation... puis soudain... Les versions ultérieures d'ECMAScript ont été publiées en utilisant un cycle de publication annuel, chaque année en juin.

  • ECMAScript 2015 (aussi appelé ECMAScript 6 ou ES6) : publication en 2015, avec l'ajout de nombreuses nouvelles fonctionnalités telles que les classes, les fonctions fléchées et les modules.
  • ECMAScript 2016 (aussi appelé ECMAScript 7 ou ES7) : publication en 2016, avec entre autres la méthode Array.prototype.includes et la boucle for-of.
  • ECMAScript 2017 (aussi appelé ECMAScript 8 ou ES8) : publication en 2017, avec entre autres les async functions et la méthode Object.values.
  • ECMAScript 2018 (aussi appelé ... vous avez compris le principe) : publication en 2018, avec entre autres la méthode Object.entries et la répétition dans les expressions régulières.
  • ECMAScript 2019 (ES10) : publié en juin 2019, avec entre autres les méthodes de chaînage d'opérateurs et la méthode Array.prototype.flat.
  • ECMAScript 2020 (ES11) : publié en juin 2020, avec entre autres les opérateurs nullish et la méthode String.prototype.matchAll.
  • ECMAScript 2021 (ES12) : publié en juin 2021, avec String.prototype.replaceAll, promise.any(), de nouveaux opérateurs logiques d'assignation tels que ??=
  • ECMAScript 2022 (ES13) : publié en juin 2022, avec hasOwn, top-level await, la cause des erreurs, etc.

Le nom de code ESNext fait toujours référence à la dernière version en cours d'élaboration.

Comment écrire du code récent en EcmaScript tout en conservant la compatibilité avec les navigateurs ?

Pour écrire du code en utilisant les dernières fonctionnalités d'ECMAScript tout en conservant la compatibilité avec les navigateurs, il existe plusieurs approches que vous pouvez utiliser :

  • Utiliser un transpileur tel que Babel pour convertir votre code ECMAScript récent en un code qui peut être exécuté dans les navigateurs plus anciens. Un transpileur est un outil qui peut analyser votre code et le convertir en un code compatible avec les versions antérieures d'ECMAScript.
  • Utiliser des bibliothèques ou des frameworks JavaScript qui prennent en charge les fonctionnalités récentes d'ECMAScript et fournissent des polyfills pour garantir la compatibilité avec les navigateurs plus anciens. Un polyfill est un morceau de code qui implémente les fonctionnalités d'une version récente d'ECMAScript dans les navigateurs qui ne les prennent pas en charge nativement.
  • Utiliser des techniques de détection de navigateur pour exécuter du code spécifique en fonction de cette version, ou plutôt de sa capacité à reconnaître les ES Modules. Cette approche est périlleuse, il vaut mieux laisser son automatisation aux outils et frameworks qui la proposent lors de la phase de compilation.

Vous devriez en général vérifier la compatibilité des navigateurs, même récents, avant d'utiliser des fonctionnalités fraîches d'ECMAScript dans votre code, sauf si vous passez par la phase de transpilation qui normalement effectue cette tâche pour vous... mais pas toujours. Consultez les tables de compatibilité des navigateurs sur des sites tels que caniuse.com pour obtenir des informations à jour.

Publié par Alsacreations.com

Les citations en HTML avec blockquote, cite et q

Il existe plusieurs éléments HTML pour structurer la sémantique de citations dans un document web :

  • blockquote - depuis HTML 3.2
  • cite - depuis HTML 3.2
  • q - depuis HTML 4

Chacun possède bien entendu un rôle différent et parfois des attributs spécifiques.

cite

Débutons par l'élément cite qui va contenir le titre d'une œuvre à laquelle une citation est faite. Il peut d'ailleurs être utilisé à l'intérieur d'un élément blockquote (ci-après) pour donner une référence à la source de la citation sous la forme du nom de l'oeuvre d'où elle provient.

Les oeuvres possibles sont nombreuses, il peut s'agir d'un livre, un film, une oeuvre d'art (peinture, sculpture, opéra, pièce de théâtre, poème, exposition...), un jeu, une chanson, un autre site web, le titre d'un article/blog, etc.

<cite>Le Rouge et le Noir</cite> - Stendhal
<cite>La Bohème</cite> - Giacomo Puccini
<cite>Papillon de lumière</cite> - Cindy Sander
<cite>Zelda Tears of the Kingdom</cite>

blockquote

L'élément blockquote (littéralement traduisible par "bloc de citation") structure une section de contenu qui est citée d'un autre document ou d'une autre source. Son contenu est souvent affiché avec des marges plus larges pour le différencier du contenu environnant. C'est d'ailleurs un élément de type bloc, qui occupe toute la largeur par défaut et provoque des retours à la ligne dans le flux naturel du document. On peut également - mais ce n'est pas obligatoire - utiliser des paragraphes <p> dans le bloc.

<blockquote>
  <p>Mais qu'est-ce que je vais devenir ? Je suis ministre, je ne sais rien faire !</p>
</blockquote>

L'élément blockquote peut posséder un attribut cite (à ne pas confondre avec l'élément du même nom) comprenant une URL vers la source originale de la citation.

<blockquote cite="https://fr.wikiquote.org/wiki/La_Folie_des_grandeurs">
  <p>Mais qu'est-ce que je vais devenir ? Je suis ministre, je ne sais rien faire !</p>
</blockquote>

À faire / à ne pas faire ?

Nombreux sont les sites qui n'exploitent pas la sémantique à son plein potentiel, souvent parce que l'outil de contribution (CMS) ne le suggère pas assez ou ne le permet pas.

Par exemple Radio France : Margaret Hamilton, la femme qui a fait atterrir l’Homme sur la Lune utilise une liste avec une seule puce pour structurer une citation :

<ul><li><em>"Ce qu’ils avaient l’habitude [...] J’étais la première à le faire marcher."</em></li></ul>

En voici la capture d'écran :

Capture d'écran du site Radio France contenant une citation

⚠️ D'un point de vue sémantique et pour l'accessibilité, ce n'est évidemment pas reconnu comme un paragraphe de citation mais comme un élément de liste (listitem). L'usage de em ne suffit pas, même si visuellement cela peut faire illusion.

Autre exemple, Wikipédia utilise mieux l'élément <blockquote> qui par ailleurs se distingue bien visuellement du reste grâce aux styles associés (police différente, bordure, marges).

Voici la capture d'écran issue de la page Margaret Hamilton :

Capture d'écran de Wikipédia comportant une citation

Pour la mention de l'autrice et de l'oeuvre, on retrouve un balisage à l'aide de <cite>, décrit ci-après (code simplifié pour la lisibilité) :

<p>
  —&nbsp;Margaret Hamilton,
  <cite>
    Lettre à <i>Datamation</i>,
    <abbr title="Premier">1<sup>er</sup></abbr> mars 1971
    <sup><a href="#cite_note-13">[13]</a></sup>
  </cite>
</p>

Du côté de la NASA (agence spatiale des États-Unis), une structure similaire est adoptée mais en choisissant cette fois de placer <cite> dans une balise <footer> du bloc de citation... ce qui n'est pas interdit en soi.

<blockquote>
  <div>
    We had to find a way and we did. Looking back, we were the luckiest people in the world; there was no choice but to be pioneers.
  </div>
  <footer>
    <cite>- Margaret Hamilton</cite>
  </footer>
</blockquote>

⚠️ Par contre <cite> contient le nom d'une personne (Margaret Hamilton), ce qui n'est pas attendu par la spécification HTML qui précise bien que...

Le nom d'une personne n'est pas le titre d'une œuvre — même si les gens appellent cette personne une œuvre — et l'élément ne doit donc pas être utilisé pour baliser les noms des personnes.

👆 Oui la citation que vous venez de lire est bien dans <blockquote> sur cette page et utilise un attribut cite vers la page de la spécification.

Voici la capture d'écran du site de la NASA :

Capture d'écran d'une citation sur le site de la NASA

Si l'on retrouve notre premier exemple, cette fois <cite> peut être utilisé à bon escient pour baliser le nom de l'oeuvre (un film).

<blockquote cite="https://fr.wikiquote.org/wiki/La_Folie_des_grandeurs">
  <p>Mais qu'est-ce que je vais devenir ? Je suis ministre, je ne sais rien faire !</p>
  <p>Louis de Funès - <cite>La Folie des grandeurs</cite> (1971), écrit par Gérard Oury</p>
</blockquote>

Si l'on veut aller plus loin dans la structuration du contenu, il faudra jeter un oeil du côté des microdonnées avec Schema.org qui propose un type Quotation utilisable avec JSON-LD, Microdata et RDFa.

q

L'élément q représente une petite citation en ligne (son nom vient de la première lettre du mot quote qui signifie - encore une fois - citation en anglais), relativement courte qui ne nécessite pas de sauts de ligne. Le contenu de l'élément q est généralement affiché entre des guillemets courts. Si vous avez besoin de structurer une citation plus longue, reportez-vous sur blockquote.

<p>Ce freluquet m'a répliqué <q>Il m'en a assez dit. Il m'a dit que vous l'aviez tué.</q></p>
<p>Et là, je lui ai répondu <q>Je suis ton père</q>.</p>

L'élément q peut posséder un attribut cite (à ne pas confondre avec l'élément du même nom) qui contiendra alors une URL vers la source originale de la citation.

<p>Maître Eolas a publié sur son blog
  <q cite="https://www.maitre-eolas.fr/post/2023/02/04/Les-raisons-de-la-col%C3%A8re">
  Rien de tel dans ces cas que de coucher sur le papier, fut-il fait de pixels, l'explication de son ire,
  et la soumettre aux débats qui font de la section commentaires le meilleur de ce blog.
  C'est toujours ça qu'Elon Musk n'aura pas.</q>
</p>

À faire / à ne pas faire ?

Retrouvons la page du site Radio France où pour une citation en ligne, dans un paragraphe de texte plus général, on aurait pu utiliser <q> à cet effet, mais où l'on retrouve finalement une emphase <em>.

<p>[...] Le Dr Paul Corto, qui l'a nommée pour la récompense se déclare "<em>surpris de découvrir qu'elle n'avait jamais été officiellement reconnue pour ses travaux pionniers. Ses concepts de logiciel asynchrone, de programmation des priorités, de tests de bout en bout et de capacité de décision humaine, comme l’affichage des priorités, ont posé les bases de la conception de logiciels ultra-fiables</em>". Non seulement Margaret Hamilton [...]</p>

En voici la capture d'écran :

Capture d'écran d'une citation en ligne sur le site RadioFrance

TL;DR ?

On résume : cite pour les noms d'oeuvres, blockquote pour les blocs de citations (plus ou moins longs) et q pour les citations courtes en-ligne dans un paragraphe de texte.

Publié par Alsacreations.com

Babel et la transpilation de code JavaScript

Babel est un outil de transpilation de code qui prend en entrée du code écrit dans une version plus récente (ou actuelle) de JavaScript et le convertit en une version compatible avec les "anciennes versions", de sorte que le code puisse être exécuté sur un plus grand nombre de navigateurs et d'appareils.

Babel utilise des plugins et des presets qui lui permettent de gérer différentes versions de JavaScript et d'appliquer les transformations nécessaires pour convertir le code en une version compatible. On peut également les configurer pour effectuer des conversions spécifiques en fonction des besoins.

(portion du tableau) La Tour de Babel par Brueghel (1563) - Kunsthistorisches Museum, Vienne

Voici un exemple de code JavaScript qui utilise une syntaxe qui n'est pas prise en charge par les "anciennes" versions de JavaScript, mais qui peut être transpilée avec Babel :

const numbers = [1, 2, 3, 4, 5];

const doubled = numbers.map((number) => number * 2);

console.log(doubled); // [2, 4, 6, 8, 10]

Il y a notamment présence de la notion d'arrow function => et de constantes avec const. Après transpilation avec Babel, le code précédent peut être réécrit ainsi :

// Code transpilé
"use strict";

var numbers = [1, 2, 3, 4, 5];

var doubled = numbers.map(function (number) {
  return number * 2;
});

console.log(doubled); // [2, 4, 6, 8, 10]

Comme on peut le voir, la syntaxe a été modifiée pour être "compatible" avec les navigateurs qui pourraient être en retard. C'est une technique qui a été très utile pendant des années, même si désormais les différences tendent à se résorber grâce à une grande période d'amélioration du support JavaScript, grâce aux mises à jour automatiques et à l'abandon des mammouths tels qu'Internet Explorer.

Vous pouvez utiliser la démonstration en ligne de Babel https://babeljs.io/repl pour explorer son fonctionnement.

Repl de Babel

Dans quel cadre Babel est il exécuté pour développer ?

Babel est (ou a été) généralement utilisé lors du développement avec des frameworks tels que React, Vue, Angular. Cela permet durant le développement d'utiliser les dernières fonctionnalités dans la syntaxe, tout en sachant que le code sera compatible avec un plus grand nombre de navigateurs.

Pour utiliser Babel lors du développement, il faut d'abord l'installer et le configurer en utilisant les plugins et les presets (pré-réglages) appropriés. Ensuite, il peut être utilisé soit en ligne de commande dans le terminal pour transpiler le code directement, soit en tant que partie d'un processus de build (compilation) plus complet pour automatiser la transpilation dès la mise en production. Les fichiers transpilés sont utilisés dans l'application en remplacement des fichiers source originaux. La plupart du temps c'est déjà en place dans la structure de base et relativement transparent dans le processus de compilation.

Exemple d'usage de Babel avec Webpack

Webpack est un outil de build très répandu, qui peut être utilisé avec Babel.

Voici un exemple de configuration de Webpack qui utilise Babel :

// webpack.config.js
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
          },
        },
      },
    ],
  },
};

Dans cet exemple, la configuration indique qu'il faut utiliser le module babel-loader pour transpiler tous les fichiers JavaScript (dont le nom se termine par .js) à l'exception des fichiers situés dans le dossier node_modules. Le preset @babel/preset-env est utilisé pour indiquer quelle version doit être ciblée lors de la transpilation. Pour utiliser cette configuration avec Webpack, il suffit d'exécuter la commande webpack dans un terminal, en se situant dans le répertoire contenant la configuration. Cela dgénérera le fichier transpilé bundle.js dans le dossier dist.

Publié par Alsacreations.com

L'API Vibration

L'API Vibration en JavaScript permet d'accéder à la fonctionnalité de vibration sur les appareils compatibles, notamment mobiles.

Pour l'utiliser, vous pouvez d'abord vérifier si l'appareil prend en charge la vibration en examinant la propriété navigator.vibrate. Si cette propriété existe, vous pouvez utiliser la méthode navigator.vibrate() pour déclencher la vibration, en précisant la durée en millisecondes.

// Vérifier au préalable si le navigateur la supporte
if ('vibrate' in navigator) {
  // Déclencher la vibration pendant 2 secondes
  navigator.vibrate(2000);
}

Vous pouvez également contrôler la durée et constituer un motif à l'aide d'un tableau d'entiers représentant chacun une durée en millisecondes pour spécifier les temps de vibration et de pause, alternativement :

if ('vibrate' in navigator) {
  // Déclencher une vibration sous forme de motif
  // Vibrer pendant 1 seconde, faire une pause pendant 0,5 seconde,
  // Vibrer pendant 0,2 seconde, faire une pause pendant 0,2 seconde,
  // Vibrer pendant 0,5 seconde, faire une pause pendant 1 seconde
  navigator.vibrate([1000, 500, 200, 200, 500, 1000]);
}

👉 Consultez sur votre mobile une démonstration avec différents motifs de vibrations par Christopher Kade.

Quel usage ?

Il n'est plus nécessaire de présenter l'usage complet que l'on fait couramment des vibrations pour notifier l'internaute dans les applications mobiles, mais résumons : attirer l'attention de l'utilisateur ou l'utilisatrice lorsque l'écran est éteint ou hors de vue par exemple à la réception d'un message, indiquer qu'un événement important se produit, ou simplement pour ajouter une touche de réalisme à l'application par exemple dans un jeu (donner l'impression que l'appareil est secoué lorsque le personnage subit un choc ou chute).

N'en abusez pas trop, et pensez à prévoir une option pour respecter les préférences de l'internaute et pouvoir désactiver les vibrations.

Publié par Alsacreations.com

À quoi sert High Resolution Time API ?

L'API High Resolution Time (ou l'API de temps à haute résolution) est une interface JavaScript qui permet d'accéder à une horloge de haute précision pour mesurer des périodes de temps avec une précision allant jusqu'à la microseconde.

Cela peut être utile pour des applications qui nécessitent une précision temporelle élevée, comme les jeux, les applications de réalité virtuelle ou tout simplement pour mesurer des écarts de performances lorsque les fonctions classiques telles que getTime() de l'objet Date ne suffisent plus.

Cette API est bien reconnue depuis 2013 par l'ensemble des moteurs de navigateurs. Ces derniers pourront néanmoins arrondir les valeurs retournées et diminuer la précision pour des raisons de sécurité et de mitigation d'usage détourné.

Comment utiliser High Resolution Time API?

Pour utiliser l'API High Resolution Time dans votre code JavaScript, vous pouvez commencer par accéder à l'objet performance et sa méthode now().

Voici un exemple simple d'utilisation de l'API High Resolution Time pour mesurer la durée d'une opération dans votre code :

// Récupération de l'heure actuelle en utilisant l'API High Resolution Time
const start = performance.now();

// Effectuer une ou plusieurs opération(s) ici...

// Récupération de l'heure actuelle une nouvelle fois
const end = performance.now();

// Calcul de la durée de l'opération
const duration = end - start;

// Affichage de la durée totale de l'opération (en ms)
console.log(duration);

Vous pouvez également utiliser l'API High Resolution Time pour mesurer des périodes de temps plus longues en utilisant les méthodes setInterval et setTimeout, qui vous permettent d'exécuter du code à des intervalles réguliers. Par exemple :

// Définition d'une fonction qui sera appelée toutes les 10 secondes
function logTime() {
  // Récupération de l'heure actuelle en utilisant l'API High Resolution Time
  var now = performance.now();

  // Affichage de l'heure actuelle dans la console
  console.log(now);
}

// Exécution de la fonction toutes les 10 secondes
setInterval(logTime, 10 * 1000);

Vous pouvez en savoir plus sur cette API en consultant la spécification W3C High Resolution Time bien entendu.

Publié par Alsacreations.com

Le plein écran facile avec l'API Fullscreen

L'API Fullscreen standard maintenu par le WhatWG vous permet de faire en sorte qu'un élément de votre page web, quel qu'il soit, occupe tout l'espace disponible de l'écran. Cela peut être utile pour les vidéos en plein écran bien entendu mais également les jeux, ou toute autre application qui nécessite un affichage en plein écran sans nécessairement être constituée de vidéo.

Pour utiliser l'API Fullscreen, vous devez d'abord vérifier que le navigateur prend en charge cette fonctionnalité. Vous pouvez le faire en utilisant la propriété fullscreenEnabled de l'objet document :

if (document.fullscreenEnabled) {
  // Le navigateur prend en charge l'API Fullscreen
} else {
  // Le navigateur ne prend pas en charge l'API Fullscreen
}

Si le navigateur prend en charge l'API Fullscreen, vous pouvez ensuite faire en sorte qu'un élément de votre page web passe en mode plein écran en utilisant la méthode requestFullscreen() :

const element = document.querySelector('#ma-video');
element.requestFullscreen();

Dans cet exemple, nous avons récupéré l'élément en question par un sélecteur et nous avons appelé la méthode requestFullscreen().

Il est important de noter que l'internaute doit accepter de passer en mode plein écran avant que cela se produise. Le navigateur affichera une notification demandant si l'internaute souhaite passer en mode plein écran ou non. Si l'internaute refuse, la méthode "requestFullscreen" ne fera rien.

Inversement, il existe une méthode exitFullscreen() pour quitter le plein écran.

Pour détecter l'acceptation ou le refus de passer en mode plein écran, vous pouvez écouter l'événement fullscreenchange toujours sur l'objet document :

document.addEventListener('fullscreenchange', () => {
  if (document.fullscreenElement) {
    // Accord de passer en mode plein écran
  } else {
    // Refus de passer en mode plein écran
  }
});

Dans cet exemple, nous avons ajouté un écouteur d'événement sur l'événement fullscreenchange. Lorsque l'événement se produit, nous vérifions si l'objet fullscreenElement de l'objet document est défini. Si c'est le cas, cela signifie que l'utilisateur a accepté de passer en mode plein écran.

Pseudo-élément ::backdrop

L'API est accompagnée d'un pseudo-élément ::backdrop qui est rendu immédiatement sous l'élément en plein écran, ce qui permet de créer un arrière-plan sombre, un ombrage ou toute autre fantaisie qui va recouvrir le document d'origine lorsqu'on est en mode plein écran.

Pour utiliser le pseudo-élément ::backdrop, il suffit de l'ajouter à la feuille de styles.

#ma-video:fullscreen::backdrop {
  background-color: rgba(0, 0, 0, 0.8);
}

Pseudo-classe :fullscreen

L'API est également complétée par une pseudo-classe :fullscreen qui va correspondre dynamiquement à tout élément passé en plein écran.

Publié par Alsacreations.com

Le format d'image APNG

Le format de fichier APNG (Animated Portable Network Graphics) est comme son nom le suggère un format d'image animé reposant sur le format PNG, déjà très bien connu.

APNG a été conçu à partir de 2004 à l'initiative de Mozilla qui héberge la spécification APNG en tant que version améliorée du format PNG et offre des fonctionnalités supplémentaires telles que (évidemment) la possibilité d'animer les images... à l'instar du GIF.

Son support s'est amélioré progressivement, entre 2009 (Firefox) et 2020 (Edge) ce qui représente une longue période de temps, et le voit désormais reconnu par tous les navigateurs. Même les anciens programmes reconnaissant PNG peuvent afficher un fichier APNG car sa première image est au format PNG valide, il y a donc en quelque sorte une rétro-compatibilité qui est relativement assurée par le fait que les données d'animation sont stockées dans un espace supplémentaire déjà prévu par le format PNG initial. Le type MIME correspondant est image/apng.

Image animée auformat APNG

Il ne s'agit pas nécessairement du format le plus optimisé pour les "images animées" car il existe bien des concurrents dans ce domaine avec des algorithmes appropriés : on privilégie de nos jours notamment les codecs vidéo (MP4, Webm, AV1) et leurs déclinaisons en formats d'images (WebP animé, AVIF animé : voir des démos). C'est d'ailleurs pour cela que les sites majeurs fournisseurs de GIFs et memes variés (Giphy, Tenor) ne vous servent en réalité, depuis bien longtemps, pas des images GIF mais de véritables et courts fichiers vidéo à leur place.

Quelles sont les différences ?

Le format PNG (Portable Network Graphics) est à la base un format d'image bitmap (ou raster) dans lequel on cherche à mémoriser les données pixel par pixel, avec une qualité supérieure à celle des formats d'image populaires tels que JPEG et GIF notamment parce que la compression ne doit pas affecter la qualité et perdre de l'information. Il utilise donc une compression sans perte pour conserver tous les détails de l'image d'origine, ce qui en fait un meilleur choix pour les images de haute qualité, icônes et schémas.

Comparaison GIF animé / APNG par https://apng.onevcat.com/demo/

En termes techniques, la principale différence vis-à-vis de son parent le PNG est l'ajout des capacités d'animation en combinant successivement plusieurs images. Le format APNG est donc un format plus avancé ou plutôt une extension de PNG tel que la spécification PNG du W3C l'indique.

Un autre ensemble de quelques tests consultables en ligne GIF vs APNG vs WebP arrive à la conclusion qu'un fichier APNG est plus léger qu'un WebP animé en mode lossless c'est-à-dire sans perte de qualité.

Comment créer des images APNG ?

S'il existe désormais de nombreux convertisseurs en ligne, l'outil le plus basique est APNG Assembler qui en ligne de commande (ou en version graphique sous Windows) va "assembler" de multiples fichiers PNG et appliquer un niveau de compression choisi. En complément gif2apng est un vrai convertisseur d'animations GIF vers APNG, et apng2gif son opposé APNG vers GIF.

Comment le format APNG est-il structuré ?

Le format APNG est binaire : il ne peut être ouvert par un éditeur de texte comme le SVG, il faudra passer par un éditeur hexadécimal tout comme pour JPEG, WebP, etc. Il stocke les données d'animation en combinant plusieurs images en une seule. Chaque image est stockée dans un chunk (que l'on peut traduire par morceau, tronçon) du fichier APNG, avec des informations sur la durée de l'image et les effets de transition à utiliser pour passer à la suivante. Des chunks supplémentaires stockent des informations sur les contrôles de l'animation, telles que la vitesse et le bouclage.

Les chunks sont alors assemblés dans un conteneur qui débute par une "signature" en début de fichier, signalant qu'il s'agit bien d'une image au format APNG, puis un bloc IHDR en amont des chunks et un bloc IEND à la fin.

On obtient donc un assemblage de frames qui étaient à l'origine des fichiers PNG indépendants, dont on a conservé uniquement les données IDAT, réécrites également en fdAT (frame data chunk) pour les images qui se suivent avec un numéro de séquence.

Structure du format PNG

Schéma provenant de la page Wikipédia APNG

Vous pouvez utiliser le très intéressant PNG file chunk inspector avec vos fichiers PNG ou des exemples fournis pour analyser leur structure en ligne, dont voici un extrait de capture d'écran :

PNG Chunk File Inspector

Un exemple de chunk d'image APNG pourrait être résumé ainsi :

IDAT
   [Données de l'image]
acTL (animation control)
   [Nombre total d'images dans l'animation]
   [Nombre de boucles dans l'animation]
fcTL (frame control)
   [Numéro de l'image]
   [Largeur de l'image]
   [Hauteur de l'image]
   [X de l'image]
   [Y de l'image]
   [Durée de l'image en millisecondes]
   [Numéro de l'image suivante]
   [Effet de transition à utiliser]

Quel est l'intérêt du format APNG par rapport au GIF ?

Le format APNG (Animated Portable Network Graphics) et le format GIF (Graphics Interchange Format) ont tous deux la même vocation à créer des animations par une succession d'images bitmap (non vectorielles). Cependant, ils diffèrent sur plusieurs points, notamment car ils ne proviennent pas de la même génération. GIF a été inventé en 1987 !

  • Qualité de l'image : Le format APNG utilise la même technologie de compression sans perte que le format PNG, ce qui lui permet de conserver tous les détails de l'image d'origine ; on peut d'ailleurs choisir zlib, 7zip, Zopfli. Le format GIF, en revanche, utilise une compression avec un algorithme ancien (LZW) et réduction du nombre de couleurs qui peut entraîner une perte de qualité.
  • Nombre de couleurs : Le format APNG peut utiliser jusqu'à 24 bits par pixel, ce qui lui permet de reproduire près de 16,8 millions de couleurs différentes. Le format GIF, en revanche, ne peut utiliser que 256 couleurs différentes par image. Il en résulte des effets d'escalier et de pixellisation visibles.
  • Nombre d'images/seconde : GIF est limité par défaut à 10 images/seconde tandis qu'il n'y a pas de limite pour APNG.
  • Transparence : Le format APNG permet l'utilisation de transparences et de fondus avec un canal alpha. Le format GIF ne connaît pas le canal alpha et ne gère la transparence que sur un seul niveau.
  • Licence : Le format APNG est un format libre et ouvert, ce qui signifie qu'il peut être utilisé gratuitement par tous. Le format GIF est était soumis à une licence plus restrictive ; lisez à ce sujet Pourquoi il n'y a pas de fichiers GIF sur le site de GNU qui résume bien la situation.

Publié par Alsacreations.com

Qu'est-ce que Vite ?

Vite est un outil front-end JavaScript qui vise à améliorer la rapidité de développement en offrant un serveur de développement rapide et une compilation optimisée pour la production. Il prend la suite d'une grande famille dans laquelle on peut évoquer Grunt, Gulp, et dernièrement Webpack.

Vite utilise la fonctionnalité ES Module Import de JavaScript pour charger les modules de manière asynchrone, ce qui permet une expérience de développement plus rapide et une compilation (étape build) plus petite pour la production. Vite est également conçu pour être facile à utiliser et à configurer, ce qui en fait un choix populaire pour les développeurs de front-end.

Vite a été développé par Evan You, le créateur de Vue.js, dans le but de créer un outil de développement de front-end plus rapide et plus efficace que Webpack, notamment pour les projets basés sur Vue.js. Cette idée initiale a été publiée sur Twitter :

Premier twit d'Evan You au sujet de Vite

Vite a ainsi été lancé en 2020 et a depuis connu un grand succès, non seulement auprès des projets Vue, mais également auprès d'autres projets de développement front-end. Il a désormais remplacé dans Vue 3 la suite d'outils Vue CLI qui était mise en avant pour Vue 2 et qui comprenait Webpack.

Vite comment ?

Plusieurs techniques ont été rassemblées :

  • Les ES Modules (EcmaScript Modules) supportés désormais dans tous les navigateurs modernes, qui permettent la suppression d'une étape de compilation.
  • esbuild qui est un outil de compilation très rapide écrit en Go et annonce des performances jusqu'à 100 fois plus rapides que des solutions classiques.
  • rollup qui produit les assets statiques et supporte un bon écosystème de plugins ainsi que ceux spécifiques à Vite.
  • le support natif de TypeScript, JSX, JSON, et des préprocesseurs CSS tels que pour les fichiers .less et .scss
  • le support du SSR (Server-Side Rendering) pour le rendu côté serveur

On peut également comprendre que le processus traditionnel est de produire le bundle à partir de tous les modules compilés pour toutes les routes existantes, ce qui nécessite un important temps de préparation. (Schémas issus de la documentation officielle de Vite)

Vite et bundle à l'ancienne

Avec ESM, le serveur est à l'écoute de toute requête, trouve la route correspondante et importe dynamiquement les modules concernés.

Vite avec ES Modules

Vite en action

Plusieurs frameworks de développement front-end populaires utilisent Vite comme outil de développement et de build, notamment :

  • Vue.js : Vite est le serveur de développement recommandé pour Vue.js et est inclus dans le kit par défaut mis en place par create-vue à la suite de quelques questions d'initialisation.
  • Svelte par l'intermédiaire du plugin vite-plugin-svelte.
  • Preact : l'alternative légère à React, avec un preset preset-vite.

Vite n'est pas lié à un framework spécifique et peut être utilisé avec n'importe quel projet de développement front-end, d'ailleurs moult exemples sont fournis officiellement pour Vue et React à la fois.

Capture du site officiel de Vite

Si vous faites déjà du Vue 3, il y a de fortes chances que Vite soit déjà utilisé par défaut (vous pouvez le voir tout simplement en lançant la commande de développement ou de compilation). Vous pouvez aussi utiliser Vite avec un projet de développement front-end (existant ou vide), avec la commande suivante :

npm init vite

Cela posera quelques questions, démarrera le serveur de développement à une URL locale et ouvrira votre application dans un navigateur.

Shell Vite init

On remarque assez aisément que pour un projet complexe comportant de nombreux composants, la phase de compilation initiale est réduite à quelques secondes alors qu'elle peut prendre jusqu'à plusieurs minutes avec Webpack.

Vous pouvez également noter que dans les outils de développement navigateur, onglet Réseau (Network) on voit passer les requêtes pour les différents modules plutôt que vers un seul import compilé.

Requêtes du navigateur vers les modules

Si vous souhaitez utiliser des fonctionnalités avancées de Vite, telles que le HMR, vous devrez peut-être ajouter des lignes de code supplémentaires à votre application pour activer ces fonctionnalités.

Hot Module Reloading

Le Hot Module Reloading (HMR) est une fonctionnalité de Vite qui permet de mettre à jour les modules de votre application sans avoir à recharger complètement la page. Cela peut être très utile lorsque vous développez une application et que vous souhaitez voir les changements que vous apportez immédiatement.

Comment le HMR fonctionne dans Vite :

  • Lorsque vous modifiez un fichier de votre application et enregistrez les changements, Vite détecte cette modification et envoie les changements au serveur de développement.
  • Le serveur de développement reçoit les changements et met à jour le module correspondant dans le cache du navigateur.
  • Le navigateur reçoit la notification de mise à jour du module et met à jour le module dans le cache du navigateur.
  • Le navigateur re-rend la page en utilisant la nouvelle version du module mise à jour, ce qui permet de voir les changements immédiatement sans avoir à recharger la page.

Le HMR est réalisé à l'aide du protocole WebSocket qui maintient une connexion persistante, vous pouvez par ailleurs l'examiner dans l'onglet réseau des outils de développement pour voir les échanges de messages.

Le HMR est une fonctionnalité très pratique qui peut grandement améliorer votre expérience de développement et vous faire gagner du temps.

Vite des plugins ?

Plusieurs plugins officiels sont disponibles notamment pour Vue 3 et ses SFC (Single File Components), la syntaxe JSX, React, etc.

Il en existe aussi de nombreux autres mis à disposition par la communauté et que l'on retrouvera dans la liste du repo awesome-vite

Vite vite vite !

Si vous souhaitez en savoir plus, consultez la documentation officielle Vite ou encore le replay de la conférence ViteConf 2022.

Capture d'écran de ViteConf

C'est parti ?

Publié par Alsacreations.com

Que sont les blob URLs ?

Les blob URLs sont des URLs (Uniform Resource Locators) générées dynamiquement qui permettent d'accéder aux données binaires stockées dans un objet Blob (Binary Large OBject) en JavaScript.

Un objet Blob peut contenir des données de différents types, comme des images, des fichiers audio ou vidéo, du texte ou tout autre type de données binaires. Cela en fait une technique utile et souple pour manipuler des pseudo-fichiers en mémoire, qui n'existent pas en tant que tels sur un serveur web. D'ailleurs on ne pourra pas générer de Blob côté serveur (back-end), cela n'existe que du côté navigateur (front-end).

🦠 Il ne faut pas le confondre avec Physarum polycephalum qui est une étrange espèce unicellulaire existant depuis des millions d'années, que vous pouvez même adopter, et qui n'est ni un animal, ni un végétal, ni un champignon.

Cet être étrange qui n'a pas de cerveau est capable de communiquer et trouver son chemin dans des labyrinthes, tel que l'ont prouvé des expériences. Il résiste au feu et à l'eau, il a une grande résistance et longévité... et a été emporté dans l'espace.

Toutes ces caractéristiques en ont fait une curiosité idéale inspirant moult livres et films. Dès 1958 on peut retrouver Steven McQueen dans The Blob suivi malheureusement un remake du même titre The Blob qui fut un désastre en 1988.

Affiche du film The Blob

En revanche, il existe un très bon jeu Tales from Space: Mutant Blobs Attack disponible sur consoles, Windows, Linux, macOS, dans lequel on incarne un blob qui doit grossir de plus en plus pour s'échapper de son laboratoire et par la suite dévorer progressivement le monde des humains.

Tales from Space: Mutant Blobs Attack

Arte vous dit tout ce qu'il faut savoir dans la vidéo YouTube Le blob, un génie sans cerveau

Manipuler du blob en JavaScript

On peut générer un Blob à partir d'un fichier grâce à l'API File ou à partir du constructeur Blob() qui va prendre en paramètre les données brutes (par exemple du texte, du code HTML, de la donnée binaire image, etc.) et d'un type MIME.

Par la suite, les blob URLs peuvent être générées à l'aide de la méthode URL.createObjectURL() de JavaScript, en passant l'objet Blob en argument. Par exemple :

// Création d'un objet Blob à partir de données
const myBlob = new Blob(['Hopla!'], {type: 'text/plain'});

// Création d'une URL blob à partir de l'objet Blob
const blobURL = URL.createObjectURL(myBlob);

// Affichage de l'URL blob générée
console.log(blobURL); // "blob:https://example.org/957b4d22-c5b5-4c5f-b5b5-f7f3b3bf2b05"

Voici un autre exemple pour du JSON :

const objet = { type: "fruit", nom: "kiwi" };
const blob = new Blob([JSON.stringify(objet, null, 2)], {type : 'application/json'});

Une fois que vous avez une URL de type blob, vous pouvez l'utiliser comme une URL classique pour accéder aux données contenues dans l'objet Blob. Par exemple, vous pouvez l'utiliser comme source d'une image <img src="blob:https://example.org/957b4d22-c5b5-4c5f-b5b5-f7f3b3bf2b05"> ou comme lien dans un élément a.

Attention, les blob URLs ne sont valides que pendant la durée de vie de l'objet Blob auquel elles sont liées, et donc très souvent durant la session de navigation. Le navigateur libère la mémoire lorsqu'on ferme la fenêtre, l'onglet, lorsqu'on recharge, etc. Une fois que le Blob est supprimé ou qu'il n'est plus accessible, la blob URL ne fonctionnera plus et devra être générée à nouveau si nécessaire.

Lire un blob s'effectue avec FileReader qui est aussi l'API de prédilection pour lire des fichiers File de manière asynchrone. Par exemple :

let reader = new FileReader();
reader.addEventListener("loadend", function() {
   // on lira le contenu de reader.result
});
reader.readAsArrayBuffer(leblob);

Publié par Alsacreations.com

Comment utiliser l'événement hashchange ?

L'événement hashchange se déclenche lorsqu'il y a un changement de l'ancre (ou hash) d'une URL, c'est-à-dire la portion après le signe #. On va le retrouver dans la propriété DOM window.location.hash.

Le hash est un élément particulier de l'URL : il ne provoque pas de (re)chargement de page lorsqu'il change, il n'est pas divulgué au serveur web dans la requête HTTP.

Hash

Dans son usage le plus courant, il est associé à l'accès aux ancres HTML. C'est-à-dire que lorsqu'on clique sur un lien <a href="#recherche"> on va pointer le focus sur l'élément possédant id="ancre" et faire défiler la page jusqu'à la cible. C'est aussi la technique utilisée par les liens d'évitement pour améliorer l'accessibilité.

Lorsque l'ancre d'une page Web change, on peut également intercepter l'événement hashchange pour exécuter du code.

// Écouter l'événement
window.addEventListener("hashchange", function(event) {
  // Récupérer la nouvelle valeur de l'ancre
  const hash = window.location.hash;

  // Exécuter du code en fonction de la valeur de hash
  // ...
});

Dans cet exemple, nous utilisons la méthode addEventListener() pour écouter l'événement hashchange qui se produit sur l'objet window. En effet, puisqu'il se passe au niveau du navigateur, il n'est pas lié à un élément du DOM en particulier. Lorsque l'événement se déclenche, on récupère la valeur de location.hash sachant que cet objet location contient d'autres informations sur l'adresse courante.

Il est aussi possible de récupérer dans l'objet événement event en premier paramètre de la fonction de callback diverses informations telles que l'ancienne URL oldURL et la nouvelle newURL.

Pour utiliser hashchange afin de charger un nouveau contenu de manière asynchrone en HTTP à l'aide de la fonction fetch() :

// Écouter l'événement hashchange
window.addEventListener("hashchange", function(event) {
  // Récupérer la nouvelle valeur de l'ancre
  const hash = window.location.hash;

  // Charger le nouveau contenu à l'aide de la fonction fetch
  fetch("/api/content/" + hash)
    .then(function(response) {
      return response.text();
    })
    .then(function(html) {
      // Mettre à jour le contenu de la page
      document.querySelector("#content").innerHTML = html;
    });
});

Dans ce cas de figure, on récupère toujours à l'aide de hashchange la nouvelle valeur de l'ancre, puis elle est transmise de manière asynchrone au serveur, ou à une API quelconque de votre choix, pour obtenir le nouveau contenu et l'injecter dans un élement déjà existant de la page grâce à innerHTML. Il faut donc faire attention à ce qui est renvoyé par le back-end soit une portion de document HTML et non l'intégralité d'une page avec head, link, style, script et compagnie ce qui ne serait pas conforme et pourrait créer de gros conflits de style et de JavaScript.

Notez que cet exemple utilise then() pour enchaîner les réponses de la promesse renvoyée par fetch(). Vous pouvez également utiliser l'opérateur await pour attendre que la promesse de fetch soit résolue, avant de mettre à jour le contenu de la page, ce qui est un peu plus lisible que de passer par then.

// Écouter l'événement hashchange
window.addEventListener("hashchange", async function(event) {
  // Récupérer la nouvelle valeur de l'ancre
  const hash = window.location.hash;

  // Charger le nouveau contenu à l'aide de la fonction fetch
  const response = await fetch("/api/content/" + hash);
  const html = await response.text();

  // Mettre à jour le contenu de la page
  document.querySelector("#content").innerHTML = html;
});

Publié par Alsacreations.com

Sécuriser les iframes avec l'attribut sandbox

L'attribut sandbox de l'élément iframe en HTML est utilisé pour restreindre les actions qui peuvent être effectuées dans l'iframe. Son rôle est d'améliorer la sécurité et la stabilité de la page web, surtout lorsque l'iframe est fournie par un service tiers que l'on ne contrôle pas, et qui pourrait être abandonné, détourné, voire hacké à l'avenir. Limiter les fonctionnalités à risque d'un iframe provenant d'un domaine tiers aide à prévenir les attaques de type clickjacking ou cross-site scripting (XSS).

Dans le document ou l'application web, on ajoute une balise <iframe> à l'endroit où l'on souhaite inclure le contenu d'un autre site. Par exemple :

<iframe src="https://www.example.org/contenu.html"></iframe>
  • L'absence de l'attribut sandbox, signifie par défaut que tout est permis : attention dino danger.
  • La présence de sandbox ou sandbox="" (sans valeur) signifie que toutes les restrictions sont appliquées par défaut : sécurité maximum.
  • L'énumération d'une ou plusieurs valeurs préfixées par allow va lever les restrictions une par une.

Par exemple, pour autoriser l'exécution de JavaScript, l'ouverture de pop-up et l'accès aux éléments de la page parente, on va utiliser la syntaxe suivante :

<iframe src="https://www.example.org/contenu.html" sandbox="allow-same-origin allow-scripts allow-popups allow-forms"></iframe>

Voici d'autres autorisations possibles :

  • allow-same-origin : permet au contenu de l'iframe d'être traité comme provenant de la même origine.
  • allow-downloads : autorise les téléchargements.
  • allow-scripts : autorise l'exécution de JavaScript dans l'iframe.
  • allow-popups : autorise l'ouverture de pop-up à partir de l'iframe.
  • allow-forms : autorise l'utilisation de formulaires dans l'iframe.
  • allow-top-navigation : autorise le contenu de l'iframe à charger une nouvelle page dans la fenêtre du navigateur.
  • allow-pointer-lock : autorise l'utilisation de la fonctionnalité de verrouillage du curseur/pointeur.
  • allow-orientation-lock : autorise le blocage de l'orientation de l'écran (sur smartphone/tablette notamment).
  • allow-presentation : autorise le lancement d'une session de présentation.

Cet attribut est épaulé par une directive CSP (Content-Security-Policy) qui définit ces valeurs au niveau des en-têtes HTTP renvoyées par le serveur, par exemple Content-Security-Policy: sandbox; ou Content-Security-Policy: sandbox allow-downloads;

Publié par Alsacreations.com

Menu accessible sur WordPress : les bases d'un menu simple

Dans cette première partie nous allons voir comment mettre en place un menu accessible simple, sans sous-menu : récapitulatif des bases, explications des notions importantes et des moyens pour rendre notre menu à un niveau accessible. C’est parti !

Créer un menu dans WordPress : les bases

Tout d’abord voyons en quelques étapes comment mettre en place un menu sur WordPress.

1) Enregistrer un emplacement de menu

Dans le fichier de configuration du thème (souvent functions.php ou un sous-fichier si vous prônez l’organisation comme chez Alsacréations) enregistrons un menu "Menu principal" avec la fonction register_nav_menu(). Il a pour slug main-menu qui nous sera utile pour afficher le menu :

function register_my_menu() {
    register_nav_menu( 'main-menu' => __( 'Menu principal', 'text-domain' ) );
}
add_action( 'after_setup_theme', 'register_my_menu' );

Dans l’administration WordPress, l’emplacement apparait dans les réglages du menu :

Dans les réglages du menu, l'emplacement “Menu principal“ est sélectionnable.

2) Afficher le menu

Il n’y a plus qu’à appeler le menu là où nous souhaitons l’afficher, dans l’en-tête header.php par exemple. Pour cela il faut utiliser la fonction wp_nav_menu() et préciser le slug précédemment enregistré :

/**
 * Affiche le menu "Menu principal" enregistré au préalable.
 */
wp_nav_menu([
    'theme_location' => 'main-menu',
]);

Cette fonction propose des options de configuration très avancées. Vous retrouverez la liste des paramètres disponibles sur la documentation officielle de wp_nav_menu.

3) Administrer le menu

Pour le moment nous souhaitons créer un menu simple. Pour cela créer un nouveau menu dans l'interface d'administration de WordPress, le nommer, et cocher l’emplacement enregistré à l’étape 1.

Dans l’administration WordPress, le menu principal est composé de 3 éléments “Accueil”, “Actualités” et “Contact”. L’emplacement coché est “Menu principal”.

Si vous avez bien suivi les étapes, vous devriez avoir un menu qui fonctionne à minima. Et voici le code généré par WordPress :

<div class="menu-menu-principal-container">
  <ul id="menu-menu-principal" class="menu">
    <li id="menu-item-256" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-home current-menu-item page_item page-item-251 current_page_item menu-item-256">
      <a href="">Accueil</a>
    </li>
    <li id="menu-item-290" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-290">
      <a href="">Actualités</a>
    </li>
    <li id="menu-item-253" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-253">
      <a href="">Contact</a>
    </li>
  </ul>
</div>

Rendre notre menu accessible

Côté accessibilité, le code généré possède quelques points à améliorer :

  • le conteneur du menu n’a pas de sémantique. C’est une simple <div>.
  • La page courante n’est pas restituée aux lecteurs d’écran.

Mais comment corriger cela ? La fonction wp_nav_menu() possède des paramètres qui pourront nous aider, mais cela ne nous permettra pas de tout corriger. Dans ce cas, il faudra modifier le code généré par WordPress.

Comment WordPress gère ce code ? Comment modifier ce code ?

Nous allons utiliser le walker Walker_Nav_Menu qui nous sera utile pour personnaliser le code généré. Mais avant, explications !

Qu’est ce qu’un Walker ?

Un walker est une classe abstraite PHP qui permet de parcourir une arborescence de données (objets ou tableaux) afin de générer du code HTML.

Par rapport à notre menu ➡️ le walker va parcourir le menu, et exécuter à chaque noeud une fonction.

Quand nous observons la classe dans le codex, le walker possède 4 fonctions :

  • start_lvl : correspond au début d’un sous-menu <ul> et son contenu.
  • end_lvl : Fin d’un sous-menu </ul>.
  • start_el : Début d’un élément du menu. Équivalent du <li> et son contenu.
  • end_el : Fin d’un élément </li>.
Visualisation des fonctions du walker Walker_Nav_Menu à travers un menu à deux niveaux.

Et l’avantage d’un walker, c’est qu’il est possible de l’étendre afin de customiser ces fonctions. Spoiler : c’est ce que nous allons faire 🤠.

Rendre notre menu sémantiquement parlant

Actuellement, notre menu est perçu simplement comme une liste, avec un conteneur ne donnant aucun contexte.

Nous allons donc ajouter un peu de sémantique pour restituer, à l’utilisateur et aux lecteurs d’écran, que c’est un menu de navigation. Pour cela, faisons appel aux landmarks ARIA.

Rappel : les landmarks permettent de déclarer des régions (header, main, footer, nav, aside, etc.) afin de structurer une page et de restituer le contexte aux lecteurs d’écran.

Ici, nous allons englober notre menu d’une balise <nav> avec un attribut ARIA role="navigation". Si plusieurs menus de navigation existent dans le site, une bonne pratique est de l’identifier via un attribut aria-label ou la combinaison aria-labelledby/id.

Si vous avez regardé en détail le codex de wp_nav_menu(), vous vous demanderez sûrement pourquoi ne pas utiliser les paramètres container et container_aria_label. Comme ils sont de type string, il n’aurait donc pas été possible de passer l’attribut role="navigation".

Nous privilégions donc de ne pas utiliser le conteneur généré par WP :

<nav role="navigation" aria-label="<?php _e('Menu principal', 'text-domain'); ?>">
    <?php
        wp_nav_menu([
            'theme_location' => 'main-menu',
            'container'      => false // On retire le conteneur généré par WP
        ]);
    ?>
</nav>

Préciser la page courante

Visuellement la page courante d’un menu peut-être indiquée par la couleur, la forme (bordure basse), une icône, etc. :

Exemple d’affichage pour indiquer la position courante (site Smashing Magazine)

Mais qu’en-est-il des personnes malvoyantes utilisant un lecteur d’écran ? Il faut une alternative HTML en plus de l’indication visuelle.

L’attribut aria-current rentre en piste ! Il permet d’indiquer aux lecteurs d’écran l’élément actif parmi un ensemble. Dans notre cas, il aura pour valeur :

  • page sur la page courante;
  • true sur la page parente, si existante.

Exemples :

<a href="#" aria-current="page">Accueil</a>
<a href="#" aria-current="true">Actualités</a>
<ul class="sub-menu">
  <li>
    <a href="#" aria-current="page">Sous-actualité</a>
  </li>
  <li>
    <a href="#">Sous-actualité</a>
  </li>
</ul>

Mais.. comment faire sur WordPress ? Si vous avez bien suivi c’est le moment d’étendre le walker 🚀

Étendre le walker par défaut

Pour cela, nous allons dans un premier temps créer un nouveau fichier menus.php et l’appeler dans le fichier functions.php.

Dans ce fichier nous allons simplement copier/coller le walker existant de WordPress Walker_Nav_Menu.

Quel est l’intérêt me direz-vous ? Simplement pour éviter de faire des erreurs. Nous aurons juste à customiser la/les fonction(s) souhaitée(s).

La seconde étape est de renommer le walker pour le distinguer d’autres potentiels walkers :

class A11y_Walker_Nav_Menu extends Walker {

Ensuite, nous allons appeler ce walker dans la fonction wp_nav_menu() en ajoutant un paramètre walker pour créer une instance de notre classe A11y_Walker_Nav_Menu :

<nav role="navigation" aria-label="<?php _e('Menu principal', 'text-domain'); ?>">
  <?php
    wp_nav_menu([
        'theme_location' => 'main-menu',
        'container'      => false,
        'walker'         => new A11y_Walker_Nav_Menu()
    ]);
  ?>
</nav>

Personnaliser notre nouveau walker

Notre objectif est d’ajouter un attribut aria-current sur un élément du menu lorsqu’il correspond à la page courante.

Comme précisé plus haut, c’est la fonction start_el() qui va permettre de modifier le contenu d’un élément du menu.

Avant tout, regardons plus en détail cette fonction :

/**
 * Starts the element output.
 *
 * @since 3.0.0
 * @since 4.4.0 The {@see 'nav_menu_item_args'} filter was added.
 * @since 5.9.0 Renamed `$item` to `$data_object` and `$id` to `$current_object_id`
 *              to match parent class for PHP 8 named parameter support.
 *
 * @see Walker::start_el()
 *
 * @param string   $output            Used to append additional content (passed by reference).
 * @param WP_Post  $data_object       Menu item data object.
 * @param int      $depth             Depth of menu item. Used for padding.
 * @param stdClass $args              An object of wp_nav_menu() arguments.
 * @param int      $current_object_id Optional. ID of the current menu item. Default 0.
 */
public function start_el( &$output, $data_object, $depth = 0, $args = null, $current_object_id = 0 ) {
    // Restores the more descriptive, specific name for use within this method.
    $menu_item = $data_object;

    // Suite de la fonction...

Les commentaires nous précisent que :

  • le paramètre $output est le résultat de la fonction sous forme de contenu HTML.
  • Le paramètre $data_object est un objet qui nous permet de récupérer toutes les informations de l’élément. À noter que la première ligne de la fonction nous précise d’utiliser $menu_item. Cette variable regroupe plusieurs clés (n’hésitez pas à explorer son contenu en utilisant var_dump($menu_item) ).

Arrêtons-nous sur la clé current. C’est un booléen qui a pour valeur true lorsque l’élément correspond à la page courante. Parfait, c’est ce que nous voulons !

Mais comment ajouter un attribut à l’élément ? Et bien WordPress ne fait pas les choses à moitié : si vous regardez bien la fonction, un paramètre $atts est mis à disposition. Il utilise le filtre nav_menu_link_attributes :

$atts = apply_filters( 'nav_menu_link_attributes', $atts, $menu_item, $args, $depth );

Ce filtre permet d’ajouter/modifier des attributs à l’élément actuel. Il faut donc ajouter, avant la ligne ci-dessus, le code suivant :

$atts['aria-current'] = $menu_item->current ? 'page' : '';

Et voilà, l’attribut est ajouté dans le code lorsque $menu_item possède la clé current. Plutôt simple, hein ?

Ajouter un attribut title si le lien s’ouvre dans un nouvel onglet

L’utilisation d’un attribut title permet d’ajouter un complément d’information. Attention à l’utiliser correctement : il faut reprendre l’intitulé du lien, puis ajouter le texte complémentaire (notes du glossaire RGAA).

Dans notre cas nous allons préciser qu’un lien s’ouvre dans un nouvel onglet lorsque son target vaut _blank:

Exemple :

<a href="#" target="_blank" title="Intitulé du lien (s'ouvre dans un nouvel onglet)">Intitulé du lien</a>

Préciser cette action permet de prévenir les utilisateurs d’un changement brusque et éviter de perturber leur navigation.

Comment le faire sur WordPress ?

Nous allons donc modifier la fonction start_el() pour ajouter un title lorsque le target est _blank. Si vous regardez bien, cette condition existe déjà :

if ( '_blank' === $menu_item->target && empty( $menu_item->xfn ) )

Il n’y a plus qu’à ajouter l’attribut title et lui donner pour valeur le titre de l’élément title suivi de notre texte :

if ( '_blank' === $menu_item->target && empty( $menu_item->xfn ) ) {

 // Attribut title : on précise que le lien s'ouvre dans un nouvel onglet
 $atts['title'] = $menu_item->title . __( ' (s\'ouvre dans un nouvel onglet)', 'text-domain' );

}

Voilà ce qu’il en est pour la mise en place d’un menu accessible simple. Cette première partie était assez longue car nous trouvions important de revenir sur les bases de la création d’un menu WordPress. La prochaine entrera directement dans le vif du sujet et concernera la gestion des sous-éléments d’un menu.

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

Le scroll maîtrisé avec scrollIntoView

La méthode scrollIntoView() du DOM est pratique pour faire défiler la page web de manière à ce qu'un élément devienne visible à l'écran... "dans la vue". Cela peut être utile lorsqu'un élément est en dehors de la zone visible de la page, par exemple s'il est caché sous la ligne de flottaison, ou si l'utilisateur a défillé (scrollé) la page jusqu'à un point plus éloigné.

Pour utiliser la méthode scrollIntoView(), vous devez d'abord sélectionner l'élément concerné en utilisant une méthode telle que document.querySelector() ou document.getElementById(), puis appeler la méthode scrollIntoView() sur cet élément. Par exemple :

// Sélection de l'élément à faire défiler
const el = document.querySelector('.mon-element');

// Faire défiler l'élément jusqu'à ce qu'il soit visible à l'écran
el.scrollIntoView();

La méthode scrollIntoView() accepte également des options pour contrôler comment l'élément est fait défiler. Par exemple, vous pouvez spécifier si l'élément doit être aligné en haut, en bas, à gauche ou à droite de la zone visible, ou si le défilement doit se faire en douceur ou instantanément. Pour utiliser ces options, vous pouvez passer un objet de configuration en argument de la méthode, comme dans l'exemple suivant :

// Sélection de l'élément à faire défiler
const el = document.querySelector('.mon-element');

// Options de défilement : aligner en haut, défilement en douceur
const scrollOptions = {
  behavior: 'smooth',
  block: 'start'
};

// Faire défiler l'élément jusqu'à ce qu'il soit visible à l'écran en utilisant les options spécifiées
el.scrollIntoView(scrollOptions);

La méthode scrollIntoView() permet de faire défiler un élément de la page web de manière à ce qu'il soit visible à l'écran en utilisant des options de défilement personnalisées si nécessaire. C'est bien plus efficace que les anciennes techniques qui consistaient à trouver l'élément cible, déterminer ses coordonnées en pixels dans la totalité du document et à provoquer un défilement équivalent de l'ensemble de la page avec window.scroll().

Publié par Alsacreations.com

❌
❌