retour

🎨 Un indicateur de couleur en CSS

L’an dernier j’ai repris et amélioré le code du site Velo Weather, un utilitaire d’affichage de la météo, adapté pour l’usage du vélo. Les informations de température, vent, etc, sont affichées heure par heure dans un tableau quotidien.

Jusque là, les couleurs pour la température ou l’indicateur d’opportunité étaient calculées par le serveur. Plutôt pratique, mais je n’étais pas super fan d’avoir ces calculs faits en Python : d’une part ça prend des ressources au serveur pour une fonctionnalité assez basique, et d’autre part ça compliquait la gestion du mode sombre que j’étais en train de développer. Le mode sombre est géré uniquement par le navigateur. Lorsque quelqu’un visite le site, mon serveur ne connait pas les préférences du navigateur, et c’est très bien comme ça. Ce qui veut dire qu’en l’état, les couleurs de l’indicateur d’opportunité ne peuvent pas être adaptées selon le mode de couleur… ça n’est pas optimal si je veux avoir des couleurs un peu différentes pour cadrer avec le mode.

Comment avoir un bloc de couleur à partir d’une information chiffrée comme un pourcentage, et d’un dégradé de 0% à 100% ? S’il s’agit d’un dégradé en opacité, en saturation ou en luminosité, c’est facile : ces valeurs sont déjà définissables en pourcentage en hsla(). Il suffit d’avoir une déclaration CSS qui utilise une propriété personnalisée, comme par exemple hsla(245deg, 20%, var(--luminosite)) pour le style, et l’outil transmet un HTML comme suit : <div style="--luminosite: {{ data.pourcentage }}%" />.

Mes cas d’usages sont un peu différents : je veux pouvoir définir chaque étape du dégradé. Pour les températures par exemple j’ai un dégradé de bleu (-5 °C) vers transparent (13 °C) puis transparent (19 °C) vers orange (35 °C), et pour l’opportunité c’est de vert (0, profite bien !) à rouge (20 et plus, c’est dangereux de sortir à vélo) en passant par un jaune et un orange. En mode sombre, les couleurs doivent être ajustées pour ne pas trop détonner avec le reste de la page.

J’ai décidé de partir avec un dégradé en CSS.

background-image: linear-gradient(0deg, rgba(58,131,180,1) 0%, rgba(131,58,180,1) 25%, rgba(253,29,29,1) 50%, rgba(252,176,69,1) 75%, rgba(212,252,69,1) 100%);
Voilà à quoi le dégradé ressemble.

Si j’étire suffisamment ce dégradé en hauteur pour qu’il soit dix à vingt fois plus haut que le bloc, le fragment du dégradé dans le bloc paraîtra presque d’une seule couleur. Il faudra ensuite positionner le point d’origine du dégradé en fonction du pourcentage, et le bloc aura la couleur désirée.

--gradient-height: 10000px;
--block-height: 300px;
--gradient-adjusted-height: calc(var(--gradient-height) - var(--block-height));

/* nouvelle taille du dégradé */
background-size: auto var(--gradient-height);

/* nouvelle position du dégradé */
background-position:
    0px
    calc(var(--gradient-adjusted-height) / 100 * var(--percentage) + var(--block-height))
;

Le calcul bizarre de la position, avec --gradient-adjusted-height et --block-height, est dû au fait que si je positionne le dégradé à 100%, ça sera comme s’il était positionné à 0%. Donc je déduis d’un bloc la hauteur du dégradé pour le calcul du pourcentage, et je le recale d’un bloc ensuite.

Au final, chaque bloc a pour couleur de fond le fragment du dégradé à cet endroit-là, grâce à la propriété --percentage (que je passe sans le sigle % étant donné que cette valeur est utilisée dans un calcul).

<div class="block" style="--percentage: 0;">0 %</div>
<div class="block" style="--percentage: 20;">20 %</div>
<div class="block" style="--percentage: 40;">40 %</div>
<div class="block" style="--percentage: 60;">60 %</div>
<div class="block" style="--percentage: 80;">80 %</div>
<div class="block" style="--percentage: 100;">100 %</div>
0 %
20 %
40 %
60 %
80 %
100 %

Et donc maintenant, je peux changer l’apparence du dégradé pour ajuster les couleurs selon l’usage, le thème, etc… ce que je me suis empressé de faire pour le nouveau mode sombre de Velo Weather !


On en discute ?…


Billets liés