<?xml version="1.0" encoding="utf-8"?>
<!-- generator="Kirby" -->
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">

  <channel>
    <title>Vincent V. Billets.</title>
    <link>https://vincent-valentin.name/tout</link>
    <generator>Kirby</generator>
    <lastBuildDate>Mon, 27 Jan 2025 00:00:00 +0100</lastBuildDate>
    <atom:link href="https://vincent-valentin.name/actualites" rel="self" type="application/rss+xml" />

        <description>Nouveaux billets chez Vincent Valentin.</description>
    
        <item>
      <title>Construire pour le Web, construire sur le Web, construire avec le Web</title>
      <link>https://vincent-valentin.name/articles/construire-pour-le-web-construire-sur-le-web-construire-avec-le-web</link>
      <guid>https://vincent-valentin.name/articles/construire-pour-le-web-construire-sur-le-web-construire-avec-le-web</guid>
      <pubDate>Mon, 27 Jan 2025 00:00:00 +0100</pubDate>
      <description><![CDATA[<p><em>Une traduction de <a href="https://csswizardry.com/2025/01/build-for-the-web-build-on-the-web-build-with-the-web/">Build for the Web, Build on the Web, Build with the Web</a> avec autorisation de l’auteur, Harry Roberts.</em></p>
<p>Si vous voulez construire pour le Web, construisez sur le Web et construisez avec le Web.</p>
<p>Si je ne devais donner qu’un seul conseil aux entreprises, ce serait <strong>d’itérer rapidement sur une plateforme qui évolue lentement.</strong></p>
<p>Au cours de la seule année dernière, j’ai vu deux clients complètement différents, dans deux secteurs complètement différents, consacrer des mois et des mois à des mises à niveau de leurs environnement de travail. Collectivement, ils ont dépensé des dizaines, voire des centaines de milliers de dollars pour réécrire des projets entiers dans le seul but de maintenir les mêmes fonctionnalités qu’avec l’itération précédente. Il ne s’agit pas d’un travail utile ou productif, mais de temps perdu à se contenter de rester à la même place.</p>
<p>C’est d&#8217;une certaine façon un emprisonnent dans un écosystème, où ajouter la moindre amélioration de performance même la plus triviale devient impossible vu que les <em>framework</em> offusquent, et parfois même empêchent de regarder sous le capot. Le pire ? Vous devrez tout recommencer dans 18 mois ! Vous êtes contraint par les choix technologiques, et vous héritez de toute une équipe de développement qui doit être payée un ou deux trimestres tous les deux ou trois ans, juste pour faire du sur-place.</p>
<p>Elles font des <strong>itérations lentes sur une plateforme qui évolue rapidement.</strong></p>
<p>Le plus triste dans tout cela, c’est qu’il s’agit d’anciens clients qui ont dû me réembaucher parce que les « mises à jour » s’accompagnaient de graves régressions de la vitesse du site. Même si c’est bon pour les affaires, je déteste faire le même travail avec le même client plus d’une fois. Après tout, on ne devrait jamais avoir à appeler deux fois le dératiseur.</p>
<p>Le Web en tant que plateforme est une valeur sûre. Par conception il n’a pas de version. C’est l’engagement que le Web prend à votre égard : profitez-en.</p>
<ol>
<li>
<p><strong>Adopter progressivement les fonctionnalités de la plate-forme Web.</strong> Pour paraphraser mon ami <a href="https://twnsnd.com/">Ryan Townsend</a> : <a href="https://www.youtube.com/watch?v=f5felHJiACE&amp;t=1202s">les clients ne veulent pas des transitions de page fluides – ils veulent un site Web qui fonctionne</a>. Ne faites pas de votre site une <em>Single Page Application</em> unique juste pour ne pas avoir à renvoyer une en-tête et un pied de page.</p>
</li>
<li>
<p><strong>Adoptez l’amélioration progressive pour créer des applications rapides et fiables qui s’adaptent au contexte de vos clients.</strong> L’intérêt d’opter pour les fonctionnalités de la plateforme Web au fur et à mesure qu’elles sont disponibles est que votre site devient adaptatif. La même base de code s’adapte à son environnement, en jouant sur ses points forts, plutôt que d’essayer de construire et d’expédier votre propre environnement à partir de zéro. Rencontrez vos utilisateurs là où ils se trouvent.</p>
</li>
<li><strong>Écrivez un code qui s’appuie sur le navigateur, et non qui s’en éloigne.</strong> En utilisant l’amélioration progressive, vous pouvez opter pour des fonctionnalités natives du navigateur qui sont généralement plus rapides, plus accessibles, plus sûres et, ce qui est peut-être le plus important pour l’entreprise, maintenues par quelqu’un d’autre.</li>
</ol>
<p>Tout cela me rappelle douloureusement quelque chose. En 2007 déjà, <a href="https://simplebits.com/about/">Dan Cederholm</a> nous présentait <a href="https://web.archive.org/web/20071212220950/http://dowebsitesneedtolookexactlythesameineverybrowser.com/">do­WebSites­Need­To­Look­Exactly­The­Same­In­Every­Browser.com</a> (je vous épargne le click : la réponse est non). Il y a près de 20 ans, la discussion portait sur des aspects visuels beaucoup plus triviaux, tels que les coins arrondis et les ombres portées, mais le sentiment reste vrai aujourd’hui : il est totalement absurde d’envoyer des centaines de kilo-octets de JavaScript pour donner à un site par ailleurs statique une navigation souple et douce. De nos jours, il suffit d’une ligne de CSS<sup id="fnref1:1"><a href="#fn:1" class="footnote-ref">1</a></sup> et, dans le pire des cas, les navigateurs qui ne le prennent pas en charge parcourent votre site comme ils ont toujours été conçus pour le faire. <a href="https://www.youtube.com/watch?v=tqOkWWV6a_U">Votre escalator est devenu un escalier</a>.</p>
<p>La plateforme Web évolue lentement, et je comprends que cela puisse être frustrant pour les développeurs qui veulent innover, mais plus d’une décennie d’expérience en matière de conseil m’a appris à maintes reprises que l’alternative est beaucoup plus restrictive à long terme. Ce qui est tout nouveau aujourd’hui commence à montrer des signes de vieillissement beaucoup plus rapidement que quelque chose qui a déjà résisté à l’épreuve du temps.</p>
<p>Chaque couche d’abstraction réalisée dans le navigateur vous éloigne de la plateforme, vous enferme davantage dans un cadre et vous éloigne de la performance.</p>
<p>Je reste convaincu que le développeur moyen n’en sait pas assez sur l’analyse commerciale et que l’analyste commercial type n’en sait pas assez sur le développement pour réconcilier pleinement les deux côtés de la médaille. Des discussions plus approfondies et plus équilibrées, à long terme, doivent être menées par les deux parties, car le verrouillage (et son coût permanent) est bel et bien réel, et les paillettes d’aujourd’hui seront rapidement le boulet de demain.</p>
<p>Je ne suis pas contre les <em>frameworks</em> front et, croyez-moi, je ne suis pas assez naïf pour croire que la seule chose qu’un <em>frameworks</em> front apporte, ce sont des transitions entre pages agréables, mais si vous vous apprêtez à en utiliser un, il faudrait que je ne sois pas en mesure de pouvoir le détecter.</p>
<p>Si vous optez pour un <em>frameworks</em> ou, à défaut, pour une <em>Single Page Application</em>, pensez sérieusement au long terme et assurez-vous de faire du très bon travail.</p>
<p>C’est <a href="https://nolanlawson.com/">Nolan Lawson</a> qui a le mieux résumé la situation lorsqu’il a déclaré que « <a href="https://nolanlawson.com/2022/06/27/spas-theory-versus-practice/">la meilleure <em>Single Page Application</em> est meilleure que la meilleur site Web multi-page ; la <em>Single Page Application</em> moyenne est pire que le site Web multi-page moyen</a> ».</p>
<div class="footnotes">
<hr />
<ol>
<li id="fn:1">
<p><code>@view-transition { navigation: auto; }</code>&#160;<a href="#fnref1:1" rev="footnote" class="footnote-backref">&#8617;</a></p>
</li>
</ol>
</div>]]></description>
    </item>
        <item>
      <title>Safari et text-overflow</title>
      <link>https://vincent-valentin.name/articles/safari-et-text-overflow</link>
      <guid>https://vincent-valentin.name/articles/safari-et-text-overflow</guid>
      <pubDate>Mon, 15 Jul 2024 00:00:00 +0200</pubDate>
      <description><![CDATA[<p>Je découvre que Safari a un comportement qu’il est le seul à proposer.</p>
<p>Quand on tronque un contenu avec un <code>overflow: hidden</code>, on peut définir la manière dont les textes se comporteront avec <code>text-overflow</code>. Généralement ce sont des points de suspension qui sont choisis. Notez que le résultat est uniquement visuel : cela n’affecte pas les lecteurs d’écrans par exemple.</p>
<pre><code>.ellipsis {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}</code></pre>
<p>Safari propose de pouvoir accéder à l’intégralité du contenu via une infobulle, qu’il génère automatiquement en fonction de si le contenu déborde ou non. Plutôt malin, même si ça ne fonctionne que sur ce navigateur à ma connaissance et qu’en version <em>desktop</em>.</p>
<p>Si on ne souhaite pas de cet ajout (car on implémente son propre système d’infobulles par exemple) il va falloir ruser. Ajouter un attribut <code>title</code> vide ne fonctionne pas.</p>
<p>Seules solutions trouvées relativement indolores :</p>
<ul>
<li>ajouter une <code>div</code> vide à côté du texte potentiellement tronqué ;</li>
<li>ou générer un pseudo élément vide avec un <code>display: block</code> (si on souhaite contrôler ça via CSS).</li>
</ul>
<p><a href="https://codepen.io/vincent-valentin/pen/yLdYYXE?editors=1100">Le CodePen dédié au sujet est ici.</a></p>]]></description>
    </item>
        <item>
      <title>Une interaction responsive</title>
      <link>https://vincent-valentin.name/articles/une-interaction-responsive</link>
      <guid>https://vincent-valentin.name/articles/une-interaction-responsive</guid>
      <pubDate>Wed, 17 Apr 2024 00:00:00 +0200</pubDate>
      <description><![CDATA[<p>Il y a plus d’un an, <i lang="en">Scott O’Hara</i> publiait  un article qui <a href="https://www.scottohara.me/blog/2022/11/07/responsive-accessibility.html">présentait une technique basée uniquement sur CSS pour activer une interaction en fonction d’un point de rupture</a>.</p>
<p>J’ai trouvé cette façon de faire très intéressante (bien qu’un peu obscure au premier abord – ce qui semble être son défaut principal) et je l’ai éprouvée plusieurs fois dans des cas réels.</p>
<p>C&#8217;est pour ces raisons que je me permets de proposer ici mon analyse de la technique, en français.</p>
<h2>Objectifs</h2>
<p>Rendre une interaction accessible nécessite certains basiques.</p>
<p>Il vous faut un élément :</p>
<ul>
<li>qui se signale comme actionnable ;</li>
<li>qui soit atteignable avec le périphérique de saisie comme avec le périphérique de pointage ;</li>
<li>qui remonte un état sémantique et visuel reflétant la position de l’interaction ;</li>
<li>qui déclenche un comportement quand l’interaction sera lancée.</li>
</ul>
<p>Imaginons maintenant que cette interaction n’a de sens que quand le composant qui l’abrite possède une largeur étroite (comme sur mobile par exemple) mais qu’elle se désactive sur une largeur plus importante.</p>
<p>Il va falloir alors désactiver (en <i lang="en">desktop</i>) tout ce qui a été fait plus haut :</p>
<ul>
<li>l’élément actionnable ne doit plus se signaler comme tel ;</li>
<li>il ne doit plus être atteignable ni au clavier ni à la souris ;</li>
<li>l’état sémantique et visuel de l’interaction ne doit plus apparaître ;</li>
<li>et aucun comportement ne doit pouvoir se déclencher.</li>
</ul>
<p>Problème : tout cela demande de modifier fortement le DOM, et d’ajouter un écouteur sur la largeur du <i lang="en">viewport</i> (ou du composant).</p>
<h2>Un cas concret</h2>
<p>Imaginons un motif de conception tel qu’un panneau dépliant (<i lang="en">disclosure</i>).</p>
<p>En mobile, on imagine un code de ce type :</p>
<pre><code>&lt;h3&gt;
    &lt;button class="toggle" type="button" aria-expanded="false" aria-controls="panel"&gt;
        Titre
        &lt;span class="toggle-arrow" aria-hidden="true"&gt;
            &lt;span class="toggle-arrow-up"&gt;↑&lt;/span&gt;
            &lt;span class="toggle-arrow-down"&gt;↓&lt;/span&gt;
        &lt;/span&gt;
    &lt;/button&gt;
&lt;/h3&gt;
&lt;div id="panel"&gt;
    &lt;p&gt;Panneau affiché ou masqué.&lt;/p&gt;
&lt;/div&gt;</code></pre>
<p>Et en <i lang="en">desktop</i>, on s’attend plutôt à ceci :</p>
<pre><code>&lt;h3&gt;Titre&lt;/h3&gt;
&lt;p&gt;Panneau toujours affiché.&lt;/p&gt;</code></pre>
<p>Ce que <i lang="en">Scott</i> propose, c’est une technique basée sur la propriété CSS <code>visibility</code> pour basculer de l’un à l’autre, uniquement via une modification CSS.</p>
<h2>Comment ça marche ?</h2>
<p>La propriété <code>visibility: hidden</code> à la réputation ne pas être accessible, à raison, car si elle masque visuellement comme on pourrait s’y attendre l’élément ciblé, elle lui supprime également tout accès :</p>
<ul>
<li>sémantique ;</li>
<li>avec un périphérique de saisie ;</li>
<li>avec un périphérique de pointage.</li>
</ul>
<p>Or, il se trouve que c’est ce qui nous intéresse ici (du moins en <i lang="en">desktop</i>) !</p>
<p>Et il se trouve de surcroît que <code>visibility: hidden</code> peut être annulée sur ses descendants avec un <code>visibility: visible</code>.</p>
<p>Quelque chose qui serait impossible avec <code>aria-hidden</code> ou <code>opacity: 0</code> par exemple.</p>
<div class="codepen" data-height="500" data-default-tab="html, result" data-slug-hash="wvZYobo" data-user="vincent-valentin">
<a href="https://codepen.io/vincent-valentin/pen/wvZYobo">Démonstration de descendants qui essayent d’annuler les propriétés héritées de leurs parents.</a>
</div>
<p style="margin-top: 1.5rem">Bref, on a tout ce qu’il nous faut pour basculer d’une version à l’autre, en appliquant (ou non) la propriété au bon endroit.</p>
<h2>Le résultat</h2>
<p><a href="https://codepen.io/vincent-valentin/pen/JjZrbex">Voici ce que ça peut donner avec un code complet</a>. Charge à vous de redimensionner votre navigateur pour basculer de la vue mobile à la vue <i lang="en">desktop</i>.</p>
<p>À travers une technologie d’assistance, voici un exemple de la vocalisation qui sera alors faite sur le titre.</p>
<ul>
<li>En <i lang="en">desktop</i> : <q>Niveau d’en-tête 3, Lorem ipsum</q>.</li>
<li>En mobile : <q>Niveau d’en-tête 3, Lorem ipsum, Étendu, button, groupe</q>.</li>
</ul>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>]]></description>
    </item>
        <item>
      <title>Un rognage rectangulaire arrondi</title>
      <link>https://vincent-valentin.name/articles/un-rognage-rectangulaire-arrondi</link>
      <guid>https://vincent-valentin.name/articles/un-rognage-rectangulaire-arrondi</guid>
      <pubDate>Sun, 14 Apr 2024 00:00:00 +0200</pubDate>
      <description><![CDATA[<p>Une découverte personnelle récente : il est possible de passer un paramètre supplémentaire à la fonction CSS <code>inset()</code> afin d’arrondir les angles du rectangle formé.</p>
<p>Un exemple avec un <code>clip-path</code> sur un élément qui se voit rogné sur ces quatre côtés de 10 pixels :</p>
<pre><code>clip-path: inset(10px round 20px);</code></pre>
<p class="codepen" data-height="600" data-default-tab="result" data-slug-hash="bGJjMLG" data-user="vincent-valentin">
<a href="https://codepen.io/vincent-valentin/pen/bGJjMLG">Exemples de clip path avec ou sans le second paramètre.</a>
</p>
<p style="margin-top: 1.5rem">Il est bien sûr possible de passer des valeurs multiples si on ne souhaite pas un rognage ou un arrondi identique aux quatre coins :</p>
<pre><code> clip-path: inset(10px 0 0 20px round 20px 60px 0);</code></pre>
<p class="codepen" data-height="600" data-default-tab="result" data-slug-hash="YzMjLLR" data-user="vincent-valentin">
<a href="https://codepen.io/vincent-valentin/pen/YzMjLLR">Exemples de clip path avec les paramètres possédant des valeurs multiples.</a>
</p>
<p style="margin-top: 1.5rem">Combiné à d’autres propriétés (ou non), ce paramètre permet des effets intéressants :</p>
<p class="codepen" data-height="800" data-default-tab="result" data-slug-hash="xxeJYXB" data-user="vincent-valentin">
  <a href="https://codepen.io/vincent-valentin/pen/xxeJYXB">Exemple interactif.</a>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>]]></description>
    </item>
        <item>
      <title>color-mix</title>
      <link>https://vincent-valentin.name/articles/color-mix</link>
      <guid>https://vincent-valentin.name/articles/color-mix</guid>
      <pubDate>Mon, 25 Mar 2024 00:00:00 +0100</pubDate>
      <description><![CDATA[<p>J’ai découvert récemment la fonction CSS <code>color-mix()</code> et elle offre plein de possibilités intéressantes. Je vous partage mes explorations.</p>
<h2>Fonctionnement</h2>
<p>Pour l’utiliser, il va falloir obligatoirement préciser à la fonction votre espace de couleur, ce qui peut faire un peu peur.</p>
<p>Si vous n’en avez aucune idée, <a href="https://developer.mozilla.org/fr/docs/Web/CSS/color_value">il y a de grandes chances que cet espace soit sRGB</a>.</p>
<hr />
<p>Je connais assez mal le sujet des espaces de couleurs, mais je crois pouvoir dire :</p>
<ul>
<li>qu’il s’agit de diverses abstractions pour représenter les couleurs dans l’espace (bidimensionnel ou tridimensionnel) ;</li>
<li>que chaque représentation a ses défauts et ses inconvénients (facilité de lecture, prédiction de couleur lorsqu’elles sont mélangées, naturel dans la création de dégradés…) ;</li>
<li>que sRGB a été pendant longtemps la référence, mais qu’il sera bientôt remplacé par OKLCH.</li>
</ul>
<hr />
<p>Une fois votre espace de couleur défini, il restera à passer en paramètre deux couleurs, éventuellement accompagnées de leurs proportions respectives (exprimées en pourcentages).</p>
<p>Par exemple : <code>color-mix(in srgb, red 25%, blue)</code>.</p>
<p>Après quelques tests, quelques enseignements : </p>
<ul>
<li>on ne peut passer que deux couleurs (pas plus, pas moins) ;</li>
<li>l’ordre des couleurs n’importe pas ;</li>
<li>si les deux proportions ne sont pas définies, elles seront automatiquement à 50 % respectivement ;</li>
<li>si une des proportions n’est pas définie, elle sera automatiquement calculée pour que le total soit à 100 % ;</li>
<li>si le total des proportions dépasse les 100 %, elles seront rééquilibrées proportionnellement pour que le total soit à 100 % ;</li>
<li>si le total des proportions n’atteint pas les 100 %, la couleur résultante deviendra semi-transparente à la hauteur de la proportion manquante.</li>
</ul>
<h2>Avantages</h2>
<p>La fonction étant native à CSS, cela lui offre des possibilités qu’on ne pouvait atteindre avec des alternatives comme Sass.</p>
<h3>La semi-transparence avec <code>transparent</code></h3>
<p>On peut passer comme couleur de mélange le mot-clef <code>transparent</code>, ce qui permet de facilement rendre une couleur semi-transparente.</p>
<p>C’est l’équivalent de natif <a href="https://sass-lang.com/documentation/modules/color/#transparentize">la fonction <code>transparentize()</code> de Sass</a>.</p>
<h3>Les variables avec <i lang="en">CSS vars</i></h3>
<p>Chaque paramètre de la fonction peut être géré avec une variable CSS si nécessaire. Je pense que ça peut être pratique, notamment  pour définir l’espace de couleur.</p>
<pre><code>.colorMix {
  background-color: color-mix(
    in var(--colorSpace, srgb),
    var(--color1),
    var(--color2)
  );
}</code></pre>
<pre><code>&lt;div class="colorMix" style="--color1: blue 25%; --color2: red 75%"&gt;&lt;/div&gt;</code></pre>
<p>Quelque soit la manière dont sera définie une couleur (en hexadécimal par exemple), elle pourra être mixée avec de la transparence.</p>
<p>Ce point est particulièrement intéressant si vous regroupez toutes vos couleurs dans des palettes au sein de votre <i lang="en">design system</i> et que vous souhaitez introduire des variations d’opacité sur cette base.</p>
<p>Bonne nouvelle supplémentaire : il semblerait que l’espace de couleur importe peu dans ce cas de figure. Impossible donc de se tromper ici.</p>
<h3>La couleur courante avec <code>currentColor</code></h3>
<p>Si on souhaite produire par exemple des palettes qui s’appliquent à des composants (imaginons un message de succès en vert, d’erreur en rouge, et d’avertissement en jaune) il sera très facile de ne passer qu’une couleur (celle du texte), et de créer des variations (d’opacité, de luminosité…) aux propriétés qui définissent l’apparence du composant en jouant à la fois avec <code>color-mix()</code> et <code>currentColor</code>.</p>
<p>Côté Sass, les fonctions de luminosité sont <a href="https://sass-lang.com/documentation/modules/color/#lighten"><code>lighten()</code></a> et <a href="https://sass-lang.com/documentation/modules/color/#darken"><code>darken()</code></a>, mais là encore, il est impossible de leur passer des variables CSS.</p>
<hr />
<p>Pour conclure, <a href="https://codepen.io/vincent-valentin/pen/PogjJvj?editors=1100">voici le CodePen qui vous permettra de tester tout cela pour vous même</a>.</p>]]></description>
    </item>
        <item>
      <title>Un focus trap moderne</title>
      <link>https://vincent-valentin.name/articles/un-focus-trap-moderne</link>
      <guid>https://vincent-valentin.name/articles/un-focus-trap-moderne</guid>
      <pubDate>Mon, 18 Mar 2024 00:00:00 +0100</pubDate>
      <description><![CDATA[<h2>Le besoin</h2>
<p>L’exemple classique pour décrire la mise en place d’un piège pour le focus, c’est l’ouverture d’une boîte de dialogue modale.</p>
<p>« Modale » signifie que l’accès à son contenu est exclusif ; le reste  (en dehors du <i lang="en">dialog</i>) est interdit et cela est signifié de plusieurs manières :</p>
<ul>
<li>graphiquement, avec un arrière-plan (souvent semi-transparent) qui vient recouvrir les parties désactivées ;</li>
<li>mécaniquement, avec ce même arrière-plan qui empêche de cliquer sur les éléments qui se situent en dessous ;</li>
<li>sémantiquement, avec une désactivation de toute la partie de l’arbre DOM associée (très souvent via un <code>aria-hidden</code>).</li>
</ul>
<p>Et je n’oublie pas la navigation au clavier (puisque c’est notre sujet) ; celle-ci doit être réduite exclusivement au contenu de la boîte de dialogue :</p>
<ol>
<li>On détecte le dernier élément focusable (ainsi que le premier) de notre boîte de dialogue.</li>
<li>On écoute les tabulations clavier.</li>
<li>Si une tabulation est déclenchée lorsque le focus est sur le dernier élément, on déplace le focus sur le premier (et inversement en cas de navigation arrière).</li>
</ol>
<p>Nous voilà avec un beau <i lang="en">focus trap</i> !</p>
<h2>Sauf que…</h2>
<p>On souhaitait désactiver la navigation clavier sur une partie du DOM ; et on l’a finalement piégée dans l’autre partie. </p>
<p>C&#8217;est presque pareil mais… Si on souhaite atteindre la barre d’adresse du navigateur, il n’est plus possible d’appuyer uniquement sur la tabulation pour ça. Heureusement, il existe d’autres raccourcis claviers dans les technologies d’assistance pour cela, mais on a quand même cassé quelque chose.</p>
<h2>Une autre piste ?</h2>
<p>L’autre approche connue, c’est de lister tous les éléments focusables en dehors de la boîte de dialogue et de les désactiver avec un <code>tabindex</code> négatif.</p>
<p>Ça fonctionne mieux et c’est plus logique, mais ça demande de ne rien oublier (ni à la désactivation, ni à la réactivation).<br />
Et ça peut amener à modifier énormément de nœuds DOM (ce qui n’est jamais très bon signe).</p>
<h2>La solution moderne</h2>
<p>On cherche donc sur plusieurs éléments :</p>
<ul>
<li>à désactiver les clics ;</li>
<li>à désactiver les focus ;</li>
<li>à supprimer leurs sémantiques ;</li>
<li>tout en conservant leurs apparences.</li>
</ul>
<p>Il existe un nouvel attribut universel appelé <code>inert</code> qui fait tout ça d’un coup, et qui permet de le faire <strong>en ciblant directement le parent commun</strong> de tout les éléments que nous souhaitons désactiver.</p>
<p>Avec très peu de modifications du DOM et sans modifier le comportement natif de focus, nous avons le résultat souhaité !</p>
<h2>Un autre cas pratique</h2>
<p>Devinez ce qu’il serait possible de faire pour les éléments d’un carrousel qui ne sont pas visibles ?</p>
<p>Je pense que nous avons là une solution tout à fait adaptée, facilement combinée avec <i lang="en">Intersection Observer</i> par exemple.</p>]]></description>
    </item>
        <item>
      <title>Les cellules de tableau vides</title>
      <link>https://vincent-valentin.name/articles/les-cellules-de-tableau-vides</link>
      <guid>https://vincent-valentin.name/articles/les-cellules-de-tableau-vides</guid>
      <pubDate>Sat, 16 Mar 2024 00:00:00 +0100</pubDate>
      <description><![CDATA[<p>Dans les tableaux de données il arrive parfois que des cellules restent vides, ce qui peut donner l’impression que votre tableau est mal structuré graphiquement si ces cellules sont nombreuses ou placées aléatoirement.</p>
<p>Aussi, on peut vouloir y placer un indicateur graphique ou textuel qui remplira la cellule.</p>
<p>La restitution des cellules vides peut différer en fonction du lecteur d’écran que vos utilisateurs utilisent, mais elle devrait rester identique quel que soit le tableau parcouru.</p>
<p>Avec <i lang="en">VoiceOver</i> sous Mac, on peut entendre par exemple « vierge, colonne trois sur quatre » ; et je ne souhaite pas que l’ajout d’un caractère typographique décoratif vienne perturber cette restitution. </p>
<p>La pseudo-classe <code>:empty</code> semble idéale ici : </p>
<ul>
<li>elle va permettre de détecter les cellules vides ;</li>
<li>l’injection d’un contenu via un pseudo-élément n’aura pas d’impact sur celle-ci.</li>
</ul>
<p>Mais comme <a href="https://vincent-valentin.name/articles/contenus-css-et-lecteurs-decrans">nous l’avons vu par le passé</a>, les contenus générés dans des pseudo-éléments sont vocalisés, nous allons donc essayer d’empêcher ça.</p>
<p>CSS prévoit la possibilité de passer une alternative aux contenus générés via cette syntaxe :</p>
<pre><code>::before {
    content: '★★★' / 'Trois étoiles';
}</code></pre>
<p>On pourrait donc envisager d’écrire quelque chose du style : </p>
<pre><code>td:empty::before {
    content: '–' / '';
}</code></pre>
<p>Malheureusement, le support de cette syntaxe reste trop aléatoire à ce jour.</p>
<p>Je retiens donc une solution qui ne se base pas que sur CSS, et je préfère injecter dans mes cellules vides ce petit bout de HTML :</p>
<pre><code>&lt;td&gt;&lt;span aria-hidden="true" data-before-content="–"&gt;&lt;/span&gt;&lt;/td&gt;</code></pre>
<p>Le <code>aria-hidden</code> permet de conserver une sémantique de cellule vide, et le tout combiné à cette règle CSS, cela fonctionne parfaitement :</p>
<pre><code>[data-before-content]::before {
    content: attr(data-before-content);
}</code></pre>
<p>Avantages à passer ainsi par un attribut de donnée (<code>data-*</code>) :</p>
<ul>
<li>le contenu textuel reste décoratif et lié à la présence de CSS ; </li>
<li>il serait plus facile de le traduire (si besoin) sans devoir générer des fichiers CSS dédiés aux langues.</li>
</ul>
<hr />
<p><a href="https://codepen.io/vincent-valentin/pen/vYbWpBp?editors=1100">Le CodePen qui permet de tester les différentes approches est ici</a>.</p>]]></description>
    </item>
        <item>
      <title>position: sticky + inset: 0</title>
      <link>https://vincent-valentin.name/articles/position-sticky-inset-0</link>
      <guid>https://vincent-valentin.name/articles/position-sticky-inset-0</guid>
      <pubDate>Thu, 14 Mar 2024 00:00:00 +0100</pubDate>
      <description><![CDATA[<p>Le mercredi après-midi au boulot, on profite d’un temps commun entre gens du même métier. (On appelle ça la guilde.) C’est l’occasion d’échanger sur des sujets divers, mais le plus souvent c’est basé sur le partage de connaissances et c’est tombé récemment sur le sujet de la position <i lang="en">sticky</i>.</p>
<p>Je ne vais pas refaire l’atelier ici, mais je constate souvent que cette méthode de positionnement est difficile à appréhender.</p>
<p>Personnellement j’aime imaginer une boîte dont le positionnement lui donne la capacité de <em>glisser</em> au sein de son conteneur (direct).  Et ceci dans le but de rester le plus longtemps possible visible dans la zone scrollable la plus proche.<br />
Par extension, il faut donc que le conteneur de la boîte positionnée ait une taille plus grande que celui-ci.</p>
<p>Après avoir parcouru avec mes collègues différents cas pratiques pour illustrer ce concept, j’ai regretté de ne pas avoir d’exemple montrant qu’on pouvait appliquer l’effet dans les quatre directions à la fois (<i lang="en">top/bottom/left/right</i>). Je savais que le concept fonctionnerait mais je n’arrivais pas à l&#8217;implémenter.</p>
<p><a href="https://codepen.io/vincent-valentin/pen/yLRRNVP">C’est ma collègue Nina qui m’a permis de débloquer l’idée et cela a abouti à ce CodePen</a>. Je l’aime beaucoup car il réalise un comportement qui apparaît relativement magique au regard du nombre de lignes associé.</p>
<p>Sans rentrer dans les détails, voici un condensé des technologies mises en jeu : </p>
<ul>
<li>la position <i lang="en">sticky</i> pour que le point rouge soit toujours visible ;</li>
<li>une variable CSS pour que les éléments puisse avoir les tailles relatives nécessaires ;</li>
<li>une grille pour réaliser son conteneur avec une astuce sur ses couleurs de fond pour faire apparaître ses gouttières ;</li>
<li>des scrollbars masquées visuellement (mais toujours présentes) quand cela est possible ;</li>
<li>une gestion des <a href="https://vincent-valentin.name/articles/les-styles-hors-viewport">dépassements sur la zone de défilement</a> ;</li>
<li>de l’adhérence sur le scroll pour que la vue se fige toujours sur certains alignements ;</li>
<li>et une petite fonction JS pour initialiser la vue.</li>
</ul>]]></description>
    </item>
        <item>
      <title>Motivation(s)</title>
      <link>https://vincent-valentin.name/articles/motivation-s</link>
      <guid>https://vincent-valentin.name/articles/motivation-s</guid>
      <pubDate>Wed, 13 Mar 2024 00:00:00 +0100</pubDate>
      <description><![CDATA[<p>Et voilà : 7 billets en 7 jours ; on peut dire que je me suis pris au jeu.</p>
<ul>
<li>Est-ce que je vais continuer ? Sans doute pas à ce rythme mais j’aimerais bien.</li>
<li>Qu’est-ce que j’en retire ? Des apprentissages ! Une envie de m’amuser ici avec la technique.</li>
<li>Est-ce que ça vous intéresse ? J’espère mais n’hésitez pas à le dire. Ici ou ailleurs, ça fait toujours plaisir.</li>
<li>Le niveau technique est-il celui que vous attendez ? J’essaye de ne pas trop forcer pour pouvoir publier plus facilement mais autant que ça vous serve quand même un peu.</li>
</ul>
<h2>Et pourquoi je me donne ce mal au fait ?</h2>
<p>Le constat est simple : je trouve que le Web ne va pas fort en ce moment, et je voulais à ma petite échelle montrer un peu l’exemple.</p>
<ul>
<li>L’exemple du Web qu’on peut apprendre à son rythme, bricoler chez soi, et s’en faire un outil personnel d’expression.</li>
<li>L’exemple du Web qu’on peut mettre en place avec un simple bloc-notes et un espace personnel, et qui n’a pas besoin que ce soit beaucoup plus technique.</li>
<li>L’exemple du Web indépendant qui n’a pas besoin d’une plateforme tierce modératrice ou éphémère.</li>
<li>L’exemple du Web hors des réseaux sociaux, qui ont fini par montrer leurs limites.</li>
<li>L’exemple du Web où l’on publie pour être lu par des humains. Et pas par des robots, qu’ils soient là pour amener du traffic ou en générer ailleurs.</li>
<li>L’exemple du Web où l’on dicte ses règles et où l’on choisit quels usages pourraient être faits de nos contenus.</li>
</ul>
<p>Faire son site personnel quoi. Et un Web comme on l’entend.</p>]]></description>
    </item>
        <item>
      <title>D&#233;tecter quand un champ texte est rempli</title>
      <link>https://vincent-valentin.name/articles/detecter-quand-un-champ-texte-est-rempli</link>
      <guid>https://vincent-valentin.name/articles/detecter-quand-un-champ-texte-est-rempli</guid>
      <pubDate>Tue, 12 Mar 2024 00:00:00 +0100</pubDate>
      <description><![CDATA[<p>Pour appliquer un style différent aux champs de formulaires de type texte en fonction de s’ils sont remplis ou non, il n’est pas nécessaire de passer par une lecture leurs valeurs en JavaScript, mais il faut bidouiller un peu en CSS.</p>
<h2>Avec un sélecteur d’attribut sur la valeur ?</h2>
<pre><code>&lt;input type="text" value="foo" /&gt;</code></pre>
<pre><code>[type="text"][value] {

}</code></pre>
<p>Ça fonctionne mais ça n’a rien de dynamique. Si l’utilisateur modifie la valeur dans le champs, cela n’aura aucun impact.</p>
<h2>Avec une pseudo-classe <code>:empty</code> ?</h2>
<pre><code>[type="text"]:empty {

}</code></pre>
<p>Ça ne fonctionne pas. La pseudo-classe ne s’applique que si l’élément n’a aucun enfant, mais notre input ne peut même pas en contenir.</p>
<h2>Avec une pseudo de classe sur la validité du champ ?</h2>
<pre><code>&lt;input type="text" required="required" /&gt;</code></pre>
<pre><code>[type="text"]:valid {

}</code></pre>
<p>Ça fonctionne mais l’attribut requis est imposé sur le champ pour que la mécanique puisse se mettre en place, ce qu’on ne souhaite pas toujours.</p>
<h2>Avec une pseudo-classe inversée sur l’affichage du <em>placeholder</em> ?</h2>
<pre><code>&lt;input type="text" placeholder="foo" /&gt;</code></pre>
<pre><code>[type="text"]:not(:placeholder-shown) {

}</code></pre>
<p>C’est la bonne approche, elle fonctionne parfaitement. La logique du sélecteur doit cependant être inversée avec un <code>:not</code> pour que ce soit l’absence du texte de substitution qui soit détectée, et non sa présence.</p>
<h2>Et si je n’utilise souhaite pas afficher de <em>placeholder</em> ?</h2>
<pre><code>&lt;input type="text" placeholder=" " /&gt;</code></pre>
<p>Avec une espace insécable, par nature invisible, on retrouve le même comportement sans que l’UX en soit altérée d’aucune manière.</p>
<hr />
<p><a href="https://arkhi.org/">Fabien</a> me pointe <a href="https://developer.mozilla.org/fr/docs/Web/CSS/:blank">la solution officielle prévue par CSS</a>, malheureusement supportée nulle part. </p>
<hr />
<p><a href="https://codepen.io/vincent-valentin/pen/BaEKPLp?editors=1100">Et comme toujours un petit CodePen de test dédié au sujet.</a></p>]]></description>
    </item>
    
  </channel>
</rss>