Bug Tracker

Opened 10 years ago

Closed 10 years ago

Last modified 8 years ago

#5743 closed bug (wontfix)

Firefox: Showing hidden Element containing scrollable Content causes Page Flicker

Reported by: bht Owned by:
Priority: major Milestone: 1.4
Component: dimensions Version: 1.3.2
Keywords: Cc:
Blocked by: Blocking:

Description

The attached testcase (Firefox only) demonstrates that a page flickers when jQuery basic style manipulation is used in one line of code to show a hidden div.

A switch in the source code var useJQuery = true/false; can be used to switch to style manipulation without jQuery where the same action does not produce any flicker.

Unfortunately I could not create any workaround for this.

The page flicker might be not so dramatic in this testcase, or not even visible on fast computers, but with complex pages it is extreme.

Attachments (5)

ScrollFlicker.html (11.5 KB) - added by bht 10 years ago.
Testcase (plain HTML)
ScrollFlickerSimple.html (11.3 KB) - added by bht 10 years ago.
Simplified testcase
ScrollFlickerSimple2.html (11.6 KB) - added by bht 10 years ago.
Simplified again, removed "display: none" as advised
MooToolsScrollFlickerSimple.html (10.0 KB) - added by bht 10 years ago.
Same testcase works with MooTools
mySolution.html (11.5 KB) - added by Šime Vidas 10 years ago.

Download all attachments as: .zip

Change History (18)

Changed 10 years ago by bht

Attachment: ScrollFlicker.html added

Testcase (plain HTML)

comment:1 Changed 10 years ago by bht

The new testcase demonstrates that page flicker occurs without CSS manipulation.

In a jQuery declared read-only call css(), jQuery.swap() is called internally that writes three browser css attributes that may cause a page refresh.

No wonder that the pages flicker.

Changed 10 years ago by bht

Attachment: ScrollFlickerSimple.html added

Simplified testcase

comment:2 Changed 10 years ago by john

Component: unfilleddimensions
Resolution: wontfix
Status: newclosed

Unfortunately there really is no fix for this - if an element is display: none you have to change its display before you can get its height and width.

Changed 10 years ago by bht

Attachment: ScrollFlickerSimple2.html added

Simplified again, removed "display: none" as advised

comment:3 Changed 10 years ago by bht

Resolution: wontfix
Status: closedreopened

In the new testcase ScrollFlickerSimple2.html, I removed display: none as advised. In addition, the testcase is more simplified than before: It uses only generic jQuery show() and hide() so that is now 100% jQuery compliant; no more direct CSS manipulation to hide and show.

So I am told that it is not possible to get the CSS attributes of an element that is hidden using standard jQuery methods.

This does not make sense, and I cannot accept that. In comparison, this is entirely possible for example with using native DOM methods, or using the MooTools toolkit. I will attach a version of the testcase that works fine with MooTools.

Changed 10 years ago by bht

Same testcase works with MooTools

comment:4 Changed 10 years ago by scottgonzalez

The MooTools test and the jQuery test are not equivalent. You're asking MooTools for a value from the element's style property and you're asking jQuery for the outerwidth. The jQuery equivalent of your MooTools code would be .css('width') not .outerWidth().

comment:5 Changed 10 years ago by bht

Scott, I don't claim that these testases are equivalent. And I don't want to distract from the original issue. May be there is an equivalent of outerWidth() in MooTools. I don't know MooTools well enough. I don't even know jQuery well enough. But whatever I throw at MooTools, it does not flicker.

The issue is that I use a minimal set of functions out of the (jQuery) box: show(), hide(), outerWidth(), and that flickers. With this new testcase we now have multiple combinations with different methods that show the same flicker behavior, which is caused by the swap() call on line 773 of the referenced jQuery library.

There is a number of combinations where jQuery flickers, and there is a number of combinations where it does not flicker. This issue is only about the flicker cases.

Changed 10 years ago by Šime Vidas

Attachment: mySolution.html added

comment:6 Changed 10 years ago by Šime Vidas

My solutions:

a) use the css() method to rerieve the dimensions of the box

or

b) save the outerWidth() return value with the data() method every time you hide the box, so that you can use box.data("outerWidth") instead of box.outerWidth()

comment:7 Changed 10 years ago by scottgonzalez

Resolution: wontfix
Status: reopenedclosed

The point is, as John said, that it's not possible to remove the flicker. The only reason I pointed out that the test cases were not equivalent is because you insisted it was possible by showing that it worked with MooTools, when in fact you did not show that at all.

I also pointed this out because you said, "So I am told that it is not possible to get the CSS attributes of an element that is hidden using standard jQuery methods." This is absolutely not true, use .css() as I mentioned.

