Stop Image Flicker With Cache-Control Extensions
Posted in Development
Image flicker in Internet Explorer/Win causes IE to get bitchslapped quite often. To get rid of this effect Dean Edwards suggests to configure Apache to keep images cached. Otherwise you need to manually change caching preferences in IE which a lot of people don’t know how to do. Besides, when images flicker, it’s you who looks bad, not the users’ IE. Dean says he’s no server expert, and neither am I, but there’s a way to configure IIS in a similar fashion.
Cache-Control Extensions is a little-known feature that was rolled out with Internet Explorer 5.0. In a nutshell, it’s a proprietary extension to the Cache-Control header IE 5.x and 6.x understand. The two extensions are pre-check and post-check.

Internet Explorer applies the following logic to objects served with these extensions:
- Upon first request, the object is cached and is served from cache until the
post-checkinterval expires. - Once the
post-checkinterval expires IE fetches the object from cache and checks for an updated one in the background. If a newer object is available it caches it. Upon every subsequent request this updated (and now cached) object is served until thepre-checkinterval expires. - Once the
pre-checkinterval elapses the object is treated as expired. IE will first ask the HTTP server if the object has changed since it was requested by the browser. If it has, IE will load the updated object.
Note: I’m not referring to web pages. I refer to objects because we might be talking about images, web pages, style sheets, external JavaScript files, etc.
As MSDN states, the Refresh button will not trigger this logic because Refresh always sends the if-modified-since request to the server. Hyperlinks do trigger this logic.
How about an example? Suppose an HTTP server sends an image with the following header:
Cache-Control: post-check=3600,pre-check=43200
Both pre-check and post-check specify time intervals in seconds. We tell IE to cache the mentioned image for 12 hours (60 * 60 * 12 seconds). The first hour (60 * 60 seconds) IE will simply display the image from its local cache. However, after 60 minutes we want it to check for a newer one in the background, i.e. it will display the cached one and then do a background check. When 12 hours are up, IE checks for a modified image first.
Set Cache-Control Extensions In IIS
The only missing piece of the puzzle is where to set these extensions to get the ball rolling. You do it in the IIS Manager snap-in. You may choose to set them on a specific folder, such is a folder with images. You may also set them on your entire web app, but hardly ever would you want to cache every single page on your site.
Fire up the IIS Manager snap-in from Administrative Tools, pick a folder in your web app, right click, go to Properties, switch to the HTTP Headers tab, and click Add. Add cache-control extensions like this:

Click Ok to dismiss the dialog. Your HTTP Headers tab should have extensions listed.

