PDA

View Full Version : FYI regarding images in CSS


mschwartz
12-06-2008, 12:45 PM
I've verified that this is true in several browsers, including FF 2, FF 3, IE 7 and IE8.

In an attempt to speed up various sites I've worked on, I notice in Firebug that many sites don't set cache headers for static objects (images, flash files, css, even javascript). This causes the browsers to issue "if modified since" type requests to the server where the server responds with "304 - not modified."

Why bother to have all that network traffic and hits on the server if your images don't change but once in a blue moon?

Apache has a directive that lets you turn on cache headers for directories and files. These headers can be set up to tell the browser that the images don't "expire" for days or hours or even years, if you so choose. When you set the headers up properly, all those 304 requests/responses go away and the WWW pages load considerably faster. Realize that if you have a page with dozens or hundreds of images, the performance benefit can be considerable. The network is also not perfect, nor can you rely on the server to respond "304 not modified" as immediately as you'd think, so those 304 requests/responses carry that additional badness.

See:
http://www.websiteoptimization.com/speed/tweak/cache/

I created a .htaccess file in ext-2.2/resources with the following contents:

<FilesMatch "\.(gif|jpg|jpeg|png)$">
Header set Cache-Control "max-age=172800, public, must-revalidate"
</FilesMatch>


I created a .htacces file with the same contents in my site's images directory as well.

I can see that my site's images do indeed have the cache header and the browser only fetches those images where I use IMG tags in my HTML, ONLY the first time I load a page after clearing my browser cache.

Now for the gotcha.

For some reason I do not understand, the browsers do not obey the cache headers for images that are referenced by css. For example, I'll pick an arbitrary line from ext-all.css:


.ext-el-mask-msg{z-index:20001;position:absolute;top:0;left:0;border:1px solid #6593cf;background:#c3daf9 url(../images/default/box/tb-blue.gif) repeat-x 0 -16px;padding:2px;}


The browsers mentioned will always issue the "if-modified-since" request for "../images/default/box/tb-blue.gif" - IF you use some Ext component that uses the ext-el-mask-msg class.

How bad is it?

A fairly simple Ext driven page: a viewport with nothing but a window open on top of it with login/password and "login" button.

With clear browser cache, I see 17 requests, 15 of those for images. And I do see this in the Response Headers in Firebug:

Cache-Controlmax-age=172800, public, must-revalidate


A simple reload of the same page, I see 17 requests, 15 of those for images and ALL of those are 304 not modified. Reload again and 15 "if-modified-since" requests again. For files like "right-corners.png" and "tip-sprite.gif" (referenced by ext-all.css).

It doesn't get better when I load a complex type layout like the RSS reader example/demo. Your results may vary, but you're likely to see 80 or more of those 304 requests.

It is a big deal. Knock out 80 304 requests and a page that used to load in 3 seconds loads in 1. Sites like the Desktop demo/extension that take 10+ seconds to load (and frankly, numerous other sites based upon Ext that I've visited) could be significantly faster (maybe 2-3 seconds).

How should it be fixed?

Well, we can hope and pray that the browser coders figure out this issue and fix it. Maybe IE will do it this year and Firefox sometime in 2011. That's the risk if that's the route to take.

The other way to fix it is for the Ext.js library to be massaged enough so all the url() can be removed from the css files and the images put in the generated HTML with IMG tags. The benefit of this approach is the Ext.js developers and community are in charge of making Ext pages load fast.

mjlecomte
12-06-2008, 05:02 PM
In case you didn't hit these and they are of any value:
http://www.webmasterworld.com/apache/3659750.htm
http://www.websiteoptimization.com/secrets/advanced/9-15-data-uri-css.html

jack.slocum
12-07-2008, 05:34 AM
Thanks for the detailed post. A few notes:

1. Using CSS background images is the preferred way to style pages, not a workaround and isn't something that will or should be removed (IMO).

2. Generated HTML using img tags will not make an if-modified request on refresh because they aren't present on page load, not because of CSS background images.

3. CSS background images do an if-modified request on refresh because they are present on page load. This is the correct behavior so I don't expect browsers to fix it.

4. Firefox will usually display the cached image while making an if-modified request.

The headers are good though when making a normal request (e.g. clicking a link, or returning to a site a 2nd time) when not explictly requesting a refresh.

mschwartz
12-08-2008, 04:31 PM
Thanks for the detailed post. A few notes:

1. Using CSS background images is the preferred way to style pages, not a workaround and isn't something that will or should be removed (IMO).

2. Generated HTML using img tags will not make an if-modified request on refresh because they aren't present on page load, not because of CSS background images.

3. CSS background images do an if-modified request on refresh because they are present on page load. This is the correct behavior so I don't expect browsers to fix it.

4. Firefox will usually display the cached image while making an if-modified request.

The headers are good though when making a normal request (e.g. clicking a link, or returning to a site a 2nd time) when not explictly requesting a refresh.

FWIW,

I've seen that url() in CSS absolutely does 304 no matter what the cache headers are. I do not see how this can be anything but a bug. I absolutely see that in flat HTML pages with no javascript, there are no 304 for images with cache heder in IMG tags (they are present on page load).

It appears that the logic for dealing with images in CSS in the browsers is quite separate from the logic for dealing with images via Javascript or img tags.

The links posted by mjlecomte verify this.

Kango_V
12-10-2008, 06:24 PM
Is there any way that ExtJs could use the same mechanism that GWT ImageBundles use. Not sure how you would go about creating them though.

I know this is planned for GXT.

This would then download one image that contains all your icons.

Just a thought.