Color overlay filter proposal


#1

Lately I’ve been needing a filter similar to Photoshop’s own layer styles/blending options. My question is if something like this is achievable with the current state of most browsers’ rendering engines.

The following images are an example of how Photoshop handles this:

Without color overlay:

With color overlay:

As far as I understand, CSS blending modes aren’t able to achieve this sort of behavior, and syntax-wise I’m thinking that something like filter: color-overlay(#ff0000) should be enough.

This is just a pretty lighweight proposal but if there’s enough attention to this post, and seems achievable, I’ll try and write a full spec for it.


#2

So it takes an image and changes the RGB value of the non-transparent pixels to match the given input?


#3

Yes, basically, but my idea is to use it for other elements as well, not only images.


#4

It should be possible to do this today using a custom defined SVG filter, referenced from CSS.

<svg …>
  <filter id="color-overlay">
    <feFlood flood-color="red"/>
    <feBlend in2="SourceAlpha"/>
  </filter>
</svg>
element {
  filter: url(#color-overlay);
}

If you want to propose this as a CSS filter shorthand, the first step would be defining it via SVG <filter>, like the currently-implemented ones.


#5

I’m not that familiar with svg filters so I tried this one out verbatim and it didn’t seem to work on a image element with transparency. I haven’t been able to find a working alternative either.


#6

Ah, fair enough. Here’s a working CodePen (except Safari, can’t figure out why right now): https://codepen.io/tigt/pen/d820feb6082472382ec0778063e9ac08?editors=1100

If you wanted to define the filter solely in CSS, you could use a data: URI created with a preprocessor. Here’s a (naïve*) example for Sass:

@function color-overlay($color) {
  @return 'url("' + 
    "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E\
%3Cfilter id='f'%3E\
%3CfeFlood flood-color='#{$color}'/%3E\
%3CfeComposite in2='SourceAlpha' operator='atop'/%3E\
%3C/filter%3E\
%3C/svg%3E#f" + '")';
}

(Escaped \ line breaks added for readability on Discourse. Browsers won’t tolerate them.)

If you need Safari support today, chaining the filter shorthands might work — something like filter: sepia(100%) hue-rotate({some amount});.

* You would need to URL-encode the $color argument.


#7

Awesome, thank you that works great!

I do also think that this sort of effect deserves to get its own filter shorthand (iOS for example has a first class image property called tintColor that produces the same effect).


#8

As a web dev this would be so handy. In fact it’s about every 6 months or so that I think surely this must be possible and try to google it only to be bummed to find out it’s still not. Right now I’m working the responsive version of a site menu which shows up as an overlay when the view port is under a certain size.

The icons need to be a different colour to show up on the different background. The site colours are stored in css variables so that they can be changed and previewed in real time when editing with the wordpress customizer editor (this design is a wordpress theme). I want to be able to set a colour overlay for an image to the value of a particular css variable. The embedded svg filter via preprocessed data string is very clever but loses the ability to use useful css functions like variables. A colour overlay css filter defiantly seems like super useful and quite generic so that it could be used in all sorts of different ways.