title: Emulate Photoshop's "Color Overlay" using CSS filters?
body: <p>I have an icon which I'd like to change the color of, using CSS. It is in a data-uri'd optimized SVG inlined in the CSS.</p>
  
  <p>Normally, this <em>wasn't</em> possible. That's why icon fonts were invented; their main advantage over SVG is being able to recieve <code>color</code> and <code>text-shadow</code> rules from CSS. Well, <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter" rel="nofollow noreferrer">CSS filters</a> are now capable of doing both things to arbitrary images, and <a href="http://caniuse.com/#feat=css-filters" rel="nofollow noreferrer">they now work in all Blink, Webkit and Gecko browsers</a>, and <a href="https://status.modern.ie/filters" rel="nofollow noreferrer">can be expected for future IE/Spartan</a>.</p>
  
  <p>A <code>text-shadow</code> replacement is easy; just use the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter#drop-shadow()" rel="nofollow noreferrer"><code>drop-shadow</code> filter</a>.</p>
  
  <p>Coloring the image into a specific color, however, has proven very tricky, despite all the necessary filters being here. My theory, up until now, is as follows:</p>
  
  <ul>
  <li>Use <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter#contrast()" rel="nofollow noreferrer"><code>contrast(0)</code></a> to turn the entire image into solid grey, while keeping the alpha channel (the Mozilla wiki says it'd become black, but in all browsers it becomes grey, must be a typo).</li>
  <li>Use <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter#sepia()" rel="nofollow noreferrer"><code>sepia(1)</code></a>, because we cannot operate on hue/saturation on a grey image. This ensures the entire image is composed of a reference color we can do math on; specifically, <code>#AC9977</code>.</li>
  </ul>
  
  <p>At this point, we should be able to turn the entire image from what is now solid <code>#AC9977</code> to any color we want using <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter#hue-rotate()" rel="nofollow noreferrer"><code>hue-rotate</code></a>, <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter#saturate()" rel="nofollow noreferrer"><code>saturate</code></a> and <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter#brightness()" rel="nofollow noreferrer"><code>brightness</code></a>.</p>
  
  <p>First, what color coordinates are browsers using? I could not find make sense of <a href="http://dev.w3.org/fxtf/filters/" rel="nofollow noreferrer">the spec</a> to be sure if it's using <a href="http://en.wikipedia.org/wiki/HSL_and_HSV" rel="nofollow noreferrer">HSL (<em>Lightness</em>) or HSV (<em>Value</em>)</a>, but since HSB (<em>Brightness</em>) is another name for HSV, I suppose it's using HSV. Furthermore, using something like <code>brightness(999)</code> saturates colors (instead of making them white), which would happen in HSV but not HSL.</p>
  
  <p>Based on this assumption, we would proceed as follows:</p>
  
  <ul>
  <li>Calculate the hue difference between <code>#AC9977</code> and the color we want, and use <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter#hue-rotate()" rel="nofollow noreferrer"><code>hue-rotate</code></a>.</li>
  <li>Calculate the saturation difference between both, and use <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter#saturate()" rel="nofollow noreferrer"><code>saturate</code></a>.</li>
  <li>Calculate the brightness difference between both, and use <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter#brightness()" rel="nofollow noreferrer"><code>brightness</code></a>.</li>
  </ul>
  
  <p>Since this is not the kind of stuff to be done by hand, we'll use the <a href="http://lesscss.org/" rel="nofollow noreferrer">LESS preprocessor</a>:</p>
  
  <pre><code>.colorize(@color) {
      @sepiaGrey: #AC9977;
      @hOffset: (hsvhue(@color) - hsvhue(@sepiaGrey)) * 1deg;
      @sRatio: unit(hsvsaturation(@color) / hsvsaturation(@sepiaGrey));
      @vRatio: unit(hsvvalue(@color) / hsvvalue(@sepiaGrey));
      -webkit-filter: contrast(0) sepia(1) hue-rotate(@hOffset) saturate(@sRatio) brightness(@vRatio);
      filter: contrast(0) sepia(1) hue-rotate(@hOffset) saturate(@sRatio) brightness(@vRatio);
  }
  </code></pre>
  
  <p>This, in my understanding, should work. <a href="http://codepen.io/anon/pen/emaJjW" rel="nofollow noreferrer">But it isn't</a>. <em>Why, and how to make it work?</em></p>
  
  <h2>Example of what I'm trying to achieve</h2>
  
  <p>Consider an icon as an image or an element (background-image, CSS-based shape, etc), with <em>any</em> color, and with a shape defined by transparency (<em>not</em> a rectangular image that could be simply overlaid). I want to make it be entirely composed of a specific color with CSS (presumably, with the use of <code>filters</code>).</p>
  
  <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://i.stack.imgur.com/Mboab.png" alt="example"></p>
  
  <p>I plan to implement this as a <a href="http://lesscss.org/features/#mixins-parametric-feature" rel="nofollow noreferrer">LESS mixin</a> that takes a color argument, but just guidance on the logic behind the HSB functions is enough.</p>