skip to Main Content

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

4

Answers


  1. 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.

    Login or Signup to reply.
  2. 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>
    Login or Signup to reply.
  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/

    Login or Signup to reply.
  4. 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>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search