Firefox Parsing 4 Digit Hex Color Values as Rgba

Firefox parsing 4 digit hex color values as rgba

This is new to Color level 4 (which is why it doesn't appear in level 3) and was indeed shipped in Firefox 49:

8 digits

The first 6 digits are interpreted identically to the 6-digit notation. The last pair of digits, interpreted as a hexadecimal number, specifies the alpha channel of the color, where 00 represents a fully transparent color and ff represent a fully opaque color.

4 digits

This is a shorter variant of the 8-digit notation, "expanded" in the same way as the 3-digit notation is. The first digit, interpreted as a hexadecimal number, specifies the red channel of the color, where 0 represents the minimum value and f represents the maximum. The next three digits represent the green, blue, and alpha channels, respectively.

What does this box-shadow query mean and how can I make it corss-browser friendly?

#0000001A is equivalent to rgba(0, 0, 0, 0.1), where 0.1 is the approximate value of 0x1a / 0xff. So,

box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.1);

Also, #RRGGBBAA format is standard, and works for everything — except, as usual, Microsoft browsers (table); not just Chrome.

RGB to hex and hex to RGB

Note: both versions of rgbToHex expect integer values for r, g and b, so you'll need to do your own rounding if you have non-integer values.

The following will do to the RGB to hex conversion and add any required zero padding:

function componentToHex(c) {
var hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}

function rgbToHex(r, g, b) {
return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}

alert(rgbToHex(0, 51, 255)); // #0033ff

What is the most efficient way to parse a CSS color in JavaScript?

