Campurkan warna HSLA dengan putih dan ubah menjadi HSL non-alfa dengan Chroma.js

Dec 10 2020

Saya memiliki sistem desain dengan banyak, banyak warna. Saya telah membuat tabel warna di mana semua warna dicampur dengan warna lain dan rasio kontras warna (CCR) dari setiap kombinasi adalah keluaran. Tujuannya adalah untuk menandai kombinasi warna yang tidak dapat diakses.

Saya menggunakan Chroma.js untuk memanipulasi warna dan mengeluarkan CCR. Ini bekerja sangat baik dengan sebagian besar warna yang ditentukan oleh HSL saya.

Masalahnya muncul ketika sistem desain saya menggunakan warna dengan saluran alfa. Menentukan bagaimana sepasang warna bekerja dengan CCR ketika salah satu atau keduanya transparan merupakan masalah. Saya mencoba beberapa hal berbeda untuk mencampur atau memadukan warna HSLA dengan putih dan kemudian menjalankan fungsi kontras di atasnya. Berikut ini cuplikan dari apa yang saya lakukan:

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

Hasilnya divisualisasikan dengan grafik yang saya susun ini. Kiri adalah dua warna dengan overlay di tengah. Dalam Adobe Illustrator, saya menggunakan transparansi 25% pada warna cokelat dan mode campuran "normal". Saya melakukan hal yang sama di CSS dan kemudian mengambil gambar layar, lalu mengukur campuran warna yang dihasilkan di Photoshop. Di sebelah kanan adalah keluaran dari fungsi warna Chroma:

Setelah mencoba apa yang saya pahami sebagai opsi di Chroma.js, saya bertanya-tanya apa lagi yang bisa saya coba untuk mendapatkan hasil saya lebih dekat dengan keluaran browser sehingga tes CCR saya akan akurat. Terima kasih semuanya.


Berkat jawaban yang diterima dari @GrahamRitchie, tabel keluaran saya sekarang terlihat seperti ini. Label "komposit" kecil menunjukkan warna yang dihasilkan oleh fungsi ini, sedangkan keluaran utama masih melapisi warna transparan satu sama lain dan latar belakang.

Jawaban

GrahamRitchie Dec 10 2020 at 18:20

Saya tidak tahu bagaimana melakukan ini dengan pustaka yang Anda sebutkan (Chroma.js) tetapi semoga fungsi JavaScript vanilla akan membantu.

Harap dicatat bahwa fungsi di bawah ini selalu mengasumsikan warna latar belakang buram agar berfungsi dengan benar (karenanya RGB latar belakang dan latar depan RGBA).

Jika Anda perlu bekerja dengan 2 warna yang keduanya memiliki saluran alfa, Anda akan menjalankan fungsi pada warna latar belakang terlebih dahulu (sebagai warna latar depan) dengan latar belakang putih lalu menggabungkan kedua warna tersebut.

Fungsi ini juga akan menggabungkan dua warna RGB, cukup menghilangkan saluran alfa saat meneruskan warna RGB Anda ( 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>