Nah, jawaban ini sudah menjadi binatang buas sendiri. Banyak versi baru, itu semakin lama bodoh. Terima kasih banyak untuk semua kontributor untuk jawaban ini. Tapi, agar tetap sederhana bagi massa. Saya mengarsipkan semua versi / sejarah evolusi jawaban ini ke github saya . Dan mulai membersihkannya di StackOverflow di sini dengan versi terbaru. Terima kasih khusus kepada Mike 'Pomax' Kamermans untuk versi ini. Dia memberiku matematika baru.
Fungsi ini ( pSBC
) akan mengambil warna web HEX atau RGB. pSBC
dapat menaungi lebih gelap atau lebih terang, atau mencampurnya dengan warna kedua, dan juga bisa meneruskannya melalui tetapi mengubah dari Hex ke RGB (Hex2RGB) atau RGB ke Hex (RGB2Hex). Semua tanpa Anda bahkan tahu format warna apa yang Anda gunakan.
Ini berjalan sangat cepat, mungkin yang tercepat, terutama mengingat banyak fiturnya. Sudah lama dalam pembuatan. Lihat keseluruhan cerita di github saya . Jika Anda ingin cara terkecil dan tercepat untuk menaungi atau menyatu, lihat Fungsi Mikro di bawah ini dan gunakan salah satu dari setan kecepatan 2-liner. Mereka bagus untuk animasi yang intens, tetapi versi ini cukup cepat untuk sebagian besar animasi.
Fungsi ini menggunakan Blending Log atau Linear Blending. Namun, itu TIDAK mengkonversi ke HSL untuk benar mencerahkan atau menggelapkan warna. Oleh karena itu, hasil dari fungsi ini akan berbeda dari fungsi yang jauh lebih besar dan lebih lambat yang menggunakan HSL.
jsFiddle dengan pSBC
github> pSBC Wiki
Fitur:
- Mendeteksi otomatis dan menerima warna Hex standar dalam bentuk string. Misalnya:
"#AA6622"
atau "#bb551144"
.
- Mendeteksi otomatis dan menerima warna RGB standar dalam bentuk string. Misalnya:
"rgb(123,45,76)"
atau "rgba(45,15,74,0.45)"
.
- Nuansa warna menjadi putih atau hitam dengan persentase.
- Memadukan warna bersama berdasarkan persentase.
- Apakah konversi Hex2RGB dan RGB2Hex pada saat yang sama, atau solo.
- Menerima kode warna HEX 3 digit (atau 4 digit w / alpha), dalam bentuk #RGB (atau #RGBA). Itu akan memperluas mereka. Sebagai Contoh:
"#C41"
menjadi "#CC4411"
.
- Terima dan (Linear) memadukan saluran alfa. Jika salah satu
c0
(dari) warna atau c1
(ke) warna memiliki saluran alpha, maka warna yang dikembalikan akan memiliki saluran alpha. Jika kedua warna memiliki saluran alfa, maka warna yang dikembalikan akan menjadi campuran linear dari dua saluran alfa menggunakan persentase yang diberikan (sama seperti jika itu merupakan saluran warna normal). Jika hanya satu dari dua warna yang memiliki saluran alpha, alpha ini hanya akan diteruskan ke warna yang dikembalikan. Ini memungkinkan seseorang untuk berbaur / menaungi warna transparan dengan tetap menjaga tingkat transparansi. Atau, jika tingkat transparansi juga harus berbaur, pastikan kedua warna memiliki alfas. Saat shading, itu akan melewati saluran alpha langsung melalui. Jika Anda ingin arsiran dasar yang juga menaungi saluran alpha, maka gunakan rgb(0,0,0,1)
atau rgb(255,255,255,1)
sebagaic1
(untuk) warna (atau setara hex-nya). Untuk warna RGB, saluran alpha warna yang dikembalikan akan dibulatkan ke 3 tempat desimal.
- Konversi RGB2Hex dan Hex2RGB tersirat saat menggunakan blending. Terlepas dari
c0
(dari) warna; warna yang dikembalikan akan selalu dalam format warna dari warna c1
(ke), jika ada. Jika tidak ada c1
warna (untuk), maka lewat 'c'
sebagai c1
warna dan itu akan menaungi dan mengubah apapun c0
warnanya. Jika hanya konversi yang diinginkan, maka masukkan 0
sebagai persentase ( p
) juga. Jika c1
warna dihilangkan atau tidak string
dilewatkan, itu tidak akan dikonversi.
- Fungsi sekunder ditambahkan ke global juga.
pSBCr
dapat melewati warna Hex atau RGB dan mengembalikan objek yang berisi informasi warna ini. Ini dalam bentuk: {r: XXX, g: XXX, b: XXX, a: X.XXX}. Di mana .r
,, .g
dan .b
memiliki rentang 0 hingga 255. Dan ketika tidak ada alfa: .a
adalah -1. Jika tidak: .a
memiliki rentang 0,000 hingga 1.000.
- Untuk output RGB, output
rgba()
berakhir rgb()
ketika warna dengan saluran alpha dilewatkan ke c0
(dari) dan / atau c1
(ke).
- Pemeriksaan Kesalahan Kecil telah ditambahkan. Itu tidak sempurna. Itu masih bisa macet atau membuat bualan. Tapi itu akan menangkap beberapa hal. Pada dasarnya, jika strukturnya salah dalam beberapa hal atau jika persentase bukan angka atau di luar ruang lingkup, itu akan kembali
null
. Contoh:, pSBC(0.5,"salt") == null
dimana menurutnya #salt
adalah warna yang valid. Hapus empat baris yang berakhir dengan return null;
untuk menghapus fitur ini dan membuatnya lebih cepat dan lebih kecil.
- Menggunakan Pencampuran Log. Pass
true
in for l
(parameter ke-4) untuk menggunakan Linear Blending.
Kode:
// Version 4.0
const pSBC=(p,c0,c1,l)=>{
let r,g,b,P,f,t,h,i=parseInt,m=Math.round,a=typeof(c1)=="string";
if(typeof(p)!="number"||p<-1||p>1||typeof(c0)!="string"||(c0[0]!='r'&&c0[0]!='#')||(c1&&!a))return null;
if(!this.pSBCr)this.pSBCr=(d)=>{
let n=d.length,x={};
if(n>9){
[r,g,b,a]=d=d.split(","),n=d.length;
if(n<3||n>4)return null;
x.r=i(r[3]=="a"?r.slice(5):r.slice(4)),x.g=i(g),x.b=i(b),x.a=a?parseFloat(a):-1
}else{
if(n==8||n==6||n<4)return null;
if(n<6)d="#"+d[1]+d[1]+d[2]+d[2]+d[3]+d[3]+(n>4?d[4]+d[4]:"");
d=i(d.slice(1),16);
if(n==9||n==5)x.r=d>>24&255,x.g=d>>16&255,x.b=d>>8&255,x.a=m((d&255)/0.255)/1000;
else x.r=d>>16,x.g=d>>8&255,x.b=d&255,x.a=-1
}return x};
h=c0.length>9,h=a?c1.length>9?true:c1=="c"?!h:false:h,f=this.pSBCr(c0),P=p<0,t=c1&&c1!="c"?this.pSBCr(c1):P?{r:0,g:0,b:0,a:-1}:{r:255,g:255,b:255,a:-1},p=P?p*-1:p,P=1-p;
if(!f||!t)return null;
if(l)r=m(P*f.r+p*t.r),g=m(P*f.g+p*t.g),b=m(P*f.b+p*t.b);
else r=m((P*f.r**2+p*t.r**2)**0.5),g=m((P*f.g**2+p*t.g**2)**0.5),b=m((P*f.b**2+p*t.b**2)**0.5);
a=f.a,t=t.a,f=a>=0||t>=0,a=f?a<0?t:t<0?a:a*P+t*p:0;
if(h)return"rgb"+(f?"a(":"(")+r+","+g+","+b+(f?","+m(a*1000)/1000:"")+")";
else return"#"+(4294967296+r*16777216+g*65536+b*256+(f?m(a*255):0)).toString(16).slice(1,f?undefined:-2)
}
Pemakaian:
// Setup:
let color1 = "rgb(20,60,200)";
let color2 = "rgba(20,60,200,0.67423)";
let color3 = "#67DAF0";
let color4 = "#5567DAF0";
let color5 = "#F3A";
let color6 = "#F3A9";
let color7 = "rgb(200,60,20)";
let color8 = "rgba(200,60,20,0.98631)";
// Tests:
/*** Log Blending ***/
// Shade (Lighten or Darken)
pSBC ( 0.42, color1 ); // rgb(20,60,200) + [42% Lighter] => rgb(166,171,225)
pSBC ( -0.4, color5 ); // #F3A + [40% Darker] => #c62884
pSBC ( 0.42, color8 ); // rgba(200,60,20,0.98631) + [42% Lighter] => rgba(225,171,166,0.98631)
// Shade with Conversion (use "c" as your "to" color)
pSBC ( 0.42, color2, "c" ); // rgba(20,60,200,0.67423) + [42% Lighter] + [Convert] => #a6abe1ac
// RGB2Hex & Hex2RGB Conversion Only (set percentage to zero)
pSBC ( 0, color6, "c" ); // #F3A9 + [Convert] => rgba(255,51,170,0.6)
// Blending
pSBC ( -0.5, color2, color8 ); // rgba(20,60,200,0.67423) + rgba(200,60,20,0.98631) + [50% Blend] => rgba(142,60,142,0.83)
pSBC ( 0.7, color2, color7 ); // rgba(20,60,200,0.67423) + rgb(200,60,20) + [70% Blend] => rgba(168,60,111,0.67423)
pSBC ( 0.25, color3, color7 ); // #67DAF0 + rgb(200,60,20) + [25% Blend] => rgb(134,191,208)
pSBC ( 0.75, color7, color3 ); // rgb(200,60,20) + #67DAF0 + [75% Blend] => #86bfd0
/*** Linear Blending ***/
// Shade (Lighten or Darken)
pSBC ( 0.42, color1, false, true ); // rgb(20,60,200) + [42% Lighter] => rgb(119,142,223)
pSBC ( -0.4, color5, false, true ); // #F3A + [40% Darker] => #991f66
pSBC ( 0.42, color8, false, true ); // rgba(200,60,20,0.98631) + [42% Lighter] => rgba(223,142,119,0.98631)
// Shade with Conversion (use "c" as your "to" color)
pSBC ( 0.42, color2, "c", true ); // rgba(20,60,200,0.67423) + [42% Lighter] + [Convert] => #778edfac
// RGB2Hex & Hex2RGB Conversion Only (set percentage to zero)
pSBC ( 0, color6, "c", true ); // #F3A9 + [Convert] => rgba(255,51,170,0.6)
// Blending
pSBC ( -0.5, color2, color8, true ); // rgba(20,60,200,0.67423) + rgba(200,60,20,0.98631) + [50% Blend] => rgba(110,60,110,0.83)
pSBC ( 0.7, color2, color7, true ); // rgba(20,60,200,0.67423) + rgb(200,60,20) + [70% Blend] => rgba(146,60,74,0.67423)
pSBC ( 0.25, color3, color7, true ); // #67DAF0 + rgb(200,60,20) + [25% Blend] => rgb(127,179,185)
pSBC ( 0.75, color7, color3, true ); // rgb(200,60,20) + #67DAF0 + [75% Blend] => #7fb3b9
/*** Other Stuff ***/
// Error Checking
pSBC ( 0.42, "#FFBAA" ); // #FFBAA + [42% Lighter] => null (Invalid Input Color)
pSBC ( 42, color1, color5 ); // rgb(20,60,200) + #F3A + [4200% Blend] => null (Invalid Percentage Range)
pSBC ( 0.42, {} ); // [object Object] + [42% Lighter] => null (Strings Only for Color)
pSBC ( "42", color1 ); // rgb(20,60,200) + ["42"] => null (Numbers Only for Percentage)
pSBC ( 0.42, "salt" ); // salt + [42% Lighter] => null (A Little Salt is No Good...)
// Error Check Fails (Some Errors are not Caught)
pSBC ( 0.42, "#salt" ); // #salt + [42% Lighter] => #a5a5a500 (...and a Pound of Salt is Jibberish)
// Ripping
pSBCr ( color4 ); // #5567DAF0 + [Rip] => [object Object] => {'r':85,'g':103,'b':218,'a':0.941}
Gambar di bawah ini akan membantu menunjukkan perbedaan dalam dua metode pencampuran:
Fungsi Mikro
Jika Anda benar-benar menginginkan kecepatan dan ukuran, Anda harus menggunakan RGB bukan HEX. RGB lebih mudah dan sederhana, HEX menulis terlalu lambat dan terlalu banyak rasa untuk dua-liner sederhana (IE. Ini bisa menjadi kode HEX 3, 4, 6, atau 8 digit). Anda juga perlu mengorbankan beberapa fitur, tidak ada pengecekan kesalahan, tidak ada HEX2RGB atau RGB2HEX. Selain itu, Anda harus memilih fungsi tertentu (berdasarkan nama fungsinya di bawah) untuk matematika pencampuran warna, dan jika Anda ingin shading atau blending. Fungsi-fungsi ini mendukung saluran alfa. Dan ketika kedua warna input memiliki alfas akan Linear Blend mereka. Jika hanya satu dari dua warna yang memiliki alfa, itu akan meneruskannya langsung ke warna yang dihasilkan. Di bawah ini adalah dua fungsi liner yang sangat cepat dan kecil:
const RGB_Linear_Blend=(p,c0,c1)=>{
var i=parseInt,r=Math.round,P=1-p,[a,b,c,d]=c0.split(","),[e,f,g,h]=c1.split(","),x=d||h,j=x?","+(!d?h:!h?d:r((parseFloat(d)*P+parseFloat(h)*p)*1000)/1000+")"):")";
return"rgb"+(x?"a(":"(")+r(i(a[3]=="a"?a.slice(5):a.slice(4))*P+i(e[3]=="a"?e.slice(5):e.slice(4))*p)+","+r(i(b)*P+i(f)*p)+","+r(i(c)*P+i(g)*p)+j;
}
const RGB_Linear_Shade=(p,c)=>{
var i=parseInt,r=Math.round,[a,b,c,d]=c.split(","),P=p<0,t=P?0:255*p,P=P?1+p:1-p;
return"rgb"+(d?"a(":"(")+r(i(a[3]=="a"?a.slice(5):a.slice(4))*P+t)+","+r(i(b)*P+t)+","+r(i(c)*P+t)+(d?","+d:")");
}
const RGB_Log_Blend=(p,c0,c1)=>{
var i=parseInt,r=Math.round,P=1-p,[a,b,c,d]=c0.split(","),[e,f,g,h]=c1.split(","),x=d||h,j=x?","+(!d?h:!h?d:r((parseFloat(d)*P+parseFloat(h)*p)*1000)/1000+")"):")";
return"rgb"+(x?"a(":"(")+r((P*i(a[3]=="a"?a.slice(5):a.slice(4))**2+p*i(e[3]=="a"?e.slice(5):e.slice(4))**2)**0.5)+","+r((P*i(b)**2+p*i(f)**2)**0.5)+","+r((P*i(c)**2+p*i(g)**2)**0.5)+j;
}
const RGB_Log_Shade=(p,c)=>{
var i=parseInt,r=Math.round,[a,b,c,d]=c.split(","),P=p<0,t=P?0:p*255**2,P=P?1+p:1-p;
return"rgb"+(d?"a(":"(")+r((P*i(a[3]=="a"?a.slice(5):a.slice(4))**2+t)**0.5)+","+r((P*i(b)**2+t)**0.5)+","+r((P*i(c)**2+t)**0.5)+(d?","+d:")");
}
Ingin info lebih lanjut? Baca artikel selengkapnya di github .
PT
(Ps Jika ada yang punya matematika untuk metode blending lain, silakan berbagi.)