Mezcle un color HSLA con blanco y conviértalo en HSL no alfa con Chroma.js

Dec 10 2020

Tengo un sistema de diseño con muchos, muchos colores. He creado una tabla de colores donde todos los colores se mezclan con todos los demás colores y se emite la relación de contraste de color (CCR) de cada combinación. El objetivo es marcar combinaciones de colores inaccesibles.

Estoy usando Chroma.js para manipular los colores y generar los CCR. Funciona de manera brillante con la mayor parte de mis colores definidos por HSL.

El problema surge cuando mi sistema de diseño usa un color con un canal alfa. Determinar el rendimiento de un par de colores con CCR cuando uno o ambos son transparentes es problemático. Estoy probando algunas cosas diferentes para mezclar o mezclar un color HSLA con blanco y luego ejecutar la función de contraste en eso. Aquí hay un fragmento de lo que estoy haciendo:

// 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

Los resultados se visualizan con este gráfico que armé. A la izquierda hay dos colores con una superposición de ellos en el medio. En Adobe Illustrator, utilicé un 25% de transparencia en el color bronceado y un modo de fusión "normal". Hice lo mismo en CSS y luego hice una captura de pantalla, luego medí la mezcla de colores resultante en Photoshop. A la derecha están las salidas de las funciones de color Chroma:

Después de haber probado lo que entiendo que son las opciones en Chroma.js, me pregunto qué más puedo intentar para acercar mis resultados a la salida del navegador para que mis pruebas CCR sean precisas. Gracias a todos.


Gracias a la respuesta aceptada de @GrahamRitchie, mi tabla de salida ahora se ve así. Las pequeñas etiquetas "compuestas" muestran los colores que fueron producidos por estas funciones, mientras que la salida principal aún superpone los colores transparentes entre sí y sobre el fondo.

Respuestas

GrahamRitchie Dec 10 2020 at 18:20

No sé cómo hacer esto con la biblioteca que mencionaste (Chroma.js) pero espero que una función básica de JavaScript te ayude.

Tenga en cuenta que la función siguiente siempre asume un color de fondo opaco para funcionar correctamente (por lo tanto, RGB de fondo y RGBA de primer plano).

Si necesita trabajar con 2 colores que tienen ambos canales alfa, primero ejecutará la función en el color de fondo (como el color de primer plano) con un fondo blanco y luego combinará los dos colores.

La función también combinará dos colores RGB, simplemente omita el canal alfa al pasar su color RGB ( 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>