Des couleurs pas invalides pour tout le monde !
Pour la construction d'un traducteur BBcode pour le futur site de Planète Casio, nommé textout puisque c'est le nom qui a été donné à la fonction qui se chargeait de la traduction avant que je ne rejoigne, et parce que je suis curieux, pour la balise [color], j'essaye d'implémenter un décodeur tolérant sur ce qu'il reçoit, et strict sur ce qu'il renvoie. Pour cela, je n'émets que des couleurs en RGB (avec une un alpha lorsque la couleur est semi-transparente, en seconde définition pour qu'au cas où le navigateur comprenne toujours au moins la forme sans l'alpha), et j'essaye de recevoir ce que les navigateurs comprennent en HTML et CSS. Et au-delà des fonctions telles que rgb(), hsl() ou hwb(), j'ai pu découvrir que « chucknorris » était une couleur valide.
Il semblerait qu'il s'agisse d'un héritage de Microsoft Internet Explorer, qui a un décodeur tolérant — un peu trop, puisque l'abus de ce décodeur a été utilisée par du spam au point d'arriver dans le Spammers' Compendium, une référence des techniques utilisées dans les spams par e-mail des années 2000, sous le nom de « Flex Hex ». J'ai découvert cette particularité au travers de la réponse de dash sur StackOverflow, en réponse à une question qui avait été pas mal partagée par des contacts à une époque (je ne saurais dire quand exactement). C'est même dans la spec' HTML ! J'ai mis un temps à comprendre la technique, alors je me suis dit qu'en plus de partager ça, j'essaierai d'expliquer un peu plus (et en français) de quoi il en retourne.
Prenons une couleur qui m'a posé problème par exemple, LuckyCharms. Puisque l'on n'utilise pas une fonction ici, on suppose qu'il s'agit d'un code hexadécimal. Il n'y a pas de # à l'entrée, mais s'il y en avait un, on aurait commencé par l'éliminer. De plus, si la chaîne à traiter faisait plus de 128 caractères, il aurait fallu la couper à 128 caractères.
La première étape est de remplacer tout ce qui n'est pas hexadécimal par un 0 : ici, cela nous donnera 00c00c0a000. On ajoute ensuite des zéros à la fin jusqu'à ce que la longueur soit divisible par trois : ici, on part de onze pour arriver à douze, on doit donc ajouter un zéro à la fin. Puis on sépare en trois parties (une pour chaque composante, rouge, vert, bleu). Cela nous donne donc 00c0 0c0a 0000. Si les parties avaient fait plus de huit caractères, on n'aurait pris que les huit caractères les plus à droite, mais ici, ce n'est pas le cas.
Ensuite, c'est là où ça se corse : on doit retirer les zéros des trois groupes en même temps, à deux conditions :
Il faut que le zéro soit commun aux trois groupes ;
Il faut qu'il reste strictement plus de deux caractères.
Ici, on ne peut donc retirer que le premier zéro, puisque le second n'est pas un zéro sur le deuxième groupe ! Cela nous donne donc 0c0 c0a 000. S'il nous reste strictement plus de deux caractères par groupe, on ne prend que les deux _premiers_ : ici, cela nous donnera donc 0c c0 00. La couleur LuckyCharms correspond donc à la couleur #0CC000 (ce qui correspond à du vert) !
Pour donner un autre exemple avec ce souci des zéros, sur l'entrée 00a0 00b0 0c00, on n'aurait enlevé que le premier zéro pour arriver sur 0a0 0b0 c00. Je ne comprenais pas ça, mon décodeur enlevait donc les zéros indépendamment et je me retrouvais avec a0 b0 c0, ce qui est incorrect puisque la sortie attendue ici est 0a 0b c0 !
Un autre exemple, suggéré par Sam Schinke sur son blog et qui met vraiment en exergue ces contraintes de longueur, est une chaîne hexadécimale quelconque : 6db6ec49efd278cd0bc92d1e5e072d689, qui fait trente-trois caractères. Pas besoin d'ajouter de zéro, trente-trois est déjà divisible par trois, on a donc onze caractères par groupe. C'est trop ! On passera donc les trois premiers caractères de chaque groupe pour en obtenir huit par groupe (le maximum), cela nous donne donc 6ec49efd cd0bc92d e072d689. Pas de zéros à passer, on peut donc se contenter de couper à deux caractères, et on obtient donc la couleur 6e cd e0 (un bleu clair).
Un dernier exemple, parce que je ne pouvais pas vous laisser sans vous le faire, est chucknorris. En éliminant les caractères inconnus, cela nous fait c00c0000000. On ajoute un zéro à la fin pour que ça fasse douze caractères, ce qui nous donne c00c 0000 0000. Les groupes font moins de huit caractères chacun, et on ne peut pas enlever les zéros au début car il n'y en a pas au début du premier groupe, on n'a plus qu'à couper, cela nous donne c0 00 00, donc du rouge plutôt clair.
Comme quoi, dans la réponse de aWebDeveloper sur StackOverflow, celui-ci n'avait pas tort : Chuck Norris ne se conforme pas aux standards du web, ce sont les standards du web qui se conforment à lui. #BADA55 !
Si vous avez la moindre question, suggestion ou correction vis-à-vis de cet article, mes coordonnées sont dans la section à propos du site (voir À propos de moi) :)