Bem, essa resposta se tornou sua própria fera. Muitas versões novas estavam ficando muito estúpidas. Muito obrigado a todos os muitos contribuidores desta resposta. Mas, para manter as coisas simples para as massas. Arquivei todas as versões / histórico da evolução desta resposta no meu github . E começou tudo de novo no StackOverflow aqui com a versão mais recente. Um agradecimento especial a Mike 'Pomax' Kamermans por esta versão. Ele me deu a nova matemática.
Esta função ( pSBC
) terá uma cor da web HEX ou RGB.pSBC
pode sombrear ou escurecer ou misturar com uma segunda cor e também pode passar direto, mas converter de Hex para RGB (Hex2RGB) ou RGB para Hex (RGB2Hex). Tudo sem você saber que formato de cor você está usando.
Isso roda muito rápido, provavelmente o mais rápido, especialmente considerando seus muitos recursos. Foi um longo período de preparação. Veja toda a história no meu github . Se você deseja a maneira absolutamente menor e mais rápida possível de sombrear ou misturar, consulte as Micro Funções abaixo e use um dos demônios de velocidade de 2 linhas. Eles são ótimos para animações intensas, mas esta versão aqui é rápida o suficiente para a maioria das animações.
Esta função usa mistura de log ou mistura linear. No entanto, NÃO converte em HSL para clarear ou escurecer adequadamente uma cor. Portanto, os resultados dessa função serão diferentes das funções muito maiores e mais lentas que usam HSL.
jsFiddle com pSBC
github> Wiki do pSBC
Recursos:
- Detecta automaticamente e aceita cores hexadecimais padrão na forma de seqüências de caracteres. Por exemplo:
"#AA6622"
ou "#bb551144"
.
- Detecta automaticamente e aceita cores RGB padrão na forma de strings. Por exemplo:
"rgb(123,45,76)"
ou"rgba(45,15,74,0.45)"
.
- Tons de cores para branco ou preto por porcentagem.
- Combina cores por porcentagem.
- Conversão Hex2RGB e RGB2Hex ao mesmo tempo, ou solo.
- Aceita códigos de cores HEX de 3 dígitos (ou 4 dígitos com alfa), no formato #RGB (ou #RGBA). Vai expandi-los. Por exemplo:
"#C41"
torna - se"#CC4411"
.
- Aceita e (Linear) combina canais alfa. Se a
c0
cor (de) ou c1
(para) tiver um canal alfa, a cor retornada terá um canal alfa. Se ambas as cores tiverem um canal alfa, a cor retornada será uma mistura linear dos dois canais alfa usando a porcentagem fornecida (como se fosse um canal de cores normal). Se apenas uma das duas cores tiver um canal alfa, esse alfa será passado apenas para a cor retornada. Isso permite misturar / sombrear uma cor transparente, mantendo o nível de transparência. Ou, se os níveis de transparência também se misturarem, verifique se ambas as cores possuem alfas. Ao sombrear, passará o canal alfa diretamente. Se você deseja sombreamento básico que também sombreie o canal alfa, use rgb(0,0,0,1)
ou rgb(255,255,255,1)
comoc1
(a) cor (ou seus equivalentes hexadecimais). Para cores RGB, o canal alfa da cor retornada será arredondado para três casas decimais.
- As conversões RGB2Hex e Hex2RGB estão implícitas ao usar o blending. Independentemente da
c0
cor (de); a cor retornada sempre estará no formato de cor c1
(para), se houver. Se não houver c1
(para) cor, passe 'c'
como a c1
cor e ela sombreará e converterá a c0
cor que for. Se apenas a conversão for desejada, passe 0
como porcentagem ( p
) também. Se a c1
cor for omitida ou não string
-passada, ela não será convertida.
- Uma função secundária é adicionada ao global também.
pSBCr
pode receber uma cor Hex ou RGB e retorna um objeto que contém essas informações de cores. Está no formato: {r: XXX, g: XXX, b: XXX, a: X.XXX}. Onde .r
, .g
e .b
tem intervalo de 0 a 255. E quando não há alpha: .a
é -1. Caso contrário: .a
tem um intervalo de 0,000 a 1.000.
- Para saída RGB, ele gera
rgba()
sobre rgb()
quando uma cor com um canal alfa foi passado em c0
(de) e / ou c1
(a).
- A verificação de erros menores foi adicionada. Não é perfeito. Ele ainda pode travar ou criar bobagens. Mas vai pegar algumas coisas. Basicamente, se a estrutura estiver errada de alguma forma ou se a porcentagem não for um número ou estiver fora do escopo, ela retornará
null
. Um exemplo:, pSBC(0.5,"salt") == null
onde, como pensa, #salt
é uma cor válida. Exclua as quatro linhas que terminam com return null;
para remover esse recurso e torná-lo mais rápido e menor.
- Usa mistura de log. Passe
true
para l
(o quarto parâmetro) para usar a mistura linear.
Código:
// 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)
}
Uso:
// 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}
A figura abaixo ajudará a mostrar a diferença nos dois métodos de mesclagem:
Micro Funções
Se você realmente deseja velocidade e tamanho, precisará usar RGB e não HEX. O RGB é mais direto e simples, o HEX escreve muito devagar e apresenta muitos sabores para um simples de duas linhas (ou seja, poderia ser um código HEX de 3, 4, 6 ou 8 dígitos). Você também precisará sacrificar alguns recursos, sem verificação de erros, sem HEX2RGB nem RGB2HEX. Além disso, você precisará escolher uma função específica (com base no nome da função abaixo) para a matemática da mistura de cores e se desejar sombreamento ou mistura. Essas funções suportam canais alfa. E quando ambas as cores de entrada tiverem alfas, elas serão combinadas linearmente. Se apenas uma das duas cores tiver um alfa, ele passará direto para a cor resultante. Abaixo estão duas funções de liner incrivelmente rápidas e pequenas:
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:")");
}
Quer mais informações? Leia o artigo completo no github .
PT
(Ps Se alguém tiver a matemática para outro método de mistura, compartilhe.)