Vâng, câu trả lời này đã trở thành con thú của riêng nó. Nhiều phiên bản mới, nó đã trở nên ngu ngốc từ lâu. Rất cám ơn tất cả những người đóng góp rất nhiều cho câu trả lời này. Nhưng, để giữ cho nó đơn giản cho công chúng. Tôi đã lưu trữ tất cả các phiên bản / lịch sử của sự tiến hóa của câu trả lời này cho github của tôi . Và bắt đầu làm sạch trên StackOverflow tại đây với phiên bản mới nhất. Một lời cảm ơn đặc biệt dành cho Mike 'Pomax' Kamermans cho phiên bản này. Ông cho tôi môn toán mới.
Hàm này ( pSBC
) sẽ lấy màu web HEX hoặc RGB. pSBC
có thể tô màu tối hơn hoặc nhạt hơn, hoặc pha trộn nó với màu thứ hai, và cũng có thể chuyển nó qua đúng nhưng chuyển đổi từ Hex sang RGB (Hex2RGB) hoặc RGB sang Hex (RGB2Hex). Tất cả mà không cần bạn biết định dạng màu nào bạn đang sử dụng.
Điều này chạy rất nhanh, có thể là nhanh nhất, đặc biệt là xem xét nhiều tính năng của nó. Đó là một thời gian dài trong việc thực hiện. Xem toàn bộ câu chuyện trên github của tôi . Nếu bạn muốn cách nhỏ nhất và nhanh nhất có thể để tạo bóng hoặc pha trộn, hãy xem các Hàm Micro bên dưới và sử dụng một trong những con quỷ tốc độ 2 lớp. Chúng rất tuyệt cho hoạt hình cường độ cao, nhưng phiên bản này ở đây đủ nhanh cho hầu hết các hoạt hình.
Chức năng này sử dụng Blend Blending hoặc Blend Blend tuyến tính. Tuy nhiên, nó KHÔNG chuyển đổi sang HSL để làm sáng hoặc làm tối màu đúng cách. Do đó, kết quả từ chức năng này sẽ khác với các chức năng lớn hơn và chậm hơn nhiều sử dụng HSL.
jsFiddle với pSBC
github> pSBC Wiki
Đặc trưng:
- Tự động phát hiện và chấp nhận màu Hex tiêu chuẩn ở dạng chuỗi. Ví dụ:
"#AA6622"
hoặc "#bb551144"
.
- Tự động phát hiện và chấp nhận màu RGB tiêu chuẩn ở dạng chuỗi. Ví dụ:
"rgb(123,45,76)"
hoặc "rgba(45,15,74,0.45)"
.
- Tô màu cho màu trắng hoặc đen theo tỷ lệ phần trăm.
- Pha trộn màu sắc với nhau theo tỷ lệ phần trăm.
- Có chuyển đổi Hex2RGB và RGB2Hex cùng một lúc, hoặc solo.
- Chấp nhận mã màu HEX 3 chữ số (hoặc 4 chữ số w / alpha), dưới dạng #RGB (hoặc #RGBA). Nó sẽ mở rộng chúng. Ví dụ:
"#C41"
trở thành "#CC4411"
.
- Chấp nhận và (Tuyến tính) pha trộn các kênh alpha. Nếu
c0
màu (từ) hoặc màu c1
(đến) có kênh alpha, thì màu được trả về sẽ có kênh alpha. Nếu cả hai màu đều có kênh alpha, thì màu được trả về sẽ là hỗn hợp tuyến tính của hai kênh alpha sử dụng tỷ lệ phần trăm đã cho (giống như đó là kênh màu bình thường). Nếu chỉ một trong hai màu có kênh alpha, thì alpha này sẽ được chuyển qua màu được trả về. Điều này cho phép một người pha trộn / tô màu một màu trong suốt trong khi duy trì mức độ trong suốt. Hoặc, nếu các mức trong suốt cũng hòa trộn, hãy đảm bảo cả hai màu đều có bảng chữ cái. Khi tô bóng, nó sẽ vượt qua kênh alpha thông qua. Nếu bạn muốn tạo bóng cơ bản cũng làm mờ kênh alpha, thì hãy sử dụng rgb(0,0,0,1)
hoặc rgb(255,255,255,1)
làmc1
(đến) màu (hoặc tương đương hex của chúng). Đối với màu RGB, kênh alpha của màu được trả về sẽ được làm tròn đến 3 chữ số thập phân.
- Chuyển đổi RGB2Hex và Hex2RGB ẩn khi sử dụng trộn. Bất kể
c0
màu (từ); màu được trả về sẽ luôn ở định dạng màu của màu c1
(to), nếu có. Nếu không có c1
màu (to), sau đó chuyển qua 'c'
làm c1
màu và nó sẽ chuyển sang màu và chuyển đổi bất kể c0
màu gì . Nếu chỉ chuyển đổi là mong muốn, thì cũng chuyển qua 0
phần trăm ( p
). Nếu c1
màu bị bỏ qua hoặc không string
được truyền vào, nó sẽ không chuyển đổi.
- Một chức năng phụ cũng được thêm vào toàn cầu.
pSBCr
có thể được chuyển qua màu Hex hoặc RGB và nó trả về một đối tượng có chứa thông tin màu này. Nó có dạng: {r: XXX, g: XXX, b: XXX, a: X.XXX}. Trong đó .r
, .g
và .b
có phạm vi từ 0 đến 255. Và khi không có alpha: .a
là -1. Mặt khác: .a
có phạm vi 0.000 đến 1.000.
- Đối với đầu ra RGB, nó sẽ tạo ra
rgba()
hơn rgb()
khi một màu sắc với một kênh alpha đã được thông qua vào c0
(từ) và / hoặc c1
(to).
- Kiểm tra lỗi nhỏ đã được thêm vào. Nó không hoàn hảo. Nó vẫn có thể sụp đổ hoặc tạo ra jibberish. Nhưng nó sẽ bắt được một số thứ. Về cơ bản, nếu cấu trúc sai theo một số cách hoặc nếu tỷ lệ phần trăm không phải là một số hoặc nằm ngoài phạm vi, nó sẽ trả về
null
. Một ví dụ : pSBC(0.5,"salt") == null
, nơi mà nó nghĩ #salt
là một màu hợp lệ. Xóa bốn dòng kết thúc bằng return null;
để loại bỏ tính năng này và làm cho nó nhanh hơn và nhỏ hơn.
- Sử dụng Trộn Log. Vượt qua
true
trong cho l
(tham số thứ 4) để sử dụng tuyến tính Blending.
Mã số:
// 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)
}
Sử dụng:
// 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}
Hình dưới đây sẽ giúp hiển thị sự khác biệt trong hai phương pháp trộn:
Chức năng vi mô
Nếu bạn thực sự muốn tốc độ và kích thước, bạn sẽ phải sử dụng RGB chứ không phải HEX. RGB đơn giản và đơn giản hơn, HEX viết quá chậm và có quá nhiều hương vị cho một lớp lót đơn giản (IE. Nó có thể là mã HEX 3, 4, 6 hoặc 8 chữ số). Bạn cũng sẽ cần phải hy sinh một số tính năng, không kiểm tra lỗi, không có HEX2RGB cũng như RGB2HEX. Đồng thời, bạn sẽ cần chọn một hàm cụ thể (dựa trên tên hàm của nó bên dưới) cho phép toán trộn màu và nếu bạn muốn tô bóng hoặc trộn. Các chức năng này hỗ trợ các kênh alpha. Và khi cả hai màu đầu vào có bảng chữ cái, nó sẽ pha trộn chúng. Nếu chỉ một trong hai màu có alpha, nó sẽ chuyển thẳng qua màu kết quả. Dưới đây là hai chức năng lót cực kỳ nhanh và nhỏ:
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:")");
}
Muốn biết thêm thông tin? Đọc toàn bộ bài viết trên github .
PT
(Ps Nếu ai có toán cho phương pháp trộn khác, vui lòng chia sẻ.)