views:

230

answers:

2

Esteemed Overflow-ers of the Stack,

So I've recently been trying to fully wrap my head around HTTP resource caching. Notably, right now I'm looking at simply the caching of a single, sprited image which is used for rendering icons / small images through out the page. Here's an explanation of the odd behavior I'm seeing:

So, on the given page I have only a single image: icons.sprite.gif. There are four elements which use the sprite to display various icons on the page. In my Apache config, I have mod_expires installed and the following cache-control directives:

ExpiresActive On
ExpiresDefault "access plus 300 seconds"

ExpiresByType text/html "access plus 1 day"
ExpiresByType text/css "access plus 1 day"
ExpiresByType text/javascript "access plus 1 day"
ExpiresByType image/gif "access plus 1 week"
ExpiresByType image/jpg "access plus 1 week"
ExpiresByType image/png "access plus 1 week"
ExpiresByType application/x-shockwave-flash "access plus 1 day"

Now, here's the weirdness. In Safari, when I load the page, the net-inspector reveals only a single request for the sprite. This is perfect, working as expected. On the other hand, with Internet Explorer and Firefox, Fidder / Firebug reveals four successful requests for the sprited image = what!? Subsequent requests result in a single cache hit, but that first load contains four concurrent requests. This seems like a pretty big wtf, as it seems to circumvent the whole point of spriting, which is to the reduce the sheer number of resource requests in a given page-load cycle.

What may be happening:

The page is loading fast enough that by the time the second element is rendered to the document which uses the sprited background image, the first request for the sprite hasn't finished yet. Accordingly, given the resource isn't yet cached, as later elements are rendered, they result in a new request for the resource, even though its already being loaded. Safari handles and prevents this somehow (I know that Safari's caching practices are somewhat different than other browsers).

So -- I'm looking for some confirmation / input here. Is this "working as expected" for these browsers -- furthermore, does it negate the performance gains associated with spriting (which does introduce css-maintenance complexities)? Alternatively, is there something wrong I'm doing?

I appreciate your thoughts / suggestions.

Cheers,

Skone

+1  A: 

Your analysis of the situation seems to be going the right direction. Here are a couple of thoughts I have:

First, the concept of maximum number of connections. Browsers set this differently. Related to this, it may be possible that Firefox / other browsers will attempt to load the same resource on multiple connections until one is successful, whereas Safari only tries one connection for a given resource.

Second, is Safari only making one call? Or is it only reporting the single successful call? That is, Safari makes 4 requests for a given resource, and the first one completes so the rest are ignored and not reported.

Third, is Safari just faster? Try a larger image or downloading over a slow connection in Safari to see if it will have the same 'problem' as the other browsers.

Finally, I generally don't believe this negates the performance gains of using sprites. Sprites are really there to help in situations where there are several 10's or perhaps 100's of images, so as to reduce the http requests. If you're using sprites for a small number of images (5-10 for example), it almost doesn't make sense in that case.

One other benefit of sprites unrelated to http requests relates to interactive lag. IE browsers in the past only downloaded images once they were shown on an element, for example on hover, creating a lag in the hover state. Sprites solved that problem.

Josh
+4  A: 

So, after extensive munging I figured out how to fix the problem.

Let say, for instance, that I create a sprite and use css as follows:

.icon { 
   background: transparent url(/media/common/images/sprite.gif) scroll no-repeat 0 -33px;
}

.logo {
   background: transparent url(/media/common/images/sprite.gif) scroll no-repeat 0 -10px;
}

In firefox, this will cause two requests for that image, as opposed to a single request for the image. The fix, accordingly, is to consolidate the css-rules as such:

.sprited {
  background: transparent url(/media/common/images/sprite.gif) scroll no-repeat 0 0;
}

.icon { 
   background-position: 0 -33px;
}

.logo {
   background-position: 0 -10px;
}

I realize this in itself is more appropriate, as it avoids duplication of the background property among sprited elements.

Anyway, hope this proves useful for another spriter to be!

Edit: After a bit of additional testing, this in fact only happens in Mozilla Firefox (platform independent). Safari and IE interpret multiple references to the same image and make a single request, while Firefox appears to make a unique request for each image linked to via CSS.

I realize its probably not specificly understood as a bug, but in an era where browsers are competing for being labeled the fastest -- seems like a potential improvement for Firefox!

What do you guys think, should I submit this to Mozilla as a bug?

Skone