15

I'm trying to treat an image the same way it is in a photoshop file - desaturating the image to grayscale, and then applying a color overlay with a multiply blend mode. To this end, I am styling a CSS background image with...

.someclass
{
    /* grayscale */
    -webkit-filter: grayscale(1); 
    filter: gray; 
    filter: grayscale(1);
    filter: url(desaturate.svg#greyscale);

    /* multiply */
    background-color: rgba(190, 50, 50, 0.65);
    background-blend-mode: multiply;
}

The problem with this is that the grayscale filter ends up desaturating red color for the blend mode. In other words, the multiply is occurring first and then the grayscale. How do I switch it so that the grayscale is applied first and then the blend mode is applied second?

I have created a fiddle (http://jsfiddle.net/g54LcoL1/1/) for the code and a screenshot (made in Photoshop) of what I would expect the the fiddle result to look like. The bottom most image, div.grayscale.multiply, should be colored red.

enter image description here

Volker E.
  • 5,911
  • 11
  • 47
  • 64
Jeff
  • 13,943
  • 11
  • 55
  • 103
  • This is impossible to do with CSS AFAIK. This is because CSS does all of its actions in matrices, so the order set for all of the properties is set. The alternatives are to save the images as grayscale before hand or perhaps use something like canvas to do one and then the other – Zach Saucier Sep 15 '14 at 06:02
  • As a 'user' of CSS, it seems to me like the way this should happen is the order by which it is declared in the code. I'm sure there is a reason why it is the way it is, but as `background-blend-mode` becomes more widely supported, people will demand more control over the order of the blends/filters. I suppose `canvas` is the way to go. I'll give it a shot. – Jeff Sep 15 '14 at 21:40
  • Css is bot-to-up language maybe that was your problem I dont know. Anyways try Pleeeease Playground it converts filters. – DifferentPseudonym Sep 17 '14 at 04:43
  • There has never been a `-moz` prefixed `filter` property. Removed it from the question… – Volker E. Mar 02 '17 at 20:50

4 Answers4

12

You can not do it with filter, but you can do it staying with blend mode for everything

the grayscale equivalent in blend is luminosity, with the image as source and a solid white as backdrop

So the background images, from bottom to top, are:

  1. white (as background-color)
  2. your image
  3. solid red (that must be specified as a gradient for now)

and the blend modes are luminosity and multiply

.test {
  width: 400px;
  height: 400px;
  background-image: linear-gradient(0deg, red, red), url("https://i.stack.imgur.com/WIMBV.png");
  background-color: white;
  background-blend-mode: multiply, luminosity;
  background-size: cover;
}
<div class="test"></div>
vals
  • 61,425
  • 11
  • 89
  • 138
  • 1
    Such an awesome solution. If Safari supported the luminosity background blend mode I'd be in heaven right now. – Joel Farris Aug 07 '15 at 03:02
  • 3
    I actually got this working even in Safari using the `mix-blend-mode` property and `filter: grayscale(100%)` on the photo. Woo! https://css-tricks.com/almanac/properties/m/mix-blend-mode/ – Joel Farris Aug 07 '15 at 03:43
  • the link to the picture of the cat does not work, I found another one but I do not know how to put it : http://4.bp.blogspot.com/_BSmKs8FzkfI/SCi18Kth3oI/AAAAAAAAACA/BzWFAOZXu3U/s1600/kitteh_puddle.jpg – oceanGermanique Nov 28 '22 at 07:33
  • 1
    @Oceangermanique Added your picture to the snippet. Thank you! – vals Nov 29 '22 at 11:41
  • @vals your solution inspired me to find another one, with only the mix_blend_mode – oceanGermanique Dec 22 '22 at 22:20
3

The blend mode is applied to the background layers, and then the filter is applied to the whole element, so they are sort of dealing with two different things: by the time that the background is calculated (including the red-ish appearance), the whole element is converted to grayscale with the filter.

There is a proposed filter() function for image references, so in theory, you should be able to apply a filter to any image as it is loaded. I think this is the idea:

.someclass {
    background-image: filter(cat.jpg, grayscale(100%));
    background-color: red;
    background-blend-mode: multiply;
}

Sadly, I don't think this is implemented anywhere yet, it's just in the draft version of the Filters spec.

In general, the order of operations in terms of these types of "post-processing" CSS effects is defined in the same order as for SVG: filtering is done first, then clipping, then masking, then blending.

(See the Blending & Compositing Spec.) So, there's nothing you can do in terms of changing that, I'm afraid.

Emil
  • 1,949
  • 2
  • 16
  • 25
3

As Joel mentioned in his comment under the accepted answer, it's possible to do this using mix-blend-mode.

In my examples I'm going to use an actual image instead of a background image because it is better for accessibility. If it has to be a background image then you can still use the same technique. Replace the image with an empty div that has background image styling like so:

<!-- Not the recommended HTML, see the other examples for better HTML -->
<div class="image-wrapper">
    <div class="image" style="background: url('https://static.decalgirl.com/assets/designs/large/clrkit.jpg') no-repeat; height: 100px; width: 100px;"></div>
</div>

Also I'm going to use the "screen" blend mode instead of "multiply" because it demonstrates the color removal more clearly.

With color removal:

.image-wrapper {
    background: red;
    display: inline-block;
}

.image-wrapper .image {
    mix-blend-mode: screen;
    filter: grayscale(100%);
}
<div class="image-wrapper">
    <img class="image" src="https://static.decalgirl.com/assets/designs/large/clrkit.jpg" alt="Colorful cats"/>
</div>

Without color removal:

.image-wrapper {
    background: red;
    display: inline-block;
}

.image-wrapper .image {
    mix-blend-mode: screen;
}
<div class="image-wrapper">
    <img class="image" src="https://static.decalgirl.com/assets/designs/large/clrkit.jpg" alt="Colorful cats"/>
</div>

More information can be found here:

https://css-tricks.com/almanac/properties/m/mix-blend-mode/

Daniel Tonon
  • 9,261
  • 5
  • 61
  • 64
1

100% MIX-BLEND-MODE

  red  =========================================
                                                |
   cat     =======                              ==== Blending (luminosity)
                  |                             |
                  ==== Blending (multiply) ===
                  |
   white =========

<div style="
  position:relative;
  background-color: rgb(255,255,255);
  height: 316px;
  width: 450px;">
  
  <div style="
    background-image:  url('http://4.bp.blogspot.com/_BSmKs8FzkfI/SCi18Kth3oI/AAAAAAAAACA/BzWFAOZXu3U/s1600/kitteh_puddle.jpg');
    height: 316px;
    width: 450px;
    position:relative;
    left:0px;
    top:0px;
    mix-blend-mode: luminosity;">
  </div>

  <div style="
    background: rgba(190, 50, 50, 0.65);
    height: 316px;
    width: 450px;
    position:absolute;
    left:0px;
    top:0px;
    mix-blend-mode: multiply;">
  </div>
</div>
oceanGermanique
  • 336
  • 3
  • 16