Color to grayscale on hover not working in IE11

J82 picture J82 · Mar 20, 2015 · Viewed 14.8k times · Source

I'm using Gray for a few elements on the site. However, I can't get it to work in IE11. For example, in the fiddle below, I use JS to add the grayscale and grayscale-fade classes so that the image fades from color to grayscale on hover. How would I get this to work in IE11? The author says that the plugin needs to be initialized for IE11 (i.e. $('article.project img').gray();), but if I add that line, all of the images turn gray by default from the start. I just want this to work in IE11. Can someone show me how?

Fiddle: http://jsfiddle.net/61jcam54/

HTML

<div id="content">
    <article class="project">
        <img width="375" height="375" src="http://i.imgur.com/jNkpAg6.gif" alt="image-title">
        <div class="overlay" style="margin-left: -1px; width: 367px;">
            <h3>Project Title</h3>
            <a class="post-link expand" href="http://google.com">+</a>
        </div>
    </article>
</div>

CSS

article.project {
  float: left;
  margin: 0 1% 2%;
  max-width: 375px;
  overflow: hidden;
  position: relative;
  -moz-user-select: none;
  -ms-user-select: none;
  -webkit-user-select: none;
}

article.project img {
  display: block;
  margin: 0;
  padding: 0;
  max-width: 100%;
  height: auto;
  -webkit-transition: all 0.2s ease;
  -moz-transition: all 0.2s ease;
  -o-transition: all 0.2s ease;
  -ms-transition: all 0.2s ease;
  transition: all 0.2s ease;
}

article.project .overlay {
  background: rgba(0, 0, 0, 0.8);
  bottom: 0;
  display: block;
  left: 0;
  opacity: 0;
  overflow: hidden;
  position: absolute;
  right: 0;
  top: 0;
  z-index: 1;
  -webkit-transition: all 0.2s;
  -moz-transition: all 0.2s;
  -o-transition: all 0.2s;
  transition: all 0.2s;
}

.hover .overlay, .active .overlay, .hover-sticky .overlay {
    opacity: 1;
}

article.project .overlay h3 {
  color: #FFF;
  font-size: 17px;
  font-size: 1.7rem;
  font-family: 'Montserrat',sans-serif;
  text-transform: uppercase;
  line-height: 1.3;
  margin-top: 3.3em;
  padding: 0 1em;
  position: absolute;
  text-align: center;
  top: 50%;
  width: 100%;
}

article.project .overlay .expand {
  border: 5px solid #FFF;
  bottom: 0;
  color: #FFF;
  display: block;
  font-size: 30px;
  height: 60px;
  left: 0;
  line-height: 50px;
  margin: auto;
  position: absolute;
  right: 0;
  text-align: center;
  top: 0;
  width: 60px;
  z-index: 2;
  -webkit-border-radius: 30px;
  -moz-border-radius: 30px;
  -ms-border-radius: 30px;
  -o-border-radius: 30px;
  border-radius: 30px;
}

/* GRAYSCALE */
.grayscale, .grayscale-sticky {
    /* Firefox 10+, Firefox on Android */
    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");

    /* IE 6-9 */
    filter: gray;

    /*
    Chrome 19+,
    Safari 6+,
    Safari 6+ iOS,
    Opera 15+
    */
    -webkit-filter: grayscale(100%);
}

.grayscale.grayscale-fade {
    -webkit-transition: -webkit-filter .2s;
}

.grayscale.grayscale-off,
article:hover .grayscale.grayscale-fade {
    -webkit-filter: grayscale(0%);
    filter: none;
}

.grayscale.grayscale-replaced {
    filter: none;
    -webkit-filter: none;
}

.grayscale.grayscale-replaced > svg {
    opacity: 1;
    -webkit-transition: opacity .2s ease;
    transition: opacity .2s ease;
}

.grayscale.grayscale-replaced.grayscale-off > svg,
article:hover .grayscale.grayscale-replaced.grayscale-fade > svg {
    opacity: 0;
}

JS

$('#content').on('mouseenter', 'article.project', function(){

    $(this).addClass('hover grayscale grayscale-fade');
    $(this).find('.post-link').hide();

}).on('mouseleave', 'article.project', function(){

    $(this).removeClass('hover grayscale grayscale-fade');
    $(this).find('.post-link').show();

});

Answer

Josh Crozier picture Josh Crozier · Mar 24, 2015

TL;DR

Here is an updated example that works in IE11 and all other supported browsers.


Exaplaination

There were a few issues...

According to the plugin that you are using, when the browser doesn't support CSS3 filters (like in IE10/11) the following applies:

...the plugin uses Modernizr._prefixes, css-filters, Inline SVG and svg-filters feature detects from Modernizr to determine browser support. If a browser supports inline SVG and SVG filters but not CSS filters, the plugin replaces the elements with SVG elements with filters.

Since the img element needs to be replaced with an SVG element in IE11, the plugin script (with Modernizr shiv) is required in order for it to work. In the jsFiddle example you provided, the script jquery.gray.min.js actually wasn't even being executed in IE11 since it was blocked due to mismatched mime types (this warning was in the console).

To work around this, I just copy/pasted the script into the example. In addition, it's worth noting that the Modernizr docs state that the script must execute before the <body> loads. This seems to be relevant in IE when using a HTML5 Shiv:

The reason we recommend placing Modernizr in the head is two-fold: the HTML5 Shiv (that enables HTML5 elements in IE) must execute before the <body>, and if you’re using any of the CSS classes that Modernizr adds, you’ll want to prevent a FOUC.

Now that the script is actually being executed in IE11, the plugin needs to be initialized and the img element needs to be replaced with an SVG. According to the plugin, the img elements will automatically be replaced if the element has the class .grayscale. Alternatively, it also looks like you can use the custom .gray() method, too. Since your example wasn't actually giving the class .grayscale to the img element, it wouldn't have being initialized in IE11.

Below, you will notice that I added the class .grayscale to the img element (in order to initialize it in IE11). In addition, the class .grayscale-off is also added to the element in order for the gray effect to be off initially. In the updated jQuery, you will see that this class is just toggled.

Here is the relevant updated HTML/CSS/jQuery:

Updated Example Here

I also shortened the jQuery a little too:

$('#content').on('mouseenter mouseleave', 'article.project', function (e){
    $('.grayscale', this).toggleClass('hover grayscale-off');
    $(this).find('.post-link').toggle();
});
.grayscale.grayscale-replaced > svg {
    opacity: 0;
    -webkit-transition: opacity .2s ease;
    transition: opacity .2s ease;
}
.grayscale.grayscale-replaced.grayscale-off > svg {
    opacity: 1;
}
<div id="content">
    <article class="project">
        <img width="375" height="375" class="grayscale grayscale-off" src="http://lorempizza.com/380/240" alt="image-title" />
        <div class="overlay">
            <h3>Project Title</h3>
            <a class="post-link expand" href="...">+</a>
        </div>
    </article>
</div>