comment:8 Changed 10 years ago by bht

Resolution: wontfix
Status: closedreopened

Scott,

You, as the software provider or authorized by him, are closing a bug without fixing it, based on information from workarounds that the requester/users provided. My attached testcases provide such workarounds, and I can produce any number of them.

As I wrote before, it is an obvious fallacy that other use cases that bypass the bug (e.g. your suggestion to use the css() method), can be used as proof to invalidate the original case.

This is very disappointing because the issue is at the heart of a core jQuery competency - providing a more reliable and simplified cross-browser API.

The bug has been pinpointed:

jQuery actively creates flicker via its own DOM manipulation in the css() call via swap(). Therefore, flicker can only be avoided if the caller is lucky enough to anticipate and match the values that jQuery sets so that the browser ignores them instead of executing them.

Sure, we are able to create such a case specific lucky situation here and say: Where is the problem? That is what you are doing, and this is unprofessional, deceiving and distracting.

It is ridiculous to suggest that I use the method (css()) that causes the flicker - to work around the flicker.

Can't you see that you have gone full circle based on the variety of testcases?

I have now created multiple extremely simple, distinct testcases that produce the same behavior. Let me add one more, lifting the total of failing different cases to three:

jQuery.show(); jQuery.hide(); jQuery.width(); Flickers

This is standard, bare-bones, consistent, by the book jQuery API use.

GUI toolkits, including browsers, provide non-destructive methods to measure components before showing them. Why should jQuery be the exception?

I am suggesting that this issue is treated as what it is, a bug in the framework. More specifically, I am requesting that the aggresive call of the swap() method is replaced by defensive code.

comment:9 Changed 10 years ago by dmethvin

Resolution: wontfix
Status: reopenedclosed

bht, the .swap() method is there because painful experienced showed that it was the best reasonable way to get the true width/height of the element. Maybe we've missed something. The bug was closed as wontfix because we don't know of a reasonable way to fix it -- think of it as cannotfix if you prefer. Do you have a patched version of jQuery that fixes the issue you've identified without regressions on the major browsers? Otherwise we've reached a dead end.

I'll close the ticket again, please don't reopen it unless you have a fix. If you think others with more programming experience may be able to help you in finding a solution, ask on the jQuery-dev forum.

comment:10 Changed 10 years ago by john

"GUI toolkits, including browsers, provide non-destructive methods to measure components before showing them."

If they do then they don't expose it to JavaScript. As it stands we're using the best possible technique to determine the dimensions of the element. As mentioned before, if an alternative to swapping is found then we will happily switch to it.

Using visibility: hidden/visible instead of display is not an acceptable solution. Elements that are visibility: hidden can still be interacted with and change the flow of the page - it is not comparable to display: none.

So, please, unless an alternative solution to swapping the display is found I consider this issue to be closed.

comment:11 Changed 10 years ago by bht

John,

I appreciate the painful efforts to provide the dimensions of an element.

Since the beginning of this, when I read the swap() call, I totally understood the dilemma.

However with the current implementation it appears that jQuery goes one step too far in providing information that may not exist in the browser at the time of the call in cases other than this.

It forces the browser, via side effect, to provide it ahead of time, and this is causing trouble.

By updating the browser with swap(), indiscriminitely, flicker is created also in cases such as this where without the call the information is in fact available at the time of the call.

Updating the machine (browser) e.g. via swap() when in fact only information about its state not an update of its state is required is by definition aggressive or destructive because it destroys the current state of the machine.

That is what I consider illegal. Let me provide an analogy. In a motor vehicle with a water cooled engine, you may want to read the oil pressure electronically.

Consider an electic circuit with interfaces to all engine functions including oil pressure measurement.

1) If the engine is stopped, is the circuit starting the engine if you get a request for reading the oil pressure?

No, because a mechanic might have his hands in the gear.

2) Is the circuit starting the engine even if it is already running?

No, because this will ruin the starter motor.

The correct answers are: 1) The motor is not running 2) Get the pressure, don't start the motor

swap() gets both answers wrong.

comment:12 Changed 10 years ago by bht

Resolution: wontfix
Status: closedreopened

Re-opening because it is a verified bug in jQuery that requires a solution.

It is unusual to close a bug before a solution is found to fix it.

We should give the community a chance to find a solution as John suggested.

This can only happen if the bug is open otherwise we will prevent a solution.

comment:13 Changed 10 years ago by john

Resolution: wontfix
Status: reopenedclosed

Nothing is preventing a solution by having the bug be closed - which is the correct state. As always, if someone comes up with a real solution here (a way to get the height/width of a display: none element without having to first show it) we will happily land it. Please don't re-open the bug unless there is a solution attached.

Note: See TracTickets for help on using tickets.