Search code examples
htmlcsssvgsvg-filterscss-filters

How to calculate required hue-rotate to generate specific colour?


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?

Edit

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.

div {
  background:url(http://richard.parnaby-king.co.uk/basket.svg) no-repeat scroll 0 0 transparent;
  background-size:5em;
  width:5em;
  height:5em;
  -webkit-filter: invert(25%) sepia() saturate(100000%) hue-rotate(174deg);
  filter: invert(25%) sepia() saturate(100000%) hue-rotate(174deg);
}
<div></div>
<p style="background: #689d94">​</p>


Solution

  • The only way to get the exact match is to use an SVG color matrix filter.

    For RGB color #689d94, which is rgb(104, 157, 148), divide each primary color's value by 255:

    Put these weights into the SVG <filter> matrix (5ᵗʰ column in the first 3 rows):

    <svg xmlns="http://www.w3.org/2000/svg">
      <defs>
        <filter id="689d94" color-interpolation-filters="sRGB">
          <feColorMatrix type="matrix" 
            values="0 0 0 0 0.40784 
                    0 0 0 0 0.61569 
                    0 0 0 0 0.58039 
                    0 0 0 1 0"/>
        </filter>
      </defs>
    </svg>
    

    The <filter> has to have id (I used the RGB hex code 689d94), so we can use it as a reference.

    Since some browsers (e.g. Firefox) don't see/use the SVG filter if the display property of the SVG element is set to none, and having this SVG element in HTML code would inconveniently occupy some space, the best way is to convert this SVG into a pure inline CSS filter.

    To get an inline filter value, take the above listed SVG code, transform it into a single line by remove line breaks and unnecessary spaces, then prepend url('data:image/svg+xml, and append the previously mentioned id as #689d94'):

    div {
      background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="71.063" height="60.938"><path d="M33.938 0l-16.97 19.906H1.625L0 21.781v8.781l1.25 1.407h4.781l5.875 28.969h46.969l6.188-28.97h4.687l1.313-1.343v-8.844L69.5 19.906H54.656L37.312 0h-3.375zm1.593 7.594l9.594 12.312H26.25l9.281-12.312zm-20.281 16s-.405 2.9 1.594 3.844c1.998.942 4.406.03 4.406.03-1.666 2.763-3.638 3.551-5.469 2.688-3.312-1.562-.531-6.562-.531-6.562zm41.188.031s2.749 4.969-.563 6.531c-2.487 1.162-4.848-1.541-5.438-2.656 0 0 2.377.88 4.375-.063 1.999-.942 1.625-3.812 1.625-3.812z"/></svg>') no-repeat; // optimized from http://richard.parnaby-king.co.uk/basket.svg
      background-size: 100%;
      display: inline-block;
      height: 5em;
      width: 5em;
    }
    #colored {
      filter: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"><defs><filter id="689d94" color-interpolation-filters="sRGB"><feColorMatrix type="matrix" values="0 0 0 0 0.40784 0 0 0 0 0.61569 0 0 0 0 0.58039 0 0 0 1 0"/></filter></defs></svg>#689d94');
      margin-left: 20px;
    }
    <!-- No <svg> in HTML; pure CSS -->
    <div></div><div id="colored"></div>
    <p style="background: #689d94">​</p>