CSS grayscale filter and background-blend-mode at same time?
Asked Answered
T

4

16

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

Talanta answered 14/9, 2014 at 18:31 Comment(4)
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 otherTella
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.Talanta
Css is bot-to-up language maybe that was your problem I dont know. Anyways try Pleeeease Playground it converts filters.Colored
There has never been a -moz prefixed filter property. Removed it from the question…Semiconscious
C
13

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.sstatic.net/WIMBV.png");
  background-color: white;
  background-blend-mode: multiply, luminosity;
  background-size: cover;
}
<div class="test"></div>
Clack answered 2/3, 2015 at 19:40 Comment(5)
Such an awesome solution. If Safari supported the luminosity background blend mode I'd be in heaven right now.Fruitarian
I actually got this working even in Safari using the mix-blend-mode property and filter: grayscale(100%) on the photo. Woo! css-tricks.com/almanac/properties/m/mix-blend-modeFruitarian
the link to the picture of the cat does not work, I found another one but I do not know how to put it : 4.bp.blogspot.com/_BSmKs8FzkfI/SCi18Kth3oI/AAAAAAAAACA/…Sandberg
@Oceangermanique Added your picture to the snippet. Thank you!Clack
@Clack your solution inspired me to find another one, with only the mix_blend_modeSandberg
D
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.

Duffie answered 1/10, 2014 at 12:47 Comment(0)
P
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/

Prance answered 20/2, 2017 at 8:44 Comment(2)
"Just replace the image with an empty div that has background image styling." can you add the example with the background-image, because i don't understand ?Sandberg
@Oceangermanique I've updated my answer with a HTML example of what I meant.Prance
S
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>
Sandberg answered 18/12, 2022 at 22:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.