Set Cache-Control Extensions Programmatically
I was in for a big surprise when I found documentation for HttpCachePolicy.AppendCacheExtension. You can accomplish what we’ve talked about in C# like this:
Response.Cache.AppendCacheExtension(
"post-check=900,pre-check=3600");
Now, if you want to serve images with this cache policy (which is a good idea) you need to assign them to the ASP.NET ISAPI extension in IIS because by default ASP.NET is not configured to pass them through its HTTP pipeline.
What I Don’t Know
What happens if either pre-check or post-check is missing? I don’t know. What happens if post-check is greater than pre-check? I don’t know either. I found no documentation on MSDN that talks about it.
71 comments
Brent Railey
on August 25, 2004
Thank you for this information, this got rid of my flickering problem I was also dealing with. I implemented the C# fix to a generated image.
Roger Johansson
on September 3, 2004
I can't figure out how to do this with Classic ASP, which is what most of our sites are on. Any hints?
Milan Negovan
on September 3, 2004
Those IIS settings are the same for ASP or ASP.NET applications. Or for any web applications hosted in IIS, for that matter.
I believe in classic ASP you can use Response.AddHeader to accomplish the same programmatically:
Response.AddHeader "Cache-Control", "post-check=3600,pre-check=43200"
Shoot me an email if you get stuck. ;)
Roger Johansson
on September 5, 2004
The IIS settings aren't always easily accessible if the site is hosted externally (which all of our clients' sites are), so being able to change it programatically is great. What you're suggesting looks like it could do the trick. Will report back when I have tested it.
Milan Negovan
on September 5, 2004
Aaaaah, your sites are hosted elsewhere. To cache images programmatically IIS needs to pass their processing to your code. Otherwise it serves them on its own.
In ASP.NET I would (1) write a custom HttpHandler, and (2) map images in IIS to the ASP.NET ISAPI. Normally, I call my hosting company and have them do this mapping because I don't have this much control over their IIS.
In classic ASP... Hmmm... There are really no HttpHandlers per se. Old-style ISAPI extensions and filters are written in C++, and I'd think a hosting company would throw a fit if you ask them to install yours.
Roger Johansson
on September 7, 2004
Just like you suspected, doing this programatically doesn't work in Classic ASP. Adding the header in IIS works, so I contacted our hosting company and had them add it where needed. Took them all of five minutes ;)
It's great to finally be flicker-free even when IE is configured the way many developers like it to be.
Andreas Wallberg
on November 27, 2004
Did anyone find a way to map these to only images, like
the ExpiresByType directive in HtAccess?
/Andreas
Jesse Hansen
on January 25, 2005
After implementing the fix above, I was still getting flickers in IE6 with Windows XP SP2 when the "Every time visit to the page" developer setting. I was able to eliminate the flicker by using the following header:
Cache-control: max-age=2592000;post-check=31449600,pre-check=31449600
You can adjust the numeric items accordingly.
I also had to check the Enable Content Expiration checkbox and set the expiration up to 30 days.
Milan Negovan
on January 25, 2005
Thank you for sharing this, Jesse!
Chris Neppes
on February 15, 2005
You can set IIS cache control manually, but for easy developer access to cache control with having to touch the Internet Services Manager, try CacheRight (http://www.cacheright.com).
You can also apply global changes more easily with this tool for IIS cache control -- it is all managed from one simple text rules file that lives in the Web root.
Cheers,
Chris @ Port80
George
on March 12, 2005
Just implemented this on my new websites. Not it flies !!!!!
Have been working as a web developer for ages, Know how to prevent caching but never thought that on images it's better to have cahing working. That thought never crossed my mind untill i saw this article.
George
on March 26, 2005
Question: Does this line "Cache-Control: post-check=3600,pre-check=43200" affect IE only or any standard browser ?
Basically is it part of the standard?
Milan Negovan
on March 27, 2005
George, as it says in this post it's "a proprietary extension to the Cache-Control header IE 5.x and 6.x understand". It's not a part of any standard.
George
on April 2, 2005
Milan, sorry i did not read carefully. I guess i was too excited. It really made a difference, especially in E-Commerce project when people often go back and forth between items and the catalog.
-----------------------------------
No the question is how do i make the same thing for FireFox for example? Will it work if i do something like that.
"Cache-Control:max-age=432000;post-check=36000,pre-check=432000" ?
Milan Negovan
on April 2, 2005
As a proprietary header to IE it shouldn't work for non-IE browsers (unless they choose to implement it).
Mike
on April 21, 2005
These two headers are completely unnecessary. Cache-Control: max-age= does just that, and much more. IE honors it very well. It's in HTTP/1.1 standard. It's honored in all proxy caches.
BTW someone mentioned earlier that they need "Cache-Control: max-age=2592000;post-check=31449600,pre-check=31449600" to get rid of the flicker. Guess what? you only need the max-age part.
In the book "HTTP Essential" the Cache-Control header is explained very clearly. I suspect Microsoft abandoned their header hack in IE6.
Johan
on April 24, 2005
Response.AddHeader "Cache-Control", "post-check=3600,pre-check=43200"
Is there an equivalent to do this for Apache php configuring the cahce settings?
Johan
on April 24, 2005
.htaccess
< FilesMatch "\.(gif|jpe?g|png)$" >
Header append Cache-Control "max-age=86400, must-revalidate"
< /FilesMatch >
would this do the job for Apache cache settings?
Simon
on April 24, 2005
I've added all the suggestions for header info, only the problem still persists. If you install ieHttpHeaders you will see IE6 still making image requests to the server.
This may be a bug in IE6. I don't have the same problem with firefox.
Travis Savo
on August 29, 2005
Seems that only masks the problem instead of hiding it.
First of all, with an expires/max-age of 'Way way way in the future', how do you deal with changing resources being cached forever on the client?
Secondly, if after caching out an image, does setting your clock ahead to after the cache expiration time cause the problem to reappear? It does for me... and I'm having a heck of a time fixing it.
Milan Negovan
on August 30, 2005
Travis, I definitely see images getting cached on the client forever (or until they clean out the cache). If it's not desired, and you expect them to change, set a reasonable timeout.
I haven't tried tweaking the system clock, but I'd imagine it can be an issue, as you point out.
Zareh
on September 28, 2005
I've set the IE setting to Check for a "Newer Page on Every Visit", and did some testing. I found the following:
Programmatic approach
I added the line of code Response.Cache.AppendCacheExtension("max-age=2592000; post-check=31449600, pre-check=31449600"); at the end of the Page_Load method.)
- Pages get cached (look at IE temp files folder, you will see a value in the expires column; web server log confirms page was not requested.)
- Images, stylesheets, etc. do NOT get cached (temp files folder entry has value "none" in the expires column; web-server log shows request for images/stylesheets.)
Setting IIS Custom Headers
I added the custom header "Cache-Control:max-age=3600" fr the virtual site.
- Pages get cached (as evidenced by value in temp files entry, and web server log)
- Images/stylesheets get cached (as evidenced by value in temp file entry expires colum - they now have an value!!! Also confirmed by web server log where there is NO request for these objects.)
The colclusion I take away is that the programmatic approach only affects the generated page, NOT the images/stylesheets/etc. the page may contain. The ONLY way to ask for caching of these objects appears to be to set a custom header value in IIS. Again, only the "max-age" value was needed 8-)
Milan Negovan
on September 29, 2005
Thank you, Zareh. Good to know this.
alkhan
on October 6, 2005
i'm amazed at the level of knowledge everyone on this post has. Unfortunately, I do not. This will sound like a "dumb" question but what is the flicker that everyone experiences? Our ASP.NET web application is strictly for data entry, running calculations and reports. It's a desktop data application transformed for the web. We have various toolbars and image files for buttons and logo. I don't seem to experience any flicker. The only annoying flicker is from the page post back when dynamically filtering/setting web controls or tree controls. You feel as though you are in an "epileptic" state when filling in data for a form. I need help with that without giving up the functionality of dynamic filtering/settings.
If someone has an example of the flickering that you are experiencing please pass it on. I'd like to see if I am experiencing the same thing without realizing ... as I said i don't have the level of knowledge as the people posting on this topic.
Al
Milan Negovan
on October 6, 2005
Al, it's not a stupid question at all. I can't think of a site that exhibits a flicker off the top of my head. Usually, you see it happen when a navigation menu has images as its backgound. You hover over the manu and IE takes a second or two to fetch the background image. This delayed change of state is the "flicker."
George
on October 27, 2005
Works great! No more annoying flickering when switching pages in IE. Please note that FireFox does a better job in eliminating flickering (caching) when switching pages.
Here's my setup in Apache 2 (.htaccess of vhost-conf):
ExpiresActive On
ExpiresByType text/html A1
ExpiresByType text/css "access plus 1 day"
ExpiresByType text/javascript "access plus 1 day"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
Header append Cache-Control "post-check=3600, pre-check=43200"
Please note that the modules expires and headers must be enabled in Apache to function.
Regards,
George
George
on October 27, 2005
Uhm, some tags were filtered in my previous post. Again:
ExpiresActive On
ExpiresByType text/html A1
ExpiresByType text/css "access plus 1 day"
ExpiresByType text/javascript "access plus 1 day"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
< IfModule mod_headers.c >
Header append Cache-Control "post-check=3600, pre-check=43200"
George
on October 27, 2005
Sorry, I give up. Please remember to enclose the directives with the appropiate module checks.
Simon
on November 2, 2005
Thanks for the Apache Fix - but asp.net runs on Windows/IIS.
Paul van Steenoven
on November 3, 2005
In case if you want to have flicker free IE mouseovers this code is for you:
a { mouseover.gif }
a:link, a:visited { regular.gif }
a:hover { mouseover.gif }
tadaah IE is flicker free :)
John Whistler
on November 4, 2005
Internet Information Services 5.0
Internet Explorer 6
I added the custom header "Cache-Control:max-age=3600" ,
but ONLY to the (virtual) directories which contain image files.
(ie., I did NOT add the header to any other content files -I want my asp application pages to never be cached).
The image flicker is gone.
Outstanding !!
Bob Everland
on December 13, 2005
Comment 33:
This does not work, this is the issue everyone is having is that styles are not cached by IE. If you follow the directions it will work. You can not programatically add the cache control using ColdFusion and classic ASP. I am curious if adding the cache control with ASP.NET makes it site wide, or only for your application.
Simone Busoli
on January 23, 2006
The only solution seems to be adding the Expires header to the response:
(C#)
Response.Expires = 10;
Where the number represents the minutes after which the response will expire.
Greg
on January 24, 2006
These solutions look great. But what if you (me in this case) are developing an application that is sold to companies around the world. Not every company uses the same web server to host the application. I would love to avoid having to do different fixes for this problem on different servers.
Simone Busoli
on January 24, 2006
You are absolutely right Greg, but actually the problem is much wider than this.
It's not only the servers that are different, but the clients too, which often is a much bigger problem.
Chris Scanlon
on January 25, 2006
I totally agree with what you're saying. I wish more people felt this way and took the time to express themselves. Keep up the great work.
Chris Scanlon
http://www.asphostingfun.com
Milan Negovan
on January 25, 2006
I hear you, Greg. I would like to avoid kludges, too. This is one of those cases where you can give yourself home field advantage if you have any degree of control over the server.
Sid
on February 7, 2006
As a note, if you want to make images stay cached forever using max-age=[big number], but you want the ability to update them, there is a solution... use a querystring. The image file "foo.jpg?1" works the same as, yet is different from, "foo.jpg?2". If you're going to use it all over the place, consider writing some helper JS code to cut down on maintenance.
Jason Holtzman
on February 16, 2006
I've heard several differnet solutions here so far, but I would like to know which one exactly works for IIS 5.0. I don't have access to our website's webserver as it is hosted remotely. I've already had them add the 'Cache-Control:max-age=3600' HTTP Header, but it doesn't seem to be working. After clearing out my Temp IE Files and reloading the home page, there still is no expiration date on the images I want cached. And the flicker is still there...
Jason Holtzman
on February 27, 2006
After further review, using the max-age header DID work for me. The only problem I still have is a slight delay with the image-shifting during rollover. Otherwise this worked like a charm.
praveen Ratnakar
on February 28, 2006
Hi!
I have set HTTP Header of IIS Folder(Video) Cache-Control:post-check=60,pre-check=120
I m saving different video file in this folder with same name(temp.wmv) But every time the same video file is played until i manually delete that file from Temporary internet Files.
Please please please Someone help me..........
I m really getting frustrated......
Ryan
on March 3, 2006
Had ISP set this header exactly as the article above said to for IIS (Cache-Control: post-check=3600,pre-check=43200) and it worked perfectly! - Thanks for info!
Kishan
on March 16, 2006
How to avoid cacheing of .js files in ASP.
Please help me I am struck very badly.
Thanks in advance.
Eric Lawrence
on April 4, 2006
Eric Lawrence from the IE Networking team here.
If you don't have both post-check and pre-check present, both directives are ignored.
If post-check > pre-check, both directives are ignored.
bughouse
on May 31, 2006
hint: mod_gzip
Jeffrey Schrab
on June 13, 2006
This saved our butts! Thanks a lot!
Julian
on June 22, 2006
Hi,
From the comments above is it better practice to use the:
Cache-Control:max-age=3600
or
Cache-Control: post-check=3600,pre-check=43200
Can you advise what happens when the 3600 or 43200 seconds expire? How do you get the images to still be cached and checked 'after the first hour'?
Similarly what do you recommend for the best practice when using the IIS HTTP Headers Enable Content Expiration. For example do you set directories to expire on a specific date say Fridays and then use that date to update the files, and then allocate another future expiration date?
If you use the Expire After... option what happens after that expiry timeframe - how do you get the content cached again?
Thanks in advance
Andrew Buck
on September 12, 2006
I spent ages trying to do this and finally found a great solution. I used a Perl script to serve the images (normal and hover images) with appropriate headers:
#!/usr/bin/perl
$|++;
my $file = '../WWW/tabhover.gif';
open(PIC, $file);
my(@MON) = qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/;
my(@WDAY) = qw/Sun Mon Tue Wed Thu Fri Sat/;
my($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime(time() + 24*3600);
$year += 1900;
$expires = sprintf("%s, %02d %s %04d %02d:%02d:%02d GMT", $WDAY[$wday], $mday, $MON[$mon], $year, $hour, $min, $sec);
print "Expires: $expires\n";
print "Content-Type: image/gif\n\n";
binmode STDOUT;
print ;
close(PIC);
exit 0;
I did it like this as I didn't want my pages cached at all. Otherwise I could have maybe put these headers in the pages themselves.
David Levin
on September 12, 2006
Thanks so much for this article! I spent hours trying to fix this myself. You saved me at least 2 days of work!
Cezary Okupski
on September 17, 2006
Travis, if you know a change took place, refer to a resource with some version identifier, id est:
http://www.example.com/example.jpg?v=20050101
http://www.example.com/example.jpg?v=20060917
Mr. Pixel
on September 29, 2006
A js only solution: add this in the HEAD of the page:
try {
document.execCommand("BackgroundImageCache", false, true);
} catch(err) {}
Works for IE6 Service Pack1
Not needed for IE7.
Check my blog for details
tomek
on October 15, 2006
How to avoid cacheing of .js files in ASP.
Please help me I am struck very badly.
Thanks in advance.
kiran
on October 17, 2006
i had tried all these ie adding postcheck,precheck etc in IIS still flickering problem doesnt go,iam getting flickering problem only in pages where we have infragistics webgrid ..if anyone have suggesttions or solns please let me know.
Milan Negovan
on October 17, 2006
My guess is you'll need to ask Infragistics. :)
kiran
on October 18, 2006
yeah,i need to do that before asking them i want to know wether anyone had faced this problem before,thanks for sugestion though
praca
on October 20, 2006
I was reading your comments kiran and i have to say i got a similar problem;/ Did you find a solution for this? Plz let me now!
Killtek
on October 31, 2006
Mr. Pixel's javascript solution works.. Thank you!!!
Adam Rogas
on November 4, 2006
Using any caching at all works with
try
{
document.execCommand("BackgroundImageCache", false, true);
} catch(err) {}
Works for IE6 Service Pack1
as per Mr. Pixel
it also does not cause the images to be stuck in cache forever as a forced page reload will refresh the images.
Plater
on November 28, 2006
As Andrew Buck did, I used a perl script to serve pages with custom headers. Now I've made the jump to ASP.NET to do the exact same thing.
Try something like the following:
Response.Clear();
Response.Cache.SetExpires(DateTime.Now.AddHours(12));
Response.ContentType="image/jpeg";
Response.WriteFile(filename);
Response.End();
The nice thing is you can use a query string or almost anything to decide what 'filename' is. I have taken to using tokens in the querystring to decide what file to return back to the browser.
Logodesign
on December 5, 2006
After further review, using the max-age header DID work for me. The only problem I still have is a slight delay with the image-shifting during rollover. Otherwise this worked like a charm.
Florian
on December 12, 2006
No more image flicker problems. Thank you so much!
Mattias
on December 14, 2006
@Plater:
Well done, now it works 100% without flickering...
Alex
on January 17, 2007
The Cache-Control HTTP Headers is part of the HTTP 1.1 standard.
It has a certain number of parameters that can be used:
* max-age=seconds - the number of seconds from the time of the request you wish this objcet to be keep into the cache;
* s-maxage=seconds - like max-age but it only applies to proxy;
* public - tell to handle the content has cacheable even if it would normally be uncacheable, it is used for example for authenticated pages;
* no-cache - force both proxy and browser to validate the document before to provide a cached copy;
* must-revalidate - tell the browser to obey to any information you give them about a webpage;
* proxy-revalidate - like must-revalidate but applies to proxy;
Guitar Teacher
on January 26, 2007
Oh God.
I only became aware of the flickering problem very late into the design stage.
The only solution I could come up was some ugly client-side hack.
Substitute the scriptless CSS menu by javascript if IE is detected -
Otherwise do nothing.
example in my guitar website
I wouldn't mind removing all the extra js junk tho
I like clean code.
but I have no .NET extension there or admin access to IIS
to force the change in cache policy.

Roger
on August 5, 2004
Looks like something I'll take a look at when I get back to work (no IIS at home - when I have a choice I use Apache ;-)). I hope it works as well as the Apache solution you mentioned above. I have implemented it on my Inverted Sliding Doors tabs demo, and it seems to do the trick.