62

I've searched a lot on the web but I cannot find a cross browser solution to fade a css backgrund image to greyscale and back.

The only working solution is to apply CSS3 filter greyscale:

-webkit-filter: grayscale(100%);

but this works just with Chrome v.15+ and Safari v.6+ (as you can see here: http://css3.bradshawenterprises.com/filters/)

Many pages online speaks about this solution to grey out elements:

filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale"); /* Firefox 10+, Firefox on Android */
filter: gray; /* IE6-9 */

(as you can see here:http://www.karlhorky.com/2012/06/cross-browser-image-grayscale-with-css.html)

But actually it does not seem to work for css background images, as the webkit filter do.

Are there any solution (maybe with jquery?) to hack this lack of support for filter on less advanced browsers?

bluantinoo
  • 1,659
  • 3
  • 18
  • 24

5 Answers5

79

Here you go:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>bluantinoo CSS Grayscale Bg Image Sample</title>
<style type="text/css">
    div {
        border: 1px solid black;
        padding: 5px;
        margin: 5px;
        width: 600px;
        height: 600px;
        float: left;
        color: white;
    }
     .grayscale {
         background: url(yourimagehere.jpg);
         -moz-filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
         -o-filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
         -webkit-filter: grayscale(100%);
         filter: gray;
         filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
     }

    .nongrayscale {
        background: url(yourimagehere.jpg);
    }
</style>
</head>
<body>
    <div class="nongrayscale">
        this is a non-grayscale of the bg image
    </div>
    <div class="grayscale">
        this is a grayscale of the bg image
    </div>
</body>
</html>

Tested it in FireFox, Chrome and IE. I've also attached an image to show my results of my implementation of this.Grayscale Background Image in DIV Sample

EDIT: Also, if you want the image to just toggle back and forth with jQuery, here's the page source for that...I've included the web link to jQuery and and image that's online so you should just be able to copy/paste to test it out:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>bluantinoo CSS Grayscale Bg Image Sample</title>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<style type="text/css">
    div {
        border: 1px solid black;
        padding: 5px;
        margin: 5px;
        width: 600px;
        height: 600px;
        float: left;
        color: white;
    }
     .grayscale {
         background: url(http://www.polyrootstattoo.com/images/Artists/Buda/40.jpg);
         -moz-filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
         -o-filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
         -webkit-filter: grayscale(100%);
         filter: gray;
         filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
     }

    .nongrayscale {
        background: url(http://www.polyrootstattoo.com/images/Artists/Buda/40.jpg);
    }
</style>
    <script type="text/javascript">
        $(document).ready(function () {
            $("#image").mouseover(function () {
                $(".nongrayscale").removeClass().fadeTo(400,0.8).addClass("grayscale").fadeTo(400, 1);
            });
            $("#image").mouseout(function () {
                $(".grayscale").removeClass().fadeTo(400, 0.8).addClass("nongrayscale").fadeTo(400, 1);
            });
        });
</script>
</head>
<body>
    <div id="image" class="nongrayscale">
        rollover this image to toggle grayscale
    </div>
</body>
</html>

EDIT 2 (For IE10-11 Users): The solution above will not work with the changes Microsoft has made to the browser as of late, so here's an updated solution that will allow you to grayscale (or desaturate) your images.

<svg>
  <defs>
    <filter xmlns="http://www.w3.org/2000/svg" id="desaturate">
      <feColorMatrix type="saturate" values="0" />
    </filter>
  </defs>
  <image xlink:href="http://www.polyrootstattoo.com/images/Artists/Buda/40.jpg" width="600" height="600" filter="url(#desaturate)" />
</svg>
Element808
  • 1,218
  • 11
  • 16
  • Hello Element, actually this is the way i always did it. I was just hoping that the panorama had evolved and i did not need to build a double layered layout! But thanks anyway :) – bluantinoo Feb 21 '14 at 12:51
  • @bluantinoo - You're welcome :) what do you mean by double layered layout? Also, I'm fairly confident that the solution I gave you is exactly what you were asking for. Your specific requests/questions were "a cross browser solution to fade a css backgrund image to greyscale and back" and "Are there any solution (maybe with jquery?) to hack this lack of support for filter on less advanced browsers?" for the fade to gray solution. That's what I've provided to you. Am I missing something? – Element808 Feb 21 '14 at 19:00
  • 1
    you're actually right, but due to the fact that my question is quite old I was just hoping that browsers now could support a more simple css rule to turn gray background images on rollover. For double layered layout I'm referring to the 1st solution you propose (two elements stacked, one gray and the other coloured). In the end I must say that your second option is maybe my favourite, as it allows a more flexible usage. Furthermore, my question is so old that I'm flagging your answer, not only is working, but it's even well explained! Thanks again :) – bluantinoo Feb 22 '14 at 23:11
  • You're welcome and thanks! For some reason this question came across my list of questions needing to be answered and was at the top of the list (still new to SO, so that's probably it lol), but after answering the question I was shocked at how old this question was and it still hadn't been answered. Glad I could help in the long run though and thanks again for the kudos :) – Element808 Feb 23 '14 at 06:34
  • 3
    This solution turns _everything_ in the affected element grey, regardless of content that's supposed to remain coloured unfortunately. – cptstarling Jul 13 '15 at 06:34
  • Cptstarling - Huh? What content, in your opinion, should be colored? The things you want gray, apply the grayscale style. The things you want unaffected, apply the nongrayscale style. Too simple. Obviously, this was tailored towards a background image, but same rules apply for most elements. If you've got a better solution, or would like me to provide a tailored solution to a problem you are encountering, I'd be happy to look at it for you. Just create an additional question and shoot me a message. – Element808 Jul 17 '15 at 22:37
  • For those using IE10-11. Microsoft has removed the normal filter use for their latest browsers via CSS, so my solution above won't work. I'll update my solution for the easiest way to grayscale your images out in these versions that I've found; however, you'll have to use SVG filters. I'll try to keep this as updated as possible as new information comes available. – Element808 Feb 23 '16 at 00:45
  • the non-prefixed variant of the grayscale filter is called `filter: grayscale(100%);`, not `filter: gray;` – honk31 Aug 08 '16 at 15:01
  • 2
    In current version of chrome (59) I had to move the last line `filter: url(...)` to be before all the other filters to make it work. Just in case someone has a similar issue. – Gal Talmor Jul 04 '17 at 17:32
17

I know it's a really old question, but it's the first result on duckduckgo, so I wanted to share what I think it's a better and more modern solution.

You can use background-blend-mode property to achieve a greyscale image:

#something {
  background-color: #fff;
  background-image: url("yourimage");
  background-blend-mode: luminosity;
}

