Boann
Boann

Reputation: 50021

Get real value of a CSS color property in script

When I use window.getComputedStyle on an element's color property, it returns a string with an rgb() or rgba() value, regardless of the syntax used to set the color originally. In Internet Explorer, when forced to use element.currentStyle instead, it apparently returns the exact color string that was originally set (although lowercased).

Here is a demonstration of my problem:

<div id=el>&nbsp;</div>
<script type="text/javascript">
var el = document.getElementById('el');
el.style.color = 'red';
if (window.getComputedStyle) {
    el.innerHTML = getComputedStyle(el, null).color;
} else {
    el.innerHTML = el.currentStyle.color;
}
</script>

Other browsers display "rgb(255, 0, 0)". IE displays "red". I want to determine the real RGB or RGBA value. So I have two questions:

  1. Is there any way to get the real value in IE... other than by parsing all potential color syntaxes manually and including a mapping of color names to values?
  2. Could the behavior of the other browsers be relied on? Are they supposed to return a value as an rgb() or rgba() string, or could they return, for example, #ff0000, or something else?

Upvotes: 5

Views: 4312

Answers (2)

jfriend00
jfriend00

Reputation: 707258

As best I can tell, the answer is "no". There is no simple way to get the color value in IE without knowing how to parse all possible color representations. When I tried to do this, I found that I even needed to recognized all possible color names like blue. It was a royal pain, but I did work out the code for it.

My code was trying to get the background color and it will even look at parent objects in order to find where the background color is set (so it's not doing exactly what you asked for) and it used the YUI version of getComputedStyle (you can substitute your own) but this is the code I used. It does handle these forms of color definition:

#fff
#ffffff
transparent
rgb(12,45,99)
rgba(12,45,99,30)
orange

And, the code:

JFL.GetBackgroundColor = function(o)
{
    var colorNames = {
        aliceblue: 'f0f8ff',
        antiquewhite: 'faebd7',
        aqua: '00ffff',
        aquamarine: '7fffd4',
        azure: 'f0ffff',
        beige: 'f5f5dc',
        bisque: 'ffe4c4',
        black: '000000',
        blanchedalmond: 'ffebcd',
        blue: '0000ff',
        blueviolet: '8a2be2',
        brown: 'a52a2a',
        burlywood: 'deb887',
        cadetblue: '5f9ea0',
        chartreuse: '7fff00',
        chocolate: 'd2691e',
        coral: 'ff7f50',
        cornflowerblue: '6495ed',
        cornsilk: 'fff8dc',
        crimson: 'dc143c',
        cyan: '00ffff',
        darkblue: '00008b',
        darkcyan: '008b8b',
        darkgoldenrod: 'b8860b',
        darkgray: 'a9a9a9',
        darkgreen: '006400',
        darkkhaki: 'bdb76b',
        darkmagenta: '8b008b',
        darkolivegreen: '556b2f',
        darkorange: 'ff8c00',
        darkorchid: '9932cc',
        darkred: '8b0000',
        darksalmon: 'e9967a',
        darkseagreen: '8fbc8f',
        darkslateblue: '483d8b',
        darkslategray: '2f4f4f',
        darkturquoise: '00ced1',
        darkviolet: '9400d3',
        deeppink: 'ff1493',
        deepskyblue: '00bfff',
        dimgray: '696969',
        dodgerblue: '1e90ff',
        feldspar: 'd19275',
        firebrick: 'b22222',
        floralwhite: 'fffaf0',
        forestgreen: '228b22',
        fuchsia: 'ff00ff',
        gainsboro: 'dcdcdc',
        ghostwhite: 'f8f8ff',
        gold: 'ffd700',
        goldenrod: 'daa520',
        gray: '808080',
        green: '008000',
        greenyellow: 'adff2f',
        honeydew: 'f0fff0',
        hotpink: 'ff69b4',
        indianred : 'cd5c5c',
        indigo : '4b0082',
        ivory: 'fffff0',
        khaki: 'f0e68c',
        lavender: 'e6e6fa',
        lavenderblush: 'fff0f5',
        lawngreen: '7cfc00',
        lemonchiffon: 'fffacd',
        lightblue: 'add8e6',
        lightcoral: 'f08080',
        lightcyan: 'e0ffff',
        lightgoldenrodyellow: 'fafad2',
        lightgrey: 'd3d3d3',
        lightgreen: '90ee90',
        lightpink: 'ffb6c1',
        lightsalmon: 'ffa07a',
        lightseagreen: '20b2aa',
        lightskyblue: '87cefa',
        lightslateblue: '8470ff',
        lightslategray: '778899',
        lightsteelblue: 'b0c4de',
        lightyellow: 'ffffe0',
        lime: '00ff00',
        limegreen: '32cd32',
        linen: 'faf0e6',
        magenta: 'ff00ff',
        maroon: '800000',
        mediumaquamarine: '66cdaa',
        mediumblue: '0000cd',
        mediumorchid: 'ba55d3',
        mediumpurple: '9370d8',
        mediumseagreen: '3cb371',
        mediumslateblue: '7b68ee',
        mediumspringgreen: '00fa9a',
        mediumturquoise: '48d1cc',
        mediumvioletred: 'c71585',
        midnightblue: '191970',
        mintcream: 'f5fffa',
        mistyrose: 'ffe4e1',
        moccasin: 'ffe4b5',
        navajowhite: 'ffdead',
        navy: '000080',
        oldlace: 'fdf5e6',
        olive: '808000',
        olivedrab: '6b8e23',
        orange: 'ffa500',
        orangered: 'ff4500',
        orchid: 'da70d6',
        palegoldenrod: 'eee8aa',
        palegreen: '98fb98',
        paleturquoise: 'afeeee',
        palevioletred: 'd87093',
        papayawhip: 'ffefd5',
        peachpuff: 'ffdab9',
        peru: 'cd853f',
        pink: 'ffc0cb',
        plum: 'dda0dd',
        powderblue: 'b0e0e6',
        purple: '800080',
        red: 'ff0000',
        rosybrown: 'bc8f8f',
        royalblue: '4169e1',
        saddlebrown: '8b4513',
        salmon: 'fa8072',
        sandybrown: 'f4a460',
        seagreen: '2e8b57',
        seashell: 'fff5ee',
        sienna: 'a0522d',
        silver: 'c0c0c0',
        skyblue: '87ceeb',
        slateblue: '6a5acd',
        slategray: '708090',
        snow: 'fffafa',
        springgreen: '00ff7f',
        steelblue: '4682b4',
        tan: 'd2b48c',
        teal: '008080',
        thistle: 'd8bfd8',
        tomato: 'ff6347',
        turquoise: '40e0d0',
        violet: 'ee82ee',
        violetred: 'd02090',
        wheat: 'f5deb3',
        white: 'ffffff',
        whitesmoke: 'f5f5f5',
        yellow: 'ffff00',
        yellowgreen: '9acd32'
    };
    function parseSingle(s)
    {
        s = s + s;
        return(parseInt(s, 16));
    }
    var color;
    while (o)
    {
        color = YD.getComputedStyle(o, "backgroundColor");
        if (color && color != "transparent")
        {
            break;
        }
        if (o == document.body)
        {
            color = "#ffffff";
            break;
        }
        o = o.parentNode;
    }
    color = color.replace(/ /g, "").toLowerCase();
    if (colorNames[color])
    {
        color = "#" + colorNames[color];
    }
    var r = 256, g = 256, b = 256;
    if (color.indexOf("#") == 0)
    {
        color = color.slice(1);
        if (color.length == 3)
        {
            r = parseSingle(color.slice(0,1));
            g = parseSingle(color.slice(1,2));
            b = parseSingle(color.slice(2,3));
        }
        else if (color.length == 6)
        {
            r = parseInt(color.slice(0,2), 16);
            g = parseInt(color.slice(2,4), 16);
            b = parseInt(color.slice(4,6), 16);
        }
    }
    else if (color.indexOf("rgb") == 0)
    {
        var results = color.match(/^rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})/);
        if (results && results.length >= 4)
        {
            r = parseInt(results[1], 10);
            g = parseInt(results[2], 10);
            b = parseInt(results[3], 10);
        }
    }
    var luminance = (0.3 * r + 0.59 * g + 0.11 * b) / 256;
    return({r: r, g: g, b: b, luminance: luminance});
}

