views:

45

answers:

2

Hello,

I'm trying to figure out how to write a function that programmatically retrieves a background-color css attribute and creates two outputs (one slightly darker than the background-color, one slightly lighter).

The idea is being able to generate a very basic linear gradient from a single color selection.

Anyone have any ideas?

+1  A: 

To generate a darker or lighter vairant, a simple possibility is just to add or subtract a fixed number to all three componenents, capping it at 0 and 255/0xFF.

Artefacto
Thanks for the comment, I'll try this out
Walker
Your colors will not appear to be at the same level of saturation if you use this method.
Jesse Dhillon
+3  A: 

To scale a color correctly, you have to multiply each RGB value by a proportion. E.g., if your color is #00417b and you want a color that is 125% lighter color then you have to do this:

var dark = {r: 0, g: 65, b: 123};
var light = {r: Math.round(Math.min(dark[r]*1.25, 255)),
             g: Math.round(Math.min(dark[g]*1.25, 255)),
             b: Math.round(Math.min(dark[b]*1.25, 255))};

Compare the result for yourself: dark is #00417b, and light is #00519A, although it's perfectly valid CSS to describe them as rgb(0, 65, 123) and rgb(0, 81, 154) and probably easier too. By scaling colors in this way they will appear to be at the same level of saturation, something that simply adding or subtracting numbers will not achieve.

Be aware that since values are clamped at [0, 255], if you keep shifting colors, then feeding them back into this process, you can destroy information about the proportion of red, green and blue in the source color. For this reason, keep the original color saved and try to use that as your input each time.

Since your question asked specifically about gradients though, this is how you would go between two color values:

// Suppose you have a container which is X pixels high and you want to insert a 1-pixel tall
// element at each pixel, going vertically

var min = Math.min;
var max = Math.max;
var round = Math.round;

function get_color_for_height(startColor, endColor, height, row) {
  var scale = row/height;
  var r = startColor[red] + scale*(endColor[red] - startColor[red]);
  var b = startColor[blue] + scale*(endColor[blue] - startColor[blue]);
  var g = startColor[green] + scale*(endColor[green] - startColor[green]);

  return {
    r: round(min(255, max(0, r))),
    g: round(min(255, max(0, g))),
    b: round(min(255, max(0, b)))
  }
}


// some psuedo-code using an imaginary framework
for(var h = 0; h < height; h++) {
  var div = new Element('div');
  div.height = 1;
  div.backgroundColor = get_color_for_height(start, end, height, h);
  container.insert('top', div);
}
Jesse Dhillon
I first was skeptical that this would preserve saturation, but according to [this article](http://ieeexplore.ieee.org/iel5/8324/26327/01167456.pdf), S = 1 - (3 * min(R,G,B))/(R+G+B), so it appears it does. +1
Artefacto
I'd add that it would be more interesting to preserve the hue, though.
Artefacto
Thanks, really thorough answer.
Walker
I believe this method preserves hue and saturation, and modulates the value. Adjusting the value is, I think, what most people think when they see gradients.
Jesse Dhillon
@Jesse No, it will not preserve the hue. Check [the equations](http://nebm.ist.utl.pt/~glopes/img/RGBtoHSI.png).
Artefacto
@Artefacto, I said I was modulating the value, not the intensity. You are referring to an HSI model; using an HSV model -- the second most popular model, behind RGB -- the hue *is* preserved.
Jesse Dhillon
@Jesse Are you saying the hue means different things in HSV and HSI?
Artefacto
@Artefacto, if you are still unconvinced you can take a look at a Python implementation I've written (http://codepad.org/sg5aXVQt) and try it out for yourself.
Jesse Dhillon
@Jesse OK, I'm convinced :p By multiplying both all the values, the branch is always the same because the color that's the min and max doesn't change.
Artefacto
@Artefacto, I used the equations from the Wikipedia page on HSV: http://en.wikipedia.org/wiki/HSL_and_HSV
Jesse Dhillon