I've been observing FOUCs on Special:UserLogin and Special:Preferences page since the ResourceLoader load order changes a few months ago. Several other users have also mentioned that they've also been observing this. On Special:Preferences, the behavior is especially ugly after form submission. The old success box is shown for a second and then the whole page changes and the mw.notification style message is shown later. This is really sad for a highly visible page like the login/signup form.
Description
Details
Related Objects
- Mentioned In
- rSVEV33d736d0f2f0: Rework Vector style of Preferences to prevent FOUC
T121221: Uncaught ReferenceError: jQuery is not defined with action=formedit on MW 1.26
T111685: Unstable interface bug in the Translate form
T112047: Special:ManageTranslatorSandbox fails to finish loading
T118339: Improve preferences styling of skins != Vector/Monobook
T110501: redirectToFragment script (redirects to section headers) behaving unreliably
T107399: Make top queue fully asynchronous
T109837: Remove top/bottom queue distinction - Mentioned Here
- T142129: Source code eval should be async in mw.loader.work
T109837: Remove top/bottom queue distinction
T112379: [Regression] Changing preferences while JS is loading will disable the save button after loading is finished
rMWc5c52ec1d8a2: resourceloader: Async all the way
T107399: Make top queue fully asynchronous
Event Timeline
Confirmed here, also on my private test wikis running git master and not much else. Almost always on Special:UserLogin. Also frequently seen on WMF wikis.
Putting
$ret .= $this->buildCssLinks() . "\n";
before
$ret .= $this->getInlineHeadScripts() . "\n";
in includes/OutputPage.php ca. line 2713 fixes the login page issue for me (not a proper solution, though)
Change 247624 had a related patch set uploaded (by saper):
Let CSS load before top JS queue starts
The preferences problem appears in wmf/1.26wmf17 and is not there with wmf/1.26wmf16, which suggests T107399 .
I see no way to fix this in the preferences, since preferences.js is already loaded as the "top" script, which should be executed early.
This is triggered by T107399 most likely indeed, but not "caused" in so far that the dependent styles for the basic layout should not be loaded with JavaScript in the first place.
Shuffling around the items in the DOM won't solve this. It may hide the bug when using a fast connection by disproportionally prioritising this particular script, but it's not a solution. (And will regress other things.)
The solution will most likely need to come from pinpointing why the layout is influenced by JavaScript, and making it render similarly without JavaScript (with JavaScript only expanding the layout, not necessarily changing the layout and positions of elements already there).
Also make sure the base styles for the view without JavaScript (yet) are loaded with addModuleStyles.
It should not be needed to load styles before the top queue starts, there is no FOUC for other things either (e.g. history page, article view, skin framework etc.). The order was carefully chosen and is unlikely to change because of this bug only.
Frankly I don't know why UserLogin is somehow special. Maybe additional top scripts weigh more.
But with 1.26wmf16 everything is much smoother. I also tried quickly reloading other pages and yes, you get a quick flash every 15 times or so - not a big problem but I think this indicates this is a general issue.
For UserLogin it is almost always, and very visible. Preferences are disaster imho.
As far as Preferences go, their top-loading script creates a whole ul#preftoc part (adds <ul> and <li>) for preferences tabs.
I think ages ago it was done in HTML, but got "modernized".
I was porting two new skins recently and I was scratching my head what is wrong.
I don't know why "top queue" gets delayed considerably, but effectively "top queue" gets reduced to a "slightly faster bottom queue", that's not good :(
I have tried commenting out all addModuleStyles and addModule out of the UserLogin page and I still keep getting this. Additional JS is only loaded in case of signup and it does not seem to smash DOM significantly.
One thing that Preferences and UserLogin have in common is a call to OutputPage::disallowUserJs()
` includes/specials/SpecialChangeEmail.php: $out->disallowUserJs(); includes/specials/SpecialChangePassword.php: $this->getOutput()->disallowUserJs(); includes/specials/SpecialJavaScriptTest.php: $out->disallowUserJs(); includes/specials/SpecialPreferences.php: $out->disallowUserJs(); # Prevent hijacked user scripts from sniffing passwords etc. includes/specials/SpecialResetTokens.php: $this->getOutput()->disallowUserJs(); includes/specials/SpecialUserlogin.php: $out->disallowUserJs(); // just in case... `
Try only commenting out addModule calls (keep addModuleStyles, since only the script queue has top/bottom separation) and work towards the resulting page rendering correctly with only the HTML response and style sheets.
This most likely means some of the styles will need to be extracted (if not already) into a styles-only module. And since interactive tabs require JavaScript, we do need some refactoring to make the no-js mode not broken (and kept as continuous page, like it is now). But the layout needs to be brought closer together.
Note you can also use .client-js and .client-nojs classes in CSS to differentiate with the target rendering. That way, the layout can have the tabs ready from the first render, without confusing the nojs mode.
What I wanted to say is that even the most conservative approach (no special page specific RL *modules at all*) triggers this bug.
I opened https://gerrit.wikimedia.org/r/#/c/247728 to refactor RL modules and start improving things.
Shall I open a separate bug for "Generate Special:Preferences tabs via HTML" to see if there is a general agreement to do so?
While I realize it may be annoying to obtain, is there a screenshot or frame capture for this issue on Special:UserLogin?
Another interesting effect which results from the delayed JavaScript execution: T112379
Change 250287 had a related patch set uploaded (by TheDJ):
Rework the Preferences to prevent FOUC
Change 250288 had a related patch set uploaded (by TheDJ):
Rework Vector style of Preferences to prevent FOUC
This issue has been independently confirmed by multiple people, so I am sure that it is real, but I have not been able to reproduce it.
If the bug only appears when network latency is sufficiently high, it might be possible to make it manifest reliably by inserting sleep() calls into the code.
Edit: I am able to reproduce this with the preferences page, but not the login page.
@ori Can you try getting enough latency by using Tor? I get it with Tor almost every time.
If you need latency and have a Mac, try using the Network Link Conditioner (NSHipster blog, Apple Download)
Change 251815 had a related patch set uploaded (by TheDJ):
Rework Monobook style of Preferences to prevent FOUC
Change 250288 merged by jenkins-bot:
Rework Vector style of Preferences to prevent FOUC
Change 251815 merged by jenkins-bot:
Rework Monobook style of Preferences to prevent FOUC
Change 251839 had a related patch set uploaded (by Ori.livneh):
Rework the Preferences to prevent FOUC
Change 251840 had a related patch set uploaded (by Ori.livneh):
Rework Vector style of Preferences to prevent FOUC
Change 251841 had a related patch set uploaded (by Ori.livneh):
Rework Monobook style of Preferences to prevent FOUC
Change 251840 merged by jenkins-bot:
Rework Vector style of Preferences to prevent FOUC
Change 251841 merged by jenkins-bot:
Rework Monobook style of Preferences to prevent FOUC
Change 251848 had a related patch set uploaded (by TheDJ):
Fix regression in I24d9b16
Thanks for working on this!
Looks like the "mw-preferences-messagebox successbox" doesn't get hidden anymore. Is that intentional? I can still observe it on the login page.
@Glaisher, yeah krinkle noticed that to, the "Fix regression in I24d9b16" patch will deal with that.
Regarding the Login page. I personally only experience this with Firefox. From what I can tell from the profile, it seems that the initial inline script tags trigger the first paint, and the parsing of the first stylesheet being done, triggers the second paint.
A diff of a random other page vs. login page.
Found it.
'mediawiki.special' => array( 'position' => 'top', 'scripts' => 'resources/src/mediawiki.special/mediawiki.special.js', 'styles' => 'resources/src/mediawiki.special/mediawiki.special.css', ),
+ Vector's skinStyles override of this. Actually, come to think of it, that was half of what was wrong with the styling of preferences as well...
This module is broken, but fixing it doesn't fix the login page on Firefox either.
edited because confusing
:( Or not.
I can still reproduce, even after fixing obvious things like that. And the weird thing is, I reworked the output to be almost equal to whatever is in any other page... The only thing i can imagine is that the startupmodule is at fault (different JS variables ?), or that it is a FF behavior, where sometimes the page is just layout'ed and painted before the first CSS stylesheet has finished downloading/parsing in a race condition.
This goes beyond my skill level now honestly.
I excluded: All the login specific styles, the mediawiki.ui styles, mediawiki.special styles. The Site modules (added or removed), skins (happens with monobook and vector). Even meta robots.
There is no easy answer. If the tabs are constructed in JavaScript, care should be taken to detect the hash during that construction so that the first appearance of the tabs is "correct" and there is no flash of the wrong tab. Using JavaScript however has the downside that instead of flashing the wrong tab, it would flash the whole page wrong (as was the case until recently).
Now that the tabs are built server-side, we can't initialise the tabs the same way since the hash fragment is unavailable to the server-side.
Two solutions come to mind:
- Use CSS tabs technique. This solution revolves around the :target CSS selector to associate the hash fragment with the selected tab and make it styled accordingly. I believe it is possible to do the whole preference panel this way, though it's not easy. See also https://css-tricks.com/css3-tabs/, https://css-tricks.com/functional-css-tabs-revisited/, and https://css-tricks.com/functional-css-tabs-re-revisited/. We may need JavaScript as a fallback to ensure all Grade A browsers function properly, but that would improve the UX at least for the majority of them and maintain status quo for the rest.
- Use the query string instead of hash fragment. Instead of using a hash fragment, we could use a query string instead. This way the server-side can preselect the appropiate tab automatically. In JavaScript, just like now, we could hijack the clicks and switch tabs accordingly. The browser address bar can be kept in sync using the History API.
Thanks @Krinkle. You are right we are talking here about server-generated HTML code and only the final touch (current selection) needs to be brought into play.
I am not thinking only about preferences here, there might be other areas were we might need just that. And now I've heard server-side generation is cool again.
Query string suggestion is actually very good. We could even use URL path for that. Just like in the good old 1997 :)
I'll try to have a look at the preferences code again.
Change 247624 abandoned by Krinkle:
Let CSS load before top JS queue starts
Reason:
Closing for now. Discussion continues on Phabricator.
Any updates on this? Are https://phabricator.wikimedia.org/T142129 and https://phabricator.wikimedia.org/T109837 supposed to fix this?
No. My previous recommendation still stands. We must not change the layout of the page client-side at page load. Rather it should be done server-side for the initial page load.
Taking a quick peek at this per an inquiry from @saper. Specifically looking at the login page...
I used to have the FOUC on login page constantly, but I'm unable to reproduce it on my laptop or desktop MW-Vagrant setups now with current master, even when throttling Firefox's network speed in the debug panel or adding sleep(10); to load.php. (Testing Firefox 61.0.2 on Linux and Mac.) Not sure yet if it's "fixed" or if I haven't found the right way to repro.
On Special:UserLogin, the HTML bits break down roughly:
doctype, charset, and title ... <script>... replace client-nojs with client-js ...</script> <script>... push variables and tokens and additional modules on the RL queue ...</script> <link rel="stylesheet" href="... RL styles ..."/> <script async="" src="... RL startup ..."></script> ... more metadata and body ... <script>... warn about deprecated modules and record the server execution time ...</script> end.
The synchronous <script>s are very simple, adjusting a class and appending stuff to a queue, and are all inline. The styles are linked before the RL startup code is loaded, but that's via a <script async> so shouldn't trigger rendering due to waiting (and if it did, you wouldn't see any text because that hasn't been parsed yet).
In my testing adding artificial delays on the styles but not on the scripts, I still don't see a FOUC -- just a blank page until it shows the login screen with styles.
@saper do you still see this on current master, and can you add some repro details if so? I really want this fixed up if it's still affecting people, as it's maddening. :)
Two years without updates later: Can anyone still reproduce this problem in 1.35 or current master?
If yes, then please provide clear steps to reproduce.
Otherwise this task will get closed (as it shouldn't become a catch-all for any FOUC issues).
Thanks.
No followup comments.
Assuming this is resolved nowadays (last comment successfully reproducing the problem was added 3 years ago).
If someone can still reproduce this problem, then please follow https://www.mediawiki.org/wiki/How_to_report_a_bug and create a new ticket.
Thanks a lot!