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

后端 未结 9 1919
甜味超标
甜味超标 2020-12-06 04:36

Given a string of a valid CSS color value:

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

Need to get an array of numbers of t

9条回答
  •  清歌不尽
    2020-12-06 05:08

    For HTML5 compatible browsers I write a single pixel into a using the specified value, and read back the rgba quad.

    For performance I memoize this function so that repeated calls for the same colour string don't have to perform the canvas operations.

    EDIT updated for ES6 and to remove jQuery dependency

    EDIT (1j01) added invalid color detection, and a function that supports passing a fallback color

    let memoize = function(factory, ctx) {
        var cache = {};
        return function(key) {
            if (!(key in cache)) {
                cache[key] = factory.call(ctx, key);
            }
            return cache[key];
        };
    };
    
    let colorToRGBA = (function() {
        var canvas = document.createElement('canvas');
        canvas.width = canvas.height = 1;
        var ctx = canvas.getContext('2d');
    
        return memoize(function(col) {
            ctx.clearRect(0, 0, 1, 1);
            // In order to detect invalid values,
            // we can't rely on col being in the same format as what fillStyle is computed as,
            // but we can ask it to implicitly compute a normalized value twice and compare.
            ctx.fillStyle = '#000';
            ctx.fillStyle = col;
            var computed = ctx.fillStyle;
            ctx.fillStyle = '#fff';
            ctx.fillStyle = col;
            if (computed !== ctx.fillStyle) {
                return; // invalid color
            }
            ctx.fillRect(0, 0, 1, 1);
            return [ ... ctx.getImageData(0, 0, 1, 1).data ];
        });
    })();
    
    colorToRGBA('white') // [255, 255, 255, 255]
    colorToRGBA('blah') // undefined
    
    let colorOrFallbackColorToRGBA = (color, fallbackColor)=> {
        // Don't short-circuit getting the fallback RGBA -
        // it's already memoized, and we want to show an error
        // if the fallback color is invalid even if the main color is valid
        var fallbackRGBA = colorToRGBA(fallbackColor);
        if (!fallbackRGBA) {
            throw new Error(`Invalid fallbackColor ${
                fallbackColor != null ? JSON.stringify(fallbackColor) : fallbackColor
            }`);
        }
        return colorToRGBA(color) || fallbackRGBA;
    };
    
    colorOrFallbackColorToRGBA('white', 'transparent') // [255, 255, 255, 255]
    colorOrFallbackColorToRGBA('blah', 'transparent') // [0, 0, 0, 0]
    

提交回复
热议问题