18

Note: If you are reading this for the fist time, you may jump directly to the UPDATE, since it addresses the issue more accurately.

So I got a web-page.

In the head I have a CSS background-image:

<style>
    #foo { background-image:url(foo.gif); }
</style>

At the bottom of the page I load my scripts:

<script src="jquery.js"></script>
<script src="analytics.js"></script>

Since the scripts are located at the bottom of the page, and the CSS at the top of the page, I assumed that browsers will load the image first. However, this seems not to be the case.

This is a screenshot from the Chrome Dev Tools:

http://www.vidasp.net/media/cssimg-vs-script.png

As you can see, the image loads after the scripts. (The vertical blue line is the page load DOMContentLoaded event. The huge 45ms gap is the time in which Chrome parses the jQuery source code.)

Now, my first question is:

Is this standard behavior in browsers? Do CSS background-images always load after all the scripts on the page?

If yes, how could I make sure that those images load before the scripts? Is there an easy and convenient solution to this problem?


UPDATE

I made a test case. This is the HTML source code:

<!DOCTYPE html>
<html>
<head>
    <style> body { background-image: url(image1.jpg) } </style>
</head>
<body>
    <div> <img src="image2.jpg"> </div>
    <script src="http://ajax.googleapis.com/ajax/.../jquery.min.js"></script>
    <script src="http://vidasp.net/js/tablesorter.js"></script>
</body>
</html>

As you can see, I have one CSS background-image, one regular image, and two scripts. And now the results:


INTERNET EXPLORER (9 beta)

http://www.vidasp.net/media/loadorder-results/ie2.png
http://www.vidasp.net/media/loadorder-results/ie1.png

Internet Explorer requests the regular image first, then the two scripts, and the CSS image last.


FIREFOX (3.6)

http://www.vidasp.net/media/loadorder-results/firefox2.png
http://www.vidasp.net/media/loadorder-results/firefox1.png

Firefox is doing it right. All resources are requested in the order in which they appear in the HTML source code.


CHROME (latest stable)

http://www.vidasp.net/media/loadorder-results/chrome2.png
http://www.vidasp.net/media/loadorder-results/chrome1.png

Chrome demonstrates the issue that made me write this question in the first place. The scripts are requested before the images.


OPERA (11)

http://www.vidasp.net/media/loadorder-results/opera1.png
http://www.vidasp.net/media/loadorder-results/opera2.png

Like Firefox, Opera is doing it right, too. :D


To sum up:

  • Firefox and Opera are requesting the resources as they appear in the source code.

Exceptions so this rule:

  • Internet explorer requests CSS background-images last
  • Chrome requests scripts before images even when the scripts appear later in the source code

Now that I laid out the issue, let me move on to my question:

How to make IE and Chrome request the images before the scripts?

Šime Vidas
  • 182,163
  • 62
  • 281
  • 385
  • "Is this standard behavior in browsers?" yes and it's even worse for css background img on :hover – Knu Jan 20 '11 at 05:17
  • If I may, I'd like to ask a counter question: For what reason is it important that the scripts/images be loaded in a particular order? Mostly I'm curious if there's an underlying problem that changing the order solves for you. – zzzzBov Jan 20 '11 at 19:58
  • @zzzzBov I want the images to be requested as soon as possible, because that means that the visitor will see them sooner. Obviously, having the images appear on the screen sooner is a good thing. – Šime Vidas Jan 20 '11 at 20:02
  • Vidas, You could add a short script to load scripts when the document has loaded if it's that much of an issue. `< 1s` load time is fast enough IMHO. People only see what they're looking for. – zzzzBov Jan 20 '11 at 20:25
  • @zzzzBov Yes I will try that. Note, in this case the delay is 45ms. But in other cases it might be considerably higher. But, regardless of the delay, **it is generally better that the images are requested first**, and that's what I'd like to achieve cross-browser. – Šime Vidas Jan 20 '11 at 21:21
  • my Firefox (18, PC) load the CSS backgrounds last..even if they are written up most in the HTML style deceleration. – vsync Jan 18 '13 at 01:20

5 Answers5

3

Use image preloading capabilities through rel="preload" attribute

<link rel="preload" href="images/mypic.jpg" as="image">

The as attribute indicates the kind of object the browser should expect. So this adds highest priorities among all images you load on page, but not change priority "JS -> Image"

<link rel="preload" href="images/mypic.jpg">

