I recently found myself needing to combine two colors. Sass has a great function for doing this, even allowing you to control the percentage of each color, but in my case the two colors needed to change every few seconds, so Sass was out of the question. Enter JavaScript.
Here's my JavaScript version of Sass' mix()
function.
var mix = function(color_1, color_2, weight) {
function d2h(d) { return d.toString(16); } // convert a decimal value to hex
function h2d(h) { return parseInt(h, 16); } // convert a hex value to decimal
weight = (typeof(weight) !== 'undefined') ? weight : 50; // set the weight to 50%, if that argument is omitted
var color = "#";
for(var i = 0; i <= 5; i += 2) { // loop through each of the 3 hex pairs—red, green, and blue
var v1 = h2d(color_1.substr(i, 2)), // extract the current pairs
v2 = h2d(color_2.substr(i, 2)),
// combine the current pairs from each source color, according to the specified weight
val = d2h(Math.floor(v2 + (v1 - v2) * (weight / 100.0)));
while(val.length < 2) { val = '0' + val; } // prepend a '0' if val results in a single digit
color += val; // concatenate val to our new color string
}
return color; // PROFIT!
};
Unlike the Sass version, my JavaScript version only accepts 6-digit hex values for the colors (#ff0000
works, but #f00
does not.) Like the Sass version, the weight
argument is an integer value between 0 and 100.
var mixed = mix('ff0000', '0000bb', 75); // returns #bf002e
Because it only accepts 6-digit hex values you may need to convert your color from RGB, particularly if you obtained it using something like window.getComputedStyle(div).backgroundColor;
, as I did. In that case, this function has you covered:
var rgb2hex = function(rgb) {
// A very ugly regex that parses a string such as 'rgb(191, 0, 46)' and produces an array
rgb = rgb.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d\.]+))?\)$/);
function hex(x) { return ("0" + parseInt(x).toString(16)).slice(-2); } // another way to convert a decimal to hex
return (hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3])).toUpperCase(); // concatenate the pairs and return them upper cased
};
Use it like so:
var color1 = window.getComputedStyle(element1).backgroundColor; // 'ff0000'
var color2 = window.getComputedStyle(element2).backgroundColor; // '0000bb'
var mixed = mix(rgb2hex(color1), rgb2hex(color2), 75); // returns #bf002e
Play with the Sass version over on SassMeister.com
@geanfarias I know this is over a year later, but yes, see my comment above. Use
Math.round()
instead ofMath.floor()
.