Closed Bug 253851 Opened 20 years ago Closed 17 years ago

Page loading "done" before CSS background images have downloaded

Categories

(Core :: CSS Parsing and Computation, defect, P2)

defect

Tracking

()

RESOLVED FIXED
mozilla1.9alpha8

People

(Reporter: mozilla, Assigned: Gavin)

References

()

Details

Attachments

(1 file, 2 obsolete files)

User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7) Gecko/20040724 Firefox/0.9.1+
Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7) Gecko/20040724 Firefox/0.9.1+

When viewing a page with a large (CSS) background image, the status bar says
that page loading is "done" before the background image has fully downloaded and
before it is displayed. This occurs when only one tab is open (hence this isn't
bug 57607).

Reproducible: Always
Steps to Reproduce:
1. Open a page with a large background image (e.g. use a complex wallpaper as a
background image to exaggerate the effect)
2. Wait

Actual Results:  
Status bar says "done" before the background image appears

Expected Results:  
Status bar shouldn't say "done" until the background image has appeared
I don't if this site has the same problem:
http://italia.errorfree.eu.org/

Try refreshing a couple of times. You should see the bug on background.
Scrolling up and down and making a selection in text draws background correctly.
Works perfectly on IE. 

I think severity should be updated to normal.
(In reply to comment #1)
> I don't if this site has the same problem:
> http://italia.errorfree.eu.org/
> 
> Try refreshing a couple of times. You should see the bug on background.
> Scrolling up and down and making a selection in text draws background correctly.

That page is indeed an example of this bug (it can be reproduced by pressing
Ctrl+F5 to force-reload the page).

However, scrolling or selecting text isn't required to make the background
appear; it appears once the image has been fully downloaded. If it doesn't
appear simply by waiting, then that's another, separate bug.

Note that this only occurs in cases where Firefox finishes rendering page
content, including inline images, before the background image can be completely
downloaded. Thus it will affect pages that contain few/small inline images and
many/large background images, and will be more noticable on a slower connection.
Confimed using Firefox 1.0, but seems fixed on the trunk.

Greg can you verify this?
I believe I've run into this bug @ http://projects.sinistrals.net/sites/yago.v1/ 

The footer's background image randomly fails on load to render but viewing the
image and going back will cause it to appear. I checked to see if it was
nglayout.initialpaint.delay time I had set causing it but it does not seem to be
it as it appears with the default value. Is this an example of the bug?
duplicate of 291172
Assignee: bugs → nobody
QA Contact: bugzilla → toolbars
*** Bug 291172 has been marked as a duplicate of this bug. ***
(In reply to comment #6)
> duplicate of 291172

On the contrary.

Although, I'm not sure about the Product/Component of this bug.. I think that
this should be Core/XXX.
Component: Toolbars → General
Version: unspecified → Trunk
style system loads background images with LOAD_BACKGROUND
Assignee: nobody → dbaron
Component: General → Style System (CSS)
Product: Firefox → Core
QA Contact: toolbars → ian
*** Bug 311372 has been marked as a duplicate of this bug. ***
Answer for comment #3: No, it is not fixed on trunk
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20051006
Firefox/1.6 ID:2005100607

This bug is also very noticable on the pages of http://www.csszengarden.com/
because almost every graphic is loaded as a background.
This is trivial to fix, since we actually have a hidden pref,
"layout.fire_onload_after_image_background_loads", that controls this.  I don't
remember the reasons for wanting it the way it is now, but I think there are
some.  That said, if we do want to fix this, we should *remove* the pref and
hard-code it to always delay onload.
One reason I seem to recall is compat with IE together with faster perceived
pageload... (both in benchmark terms and in terms of background images that are
outside the viewport not affecting onload).
(In reply to comment #13)
> One reason I seem to recall is compat with IE together with faster perceived
> pageload... (both in benchmark terms and in terms of background images that are
> outside the viewport not affecting onload).

Well, it might make the browser seem faster, but it tricks the user into
thinking the page has loaded before it actually has.

And IMO it is kind of annoying seeing backgrounds suddenly appearing a few
seconds after the page has already "loaded".
Summary: Page loading "done" before background images have downloaded → Page loading "done" before CSS background images have downloaded
*** Bug 319970 has been marked as a duplicate of this bug. ***
I can reproduce the bug on this URL: http://www.ghorkov.com

When you select the "Red Alert" stylesheet (that features a 400KB 24-bit PNG image) the status bar says "done" even though the massive PNG image hasn't loaded yet, there is no indiction that it was loading the image (other than my bandwidth indicator going through the roof for what initially seems like an average blog)
*** Bug 337206 has been marked as a duplicate of this bug. ***
I think this is more than a minor bug and should be upgraded.

A more serious ramification of this bug is that it makes it impossible to trigger a script after the page has fully painted when there are a significant number of background images.  Window.onload and document.body.onload are triggered without any regard to the background images.  Not only is this illogical and contrary to established convention, but there are many reasons why a developer may want to delay execution of a script until after the page has fully painted.  As long as window.onload and document.body.onload are broken, Firefox provides no way to do this.

Please see the test site I have set up to demonstrate this problem:

http://www.sandbox-project.com/test.html

It is ironic that one explanation for this bug has been that it is an intentional feature designed to make pages appear to load faster.  It can actually have the opposite effect!  If a developer wants to execute scripts immediately ~after~ the page is fully painted, the logical way to do this and the establised convention is to set them to run upon window.onload or document.body.onload.  But as long as Firefox triggers window.onload and document.body.onload without regard to the background images, these events are triggered prematurely and the background images actually halt painting until the scripts have been fully exectuted.  This can result in an annoying delay.  It significantly ~slows~ the perceived load time of the page!

It is a bad idea to fudge things to try to get the browser to seem faster.  Firefox should do things the correct way, and not try to emulate IE.  That is especially true in this case....  There is no reason to fudge things to emulate IE -- IE is handling the onload events correctly!  The only browser that I have found that triggers the window.onload and document.body.onload events before the background images have painted is Firefox.  That makes me really unhappy because I prefer to complain that IE is the crackhead browser and hold Firefox as my shining example of the standards-compliant browser that gets things right.  I hope this bug is fixed and I can say that again soon.

You can see a more detailed discussion about this bug as I am experiencing it at bug 337206.  I filed that before it was pointed out to me that this bug had alraeady been reported here.   You can also find an interesting discussion about this bug at the thread I initiated at the mozillazine Web Development/Standards Evangelism forum:

http://forums.mozillazine.org/viewtopic.php?t=413504

Thanks very much for your help addressing this matter.  Everyone has done a phenomenal job with Firefox -- it is a wonderful browser.  M$ (and Apple), with all their bucks, can't beat it.
If the fix is trivial, and all we need to do is to set the boolean value
layout.fire_onload_after_image_background_loads to true, let's do it!

If there is a case to be made that it is correct to do things they way they are done now, what is it?  Otherwise, I hope this fix is included in the next upcoming release.
OK, if IE does wait for backgrounds for onload (and I've just confirmed that IE6 does, using the testcase in comment 18), we should probably make this change.  roc, dbaron, do you see any reasons not to that I'm missing?

Sadly, I have no tree till May 29; someone care to produce a patch?  The relevant code is at http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/layout/style/nsCSSValue.cpp&rev=1.36&mark=383-394,399#382 -- you want to remove that first block and pass nsIRequest::LOAD_NORMAL to LoadImage, then remove the aIsBackground arg to the nsCSSValue::Image constructor and fix things up the call chain as needed.
Would it be worth just flipping the pref and getting some feedback first?
(In reply to comment #21)
> Would it be worth just flipping the pref and getting some feedback first?
> 

Yes, please try it out, and visit my test site.  You will see that it fixes the problem.
I mean would it be worth just flipping the pref for 1.9a1, to get some feedback from a wider range of users.

There's clearly a tradeoff here. In some cases it is going to slow things down for users, such as when an onload script has to run before a page becomes useful.
Attached patch flip the pref (obsolete) — Splinter Review
Assignee: dbaron → gavin.sharp
Status: NEW → ASSIGNED
Attached patch remove the code (obsolete) — Splinter Review
OS: Windows XP → All
Hardware: PC → All
Target Milestone: --- → mozilla1.9alpha
(In reply to comment #23)

> There's clearly a tradeoff here. In some cases it is going to slow things down
> for users, such as when an onload script has to run before a page becomes
> useful.
> 

I don't see this as a problem.  I don't know of any other browser that handles window.onload or document.body.onload this way.  Anyone who expects onload to trigger before the page becomes useful is writing specifically for Firefox.  That is getting away from standards.  Besides, there is another way to accomplish that -- you can simply execute script without waiting for window.onload, or you can attach it to some other event.  If the code is supposed to execute after a particular element on the page has loaded, but doesn't need to wait for the entire page, you can attach it to [theElement].onload.  There is however no other way of triggering code to execute imediately after the page paints except to use window.onload or document.body.onload.

In the spirit of following established convention and web standards, as well as to provide useful functionality that is available no other way, window.onload should not trigger until the page has fully painted.  And from a logical perspective, if the background images are not part of the window, where do they exist?  If we agree they are logically part of the window, window.onload should not fire until after they have painted.

If you want to have it both ways, ~maybe~ it is possible to argue that background images set in the css are not technically part of the document body, and document.body.onload can trigger before waiting for those to paint.  But I don't think that makes sense either, and other browsers don't do it that way.  So I think that this, too, is a bad idea.
I strongly disagree with this bug. I want JS to execute as soon as it can. Especially user/password prefills.

There's no point of any such delay.
(In reply to comment #27)
> I strongly disagree with this bug. I want JS to execute as soon as it can.
> Especially user/password prefills.
> 
> There's no point of any such delay.
> 

There are already ways to do that:

1) put it in the head
2) put it in an external file and call it from the head.

Either way, it will execute before the browser even begins to paint the page.
P.S., The whole point of tying a script to an event is to make sure it does not execute until the event has fired.  If you don't want to wait, don't tie it to an event.  But if you want to tie it to an event, we must count on the browser to fire that event accurately.  Firefox is not.  It is as simple as that.
We could just flip the pref in 1.9a1, sure.
Comment on attachment 222557 [details] [diff] [review]
flip the pref

Do this for now, then.
Attachment #222557 - Flags: superreview?(dbaron)
Attachment #222557 - Flags: review?(bzbarsky)
Attachment #222557 - Flags: review?(bzbarsky) → review+
I think what's important and useful about onload is that it fires after everything has loaded *as far as script can tell*. DOM and layout are stable and won't change anymore unless script itself changes them. This is a good, safe time for scripts to run that want to touch the DOM or do something that depends on the layout of the page.

I can't think of cases where in-page scripts need to know that all background images have loaded that aren't very contrived. Therefore I don't think that delaying firing onload until that time is useful.

On the other hand, fixing the original issue reported in this bug would make a lot of sense: delay notifying browser chrome such as the status bar, progress bar etc until all background images have finished loading.
(In reply to comment #32)
> I can't think of cases where in-page scripts need to know that all background
> images have loaded that aren't very contrived. Therefore I don't think that
> delaying firing onload until that time is useful.

I can provide two examples of sites that need to know background images have loaded before triggering window.onload.

http://www.sandbox-project.com
http://www.brianmaniere.com

At sandbox-project.com, css sets background images to build the interactive nav bar.  It also waits for window.onload to preload images that are not necessary for the immediate page, but may be necessary later due to user interactivity.  The "sand" image under the page title may rotate if the user clicks it, to cycle through alternate views of the sand.  These additional images are not necessary right away, but it is necessary to preload them after the page paints in order for them to load quickly should a user want to interactively click through them.  Because firefox fires window.onload before the nav bar images are painted, the nav bar stops painting once window.onload has fired, and waits for the additional images to be preloaded.  This is really ugly, and it is only ugly for Firefox users.  The way I have gotten around it for now is to use a setTimeout to delay the execution of the window.onlaod script for a few seconds, providing enough time for the nav bar images to fully paint (at least for most users).  I would rather not preload the navbar images.  Maybe it is tacky, but I like the way there is a rolling flicker from left to right across the nav bar as the tabs load their various colors.

brianmaniere.com is perhaps an even better example.  Like at sandbox-project.com, there are additional images available to this page that are not immediately necessary, but may be revealed later upon user interactivity.  The user may click the photo (or my name) and replacing the photo with a new one -- cycling through an set of many.  These images are of different sizes, so it is particularly important to preload them.  Otherwise the current image is resized to the dimensions of the next one and appears this way distorted until the next one has loaded.  I don't want to preload them before the page has painted because that would cause an annoying delay waiting for the page to first appear.  Like at sandbox-project.com, I have to implement a setTimeout to delay execution of the image preloading script in order to get around Frefox's premature firing of window.onload.

I hope you don't consider these cases contrived.  In any case, these sites work fine for all visitors except those using Firefox.  I would like them to look as good in Firefox as they do for everyone else.   Firefox users are my favorite visitors -- I'm one of them!  For now it is ok to use the setTimeout method, but that should not be necessary, it is extra code, extra delay, and I would rather not have to use it just for one browser.
(In reply to comment #33)
> Because firefox fires window.onload before the nav bar images
> are painted, the nav bar stops painting once window.onload has fired, and
> waits for the additional images to be preloaded.

I'm not sure why the nav bar would stop painting. Perhaps it's because its image loads are competing for network bandwidth with the scripted image loads, is that it?

If that's what it is, then we could perhaps address the problem by prioritizing CSS background image loads that were kicked off before "onload" fired above loads started after "onload" fired.
(In reply to comment #34)

> I'm not sure why the nav bar would stop painting. Perhaps it's because its
> image loads are competing for network bandwidth with the scripted image loads,
> is that it?

Yes, that could be it, and moreover, FF seems to give the scripted image loads priority.

> If that's what it is, then we could perhaps address the problem by prioritizing
> CSS background image loads that were kicked off before "onload" fired above
> loads started after "onload" fired.

That might work.  But I'm not sure FF is reliably kicking off the CSS background image loads before it fires window.onload.  Is there way to check?

I don't understand the inner workings of Firefox, so my apologoies for asking:  Are you suggesting a different approach to solving the problem than the one Gavin and Boris have been discussing?

If so, I don't know enough to have an opinion which approach is most appropriate.  But generally, I think we should look to standards for guidance.

Is there an official standard that specifies whether CSS background images are part of the window?

If not, is there a defacto standard, as determined by the established practice of the major browsers?

It seems like all the other major browsers treat css background images as if they are part of the window.  Or has anyone found a browser (besides FF) that does not?

If there is a standard, whether official or defacto, do we have a compelling reason to break it?

If not, I think it it is important for code to execute predictably cross-browser.  If there are two approaches to solving the problem, I think we should adopt the one that most closely matches the way other browsers handle it.

Sorry for my persistence about this.  I know much less about FF than most people here.  But I haven't seen a compelling reason to do it the current way, and it seems to me there are compelling reasons not to.  I guess I am stuck on that.

Thank you.
(In reply to comment #35)
> Yes, that could be it, and moreover, FF seems to give the scripted image loads
> priority.

Yes, those get priority over background images when scheduling HTTP requests.

> But I'm not sure FF is reliably kicking off the CSS
> background image loads before it fires window.onload.

It puts the background image loads in the HTTP queue before diring onload.  The requests may not have been made to the server yet.
Hi everyone,  just checking up on this.  Did this make it into 1.9a1, or has any other action been taken?

thanks.
Brian, the patch is waiting for reviews.
Flags: blocking1.9?
Whiteboard: [patch-r?]
I disagree with the latest patch here. I don't think we should hold off firing onload until background images are loaded.

Admittedly I don't fully understand brians explanation, so if I'm missing something please do let me know. But it seems like those examples just want certain images preloaded before onload fires. That has always been done using <img> tags. They are hacked such as they are loaded as soon as possible, and those loads block onload. This happens weather the images are displayed or not.

And if you want things to load and be displayed in a certain order you should use scripting, not rely on that network will deliver the images in a certain order.

Starting scripts earlier is going to help vastly more pages than the pages that are experiencing the problem brian has.

I do agree that we shold not display 'done' in the UI until backgrounds are shown though.
> I don't think we should hold off firing onload until background images are
> loaded.

Even for compat with other browsers?

> I do agree that we shold not display 'done' in the UI until backgrounds are
> shown though.

Then you have to break Necko API compat.
(In reply to comment #40)
> > I don't think we should hold off firing onload until background images are
> > loaded.
> 
> Even for compat with other browsers?

How do you define compat? Do sites really break over this, or are we mearly doing things differently from IE?

From what I understand from brians post he tries to preload images by setting CSS backgrounds, rather than by creating <img>s. I stronly doubt that this is common practice since I know both tools and conventions dating back to at least 1997 that did preloading using <img>s.

So I stronly suspect that what brian is doing is very rare (and has an easy fix). On top of that the sideeffect is 'mearly' graphical.

> > I do agree that we shold not display 'done' in the UI until backgrounds are
> > shown though.
> 
> Then you have to break Necko API compat.

Can't we add another notification for when background loads for a loadgroup are finished?
> From what I understand from brians post he tries to preload images by setting
> CSS backgrounds

I think you misunderstood (and looking at the actual page would make that pretty clear).  What Brian is doing, as far as I can tell, is preloading images using normal preload methods (img.src) in window.onload.  Then what happens is the following:

1)  Onload fires before backgrounds have loaded.
2)  Onload handler starts preloads
3)  Preloads have a higher priority than the background loads (see the end of
    NewImageChannel()).
4)  Whatever background loads have not started yet (that is, are waiting in the
    HTTP impl queue) will not start until all preloads are complete.
5)  As a result, backgrounds don't get painted until all image preloads are
    done, whenever that is.

There is no easy fix on Brian's end, and I'm pretty sure that doing image preloads from window.onload is not that rare.  I agree that the effect is largely cosmetic, but cosmetics are important on the web.

> Can't we add another notification for

Maybe to nsIWebProgressListener2.... maybe.
Hmm.. Ok, now I understand what's going on. Yes, that is indeed bad. I don't suppose it's possible to change the priority of the background images before onload fires so that they at that point are given equal priority with everything else?
It's possible, maybe.... darin would know better.
Boris described the isse clearly and accurately in comment #42.

It's worth nothing that a slew of popular "web standards" books reccommend using css background images for various cases, in order to get around some IE peculiarities among other things.  Zeldman's Designing with Web Standards is one example; pretty much all of Eric Meyer's books are more.  And yes, image preloading scripts are almost routinely attached to window.onload (or body.onload).  So although the issue is cosmetic, I believe it affects a lot of sites, and is a particular annoyance to the web designers who should be FF's biggest supporters-- those building with "web standards".

Besides, in this case, FF seems to be the exception that contradicts established expectations for browser behavior.  I think is a bad thing unless there is a really good reason.
I have ran into the problem described by this bug where onload is fired before the background images.

Like Brian, I am using onload to preload some images that are not a priority so I want to delay them until the page is done. Of course, because of the current default Mozilla behavior the background CSS images get delayed until all of images that my scripts load.

Background images are fairly common CSS trick to combat some of the IE's weirdness and to get repeat patterns so I cannot remove them. The images I am preloading the script are fairly large so the the user experience is seriously affected.

I will try to work around by delaying my preloaded images.

You have my vote for changing the default setting. I think onload should only be fired when the page has been loaded including background images; that is the most natural interpretation of the onload event.

Thanks for a great a browser.


We definitely should do something here, although I'm not sure exactly what.
Flags: blocking1.9?
Whiteboard: [patch-r?] → [patch-r?][wanted-1.9]
Another use case for fixing this is that we actually are adding things, like canvas drawWindow (accessible to chrome only), that will work or not depending on whether background images have loaded.  I think anything where it does matter is necessarily accessible to chrome only, though.
Actually, we might want to expose drawWindow to content, if we're really careful about it.

I still think we should just block onload on background loads....  It gives us compat with other UAs, and I'm seeing less and less of a difference between a background image and an <img> and a ":before { content: url() }" (both of which we block onload for).
(In reply to comment #49)
> It gives us compat with other UAs,

Hrm, I'd thought it was the other way around, but I don't actually see any data in the bug either way.

> and I'm seeing less and less of a difference between a
> background image and an <img> and a ":before { content: url() }" (both of which
> we block onload for).

The ones that do block onload can change the layout of the page, affecting various APIs that the page can use (offsetHeight, etc.).
Hmm.  I thought people had been reporting that IE now blocks onload on backgrounds, but I'm not sure whether I indeed saw this and if so where...
(In reply to comment #51)
> Hmm.  I thought people had been reporting that IE now blocks onload on
> backgrounds, but I'm not sure whether I indeed saw this and if so where...
> 

I just double checked and IE6 does block onload until backround images are loaded.
IE has been blocking onload until bqackground images have loaded since as far back as at least IE 5.  The whole rationale behind this bug report seems to be that FF is the only browser that does not.  To witness this, you can still compare different UAs on my demo page, which is still up:

http://www.sandbox-project.com/test.html
(In reply to comment #42)
[...]
> 4)  Whatever background loads have not started yet (that is, are waiting in the
>     HTTP impl queue) will not start until all preloads are complete.
[...]

Prioritizing has been mentioned. Shouldn't pipelining help as well?
According to <http://wiki.mozilla.org/Firefox3/StatusMeetings/2007-04-24>, enabling it is considered for Firefox 3.
(In reply to comment #53)
> IE has been blocking onload until bqackground images have loaded since as far
> back as at least IE 5.  The whole rationale behind this bug report seems to be
> that FF is the only browser that does not.  To witness this, you can still
> compare different UAs on my demo page, which is still up:
> 
> http://www.sandbox-project.com/test.html
> 
I get the "window onload has been triggered" pop-up from your testpage before all the images are painted under IE7.
QA Contact: ian → style-system
https://bugzilla.mozilla.org/show_bug.cgi?id=386620 may soon be declared a dupe of this bug. I just wanted to suggest that if this is true, then using reftest on http://www.w3.org/Style/CSS/Test/CSS2.1/current/t0905-c5525-fltmrgn-00-c-ag.htm may provide a nicely automatable way to test for the fix to this bug.
Comment on attachment 222557 [details] [diff] [review]
flip the pref

sr=dbaron.  Let's do it.
Attachment #222557 - Flags: superreview?(dbaron) → superreview+
Priority: -- → P2
Whiteboard: [patch-r?][wanted-1.9] → [wanted-1.9][checkin needed]
Target Milestone: mozilla1.9alpha1 → mozilla1.9beta1
Comment on attachment 222558 [details] [diff] [review]
remove the code

Er, we probably want this patch instead, so r+sr=dbaron.  This is simple enough to back out if we decide to change the other way.
Attachment #222558 - Flags: superreview+
Attachment #222558 - Flags: review+
(In reply to comment #55)
> I get the "window onload has been triggered" pop-up from your testpage before
> all the images are painted under IE7.

I just tested IE6, IE7, Safari 3 Beta, and Opera 9.21 on Windows, and they all match our behavior with this patch applied. IE doesn't display the image until the alert has been dismissed, but it does wait for it to be loaded before triggering onload, which is what we care about.
Attachment #222557 - Attachment is obsolete: true
Attachment #222558 - Attachment is obsolete: true
mozilla/layout/style/nsCSSDataBlock.cpp 	1.31
mozilla/layout/style/nsCSSValue.cpp 	1.42
mozilla/layout/style/nsCSSValue.h 	1.48
mozilla/content/html/content/src/nsGenericHTMLElement.cpp 	1.720
Status: ASSIGNED → RESOLVED
Closed: 17 years ago
Resolution: --- → FIXED
Whiteboard: [wanted-1.9][checkin needed] → [wanted-1.9]
Two questions now that this issue is fixed:

1) How will it affect nsIWebProgressListener? Will add-ons that implement this interface be notified when background images are being loaded (they are not currently being notified).

2) When should we expect it to be part of a 2.0.x release?
I don't know the answer to your first question, but the answer to your second is "almost certainly never".
nsIWebProgressListeners will now see background image loads.
Flags: in-testsuite?
Flags: wanted1.9+
Whiteboard: [wanted-1.9]
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: