Il est souvent reproché aux développeurs front-end d'utiliser des abstractions inutilement complexes sous couvert d'une volonté de "s'amuser" avec celles-ci plutôt que de concevoir des sites simples, accessibles et performants.
Personnellement, j'apprécie énormément react-native-web et ai tendance à m'en servir systématiquement et ce même si la plupart du temps il n'est même pas question de partage de code avec une application mobile.
Ce qui veut dire que je suis régulièrement tenu d'écrire du code de la sorte:
import { Pressable } from "react-native";
<Pressable
accessibilityRole="button"
style={({ hovered, focused, pressed }) => [
{ backgroundColor: "red" },
hovered && { backgroundColor: "blue" },
focused && { backgroundColor: "green" },
pressed && { backgroundColor: "pink" },
]}
>
Click me
</Pressable>;
Vous allez me dire que c'est horrible. J'utilise une <div>
en lieu et place
d'un <button>
, du CSS-in-JS pour styliser mon élément et je fais même
totalement l'impasse sur l'usage des pseudo-classes :hover
et :focus
!
Pourquoi diable s'acharner à réimplémenter ce qui existe de base sur la plateforme web et qui fonctionne bien?
Déconstruisons donc cet exemple. Je souhaite créer un bouton rouge qui sera bleu au survol, vert quand il aura le focus et rose quand il sera pressé.
Implémentons notre solution naïvement:
<button>Click me</button>
button {
appearance: none;
background-color: red;
}
button:hover {
background-color: blue;
}
Cela ne suffira pas. En effet, mon bouton deviendra bleu lors d'un appui sur smartphone ou autre appareil tactile.
Heureusement, il existe une bride de solution: le media query
hover
.
hover est une caractéristique média CSS (cf. @media) qui permet de vérifier si le dispositif de saisie/d'entrée principal permet à l'utilisateur de survoler les éléments.
Il serait donc possible de corriger le problème de la sorte:
button {
appearance: none;
background-color: red;
}
@media (hover: hover) {
button:hover {
background-color: blue;
}
}
Sauf qu'encore une fois, tout cela reste imparfait. Depuis peu, il est devenu possible d'utiliser un périphérique de pointage (type souris donc, avec son curseur) sur iPad et, je vous le donne en mille, le dispositif d'entrée principal restant l'écran tactile, les styles présents dans le media query en question ne seront pas activés lors du survol du curseur.
L'affaire serait donc insoluble? Pas nécessairement, mais résoudre tous les
problèmes inhérents à chaque appareil et situation afin de normaliser le
comportement de cette interaction pourtant basique n'est au final pas mince
affaire, comme peuvent l'attester l'implémentation des abstractions offertes par
react-native-web
ou
@react-aria
.
Rebelote, traitons le problème naïvement:
button {
appearance: none;
background-color: red;
}
button:focus {
background-color: green;
}
Tout comme pour le cas du survol, cette solution est loin d'être parfaite puisque le style appliqué normalement au focus sera visible au clic.
Pire encore, l'apparition du focus-ring, pourtant indispensable à une bonne
navigation au clavier, poussera grand nombre de développeurs non sensibilisés au
sujet à appliquer le fameux outline-style: none
et à anéantir une grande part
de l'accessibilité du site au passage.
Mais tout comme le cas du survol, il existe une bride de solution: la
pseudo-classe
:focus-visible
.
La pseudo-classe :focus-visible s'applique lorsqu'un élément correspond à la pseudo-classe focus et que l'agent utilisateur détermine, via une heuristique, que le focus devrait être mis en évidence sur l'élément (la plupart des navigateurs affichent un contour en surbrillance par défaut).
button {
appearance: none;
background-color: red;
}
button:focus-visible {
background-color: green;
}
Et tout comme le media query hover
, cette solution reste imparfaite: si l'on
met de côté son support navigateur restreint à l'heure où je rédige cet article,
on peut également pointer du doigt le fait que le focus reste "cassé" en
JavaScript. En effet, il n'est pas encore question d'un événément
focus-visible
et l'événement focus
reste déclenché lors du clic sur certains
navigateurs.
Il vous sera donc très difficile de réagir à une réelle intention de focus, sauf
si, encore une fois, vous utilisez des abstractions offertes par
react-native-web
,
@react-aria
ou autre.
<button>
Reste un dernier point: l'usage d'une <div>
à la place d'un <button>
.
L'argument souvent avancé contre cela est le suivant :
Utiliser une
<div>
pour réimplémenter un bouton en lieu et place d'un<button>
peut ruiner l'accessibilité de celui-ci.
Je suis absolument d'accord avec ce point. Réimplémenter le comportement d'un bouton en partant de zéro est complexe, vous mènera certainement à commettre un tas d'erreurs et je vous le déconseille fortement.
Seulement ici ce n'est pas le cas : j'utilise une abstraction qui a correctement
été pensée et ne souffre d'aucun réel défaut d'accessibilité si on la compare à
un <button>
. Sachant qu'en plus il y a encore très peu, les <button>
souffraient de
problèmes de styling
et que donc, il m'est nécessaire soit d'en tenir compte, soit de ne pas
supporter certaines versions de navigateurs pourtant récentes.
Si j'ai ce composant <Pressable>
à ma disposition, qui a le bon goût de ne pas
souffrir des problèmes présentés plus haut et réagit tel que la logique le
voudrait lors du survol, du focus ou encore de l'appui… Pourquoi devrais-je donc
m'en passer?
Afin de faciliter l'accessibilité clavier, il est important de "capturer" et de
borner le focus lors de l'apparition d'une modale, par exemple (ce qu'on appelle
communément le focus-trapping
).
Il existe actuellement 2 potentielles solutions à ce problème. L'une, haut
niveau, est l'élément natif
<dialog>
,
l'autre, plus bas niveau (et plus intéressante selon moi) est l'attribut
inert
.
Ces solutions ne sont malheureusement pour le moment pas très bien, voire pas du
tout, supportées par les navigateurs.
Tout comme les modales, elles sont présentes dans une majeure partie des interfaces web actuelles et pourtant il n'existe actuellement aucune méthode simple et sans abstraction qui nous permette d'en créer une.
Dans un futur proche, peut-être (je l'espère) que la proposition de Microsoft sera retenue, mais en attendant, bon courage pour implémenter ça "à la main" si vous souhaitez que celles-ci soient fonctionnelles sur tous les navigateurs, tout type d'appareil et de surcroît parfaitement accessibles.
Qu'en est-il de tout ces besoins devenus quasiment primaires:
<switch>
?type=number
(actuellement cassé)?Avant tout, arrêtons de blâmer les développeurs qui découvrent aujourd'hui cette complexité monstre et cessons de leur déconseiller d'utiliser des abstractions, de leur dire de "juste apprendre le HTML, CSS et JS" car ce comportement est dangereux et ne tient pas compte d'une chose : si vous avez vu vécu l'évolution du web et vu apparaitre des courants tels que le responsive design, de nouveaux types d'appareils tels que les smartphones et eu le temps de vous adapter à ces changements, ce n'est pas le cas de développeurs plus juniors qui se retrouvent aujourd'hui face à une quantité astronomique de problématiques, sans courbe d'apprentissage naturelle guidée par l'évolution des usages.
L'accessibilité vous tient à cœur? Parfait. Conseillez-leur d'utiliser une abstraction simple qui leur garantira un bon résultat, plutôt que de leur conseiller de devenir un expert absolu sur le domaine afin de ne pas se tirer une balle dans le pied. S'il sont intéressés par le sujet, ils se pencheront sur la façon dont est conçue celle-ci, s'ils ne le sont pas, et bien, au moins les utilisateurs de leurs sites bénéficieront d'une meilleure accessibilité. Et je pense que c'est ce qui importe le plus: l'objectif est plus important que le moyen.
Ensuite, posons-nous réellement la question de la nécessité de ces ajouts continuels de solutions de haut niveau dans la plateforme web, qui débarquent sans que jamais rien ne semble vraiment être officiellement déclaré caduque. En effet, toutes les solutions énoncées précédemment viennent ou viendront en plus de tout ce qui peut déjà exister.
La plateforme déborde. J'en prends pour exemple une donnée qui me semble totalement absurde, le nombre de propriétés CSS actuel: 520 (+132 en attente). Outre le fait que cela rend extrêmement complexe l'apparition de nouveaux navigateurs web, cela rend la charge mentale du développeur incommensurable. Il en va de même avec l'évolution de la syntaxe JavaScript, l'augmentation du nombre de sélecteurs CSS, l'apparition de nouvelles APIs, etc.
Imaginez si demain un nouveau paradigme d'utilisation venait à apparaitre (une interaction autre que le touch, par exemple) ou si un nouveau type de pattern UI gagnait en popularité (comme a pu le faire le switch). Devrait-on continuer à empiler…? Ou devrait-on accepter le fait que le web a plus que jamais besoin d'abstractions au dessus de concepts bas niveau, que celles-ci soient des bibliothèques exécutées au runtime ou carrément des langages de plus haut niveau qui compileront vers du HTML, CSS et JS en guise de bytecode?
L'avenir est incertain, imitez-le.