function parseColor(input) {
var m;

Obviously, the numeric values will be easier to parse than names. So we do those first.

    m = input.match(/^#([0-9a-f]{3})$/i)[1];
if( m) {
// in three-character format, each value is multiplied by 0x11 to give an
// even scale from 0x00 to 0xff
return [
parseInt(m.charAt(0),16)*0x11,
parseInt(m.charAt(1),16)*0x11,
parseInt(m.charAt(2),16)*0x11
];
}

That's one. Now for the full six-digit format:

    m = input.match(/^#([0-9a-f]{6})$/i)[1];
if( m) {
return [
parseInt(m.substr(0,2),16),
parseInt(m.substr(2,2),16),
parseInt(m.substr(4,2),16)
];
}

And now for rgb() format:

    m = input.match(/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i);
if( m) {
return [m[1],m[2],m[3]];
}

Optionally, you can also add support for rgba format, and even hsl/hsla if you add an HSL2RGB conversion function.

Finally, the named colours.

    return ({
"red":[255,0,0],
"yellow":[255,255,0],
// ... and so on. Yes, you have to define ALL the colour codes.
})[input];

And close the function:

}

Actually, I don't know why I bothered writing all that. I just noticed you specified "assuming a major browser", I'm assuming that also means "up-to-date"? If so...

function parseColor(input) {
var div = document.createElement('div'), m;
div.style.color = input;
m = getComputedStyle(div).color.match(/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i);
if( m) return [m[1],m[2],m[3]];
else throw new Error("Colour "+input+" could not be parsed.");
}

An up-to-date browser will convert any given colour to rgb() format in its computed style. Just get it back, and read it out.

Which color is #0000?

From http://dev.w3.org/csswg/css-color/#hex-notation:

4 digits


This is a shorter variant of the 8-digit notation, "expanded" in the
same way as the 3-digit notation is. The first digit, interpreted as a
hexadecimal number, specifies the red channel of the color, where 0
represents the minimum value and f represents the maximum. The next
three digits represent the green, blue, and alpha channels,
respectively.

transparent, like rgba(0, 0, 0, 0.0)

not supported yet tho. From http://www.w3.org/TR/CSS2/syndata.html#parsing-errors:

Illegal values. User agents must ignore a declaration with an illegal value.

Here's a testcase. Yellow background = not supported. Transparent (white) background = supported.

http://jsfiddle.net/p5aJJ/

<div class="test">hello</div>

...

div {
background-color: yellow;
}

div.test {
background-color: #0000;
}

Programmatically Lighten or Darken a hex color (or rgb, and blend colors)

Well, this answer has become its own beast. Many new versions, it was getting stupid long. Many thanks to all of the great many contributors to this answer. But, in order to keep it simple for the masses. I archived all the versions/history of this answer's evolution to my github. And started it over clean on StackOverflow here with the newest version. A special thanks goes out to Mike 'Pomax' Kamermans for this version. He gave me the new math.


This function (pSBC) will take a HEX or RGB web color. pSBC can shade it darker or lighter, or blend it with a second color, and can also pass it right thru but convert from Hex to RGB (Hex2RGB) or RGB to Hex (RGB2Hex). All without you even knowing what color format you are using.

This runs really fast, probably the fastest, especially considering its many features. It was a long time in the making. See the whole story on my github. If you want the absolutely smallest and fastest possible way to shade or blend, see the Micro Functions below and use one of the 2-liner speed demons. They are great for intense animations, but this version here is fast enough for most animations.

This function uses Log Blending or Linear Blending. However, it does NOT convert to HSL to properly lighten or darken a color. Therefore, results from this function will differ from those much larger and much slower functions that use HSL.

jsFiddle with pSBC

github > pSBC Wiki

Features:

  • Auto-detects and accepts standard Hex colors in the form of strings. For example: "#AA6622" or "#bb551144".
  • Auto-detects and accepts standard RGB colors in the form of strings. For example: "rgb(123,45,76)" or "rgba(45,15,74,0.45)".
  • Shades colors to white or black by percentage.
  • Blends colors together by percentage.
  • Does Hex2RGB and RGB2Hex conversion at the same time, or solo.
  • Accepts 3 digit (or 4 digit w/ alpha) HEX color codes, in the form #RGB (or #RGBA). It will expand them. For Example: "#C41" becomes "#CC4411".
  • Accepts and (Linear) blends alpha channels. If either the c0 (from) color or the c1 (to) color has an alpha channel, then the returned color will have an alpha channel. If both colors have an alpha channel, then the returned color will be a linear blend of the two alpha channels using the percentage given (just as if it were a normal color channel). If only one of the two colors has an alpha channel, this alpha will just be passed thru to the returned color. This allows one to blend/shade a transparent color while maintaining the transparency level. Or, if the transparency levels should blend as well, make sure both colors have alphas. When shading, it will pass the alpha channel straight thru. If you want basic shading that also shades the alpha channel, then use rgb(0,0,0,1) or rgb(255,255,255,1) as your c1 (to) color (or their hex equivalents). For RGB colors, the returned color's alpha channel will be rounded to 3 decimal places.
  • RGB2Hex and Hex2RGB conversions are implicit when using blending. Regardless of the c0 (from) color; the returned color will always be in the color format of the c1 (to) color, if one exists. If there is no c1 (to) color, then pass 'c' in as the c1 color and it will shade and convert whatever the c0 color is. If conversion only is desired, then pass 0 in as the percentage (p) as well. If the c1 color is omitted or a non-string is passed in, it will not convert.
  • A secondary function is added to the global as well. pSBCr can be passed a Hex or RGB color and it returns an object containing this color information. Its in the form: {r: XXX, g: XXX, b: XXX, a: X.XXX}. Where .r, .g, and .b have range 0 to 255. And when there is no alpha: .a is -1. Otherwise: .a has range 0.000 to 1.000.
  • For RGB output, it outputs rgba() over rgb() when a color with an alpha channel was passed into c0 (from) and/or c1 (to).
  • Minor Error Checking has been added. It's not perfect. It can still crash or create jibberish. But it will catch some stuff. Basically, if the structure is wrong in some ways or if the percentage is not a number or out of scope, it will return null. An example: pSBC(0.5,"salt") == null, where as it thinks #salt is a valid color. Delete the four lines which end with return null; to remove this feature and make it faster and smaller.
  • Uses Log Blending. Pass true in for l (the 4th parameter) to use Linear Blending.

Code:

// 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)
}

Usage:

// 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}

The picture below will help show the difference in the two blending methods:

Sample Image



Micro Functions

If you really want speed and size, you will have to use RGB not HEX. RGB is more straightforward and simple, HEX writes too slow and comes in too many flavors for a simple two-liner (IE. it could be a 3, 4, 6, or 8 digit HEX code). You will also need to sacrifice some features, no error checking, no HEX2RGB nor RGB2HEX. As well, you will need to choose a specific function (based on its function name below) for the color blending math, and if you want shading or blending. These functions do support alpha channels. And when both input colors have alphas it will Linear Blend them. If only one of the two colors has an alpha, it will pass it straight thru to the resulting color. Below are two liner functions that are incredibly fast and small:

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:")");
}

Want more info? Read the full writeup on github.

PT

(P.s. If anyone has the math for another blending method, please share.)

Get a color component from an rgb string in Javascript?

NOTE - We're all on board with the regex ate my brains and kicked my dog attitude, but the regex version just seems the better method. My opinion. Check it out.

Non-regex method:

var rgb = 'rgb(200, 12, 53)';

rgb = rgb.substring(4, rgb.length-1)
.replace(/ /g, '')
.split(',');

console.log(rgb);

http://jsfiddle.net/userdude/Fg9Ba/

Outputs:

["200", "12", "53"]

Or... A really simple regex:

EDIT: Ooops, had an i in the regex for some reason.

var rgb = 'rgb(200, 12, 53)';

rgb = rgb.replace(/[^\d,]/g, '').split(',');

console.log(rgb);

http://jsfiddle.net/userdude/Fg9Ba/2



Related Topics



Leave a reply



Submit