Declaration without as allow to preload images even before js load, increasing Image loading priority.

Preloading feature

VadimB
  • 5,533
  • 2
  • 34
  • 48
3

Most latest browsers to this kind of unpredictable parallel preloading of stuff these days, for performance reasons and basically ruining any chance of creating an order for loading components. This of course happens once the full DOM has been loaded. Same story as with JQuery lazy loading of images, which has been broken for a while now.

Shinnok
  • 6,279
  • 6
  • 31
  • 44
  • I don't want to lazy load the images, I want the opposite: I want to load the images first, as soon as possible. – Šime Vidas Jan 20 '11 at 19:49
2

Consider that the browser can't do anything till it builds the DOM. So first it parses the whole page, THEN it loads the images (even if they're from the CSS).

You could load the images in DATA segments inline in the CSS or the page, that might speed those things up, or you could inject the jQuery reference after the page is loaded (say set a timer for 500 ms) but obviously that will affect usability to some extent.

Now, I'm pretty sure this is all implementation dependent, you could always find a browser that would load images as it came to them, but consider what it means to build a DOM and then to fill it in.


http://en.wikipedia.org/wiki/Data_URI_scheme

If SO doesn't strip it, there should be a red dot between here and the code :\

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGPC/xhBAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IAAAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFoZSBHSU1Q72QlbgAAAF1JREFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jqch9//q1uH4Tzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0vr4MkhoXe0rZigAAAABJRU5ErkJggg==" alt="Red dot" />

So that's what I meant, use the DATA URI scheme

jcolebrand
  • 15,889
  • 12
  • 75
  • 121
  • @drackenstern Could you elaborate on those DATA segments? I haven't heard of that. ... Yes, I think lazy loading the scripts would be a solution. However, a rather unpleasant solution. – Šime Vidas Jan 20 '11 at 19:58
  • When I get back from lunch sure – jcolebrand Jan 20 '11 at 20:00
  • @drachenstern OK, no hurry :) – Šime Vidas Jan 20 '11 at 20:04
  • @drachenstern Aha, interesting :) However, this method is obviously not a good solution, since this disables image caching. – Šime Vidas Jan 20 '11 at 21:07
  • @SimeVidas I know but I was trying to see what could be done to help you out. Now, if it's in the CSS then the CSS will be cached and that will speed some things up. But no, you have a size limitation amongst other things. I think it's just that the browser vendors don't implement the same – jcolebrand Jan 20 '11 at 21:09
  • @drachenstern I think lazy loading the scripts is the only solution here. I believe I watched a lecture where a guy from Yahoo or Google advocated this method - where all the SCRIPT elements are created dynamically on page load. I will try to find that video... – Šime Vidas Jan 20 '11 at 21:11
  • @SimeVidas ~ Yep, that's what I would do. Best of luck and keep us updated. – jcolebrand Jan 20 '11 at 21:29
  • @drachenstern I have come across this article: http://www.nczonline.net/blog/2009/07/28/the-best-way-to-load-external-javascript/ However, adding external scripts dynamically does not resolve my issue `:(` It would work if I used a timeout to load the script dynamically, but that seems like a stupid technique. – Šime Vidas Jan 21 '11 at 03:15
  • For the requirement of blocking the parsing of the jQuery till your DOM is ready, I think that's your only option. – jcolebrand Jan 21 '11 at 03:29
  • @drachenstern I don't understand. What do you mean? – Šime Vidas Jan 21 '11 at 03:48
2

A possible option is to load all those images that you need at the start of your script. See this TechRepublic article for more info.

Community
  • 1
  • 1
Behrang
  • 46,888
  • 25
  • 118
  • 160
2

We solved this problem using .load inside the .ready jquery call

something like:

jQuery(document).ready(function($){
  jQuery('#my_container img').load(function($){
     /* SCRIPT */
  });
});
Vitor Hugo
  • 21
  • 1
  • This is a good idea. Do you have experience about the reliability of this method? – Šime Vidas Apr 19 '11 at 19:16
  • yes, I made that on a plugin for wordpress based site and it worked very well. – Vitor Hugo Apr 20 '11 at 19:06
  • However, there is one problem with this solution. It is possible that the image load event fires *before* the DOM ready event. In that case, the scripts would never get loaded. I guess one could circumvent this problem by using native API to bind the load event (for instance, the `onload` property), since that approach wouldn't require jQuery. – Šime Vidas Apr 20 '11 at 19:39