I am trying to show some images on a page where they should be shown in grayscale, except on mouse hover when they smoothly transition into color. I've made it work nicely on IE, Chrome and Firefox, but it doesn't work on Safari 5.x. The problem is on Safari for Mac and Safari for Windows. Here is the code I have so far:
filter: url('desaturate.svg#greyscale');
filter: gray;
-webkit-filter: grayscale(1);
The first line loads an external .svg filter (I don't inline it with a url("data:... rule because I want to avoid a bug in old versions of Firefox).
The second line is for IE and seems to work just as well as filter:progid:DXImageTransform.Microsoft.BasicImage(grayScale=1);.
The last line about webkit is supposed to work on Safari 6 and above, as well as Chrome.
Is there any CSS rule to show the images with grayscale on Safari 5.x? Or, if that is not possible, can someone recommend a javascript solution, preferably one that will handle the animation to and from grayscale? I would like to avoid a server-side hack with grayscale images because that will mess up my HTML and then I'll have to do some nasty browser detection to serve HTML conditionally.
thanks
Edit:
As this has turned out to be a "notable question", please don't keep posting here more answers that only work on Safari 6 and above, or answers that include an .svg file in a data url. At the time when I wrote the OP, it was important for me to support some versions of Safari and Firefox that are today considered very dated, but nevertheless that was my original question.
I am well aware that for modern browsers grayscale filtering is easily accomplished with a few lines of CSS code, but the graphics designer was using Safari 5.x and the client was using Firefox 3.x at the time I did this project. The solution that worked for me was what Giona suggested, i.e. to use Modernizr to test for css-filtering, and if it's not supported to fall back to javascript.
If I was doing the same thing today, I'd be telling both to go update their browsers!
As you can see on caniuse.com , CSS3 filters are supported by very few browsers at the moment.
There are many JavaScript/jQuery fallback if you Google "javascript grayscale plugin".
Here are some:
Grayscale.js
jQuery GreyScale plugin
Hoverizr
Do it with canvas (tutorial)
But i've no experience with them, so i can't suggest you which one is the best.
I tried jQuery Black And White long time ago, and it gave me a lot of issues with relative/absolute positioned images, so maybe avoid it.
Including this Modernizr build into your pages, you can target browser not supporting filters via Javascript:
if(!Modernizr.css_filters){
/* javascript fallback here */
}
or CSS:
.no-css_filters .element {
/* css fallback here */
}
Oh, and don't forget dowebsitesneedtolookexactlythesameineverybrowser?
It's really simple, actually:
http://www.karlhorky.com/2012/06/cross-browser-image-grayscale-with-css.html
http://jsfiddle.net/KDtAX/487/
I tried using the javascript fallback, but it really made no sense, and it was really slow on large images. This made a lot more sense. Note that there is a new syntax for grayscale, and I had to manually edit the resulting minified CSS from LESS.
Here's my mixin:
.filter (...) {
-webkit-filter: #arguments;
-moz-filter: #arguments;
-ms-filter: #arguments;
-o-filter: #arguments;
filter: #arguments;
}
And my class:
.grayscale-hover, .home-image {
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 see http://jsfiddle.net/KDtAX/487/*/
.filter(grayscale(1) blur(1px));
filter: gray; /* IE6-9 */
-webkit-backface-visibility: hidden; /* Fix for transition flickering */
&:hover {
.filter(none);
filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'1 0 0 0 0, 0 1 0 0 0, 0 0 1 0 0, 0 0 0 1 0\'/></filter></svg>#grayscale");
}
}
Works and tested in IE 6+, Firefox, Chrome.
This is something like that:
.grayscale {
filter: url(css/grayscale.svg#greyscale);
-webkit-filter: grayscale(1);
-moz-filter: grayscale(100%);
-ms-filter: grayscale(100%);
-o-filter: grayscale(100%);
}
You need to download the svg file either.
This one worked great for me:
img { float:left;
filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\' filterRes=\'800\'><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+ */
filter: gray; /* IE6-9 */
-webkit-filter: grayscale(100%); /* Chrome 19+ & Safari 6+ */
-webkit-backface-visibility: hidden; /* Fix for transition flickering */
-webkit-transition: all 1.5s ease;
-moz-transition: all 1.5s ease;
-ms-transition: all 1.5s ease;
-o-transition: all 1.5s ease;
transition: all 1.5s ease;
z-index: 40 !important;
display:block;
}
img:hover {
filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\' filterRes=\'800\'><feColorMatrix type=\'matrix\' values=\'1 0 0 0 0, 0 1 0 0 0, 0 0 1 0 0, 0 0 0 1 0\'/></filter></svg>#grayscale");
-webkit-filter: grayscale(0%);}
The images looks really overexposed in Safari however (But they are in greyscale). And the transition isn't supported by Firefox.
Related
So, I have code for hover effect on picture. It works fine on Chrome, but problem is when I open site on Firefox. Here is code:
img.img-responsive {
/* for Webkit browsere, Chrome 19+, Safari 6+ ... */
-webkit-filter: grayscale(1);
/* this is for Firefox 3.5+, Firefox mobile */
filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'>
<filter id=\'gs\'><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>#gs");
/* for IE6+ */
filter: gray;
}
img.img-responsive:hover {
/* for Webkit browsere, Chrome 19+, Safari 6+ ... */
-webkit-filter: grayscale(0);
/* this is for Firefox 3.5+, Firefox mobile */
filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'>
<filter id=\'gs\'><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>#gs");
/* for IE6+ */
filter: gray;
}
So, what should I do that hover effect works on Firefox? Pictures are shown in black-white and when you hover them color should appear.
filter: grayscale(100%) /* Or lower */
should work in a latest version of Firefox. But then again, this is Firefox.
If it doesn't, try replacing your 'filter' url with this:
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 3.5+ */
By the way, a simple Google search for "Firefox Grayscale" turned out a StackOverflow reply to your question. It was answered by defau1t a while ago:
CSS Filter not working in Firefox
thanks for help but this didn't solve my problem. Either your answers works for me. Now hover effect works only in one solution, picture is now in color and when I hover it it becomes black-white. I need opposite, picture has to be black-white and when I hover it, it has to be in color.
The filter effect you are using for Firefox seems to be very convoluted. All modern browsers should be able to use the CSS3 notation now, but specific selectors for slightly older browsers are available;
You might need to use the -moz selector for your version of Firefox.
The full list for all browsers is below;
img {
filter: grayscale(0);
-webkit-filter: grayscale(0);
-moz-filter: grayscale(0);
-o-filter: grayscale(0);
-ms-filter: grayscale(0);
}
img:hover {
filter: grayscale(1);
-webkit-filter: grayscale(1);
-moz-filter: grayscale(1);
-o-filter: grayscale(1);
-ms-filter: grayscale(1);
}
Hope this helps.
try JS fix
It is using javascript to detect the browser and creates a canvas and then uses filter.
http://www.majas-lapu-izstrade.lv/cross-browser-grayscale-image-example-using-css3-js/
I am making cross-browser image effect, but the effects in different browsers are quite different. I think the filter values are the problem. Here are the codes.
CSS
img {
filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.85 0.85 0.85 0 0 0.85 0.85 0.85 0 0 0.85 0.85 0.85 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
filter: grayscale(85%);
-webkit-filter: grayscale(85%);
}
div {
filter: blur(2px);
-webkit-filter: blur(2px);
filter: url("data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\"><filter id=\"svgBlur\" x=\"-2%\" y=\"-2%\" width=\"104%\" height=\"104%\"><feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"5\"/></filter></svg>#svgBlur");
}
HTML
<div><img src="http://www.presidiacreative.com/wp-content/uploads/2012/04/interior-design-22.jpg" /></div>
Here is the jsFiddle
Last, here is the screenshot ( Left: Firefox 25, Right: Chrome 31 ).
Note: Target Browser support: Chrome 30+, Firefox 20+, Safari 6+, IE7+
Unfortunately Firefox 25 doesn't currently support most of the CSS3 filters.
This link shows that most of your target browsers don't either!
I am not really sure that I got really the same results in FF than in Chrome, but I show the way, and you can finally set the fine adjusts.
The grayscale filter works by taken colors from their original color and putting them in the other colors, averaging the color distribution.
To set it at less than 100%, you need to keep a greater proportion of color in the original one.
img {
filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\
'1 0.6 0.6 0 0
0.6 1 0.6 0 0
0.6 0.6 1 0 0
0 0 0 1 0\'/></filter></svg>#grayscale");
filter: grayscale(85%);
-webkit-filter: grayscale(85%);
}
In this matrix, I have increased the diagonal values to 1, and lowered the others to 0.6. If you want to keep more color from the original, lower the 0.6 values, but keep the 1 in the diagonal as they are
on the other side, I have lowered the blur amount. PLay with the stdDeviation value
div {
filter: blur(2px);
-webkit-filter: blur(2px);
filter: url("data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\"><filter id=\"svgBlur\" x=\"-2%\" y=\"-2%\" width=\"104%\" height=\"104%\"><feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"4\"/></filter></svg>#svgBlur");
}
demo
A much better solution
img {
filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.5 0.3 0.3 0 0 0.3 0.5 0.3 0 0 0.3 0.3 0.5 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
filter: grayscale(85%);
-webkit-filter: grayscale(85%);
}
div {
filter: blur(2px);
-webkit-filter: blur(2px);
filter: url("data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\"><filter id=\"svgBlur\" x=\"-2%\" y=\"-2%\" width=\"104%\" height=\"104%\"><feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"2\"/></filter></svg>#svgBlur");
}
demo 2
A formula to calculate the matrix would be. non diagonal values grayscale percentage / 3. in your case, 0.85 / 3 = 0.28. Diagonal values, the previous + (1 - percentage). In your case 0.28 + (1 - 0.85) = 0.43.
As #kmoe said your target browsers don't support this and even the ones that does the results may vary so your best solution would be to use a transparent blurred image as a mask over your original images. See if that helps :)
I have 3 icons of FCB, twitter and RSS and I want them to be grayscale but on hover they should change to color version. It is working great but these 3 images looks a bit different in grayscale. Is there a way to make them looks the same?
This is my code for grayscale:
img.grayscale{
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;
-webkit-filter: grayscale(1);
}
RSS and twitter looks almost the same but FCB icon is a lot darker. I think that the only way is to play with grayscale percentage. Is there any other solution?
You can add a class of fb on the fb image and set
img.fb {
opacity: 0.7;
}
This will give the illusion of making the image more light.
Here is the jsfiddle
I've run into a problem getting Firefox's filter css property to grayscale properly on the printed page. For some reason, the grayscaled image is not visible on the printout, though it displays as expected onscreen. After referring to questions like this one, I've gotten to this point (simplified to demonstrate the issue):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title></title>
<style type="text/css">
.grayscale {
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+ */
filter: gray; /* IE6-9 */
-webkit-filter: grayscale(100%); /* Chrome 19+ & Safari 6+ */
filter: grayscale(100%);
}
img {
width:100px;
}
</style>
</head>
<body>
<img class="grayscale" src="http://alltheragefaces.com/img/faces/png/rage-nuclear.png" />
<img src="http://alltheragefaces.com/img/faces/png/rage-nuclear.png" />
</body>
</html>
And here's the fiddle
Is there a viable workaround for this, or am I doing something wrong? Applying the filters to other elements seems to cause the same problem. I would greatly appreciate any constructive input.
Note: Using Firefox v20.0.1
It turns out this almost appears to be a browser bug in FireFox. I noticed that anytime (on screen) when an svg is referenced that the browser can't find, the I would get the exact same issue as I did when printing: the image layout would be reserved, but it would be blank space. This prompted me to wonder if there was a difference in what could be loaded/found when rendering for a printer rather than the screen, so I started trying different ways of loading/referencing the svg. I tried loading the svg from a separate file, from an id in the html, and inline, all in combination with defining the filter in a separate css file, in-page classes, and inline styles. Of all the combinations, this is what worked:
Define the svg in html, and reference it using inline styles or in-page css classes.
I know it sounds weird, but literally everything else I tried breaks, including doing everything the same but setting the filter css property in an external css file. Going the in-page class approach, here's what the fixed html would look like:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title></title>
<style type="text/css">
.grayscale {
filter: url(#grayscale); /* Firefox 10+ */
filter: gray; /* IE6-9 */
-webkit-filter: grayscale(100%); /* Chrome 19+ & Safari 6+ */
}
img {
width:100px;
}
</style>
</head>
<body>
<img class="grayscale" src="http://alltheragefaces.com/img/faces/png/rage-nuclear.png" />
<img src="http://alltheragefaces.com/img/faces/png/rage-nuclear.png" />
<svg xmlns='http://www.w3.org/2000/svg' height="0px">
<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>
</body>
</html>
And again, the modified fiddle from which you can print and now see the image just fine in Firefox.
Siiigh, this is the kind of thing I'd expect from IE...hopefully helps save somebody some time/grief/murderous thoughts
What's the best way (if any) to make an image appear "grayed out" with CSS (i.e., without loading a separate, grayed out version of the image)?
My context is that I have rows in a table that all have buttons in the right most cell and some rows need to look lighter than others. So I can make the font lighter easily of course but I'd also like to make the images lighter without having to manage two versions of each image.
Does it have to be gray? You could just set the opacity of the image lower (to dull it). Alternatively, you could create a <div> overlay and set that to be gray (change the alpha to get the effect).
html:
<div id="wrapper">
<img id="myImage" src="something.jpg" />
</div>
css:
#myImage {
opacity: 0.4;
filter: alpha(opacity=40); /* msie */
}
/* or */
#wrapper {
opacity: 0.4;
filter: alpha(opacity=40); /* msie */
background-color: #000;
}
Use the CSS3 filter property:
img {
-webkit-filter: grayscale(100%);
-moz-filter: grayscale(100%);
-o-filter: grayscale(100%);
-ms-filter: grayscale(100%);
filter: grayscale(100%);
}
The browser support is pretty decent, https://caniuse.com/css-filters.
Your here:
<img src="img.jpg" />
Css Gray:
img{
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: grayscale(100%);
-moz-filter: grayscale(100%);
-ms-filter: grayscale(100%);
-o-filter: grayscale(100%);
filter: gray; /* IE6-9 */
-webkit-filter: grayscale(100%); /* Chrome 19+, Safari 6+, Safari 6+ iOS */}
Ungray:
a:hover img{
filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'1 0 0 0 0, 0 1 0 0 0, 0 0 1 0 0, 0 0 0 1 0\'/></filter></svg>#grayscale");
filter: grayscale(0%);
-moz-filter: grayscale(0%);
-ms-filter: grayscale(0%);
-o-filter: grayscale(0%);
filter: none ; /* IE6-9 */
zoom:1; /* needed to trigger "hasLayout" in IE if no width or height is set */
-webkit-filter: grayscale(0%); /* Chrome 19+, Safari 6+, Safari 6+ iOS */
}
I found it at: http://zkiwi.com/topic/chuyen-hinh-mau-thanh-trang-den-bang-css-nhu-the-nao
Edit: IE10+ does not support DX filters as IE9 and earlier have done, nor does it support a prefixed version of the greyscale filter.
You can fix it, use one in two solutions below:
Set IE10+ to render using IE9 standards mode using the following meta element in the head: <meta http-equiv="X-UA-Compatible" content="IE=9">
Use an SVG overlay in IE10 to accomplish the greyscaling internet explorer 10 - howto apply grayscale filter?
If you don't mind using a bit of JavaScript, jQuery's fadeTo() works nicely in every browser I've tried.
jQuery(selector).fadeTo(speed, opacity);
Better to support all the browsers:
img.lessOpacity {
opacity: 0.4;
filter: alpha(opacity=40);
zoom: 1; /* needed to trigger "hasLayout" in IE if no width or height is set */
}
To gray out:
“to achromatize.”
filter: grayscale(100%);
#keyframes achromatization {
0% {}
25% {}
75% {filter: grayscale(100%);}
100% {filter: grayscale(100%);}
}
p {
font-size: 5em;
color: yellow;
animation: achromatization 2s ease-out infinite alternate;
}
p:first-of-type {
background-color: dodgerblue;
}
<p>
⚡ Bzzzt!
</p>
<p>
⚡ Bzzzt!
</p>
“to fill with gray.”
filter: contrast(0%);
#keyframes gray-filling {
0% {}
25% {}
50% {filter: contrast(0%);}
60% {filter: contrast(0%);}
70% {filter: contrast(0%) brightness(0%) invert(100%);}
80% {filter: contrast(0%) brightness(0%) invert(100%);}
90% {filter: contrast(0%) brightness(0%);}
100% {filter: contrast(0%) brightness(0%);}
}
p {
font-size: 5em;
color: yellow;
animation: gray-filling 5s ease-out infinite alternate;
}
p:first-of-type {
background-color: dodgerblue;
}
<p>
⚡ Bzzzt!
</p>
<p>
⚡ Bzzzt!
</p>
Helpful notes
What's the difference between CSS3 filter grayscale and saturate?
https://www.w3.org/TR/filter-effects-1
Here's an example that let's you set the color of the background. If you don't want to use float, then you might need to set the width and height manually. But even that really depends on the surrounding CSS/HTML.
<style>
#color {
background-color: red;
float: left;
}#opacity {
opacity : 0.4;
filter: alpha(opacity=40);
}
</style>
<div id="color">
<div id="opacity">
<img src="image.jpg" />
</div>
</div>
You can use rgba() in css to define a color instead of rgb(). Like this:
style='background-color: rgba(128,128,128, 0.7);
Gives you the same color as rgb(128,128,128) but with a 70% opacity so the stuff behind only shows thru 30%. CSS3 but it's worked in most browsers since 2008. Sorry, no #rrggbb syntax that I know of. Play with the numbers - you can wash out with white, shadow out with gray, whatever you want to dilute with.
OK so you make a a rectangle in semi-transparent gray (or whatever color) and lay it on top of your image, maybe with position:absolute and a z-index higher than zero, and you put it just before your image and the default location for the rectangle will be the same upper-left corner of your image. Should work.
Considering filter:expression is a Microsoft extension to CSS, so it will only work in Internet Explorer. If you want to grey it out, I would recommend that you set it's opacity to 50% using a bit of javascript.
http://lyxus.net/mv would be a good place to start, because it discusses an opacity
script that works with Firefox, Safari, KHTML, Internet Explorer and CSS3 capable browsers.
You might also want to give it a grey border.