IE7, ClearType, DXImageTransforms and Fade Animation Fuzziness

A while back I wrote a post about adding animation effects to the AjaxControlToolkit's Tab control.  The demo I created for the post used the toolkit's FadeIn animation to fade the selected tab into view as it became active.  I thought this turned out pretty well, however I noticed that after the fade animation finished running the tab's text contents remained a little blurry. 

Compare the before and after.

 

To see this for yourself, open the demo page and click on the 'Play Fade Animation' button at the top of the screen.  Notice how the text looks a little blurry after the animation runs?  

Ted Glaza responded to that original post and provided a hint as to what might be causing the problem

The problem you're seeing with the FadeIn animation has to do with how IE and ClearType work together. Searching "IE ClearType Opacity" should provide more details. - Ted Glaza

This week I found some time to look into this.  I followed Ted's advise and did a little searching.  Here is where it took me ...

Live Demo | Download (ASP.NET 2.0 and Toolkit 1.0.10920.0)

What Is ClearType?

Its a Microsoft technology that aims to make text a bit more readable.  I used the resources below to get familiar with the details.

From Wikipedia

image

From Microsoft

image

How Does The FadeIn Animation Work?

The FadeIn animation makes a call into the toolkit's JavaScript helper library to a function called setElementOpacity.  setElementOpacity lives with the other common toolkit scripts in Common.js, if you haven't browsed this file you might want to - it has more than a few useful functions.  Here is the listing for setElementOpacity

image

When setElementOpacity is called, the first thing the function does is check for the existence of the element argument's filters attribute, if it doesn't exist, it sets the element's opacity style attribute to the supplied value.  For most browsers, this is the path that is taken.  However, if the filters property is defined (IE only) the Alpha DXImageTransform filter is applied to the element. 

Why Does My Text Look Fuzzy After The FadeIn Animation Runs In IE7?

Well, it turns out there is an issue with DXTransforms and ClearType in IE7.  According to the IE Program Manager for ClearType

During our testing we noticed that DXTransforms are sometimes applied to elements that contain text (now rendered in ClearType).  As our users also noticed, the ClearType text then looks extremely blurry - unfortunately these two technologies just don’t mix well.  This is because the basic convolution transform used by DXTransforms does not take into account the spatial nature of ClearType.

To ensure good readability of Text in IE, in the Release Candidate build we decided to disable ClearType on elements that use any DXTransform.  We will render the text in those elements as aliased text, in order to increase readability.  The rest of the text in the page will render with ClearType.  This may explain why some sites (or portions of sites) will render as aliased text, rather than ClearType.

So there you go, in IE7, the FadeIn animation (and everything else that calls setElementOpacity) uses a DXTransform to set opacity.  DXTransforms and ClearType don't mix well in IE7, so the IE7 team chose to disable ClearType on elements with a DXTransform. 

The bottom line ... My text looks fuzzy because it isn't being rendered using ClearType.

Are There Any Workarounds?

Kind of.  

Workaround #1: Use removeAttribute to Clear the Filter

You can use the style.removeAttribute function to explicitly remove the filter style after the animation has run.  Because the DXTransform is removed, IE will render the text using ClearType again and the fuzziness will be gone.  In the demo page for this post, I included a small JavaScript function (removeFilter) that clears the filter attribute.  To have this run after the FadeIn animation, I added a ScriptAction to make the function call.  Here is the markup for the animation, below that is the JavaScript function.  P2 is the ID of the paragraph that is the target of the FadeIn animation.

image

image

This works pretty well, but there is a little bit of a glitch.  While the FadeIn animation is running, ClearType rendering is turned off because a DXtransform is applied.  Then my removeFilter function runs and removes the filter causing the text to immediately sharpen.  If you look closely you can tell when this happens because the letters appear to widen.

Workaround #2: Apply the FadeOut Animation to an Overlayed DIV

The other workaround I tried was to overlay the element I was going to apply the FadeIn to with another DIV element.  And instead of Fading in the original element, I applied the FadeOut animation to the overlayed DIV.  So instead of my content being faded-in, the overlayed DIV is being faded-out.  This causes it to slowly disappear and provide the illusion that my underlayed content is being faded in.  Here is the JavaScript for the function that handles this. 

image  

This worked great - no fuzziness and the underlayed element keeps its ClearType rendering throughout the animation.  It does require a bit more work as you will have to keep track of creating, sizing and possibly some other attributes of the overlayed element, but I thought the end result looked pretty good and figured I would share it.

That's it.  Enjoy!