Upvotes: 3

Boann
Boann

Reputation: 50021

As suggested I examined CMS's answer here which uses queryCommandValue. For the equivalent of CSS 'color' rather than 'backround-color', I had to use 'ForeColor' rather than 'BackColor', but this technique seems to work perfectly for getting the real value in IE.

Here is the amended, working version of the example in my question:

<div id=el>&nbsp;</div>
<script type="text/javascript">
var el = document.getElementById('el');
el.style.color = 'red';
if (window.getComputedStyle) {
    el.innerHTML = getComputedStyle(el, null).color;
} else {
    var oRG = document.body.createTextRange();
    oRG.moveToElementText(el);
    var iClr = oRG.queryCommandValue('ForeColor');
    el.innerHTML = 'rgb('+(iClr & 0xFF)+','+((iClr & 0xFF00)>>8)+','+((iClr & 0xFF0000)>>16)+')';
}
</script>

I've been looking for an answer to my second question, but there doesn't seem to be one. If I'm reading it correctly, this page: http://www.w3.org/TR/css3-color/ explains that browsers may return, for the computed value, either a "six digit hex value or rgb(...) functional value, with an alpha value of 1" (?). It says transparent returns rgba(0,0,0,0). And finally it says, "for all other values, the computed value is the specified value". This is not clear at all. E.g., must it use RGB integers or can it use percentages? May there be space around the values? Can the "specified value"'s letter case be preserved? What about hsl() and hsla() colors?

In practice, it seems that browsers normalize the values to return rgb(...) or rgba(...), with the red-green-blue as integers and the alpha as a decimal, with a single space after each comma, although this doesn't seem to be formally specified. As an exception, Firefox seems to return transparent if the color's alpha value is 0, regardless of the other values or how it was set; e.g., rgba(255, 0, 255, 0).

So, IE's odd way for getting an RGB int is far simpler, if you can use it.

Upvotes: 0

Related Questions