Bueno, esta respuesta se ha convertido en su propia bestia. Muchas versiones nuevas, se estaba volviendo estúpido por mucho tiempo. Muchas gracias a todos los grandes contribuyentes a esta respuesta. Pero, para mantenerlo simple para las masas. Archivé todas las versiones / historia de la evolución de esta respuesta en mi github . Y comencé de nuevo en StackOverflow aquí con la versión más nueva. Un agradecimiento especial para Mike 'Pomax' Kamermans por esta versión. Me dio las nuevas matemáticas.
Esta función ( pSBC
) tomará un color web HEX o RGB. pSBC
puede sombrearlo más oscuro o más claro, o mezclarlo con un segundo color, y también puede pasarlo directamente pero convertir de Hex a RGB (Hex2RGB) o de RGB a Hex (RGB2Hex). Todo sin siquiera saber qué formato de color está utilizando.
Esto funciona muy rápido, probablemente el más rápido, especialmente teniendo en cuenta sus muchas características. Fue mucho tiempo en la fabricación. Ver toda la historia en mi github . Si desea la forma más pequeña y rápida posible de sombrear o mezclar, vea las Micro Funciones a continuación y use uno de los demonios de velocidad de 2 líneas. Son excelentes para animaciones intensas, pero esta versión aquí es lo suficientemente rápida para la mayoría de las animaciones.
Esta función utiliza la combinación de registros o la combinación lineal. Sin embargo, NO se convierte a HSL para aclarar u oscurecer adecuadamente un color. Por lo tanto, los resultados de esta función diferirán de las funciones mucho más grandes y lentas que usan HSL.
jsFiddle con pSBC
github> pSBC Wiki
caracteristicas:
- Detecta automáticamente y acepta colores Hex estándar en forma de cadenas. Por ejemplo:
"#AA6622"
o "#bb551144"
.
- Detecta automáticamente y acepta colores RGB estándar en forma de cadenas. Por ejemplo:
"rgb(123,45,76)"
o "rgba(45,15,74,0.45)"
.
- Sombrea los colores a blanco o negro por porcentaje.
- Mezcla colores por porcentaje.
- Hace la conversión Hex2RGB y RGB2Hex al mismo tiempo, o solo.
- Acepta códigos de color HEX de 3 dígitos (o 4 dígitos con alfa), en la forma #RGB (o #RGBA). Los ampliará. Por ejemplo: se
"#C41"
convierte "#CC4411"
.
- Acepta y (Lineal) combina canales alfa. Si el
c0
color (desde) o el color c1
(hasta) tiene un canal alfa, entonces el color devuelto tendrá un canal alfa. Si ambos colores tienen un canal alfa, entonces el color devuelto será una mezcla lineal de los dos canales alfa usando el porcentaje dado (como si fuera un canal de color normal). Si solo uno de los dos colores tiene un canal alfa, este alfa solo se pasará al color devuelto. Esto permite mezclar / sombrear un color transparente mientras se mantiene el nivel de transparencia. O, si los niveles de transparencia también se combinan, asegúrese de que ambos colores tengan alfa. Al sombrear, pasará el canal alfa directamente. Si desea un sombreado básico que también sombree el canal alfa, use rgb(0,0,0,1)
o rgb(255,255,255,1)
como suc1
(a) color (o sus equivalentes hexadecimales). Para los colores RGB, el canal alfa del color devuelto se redondeará a 3 decimales.
- Las conversiones RGB2Hex y Hex2RGB están implícitas cuando se usa la combinación. Independientemente del
c0
color (de); el color devuelto siempre estará en el formato de color c1
(a), si existe. Si no hay c1
color (a), entonces pase 'c'
como c1
color y sombreará y convertirá el c0
color que sea. Si solo se desea la conversión, entonces pase 0
como porcentaje ( p
) también. Si c1
se omite el color o string
se pasa un no , no se convertirá.
- También se agrega una función secundaria a la global.
pSBCr
se le puede pasar un color Hex o RGB y devuelve un objeto que contiene esta información de color. Está en la forma: {r: XXX, g: XXX, b: XXX, a: X.XXX}. Donde .r
, .g
y .b
tienen un rango de 0 a 255. Y cuando no hay alfa: .a
es -1. De lo contrario: .a
tiene un rango de 0,000 a 1,000.
- Para la salida RGB, se emite cuando se
rgba()
pasa rgb()
un color con un canal alfa a c0
(desde) y / o c1
(hasta).
- Se ha agregado la comprobación de errores menores. No es perfecto Todavía puede bloquearse o crear jibberish. Pero atrapará algunas cosas. Básicamente, si la estructura es incorrecta de alguna manera o si el porcentaje no es un número o está fuera de alcance, volverá
null
. Un ejemplo: pSBC(0.5,"salt") == null
donde, como cree, #salt
es un color válido. Elimine las cuatro líneas que terminan con return null;
para eliminar esta característica y hacerla más rápida y más pequeña.
- Utiliza la combinación de registros. Pase
true
por l
(el 4º parámetro) para usar Linear Blending.
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}
La siguiente imagen ayudará a mostrar la diferencia en los dos métodos de fusión:
Micro funciones
Si realmente quieres velocidad y tamaño, tendrás que usar RGB, no HEX. RGB es más directo y simple, HEX escribe demasiado lento y viene en muchos sabores para un simple dos líneas (es decir, podría ser un código HEX de 3, 4, 6 u 8 dígitos). También deberá sacrificar algunas funciones, sin verificación de errores, sin HEX2RGB ni RGB2HEX. Además, deberá elegir una función específica (según el nombre de la función a continuación) para las matemáticas de combinación de colores, y si desea sombrear o combinar. Estas funciones admiten canales alfa. Y cuando ambos colores de entrada tienen alfa, se combinarán linealmente. Si solo uno de los dos colores tiene un alfa, lo pasará directamente al color resultante. A continuación hay dos funciones de línea que son increíblemente rápidas y pequeñas:
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:")");
}
¿Quieres más información? Lea el artículo completo en github .
PT
(Ps. Si alguien tiene las matemáticas para otro método de combinación, por favor comparta).