Search code examples
javascriptcssperformanceparsingcolors

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


Given a string of a valid CSS color value:

  • #fff
  • #ffffff
  • white
  • rgb(255, 255, 255)

I need to get an array of numbers of the following format: [R, G, B]

What is the most efficient way of doing this in JavaScript (assuming a major browser)?


Solution

  • 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.