Mélangez une couleur HSLA avec du blanc et convertissez-la en HSL non alpha avec Chroma.js

Dec 10 2020

J'ai un système de conception avec de très nombreuses couleurs. J'ai créé une table de couleurs où toutes les couleurs sont mélangées avec toutes les autres couleurs et le rapport de contraste des couleurs (CCR) de chaque combinaison est sorti. Le but est de signaler les combinaisons de couleurs inaccessibles.

J'utilise Chroma.js pour manipuler les couleurs et générer les CCR. Cela fonctionne à merveille avec la plupart de mes couleurs définies par HSL.

Le problème vient lorsque mon système de conception utilise une couleur avec un canal alpha. Déterminer comment une paire de couleurs fonctionne avec CCR lorsque l'une ou les deux sont transparentes est problématique. J'essaie plusieurs choses différentes pour mélanger ou mélanger une couleur HSLA avec du blanc, puis exécuter la fonction de contraste là-dessus. Voici un extrait de ce que je fais:

// where either foreground or background has an alpha value present less than 1
var background = chroma.mix(background, '#fff', 1, 'lab').css();
var foreground = chroma.mix(foreground, background, 1, 'lab').css();
var ccr = chroma.contrast(foreground, background);
// lab gets the closest but not the same as the way CSS overlays colors

Les résultats sont visualisés avec ce graphique que j'ai assemblé. À gauche, deux couleurs avec une superposition au milieu. Dans Adobe Illustrator, j'ai utilisé une transparence de 25% sur la couleur beige et un mode de fusion "normal". J'ai fait la même chose en CSS, puis je l'ai filmé à l'écran, puis j'ai mesuré le mélange de couleurs résultant dans Photoshop. À droite se trouvent les sorties des fonctions de couleur Chroma:

Après avoir essayé ce que je comprends être les options de Chroma.js, je me demande ce que je peux essayer d'autre pour rapprocher mes résultats de la sortie du navigateur afin que mes tests CCR soient précis. Merci a tous.


Grâce à la réponse acceptée de @GrahamRitchie, ma table de sortie ressemble maintenant à ceci. Les petites étiquettes «composites» montrent les couleurs produites par ces fonctions, tandis que la sortie principale superpose toujours les couleurs transparentes les unes aux autres et sur l'arrière-plan.

Réponses

GrahamRitchie Dec 10 2020 at 18:20

Je ne sais pas comment faire cela avec la bibliothèque que vous avez mentionnée (Chroma.js) mais j'espère qu'une fonction JavaScript vanille vous aidera.

Veuillez noter que la fonction ci-dessous suppose toujours une couleur d'arrière-plan opaque pour fonctionner correctement (d'où le RVB d'arrière-plan et le RVBA de premier plan).

Si vous avez besoin de travailler avec 2 couleurs qui ont toutes deux des canaux alpha, exécutez d'abord la fonction sur la couleur d'arrière-plan (comme couleur de premier plan) avec un arrière-plan blanc, puis combinez les deux couleurs.

La fonction combinera également deux couleurs RVB, omettez simplement le canal alpha lors du passage de votre couleur RVB ( convertToRGB({r,g,b}, {r,g,b}))

function convertToRGB(frontRGBA, backgroundRGB){

var rtrn = {};
//allows the function to just accept a front colour and assume the background is a plain white.
backgroundRGB = backgroundRGB || {r:255,g:255,b:255};

//allows a RGB value to be passed in assuming full alpha channel.
frontRGBA.a = frontRGBA.a || 1;

//normalise the alpha channel across the foreground and background.
rtrn.r = ((1 - frontRGBA.a) * backgroundRGB.r) + (frontRGBA.a * frontRGBA.r);
rtrn.g = ((1 - frontRGBA.a) * backgroundRGB.g) + (frontRGBA.a * frontRGBA.g);
rtrn.b = ((1 - frontRGBA.a) * backgroundRGB.b) + (frontRGBA.a * frontRGBA.b);

//just check that we don't end up with a value greater than 255 for any channel.
rtrn.r = (rtrn.r > 255) ? 255 : rtrn.r;
rtrn.g = (rtrn.g > 255) ? 255 : rtrn.g;
rtrn.b = (rtrn.b > 255) ? 255 : rtrn.b;

return rtrn;

}


var backgroundRGB = {r:165,g:193,b:211};
var frontRGBA = {r:210,g:203,b:178,a:0.25};

//used for example
var rgb = convertToRGB(frontRGBA, backgroundRGB); 
document.querySelector(".output").style.background = "rgb(" + rgb.r + "," + rgb.g + "," + rgb.b + ")";
document.querySelector(".output").innerHTML = "Output<br/>R:" + rgb.r + "<br/>G:" + rgb.g + "<br/>B:" + rgb.b;
.container div{
   width: 200px;
   height: 200px;
   float: left;
}
.div1{
    background: rgba(165,193,211,1);
}
.div2{
    background: rgba(210,203,178,0.25);
}
<div class="container">
<div class="div1">Background<br/>R:165<br/>G:193<br/>B:211<br/>A:1</div>
<div class="output">Output</div>
<div class="div2">Foreground<br/>R:210<br/>G:203<br/>B:178<br/>A:0.25</div>

</div>