views:

75

answers:

2

Hi,

Is it possible to use javascript to determine what color is one shade darker than the current background? Maybe some hexadecimal addition/subtraction?

I have a menu that can be any color and if it wasn't too difficult it would be great if the submenu could be one shade darker. Does anyone know how to achieve this effect?

+1  A: 

as AB comments, 'shade' isn't very well defined. nonetheless, it might be easier to think of this in some other colour representation, such as 'V' in hsv.

you could either convert, decrease v and convert back, or figure out what decreasing v maps to in rgb hex

second
“V” is “value” IIRC, and decreasing it by 5-10% (before mapping back) produces a reasonably pleasant effect. The main thing to watch out for is maintaining contrast with the menu text; I tinkered around with ways to get that right about 10 years ago, but never got a result I was entirely satisfied with. (I also don't know where I put the code… :-))
Donal Fellows
@Donal: You can usually calculate reliable contrast by inverting the color `(255-channel)`. If the resulting color is too similar in contrast then add the difference a second time to 'push back' the color value: `if (abs(new_channel-channel) < cutoff) new_channel += new_channel-channel`
slebetman
@slebetman: Inverting the color channels fails badly when you're working with mid-gray. Better to detect whether the color is “closer” to black or white and pick the other of that pair, but I never really settled on a metric for “closeness”.
Donal Fellows
@Donal: That's where the second step of the algorithm comes in: push the color further from midpoint if it is too close. All you need is to experiment with the value of `cutoff`;
slebetman
@slebetman: That's still overcomplicated. Clamping to black or white does a good job and is easier to implement.
Donal Fellows
A: 

Something like this:

function shadeColor(color, shade) {
    var colorInt = parseInt(color.substring(1),16);

    var R = (colorInt & 0xFF0000) >> 16;
    var G = (colorInt & 0x00FF00) >> 8;
    var B = (colorInt & 0x0000FF) >> 0;

    R = R + Math.floor((shade/255)*R);
    G = G + Math.floor((shade/255)*G);
    B = B + Math.floor((shade/255)*B);

    var newColorInt = (R<<16) + (G<<8) + (B);
    var newColorStr = "#"+newColorInt.toString(16);

    return newColorStr;
}

Usage:

var newColor = shadeColor("#AA2222", -10);
alert(newColor); //Results in #a32020

Here is an example code to test it: http://pastebin.com/g6phySEv

Max