If you want to remove the effect, just change the blend-mode to initial.

You may need to play a little bit with the background-color if this element is over something with a background. What I've found is that the greyscale does not depend on the actual color but on the alpha value. So, if you have a blue background on the parent, set the same background on #something.

You can also use two images, one with color and the other without and set both as background and play with other blend modes.

https://www.w3schools.com/cssref/pr_background-blend-mode.asp

It won't work on Edge though.

EDIT: I've miss the "fade" part of the question.

If you wan't to make it fade from/to grayscale, you can use a css transition on the background color changeing it's alpha value:

#something {
  background-color: rgba(255,255,255,1);
  background-image: url("yourimage");
  background-blend-mode: luminosity;
  transition: background-color 1s ease-out;
}
#something:hover {
  background-color: rgba(255,255,255,0);
}

I'm also adding a codepen example for completeness https://codepen.io/anon/pen/OBKKVZ

arieljuod
  • 13,456
  • 2
  • 19
  • 31
  • 1
    Really nice answer, but how does it downscale to Edge? – bluantinoo Feb 13 '19 at 21:41
  • @bluantinoo, I'm not sure, I don't have Windows so no Edge, but it looks that there's some polyfill for Edge https://github.com/idevsoftware/js-background-blend-mode that uses a Canvas and other tehniques using SVG, but I can't help more than that. – arieljuod Feb 13 '19 at 23:37
16

Using current browsers you can use it like this:

img {
  -webkit-filter: grayscale(100%); /* Chrome, Safari, Opera */
  filter: grayscale(100%);
}

and to remedy it:

img:hover{
   -webkit-filter: grayscale(0%); /* Chrome, Safari, Opera */
   filter: grayscale(0%);
}

worked with me and is much shorter. There is even more one can do within the CSS:

filter: none | blur() | brightness() | contrast() | drop-shadow() | grayscale() |
        hue-rotate() | invert() | opacity() | saturate() | sepia() | url();

For more information and supporting browsers see this: http://www.w3schools.com/cssref/css3_pr_filter.asp

Sven Ya
  • 442
  • 5
  • 10
  • 3
    It works insofar as it makes the entire element (including the background image) grayscale, but any colorful images within the element will also be grayscale – Robert Townley Jul 26 '18 at 23:43
-4

You can also use:

img{
   filter:grayscale(100%);
}


img:hover{
   filter:none;
}
-5

You don't need to use complicated coding really!

Greyscale Hover:

-webkit-filter: grayscale(100%);

Greyscale "Hover-out":

-webkit-filter: grayscale(0%);


I simply made my css class have a separate hover class and added in the second greyscale. It's really simple if you really don't like complexity.

Aria
  • 7