TrackBack

TrackBack URL for this entry:
http://mattberseth.com/blog-mt/mt-tb.fcgi/95

Comments


This one has been perplexing me for awhile. Thanks for workarounds!

Great stuff Matt! I saw this behavior with someones machine where they still had an IE7 beta installed and the text was completely fuzzy. Good to know the root cause now.

One issue with the overlayed div workaround is that you cant select the text after it fades in. You may want to set the overlay to display:none after the animation finishes.

@Eric -

Nice catch. You are right, the div should hidden or removed after the animation runs.

Matt.

Posted by: Joel Peterson on December 20, 2007 12:00 AM

Im glad my mental reminder resulted in some sort of a resolution. Ill be looking forward to implementing this tomorrow.

At long last.

interesting article, dunno about the code as images though

@Joel -

Hi Joel. I would be interested in hearing if you were able to use either of these solutions. Or if you came up with some other workaround.

Matt

Posted by: Simon Toulson on January 14, 2008 12:00 AM

Thanks Matt. This was causing me grief with jQuery FadeIn. Yours is the only relevant article Ive found on the subject.

Excellent and timely article. I came across this problem today. Thanks for sharing your discovery.

Problem solved. Thanks for sharing this!

Posted by: Art Vandelay on March 25, 2008 12:00 AM

You sir, are a captain among programmers and a king among men!

Posted by: E on October 1, 2008 04:24 PM

Could use a little help with this. How would you initiate cleartype for this code?

Thanks!

var slider=function(){
var array=[]; var speed=10; var timer=10;
return{
init:function(t,c){
var s,ds,l,i,y;
s=document.getElementById(t);
ds=s.getElementsByTagName('div');
l=ds.length; i=y=0;
for(i=0;i var d,did; d=ds[i]; did=d.id;
if(did.indexOf("header")!=-1){
y++; d.onclick=new Function("slider.process(this)");
}
else if(did.indexOf("content")!=-1){
array.push(did.replace('-content',''));
d.maxh=d.offsetHeight;
if(c!=y){
d.style.height='0px';
d.style.display='none'
}
else{
d.style.display='block'
}
}
}
},
process:function(d){
var cl,i; cl=array.length; i=0;
for(i;i var s,h,c,cd;
s=array[i]; h=document.getElementById(s+'-header');
c=s+'-content'; cd=document.getElementById(c); clearInterval(cd.timer);
if(h==d&&cd.style.display=='none'){
cd.style.display='block';
this.islide(c,1);
}
else if(cd.style.display=='block'){
this.islide(c,-1)}
}
},
islide:function(i,d){
var c,m; c=document.getElementById(i); m=c.maxh; c.direction=d; c.timer=setInterval("slider.slide('"+i +"')",timer)
},
slide:function(i){
var c,m,h,dist; c=document.getElementById(i); m=c.maxh; h=c.offsetHeight;
dist=(c.direction==1)?Math.round((m-h)/speed):Math.round(h/speed);
if(dist dist=1
}
c.style.height=h+(dist*c.direction)+'px'; c.style.opacity=h/c.maxh; c.style.filter='alpha(opacity='+(h*100/c.maxh)+')';
if(h c.style.display='none'; clearInterval(c.timer);
}
else if(h>(m-2)&&c.direction==1){clearInterval(c.timer)
}
}
};
}
();

Great post! Thank you.
The first workaround did it for me.

Sadly, even tho this is currently only a problem in IE7, it looks like IE8 is going to inherit this behavior. The second beta does at least.

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Consulting Services

Yep - I also offer consulting services. And heck, I'll do just about anything. If you enjoy my blog just drop me an email describing the work you need done.

Recent Comments

  • Atli Þór wrote: Great post! Thank you. The first workaround did it for me. Sadly, even tho this is currently only a...
  • E wrote: Could use a little help with this. How would you initiate cleartype for this code? Thanks! <blockq...
  • Art Vandelay wrote: You sir, are a captain among programmers and a king among men! ...
  • Ryan Baxter wrote: Problem solved. Thanks for sharing this! ...
  • Andre wrote: Excellent and timely article. I came across this problem today. Thanks for sharing your discovery. ...
  • Simon Toulson wrote: Thanks Matt. This was causing me grief with jQuery FadeIn. Yours is the only relevant article Ive ...
  • Matt Berseth wrote: @Joel - Hi Joel. I would be interested in hearing if you were able to use either of these solutio...
  • Chris Olberding wrote: interesting article, dunno about the code as images though ...