Що ж, ця відповідь стала власним звіром. Багато нових версій, це стало дурно довго. Велике спасибі всім дуже великим учасникам цієї відповіді. Але для того, щоб це було просто для мас. Я заархівував усі версії / історію розвитку цієї відповіді на свій github . І почав це з чистого на StackOverflow тут, з новітньою версією. Особлива подяка висловлена Майку "Pomax" Камермансу за цю версію. Він дав мені нову математику.
Ця функція ( pSBC
) буде приймати колір веб-сторінки HEX або RGB. pSBC
може затінювати його темніше або світліше, або поєднувати його з другим кольором, а також може передавати його прямо через перетворення з Hex в RGB (Hex2RGB) або RGB в Hex (RGB2Hex). Все, навіть не знаючи, який кольоровий формат ви використовуєте.
Це працює дуже швидко, мабуть, найшвидше, особливо враховуючи його безліч особливостей. Це було тривалий час у створенні. Подивіться всю історію на моєму github . Якщо ви хочете зробити найменший і швидкий можливий спосіб відтінити або змішати, перегляньте мікрофункції нижче та скористайтеся одним із демонів швидкості на 2 вкладиші. Вони чудово підходять для інтенсивної анімації, але ця версія тут досить швидка для більшості анімацій.
Ця функція використовує змішування журналу або лінійне змішування. Однак він НЕ перетворюється на HSL, щоб правильно освітлити або затемнити колір. Тому результати цієї функції будуть відрізнятися від тих значно більших та повільніших функцій, які використовують HSL.
jsFiddle з pSBC
github> pSBC Wiki
Особливості:
- Автоматично виявляє та приймає стандартні шістнадцяткові кольори у вигляді рядків. Наприклад:
"#AA6622"
або "#bb551144"
.
- Автоматично визначає та приймає стандартні кольори RGB у вигляді рядків. Наприклад:
"rgb(123,45,76)"
або "rgba(45,15,74,0.45)"
.
- Відтінки кольорів до білого або чорного у відсотках.
- Змішує кольори разом у відсотках.
- Перетворює Hex2RGB і RGB2Hex одночасно або окремо.
- Приймає тризначні (або чотиризначні ш / альфа) коди кольорів HEX у формі #RGB (або #RGBA). Це розширить їх. Наприклад:
"#C41"
стає "#CC4411"
.
- Приймає та (лінійно) змішує альфа-канали. Якщо або
c0
(від) колір, або колір c1
(до) має альфа-канал, то повернутий колір матиме альфа-канал. Якщо обидва кольори мають альфа-канал, то повернутий колір буде лінійною сумішшю двох альфа-каналів, використовуючи заданий відсоток (так само, як якщо б це був звичайний кольоровий канал). Якщо лише один з двох кольорів має альфа-канал, ця альфа буде просто передана через повернений колір. Це дозволяє змішувати / відтіняти прозорий колір, зберігаючи рівень прозорості. Або, якщо рівні прозорості повинні також змішатися, переконайтеся, що в обох кольорах є альфа-алфавіти. При затіненні він пройде альфа-канал прямо через. Якщо ви хочете базове затінення, яке також затінює альфа-канал, тоді використовуйте rgb(0,0,0,1)
або rgb(255,255,255,1)
як вашc1
(до) колір (або їх шестигранні еквіваленти). Для кольорів RGB альфа-канал повернутого кольору буде округлений до 3 знаків після коми.
- Конверсії RGB2Hex і Hex2RGB неявні при використанні змішування. Незалежно
c0
від кольору (від); повернутий колір завжди буде у кольоровому форматі c1
(до) кольору, якщо такий існує. Якщо немає c1
(в) кольору, тоді передайте його 'c'
як c1
колір, і він буде відтіняти і перетворювати будь-який c0
колір. Якщо потрібна лише конверсія, тоді також передайте її 0
як відсоток ( p
). Якщо c1
колір опущено або не string
передано, він не перетвориться.
- До вторинної функції додається і глобальна.
pSBCr
може передаватися шістнадцятковий або RGB-колір, і він повертає об'єкт, що містить цю інформацію про колір. Його у вигляді: {r: XXX, g: XXX, b: XXX, a: X.XXX}. Де .r
, .g
і .b
мають діапазон від 0 до 255. А коли немає альфа: .a
є -1. В іншому випадку: .a
має діапазон від 0,000 до 1 000.
- Для виведення RGB, він виводить
rgba()
більш , rgb()
коли колір з альфа - каналом був переданий в c0
(з) і / або c1
(с).
- Додано незначну перевірку помилок. Це не ідеально. Він все ще може вийти з ладу або створити ритм. Але це зловить деякі речі. В основному, якщо структура якимось чином помиляється або якщо відсоток не є числом чи не виходить за межі, вона повернеться
null
. Приклад:, pSBC(0.5,"salt") == null
де, як він думає, #salt
є дійсним кольором. Видаліть чотири рядки, якими закінчується, return null;
щоб видалити цю функцію та зробити її швидшою та меншою.
- Використання змішування журналу. Перейдіть
true
на l
(четвертий параметр) для використання лінійного змішування.
Код:
// 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)
}
Використання:
// 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}
На малюнку нижче допоможе показати різницю двох методів накладання:
Мікрофункції
Якщо ви дійсно хочете швидкості та розміру, вам доведеться використовувати RGB, а не HEX. RGB більш простий і простий, HEX пише занадто повільно і містить занадто багато ароматів для простого дволанкового (IE. Це може бути 3, 4, 6 або 8-значний HEX-код). Вам також потрібно буде пожертвувати деякими функціями, без перевірки помилок, без HEX2RGB і RGB2HEX. Крім того, вам потрібно буде вибрати конкретну функцію (виходячи з назви її функції нижче) для математики змішування кольорів, і якщо ви хочете затінення або змішування. Ці функції підтримують альфа-канали. І коли в обох вхідних кольорах є альфа, це лінійне змішування їх. Якщо в одному з двох кольорів є альфа, він передасть його прямо через отриманий колір. Нижче наведено дві функції вкладишів, які неймовірно швидкі та малі:
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:")");
}
Хочете більше інформації? Прочитайте повну запис на github .
PT
(Ps Якщо у когось є математика для іншого методу накладання, будь ласка, поділіться.)