6

I've a PNG file named icons.png hosted on an apache server. Basically this file is a combination of other small image elements (CSS Sprite). This file loads with a normal 200 OK response when the page loads for the 1st time.

After the page loads; there are some links hovering on which a custom tooltip is triggered. This tooltip displays part of the image from the icons.png file as a background image of some HTML elements.

For example the HTML code is like this:

jQuery(".profile").tipTip({delay: 200, defaultPosition: "top", content: "<a href='#' style='width: 32px; height: 32px; display: block; background: url(images/icons.png) no-repeat -200px -64px'></a>"});

[There are some other places in the HTML file where icons.png has been referred to]


Now every time I hover on the link, the tooltip is showing up, but simultaneously the browser is sending a HTTP request to the server for the icons.png file. And the response code from the server is coming as 304 Not Modified.

Although the content of the file is not being fetched, but the overhead of sending the headers (around 166 Bytes) is still there every time, which in turn is causing a latency of 1.5 s (I'm on a damn slow connection). During this period of 1.5 s the tooltip element has no background image & suddenly the image is showing up out of nowhere.


Here are some screen-shots of

  • Chrome network panel:

Chrome

  • Firebug net panel:

Firefox

  • HTTP headers:

Headers


As far as I know once a resource has been fetched the browser should hold it in its cache & fetch from there whenever necessary, instead of requesting the server multiple times.

As I've found out that the server is not sending any "Expires" or "Cache-Control" header along with the content. I'm not sure whether this can be the reason behind such exceptional behavior of Chrome. Any suggestion is highly appreciated.

P.S: The application is hosted on Heroku's shared hosting environment. I'm using Firefox 15.0 & Chrome Version 21.0.1180.89 on Ubuntu 12.04 x86_64.

dibyendu
  • 515
  • 1
  • 5
  • 16
  • 1
    You are right, you need to set the `Cache-Control` and `Expires` headers. Is `icons.png` hosted on your own apache server or heroku? – vikraman Mar 05 '13 at 12:49
  • 1
    @vh4x0r, I've added the required `Cache-Control` configurations to a `.htaccess` file & tested it on my `localhost`. Now the response headers are coming like [this](http://i.imgur.com/2hayEoi.png). And now Chrome is performing the expected thing, i.e to fetch from cache with response **200 OK (from cache)** without requesting the server. See the screen-shot of [chrome](http://i.imgur.com/JUyAn2M.png). But even now Firefox is still making a trip to the server with an eventual **304 Not Modified** response (see the [screen-shot](http://i.imgur.com/zd2C8gk.png) of firebug). Can you justify this ? – dibyendu Mar 05 '13 at 13:38
  • I cannot, but I would ask you to update firefox, and recheck your cache settings in `about:config`. Also, try experimenting with the `Last-Modified` header. – vikraman Mar 05 '13 at 13:52

2 Answers2

2

Every time you show an element for the first time, that is the point at which it downloads any associated background images... in modern browsers at least.

Your multiple requests are likely to be because they are the times you hovered over a new tooltip, bringing it in to visibility, and thus prompting the image to be called.

Your instincts are right though, the issue would be that if no caching header configuration is done directly on your server, or through .htaccess files, then it will keep requesting the server with a http request to see if it needs to download a newer version or not. As soon as you sort out your "expires" headers, which can be set through mod_expires, it'll start to return a locally requested version of the file each time instead.

Source: http://httpd.apache.org/docs/2.2/mod/mod_expires.html

niaccurshi
  • 1,265
  • 9
  • 9
  • Thanks for replying. But it's not every time I hover on a different element, rather a new request is being sent when I hover on the same element to trigger the same tooltip. And since Heroku is providing the hosting environment; there is no external way like .htaccess that I can change apache's configuration with. – dibyendu Mar 05 '13 at 11:28
  • Interesting. Does your javascript code recreate the tooltip each time or only once and "hide" it? – niaccurshi Mar 05 '13 at 11:29
  • I checked the JS plugin. It's essentially a create once & toggle between show/hide type of plugin. – dibyendu Mar 05 '13 at 11:34
  • I'm taking a look at the code, and what it does is create a single "holder" element that is hidden. It then, on hover, changes the content in that element and shows it, positioning it over the correct link. This is almost certainly what is causing your multiple requests, as the css, including the background-image, keeps being rewritten each time. At least this is the functionality on the plugin's website! – niaccurshi Mar 05 '13 at 11:37
  • And is there any way by which I can be sure that it's actually server cache header issue ? – dibyendu Mar 05 '13 at 11:37
  • The fact that it is not returning a header of "200 OK (from cache)" should be enough to show that, but I'd say setting up some expires rules, maybe in a .htaccess file for ease, would give you the answer as to whether it's an issue of the cache headers having an effect or not? – niaccurshi Mar 05 '13 at 11:42
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/25602/discussion-between-dibyendu-and-niaccurshi) – dibyendu Mar 05 '13 at 13:49
1

I just recently came across with this behaviour as well, during developing locally. An element with a sprite background had a :hover state in the CSS file, which pointed on the same sprite background image with a different background position and that caused a very small, but nevertheless noticeable latency when switching the background of the element.

.class {
    background: transparent url('sprite.png') 0 0 scroll;
}

.class:hover {
    background: transparent url('sprite.png') -50px 0 scroll;
}

One way of making sure this doesn't happen is simply using the background-position CSS property only.

.class {
    background: transparent url('sprite.png') 0 0 scroll;
}

.class:hover {
    background-position: -50px 0;
}

Of course cache control is still necessary, this approach of coding can save you some headache.

pentzzsolt
  • 1,001
  • 1
  • 9
  • 18