I have a white image that I am using as a background for a div, and I would like to colour to match the themes main colour. I am aware I can do:
filter: sepia() saturate(10000%) hue-rotate(30deg);
and cycle through hue-rotate
to find a colour, but is it possible to calculate this value in advance? Given that the specified hex value is quite dark, I imagine I will need to include the invert(%)
filter as well.
Given a hex value of #689d94
what math do I need to do to calculate the desired hue-rotate
and invert
value to convert my white background image into the same colour?
Here's a snippet of a div
with a white background image being filtered green. The trick here, is it is the whole of the div
that is being filtered, not just the image. If I was to enter some text into the div
the text colour would turn green as well.
The key in this case is to define an initial color. White nor black or any gray-scale is technically an actual color - you can't saturate or rotate it. You'll have to "colorize" it somehow, and the sepia filter is the only filter which do some form of colorizing.
It would be easier if your image was pure 100% red. Then you could just add the target degree directly and adjust saturation and lightness using HSL for target. For a white color start point the first step is to convert and define an intermediate color so we can saturate and rotate it later on.
Lets first darken the white image and apply sepia to get a "base" color we can work with:
filter: brightness(50%) sepia(1);
This will produce RGB color value of approximately:
rgb(178, 160, 128)
Step two is to convert that to HSL color-space which gives us:
hsl(38, 24.5%, 60%);
div {
background:url(http://richard.parnaby-king.co.uk/basket.svg) no-repeat;
background-size:5em;
width:5em;
height:5em;
-webkit-filter: brightness(50%) sepia(1);
filter: brightness(50%) sepia(1);
}
<div></div>
These two first steps are static and its result will be reused every time we need to find a target adjustment (the actual value of sepia is defined in the SVG Filters specification).
Now we need to calculate what we need to apply to this base color to get target color. First convert target color, for example #689d94 as given in the question, to HSL:
hsl(170, 21.3%, 51.2%);
Then we have to calculate the difference between those. Hue is calculated by simply subtracting base from target. The same for Saturation and Lightness, but as we assume 100% of the base value we need to subtract the result from 100% to end up with a diff for the accumulated values:
H: 170 - 38 -> 132°
S: 100 + (24.5 - 21.3) -> 103.2% (relative to base 100% = 3.2%)
L: 100 + (51.2 - 60.0) -> 91.2% (relative to base 100% = -8.8%)
Convert those values to a filter-string by appending it to the existing filter, then set it on the div:
/* ------ base color ------ ------- new target -------------------------------*/
filter: brightness(50%) sepia(1) hue-rotate(132deg) saturate(103.2%) brightness(91.2%);
And to set it you would probably do something like this assuming filter and divElement are already declared:
...
filter = "brightness(0.5) sepia(1) hue-rotate(132deg) saturate(103.2%) brightness(91.2%)";
divElement.style.filter = filter;
divElement.style.webkitFilter = filter;
Note that there is likely rounding errors as RGB is represented as integer, while HSL is floating point, so the actual result may not be exact, but it should get pretty close.
div {
background:url(http://richard.parnaby-king.co.uk/basket.svg) no-repeat;
background-size:5em;
width:5em;
height:5em;
-webkit-filter:
brightness(50%) sepia(1) hue-rotate(132deg) saturate(103.2%) brightness(91.2%);
filter:
brightness(50%) sepia(1) hue-rotate(132deg) saturate(103.2%) brightness(91.2%);
}
<div></div>
<span style="font:14px sans-serif;padding:7px;color:#fff;background:#689d94">
Target color</span>
Viable alternative options are: