Internet Explorer Cleartype vs jQuery Opacity

February 1, 2012 by jason

Sometimes I come across a bug (usually in internet explorer) that just makes me gasp at how horribly something can go wrong simply because the browser was poorly implemented.  This week that honor once again goes to IE.  Below, you will see a couple screen captures of the exact same browser content as rendered in Chrome (on the left) vs. IE (on the right).

jQuery cycle element
Chrome   Internet Explorer
     
jQuery fadeTo() element
Chrome   Internet Explorer

What you see is the result of cleartype text that has had an opacity filter applied to it.  In one case this is caused by jQuery cycle plugin, and the other the result of a jQuery fadeTo() animation.  In both cases, the end result is pretty ugly if not completely unreadable.  I've seen this behavior before in IE when animating png files with alpha transparency, but at least once the animation is over, the graphic regains it's original appearance.  In both of these examples, the animation is not currently running, so this is just what the static text is destined to look like.

What is happening here? Basically, internet explorer has not implemented the w3c standard "opacity" css property, instead opting to rely on their own filter(opacity) property which is handled internally quite different.  The outcome is that cleartype passed through the opacity filter is converted to non-cleartype and loses the nicely anti-aliased edges, resulting in a chunky, unattractive mess.

Without getting completely negative about IE and how horrible it and all of its users may be, I'm really creating this post to offer a fix that has worked to alleviate these problems and give your IE users a fighting chance of enjoying the website experience you have worked so hard to achieve.

jQuery cycle plugin

The cycle plugin (which I absolutely love and use pretty much on every website) relies on the jQuery library to handle the DOM traversing, element modifying, and animations associated with creating some sort of revolving content.  Because of this, when cleartype text is animated, the cycle plugin tries to mask the ugly text edges by automatic adding the first available background color to the element containing the text.  Sometimes this can actually help, but in my case, the containing element had no background and is being displayed on an element with a image based background.  The next available color background callout (searching up the DOM tree) happens to be the same color as the text itself.  White text on white background = not so good for readability.  Luckily, the cycle plugin developers have included some little known options to avoid this problem and help render the cleartext in IE.  Basically just add these two lines to your cycle definition and relax.

jQuery('.node-homepage-text-slideshow .field-items').each( function(i) {
  jQuery(this).cycle({
   fx: 'scrollHorz',
   speed:  500,
   timeout: 0,
   pager: '#pager-'+i,
   prev: '#prev-'+i,
   next: '#next-'+i,
   cleartype: true,       // <---- Add this option 
   cleartypeNoBg: true    // <---- and this option
  });
});

jQuery fadeTo() animation

Similar to the cycle plugin, the fadeTo() animation (as well as any animate() function that includes the opacity property) relies on the filter(opacity) property when viewed in IE.  The problem this time, is that once the animation is complete, the filter property is never actually removed, so the text is stuck being viewed with cleartype deactivated.  The work around is fairly simple.  Just add a callback function that removes the filter attribute once the animation is complete.  This can get pretty annoying and sloppy within your code if you are using these animations often, or are chaining them within a larger framework.  The solution I chose was based on a response I discovered on stackOverflow.  Basically we create our own jQuery extensions that perform the animation with the callback built in.  This way, we can choose to call the custom function when removing the filter is necessary, or just stick to the base function when it isn't.  Either way, the jQuery code looks nearly identical with only a slight change to the method name.

First add the following to your document:

(function($) {
    $.fn.customFadeIn = function(speed, callback) {
        $(this).fadeIn(speed, function() {
                if(jQuery.browser.msie)
                        $(this).get(0).style.removeAttribute('filter');
                if(callback != undefined)
                        callback();
        });
    };
$.fn.customFadeTo = function(speed, opacity, callback) {
        $(this).fadeTo(speed,opacity, function() {
                if(jQuery.browser.msie && opacity != 0)
                        $(this).get(0).style.removeAttribute('filter');
                if(callback != undefined)
                        callback();
        });
    };
$.fn.customAnimate = function(properties, speed, easing, callback) {
        $(this).animate(properties, speed, easing, function() {
                if(jQuery.browser.msie)
                        $(this).get(0).style.removeAttribute('filter');
                if(callback != undefined)
                        callback();
        });
    };
})(jQuery);

Then simply call the animation variation that you need just as you would the original animation function:

jQuery('#overlay').stop(true,true).customFadeTo('fast', 1.0);

Winner: jQuery

Even though jQuery chokes a bit when it comes to handling filter(opacity), at least they give you the tools you need to work around the shortcomings as best as you can.  Sadly, Internet Explorer will never be a winner.

If by some chance you are reading this and you are using IE 6... please go away.  IE 7, Upgrade already! IE 8, at least you aren't those other two schmucks. IE 9, sure, it's getting better, but you are missing out on so much! IE 10, you should know better, you really should.

Comments

Hi Jason!  Thank you so much for this!  I was wondering if you have a working demo of this that I could reference?  Thanks again! 

@Amy: There is no demo created specifically to showcase this functionality, but you can see the "cleaned up" end result by viewing the Aiko Agency website, where I discovered this behavior.