-2

I've been noticing that if I set a style color to a named color or RGB value it will retain that literal value when retrieved. However, when set to a hex string or HSL string it gets automatically converted to an RGB string instead:

let body = document.querySelector('body');
console.log(body.style.backgroundColor); // ""

body.style.backgroundColor = 'white';
console.log(body.style.backgroundColor); // white

body.style.backgroundColor = 'rgb(255, 0, 0)';
console.log(body.style.backgroundColor); // rgb(255, 0, 0)

body.style.backgroundColor = '#0080ff';
console.log(body.style.backgroundColor); // rgb(0, 128, 255)

body.style.backgroundColor = 'hsl(195, 100%, 50%)';
console.log(body.style.backgroundColor); // rgb(0, 191, 255)

What's the rationale behind this behavior?

Altay_H
  • 489
  • 6
  • 14
  • Let's take the #0080ff as an example. Split the hex number in pairs of 2 (00, 80, ff) and just convert those pairs to decimal (00, 128, 255). Same vice versa if you want to convert rgb to hex. – newBee Jun 15 '18 at 12:47
  • I know _how_ to convert a hex string to rgb. I don't understand why I can't retrieve a hex string I stored in a CSS style without it being _automatically_ converted to rgb, especially when the same does not happen for html color names I do the same thing with. – Altay_H Jun 15 '18 at 12:49
  • #0080ff is 00 red, 80 green and ff blue. For exemple if you set full red "ff" and nothing else then you get red: #ff0000. rgb. – Firefly Jun 15 '18 at 12:54
  • Guessing: If you address a color by name it will keep the name. If you define the color using rgb, hex, ... it will "normalize" the value to rgb. – newBee Jun 15 '18 at 12:58
  • @newBee Yes, I know this is the behavior. I want to know _why_ it was designed this way. It seems arbitrary and inconsistent to apply this transform to hex and hsl, but not to named colors. – Altay_H Jun 15 '18 at 15:01

2 Answers2

2

It seems to be a consensus among browser vendors to retrieve colors from HTMLElement.style (and CSS2Properties object) as normalized keyword if it was set by keyword, in normalized rgb format otherwise, and in normalized rgba for colours with alpha value smaller than 1.

Notice that getComputedStyle contains strictly rgb/rgba values only.

This snippet seems to be yielding quite similar outcome in all browsers:

`red
Red
rED
#f00
#Ff0000
rgb(255,0,0)
rgba(255,0,0,1)
rgba(255,0,0,0.8)
hsl(0, 100%, 50%)`.split(`
`).forEach(c => {
  document.body.style.color = c;
  console.log({
    'set     ': c,
    'style   ': document.body.style.color,
    'computed': getComputedStyle(document.body).color
  })
});
.as-console-wrapper.as-console-wrapper {
  top: 0;
  max-height: none;
}

Same "keyword normalization" happens even when reading from CSS2Properties object from CSSStyleRule:

document.write(document.styleSheets[0].cssRules[0].style.getPropertyValue('color'))
body { color: rED;}

Couldn't find authoritative statement in any standard telling UA vendors to make it this way, though.

myf
  • 9,874
  • 2
  • 37
  • 49
  • Indeed, the [CSS spec](https://www.w3.org/TR/css-color-3/#color0) states that the `computed value` should be an rgb triplet when alpha is 1, and an rgb quadruplet otherwise. However, the plain `value` is simply which would lead me to believe the string it was set to should remain unaltered. – Altay_H Jun 15 '18 at 15:29
  • I was hoping for a delve into the history of javascript and web standards, but I guess sometimes the best answer we have is just that it's been lost to history and no one knows or cares why the inconsistencies we live with came to be. – Altay_H Jun 21 '18 at 21:25
  • 1
    Sure, I hope I'll stumble upon relevant bit of information sometimes and add it here. Also, I fell sorry for the downvotes of such interesting question, and a bit guilty for the upvotes of technically no-answer that in fact just reformulated your question. – myf Jun 28 '18 at 18:46
0

However, when set to a hex string or hsl string it gets automatically converted to an rgb string instead

No conversion takes place at all. It is the same identical representation. Its default output is in rgb(r,g,b) format. What differs is the setter takes different equivalent input formats and then internally parses them to the same representation.

Attersson
  • 4,755
  • 1
  • 15
  • 29