Page MenuHomePhabricator

MediaWiki UI styles loaded in head but unused on most pages
Closed, DeclinedPublic

Description

mediawiki.ui.button, mediawiki.ui.anchor, mediawiki.ui.icon are loaded on all pages yet are only used in several JS workflows and on various special pages.
These should be loaded via JavaScript only when needed.
Note: On some pages this will create loading the file twice due to known RL bug T87871.

.mw-ui-button.mw-ui-big
.mw-ui-button.mw-ui-block
.mw-ui-button.mw-ui-progressive.mw-ui-quiet,.mw-ui-button.mw-ui-primary.mw-ui-quiet
.mw-ui-button.mw-ui-progressive.mw-ui-quiet:hover,.mw-ui-button.mw-ui-progressive.mw-ui-quiet:focus,.mw-ui-button.mw-ui-primary.mw-ui-quiet:hover,.mw-ui-button.mw-ui-primary.mw-ui-quiet:focus
.mw-ui-button.mw-ui-progressive.mw-ui-quiet:active,.mw-ui-button.mw-ui-progressive.mw-ui-quiet.mw-ui-checked,.mw-ui-button.mw-ui-primary.mw-ui-quiet:active,.mw-ui-button.mw-ui-primary.mw-ui-quiet.mw-ui-checked
.mw-ui-button.mw-ui-progressive.mw-ui-quiet:disabled,.mw-ui-button.mw-ui-primary.mw-ui-quiet:disabled
.mw-ui-button.mw-ui-constructive
.mw-ui-button.mw-ui-constructive:hover
.mw-ui-button.mw-ui-constructive:focus
.mw-ui-button.mw-ui-constructive:focus::-moz-focus-inner
.mw-ui-button.mw-ui-constructive:active,.mw-ui-button.mw-ui-constructive.mw-ui-checked
.mw-ui-button.mw-ui-constructive:disabled
.mw-ui-button.mw-ui-constructive:disabled:hover,.mw-ui-button.mw-ui-constructive:disabled:active,.mw-ui-button.mw-ui-constructive:disabled.mw-ui-checked
.mw-ui-button.mw-ui-constructive.mw-ui-quiet
.mw-ui-button.mw-ui-constructive.mw-ui-quiet:hover,.mw-ui-button.mw-ui-constructive.mw-ui-quiet:focus
.mw-ui-button.mw-ui-constructive.mw-ui-quiet:active,.mw-ui-button.mw-ui-constructive.mw-ui-quiet.mw-ui-checked
.mw-ui-button.mw-ui-constructive.mw-ui-quiet:disabled
.mw-ui-button.mw-ui-destructive
.mw-ui-button.mw-ui-destructive:hover
.mw-ui-button.mw-ui-destructive:focus
.mw-ui-button.mw-ui-destructive:focus::-moz-focus-inner
.mw-ui-button.mw-ui-destructive:active,.mw-ui-button.mw-ui-destructive.mw-ui-checked
.mw-ui-button.mw-ui-destructive:disabled
.mw-ui-button.mw-ui-destructive:disabled:hover,.mw-ui-button.mw-ui-destructive:disabled:active,.mw-ui-button.mw-ui-destructive:disabled.mw-ui-checked
.mw-ui-button.mw-ui-destructive.mw-ui-quiet
.mw-ui-button.mw-ui-destructive.mw-ui-quiet:hover,.mw-ui-button.mw-ui-destructive.mw-ui-quiet:focus
.mw-ui-button.mw-ui-destructive.mw-ui-quiet:active,.mw-ui-button.mw-ui-destructive.mw-ui-quiet.mw-ui-checked
.mw-ui-button.mw-ui-destructive.mw-ui-quiet:disabled
.mw-ui-button.mw-ui-quiet
.mw-ui-button.mw-ui-quiet:hover,.mw-ui-button.mw-ui-quiet:focus
.mw-ui-button.mw-ui-quiet:active,.mw-ui-button.mw-ui-quiet.mw-ui-checked
.mw-ui-button.mw-ui-quiet:disabled
.mw-ui-button.mw-ui-quiet:hover,.mw-ui-button.mw-ui-quiet:focus
.mw-ui-button.mw-ui-quiet:active,.mw-ui-button.mw-ui-quiet:disabled
a.mw-ui-button
a.mw-ui-button:hover,a.mw-ui-button:focus
.mw-ui-button-group > *
.mw-ui-button-group > *:first-child
.mw-ui-button-group > *:not(:first-child)
.mw-ui-button-group > *:last-child
.mw-ui-button-group
.mw-ui-button-group *
.mw-ui-button-group .mw-ui-block

Event Timeline

Jdlrobson assigned this task to Gilles.
Jdlrobson raised the priority of this task from to Medium.
Jdlrobson updated the task description. (Show Details)
Jdlrobson added subscribers: Jdlrobson, gerritbot, phuedx and 2 others.

They're available so content pages can use them...

Jdlrobson set Security to None.

I don't think this is an issue specific to mobile web, as these are seemingly coming from a piece of code in core that affects everything. If I follow what you're saying @Legoktm, users can invoke those styles from wikitext content, is that correct?

Now, regarding the bigger issue of all this loading in the head in general, the best course of action is probably to look at all the rules and see which ones need to be in the head. Some do, as on mobile for example the site header contains icons, a text input in general and a button in noJS mode, which if I'm following correctly, draw their styles from those modules. But for example, hover styles, active styles, focus styles, etc. could maybe afford to be loaded async after firstPaint with minimal impact on the UX, as most people would have the style loaded/cached by the time they hover or click one of these elements.

@Gilles currently they are just available and editors can change markup to make use of these classes. This is problematic as the majority of pages do not make use of them and they would be better loaded via JS.

Is there any way editors could invoke the loading of these styles on the pages that need them and we could only load them in the head for special pages which specifically depend on them?

I'm not familiar enough with our parsing architecture to know if it would be possible to add those modules to the page based on whether or not the wikitext served makes use of them. Maybe @GWicke would know?

Then there's the issue of gadgets, if these styles are used by them. I guess all they would have to do is to load these styles via JS before making use of them, just like we do. That's just a breaking change that would need to be communicated.

I would hazard a guess that usage of these is low enough for this to be manageable. Also long term it's been pretty clear that oojs ui is what editors will be expected to use which as far as I understand will require JavaScript cc @matmarex

Then there's the issue of gadgets, if these styles are used by them. I guess all they would have to do is to load these styles via JS before making use of them, just like we do. That's just a breaking change that would need to be communicated.

Gadgets should be generally expected to explicitly specify their dependencies regardless of what is being loaded by default, exactly so that making changes like this one is not impossible. This, at least, should be easy enough to check with the mwgrep tool and fix (hopefully there aren't hundreds of them).

I would hazard a guess that usage of these is low enough for this to be manageable. Also long term it's been pretty clear that oojs ui is what editors will be expected to use which as far as I understand will require JavaScript cc @matmarex

Actually, in spite of the name, OOjs UI widgets can exist without JavaScript (I've been trying to get it renamed to "OOUI"); there exists a parallel implementation in PHP, limited to the features that can be built with "static" HTML, but fully usable. We've been unofficially calling it OOUI PHP. It's already deployed and can be used: the Collection extension builds some pretty buttons with it, and I think Flow has began to adopt it too.

Is there any way editors could invoke the loading of these styles on the pages that need them and we could only load them in the head for special pages which specifically depend on them?

I'm not familiar enough with our parsing architecture to know if it would be possible to add those modules to the page based on whether or not the wikitext served makes use of them. Maybe @GWicke would know?

Right now we have no way to load these conditionally, but that could be easily solved in at least three ways:

  • A wikitext parser function that would add the necessary modules to the page's ParserOutput. This would be like three lines of code, the decision on whether to load the stuff would be off-loaded to the users. Existing usages would also have to be updated, and the new function documented.
  • A client-side loader in JavaScript, like we do for e.g. sortable tables in resources/src/mediawiki.page/mediawiki.page.ready.js. Seamless, but obviously JS-only.
  • Some server-side processing; we could parse the generated page HTML into DOM, traverse it and see if there are any interesting classes, and if yes, add the modules to the ParserOutput. This would be the best if we can pull it off, but I'm not sure how to. @Jdlrobson, you probably know more about this than me, since mobile web applies some DOM-based transformations to page content?

Then there's the issue of gadgets, if these styles are used by them. I guess all they would have to do is to load these styles via JS before making use of them, just like we do. That's just a breaking change that would need to be communicated.

Gadgets should be generally expected to explicitly specify their dependencies regardless of what is being loaded by default, exactly so that making changes like this one is not impossible. This, at least, should be easy enough to check with the mwgrep tool and fix (hopefully there aren't hundreds of them).

I would hazard a guess that usage of these is low enough for this to be manageable. Also long term it's been pretty clear that oojs ui is what editors will be expected to use which as far as I understand will require JavaScript cc @matmarex

Actually, in spite of the name, OOjs UI widgets can exist without JavaScript (I've been trying to get it renamed to "OOUI"); there exists a parallel implementation in PHP, limited to the features that can be built with "static" HTML, but fully usable. We've been unofficially calling it OOUI PHP. It's already deployed and can be used: the Collection extension builds some pretty buttons with it, and I think Flow has began to adopt it too.

Sure but how are we planning to allow /editors/ to invoke them? Are we going to create OOLua UI, or will editors have to replicate the markup? What I was getting at is that this is the reason @Legoktm says they are in the head in the first place for all pages and not loaded on an as-needed basis.

Is there any way editors could invoke the loading of these styles on the pages that need them and we could only load them in the head for special pages which specifically depend on them?

I'm not familiar enough with our parsing architecture to know if it would be possible to add those modules to the page based on whether or not the wikitext served makes use of them. Maybe @GWicke would know?

Right now we have no way to load these conditionally, but that could be easily solved in at least three ways:

  • A wikitext parser function that would add the necessary modules to the page's ParserOutput. This would be like three lines of code, the decision on whether to load the stuff would be off-loaded to the users. Existing usages would also have to be updated, and the new function documented.

Personally I would like the styles to be loaded on a basis
e.g. {{oojsui|button|options}} causes the loading of the appropriate modules.
Allowing editors to decide when styles should be loaded is dangerous as it could lead to pages which load the styles but do not makeuse of them.

  • A client-side loader in JavaScript, like we do for e.g. sortable tables in resources/src/mediawiki.page/mediawiki.page.ready.js. Seamless, but obviously JS-only.
  • Some server-side processing; we could parse the generated page HTML into DOM, traverse it and see if there are any interesting classes, and if yes, add the modules to the ParserOutput. This would be the best if we can pull it off, but I'm not sure how to. @Jdlrobson, you probably know more about this than me, since mobile web applies some DOM-based transformations to page content?

We're hoping to use Parsoid and not do any DOM traversal before output. Ideally, we should parse once, work out RL modules needed and store that along side - maybe as a page property. Wondering what ideas @GWicke might have around this...?

@Gilles has suggested hover styles should be moved to the bottom of the page and we could load a lighterweight alternative at the top of the page.

This bug is weird, we're doing this intentionally thanks to @kaldari et al's work at the end of 2013. To quote myself from gerrit 114085:
"Wikis have too many templates like commons:Template:Clickable_button dependent on jquery.ui.button that don't work if JavaScript isn't enabled. mediawiki.ui.button is a lighter-weight piece of CSS that we own and can improve, and transitioning wiki content to it requires that we provide it."

If I follow what you're saying @Legoktm, users can invoke those styles from wikitext content, is that correct?

Yes, and they do. WMF (specifically Steven Walling ad hoc after hours as I recall) told the community that Agora, now mediawiki.ui, is the future, and so we intentionally ship this subset of it on every page (see gerrit 114085 and gerrit 98869) to evolve from the unmitigated crap of the aforementioned {{clickable button}} and enwiki's {{Blue button}} (1.6kB of CSS every time the template is used) and to promote UI-Standardization instead of 15+ different button templates on each major wiki.

So we shouldn't get rid of this until we have something better.

they would be better loaded via JS.

That seems a non-starter for wikitext templates and raw <span class="mw-ui-button" ...> unless someone can demonstrate their use across 800 wikis is JS-only.

Sure but how are we planning to allow /editors/ to invoke them? Are we going to create OOLua UI, or will editors have to replicate the markup?

Wiki editors could change a wikitext template like {{Blue button}} to replicate the complex divs and spans and classes of OOUI, but that seems really prone to error. OOUI isn't suited for raw <span class="">, the product manager for UI standardization should be deprecating that.

Personally I would like the styles to be loaded on a basis
e.g. {{oojsui|button|options}} causes the loading of the appropriate modules.

That looks like a wikitext template. AIUI a wikitext template can't load JavaScript, nor can a Lua module.

The existing common use of button templates in wikitext templates has to have some fallback for no-JavaScript, so might as well be OOUI PHP, so this might as well be a PHP parser function {{#ooui: button|options}} that does the right thing. This avoids needing to do implicit page parsing for OOUI elements, because it's telling the parser to put OOUI PHP in its output. Is there a Phab task to create such a parser function?

For JavaScript-only button uses, wiki gadget writers can already write JS that does

mw.loader.using( 'oojs-ui', function() {
   // build my UI with OOjs UI like VE and OOjs UI sample code.
} );

The existing common use of button templates in wikitext templates has to have some fallback for no-JavaScript, so might as well be OOUI PHP, so this might as well be a PHP parser function {{OOUI: button|options}} that does the right thing. This avoids needing to do implicit page parsing for OOUI elements, because it's telling the parser to put OOUI PHP in its output. Is there a Phab task to create such a parser function?

There was T88026, which is marked as resolved, but the code is not live on Wikimedia wikis and possibly not actually merged, just up for review? The syntax there is rather "unidiomatic" in wikitext and apparently unsafe by design (may allow generation of arbitrary HTML), so we'd probably need to start from scratch anyway.

The bug is not that weird.
The fact is no matter the good intentions, MediaWiki UI styles are barely being used by template editors. They are loaded in the head and block rendering of the page.

To follow on from @matmarex 's comment I would personally like to see them limited to special pages and JavaScript usage from now until we have a viable alternative.

Buttons with these styles are used prominently on some help pages on the Polish Wikipedia: e.g. https://pl.wikipedia.org/wiki/Pomoc:Pierwsze_kroki (linked from main page and sidebar) or https://pl.wikipedia.org/wiki/Pomoc:Przewodnicy.

'mediawiki.ui.button' module (the only one loaded everywhere) is only 6.5 kB according to output of mw.loader.inspect(), or about 1 kB gzipped. I welcome page size concerns, but do we really not have bigger fish to fry?

('mediawiki.ui.anchor' and 'mediawiki.ui.icon' mentioned in task description are not used by core at all, and as far as I'm concerned you can kill them anytime. Some other 'mediawiki.ui.*' modules are loaded only when actually needed on some special pages.)

(Speaking of mobile only, the module seems to necessary on (almost?) all pages to style the 'Read in another language' button at the bottom.)

on (almost?) all pages to style the 'Read in another language' button at the bottom.

If the page has versions in other languages: yes, it's needed :)

... a PHP parser function {{OOUI: button|options}} that does the right thing for [button templates in wikitext]... Is there a Phab task to create such a parser function?

There was T88026, which is marked as resolved,

As I understood it, that bug was filed in the context of the Living style guide, which needs to create sample OOUI elements in wiki text. So Extension:OOUIPlayground implements an <ooui-demo> tag containing widget JSON parameters that turns into PHP widget invocation. It's solid code similar to what wiki pages need, but AFAICT it doesn't implement action or linking. So I filed T101666: Create parser tag(s) that render OOUI PHP widgets.

but the code is not live on Wikimedia wikis

OOUIPlayground is solely live on the LSG site, until T93610.

Change 235289 had a related patch set uploaded (by Ori.livneh):
Deprecate unconditional loading of mediawiki.ui.button on all pages

https://gerrit.wikimedia.org/r/235289

Change 235286 had a related patch set uploaded (by Ori.livneh):
Deprecate unconditional loading of mediawiki.ui.button on all pages

https://gerrit.wikimedia.org/r/235286

Can I suggest we make this module position bottom.

In terms of avoiding flashes of unstyled content I think the best solution for mobile would be to have a lightweight base mediawiki ui style file which loads in the top (either in core or in MobileFrontend - preferably former) which sets width and height and padding of elements (all the hover and colouring can come from styles in the bottom).

Change 235289 merged by jenkins-bot:
Deprecate unconditional loading of mediawiki.ui.button on all pages

https://gerrit.wikimedia.org/r/235289

Change 235297 had a related patch set uploaded (by Jdlrobson):
Load mediawiki.ui.button and icon styles at bottom of page.

https://gerrit.wikimedia.org/r/235297

Change 235286 merged by jenkins-bot:
Deprecate unconditional loading of mediawiki.ui.button on all pages

https://gerrit.wikimedia.org/r/235286

Change 235297 had a related patch set uploaded (by Legoktm):
Load mediawiki.ui.button anchor and icon styles at bottom of page.

https://gerrit.wikimedia.org/r/235297

Change 235297 abandoned by Jdlrobson:
Load mediawiki.ui.button anchor and icon styles at bottom of page.

https://gerrit.wikimedia.org/r/235297

Moved out of sprint and abandoned patch. Not sure of path forward at current time. Button hover styles for instance are needed for non-js users but are unnecessarily loaded at top.

Given:
"The Performance Team is looking to re-consolidate the stylesheet queue back into top-only over the next quarter (done last week in b7c0e537e; but held out of deployment until we have better metrics to prove it). The split was an experiment that only started a few weeks ago with an ad-hoc implementation (to split them up). I don't believe it improved rendering or performance."
guidance would be appreciated from the perf team.

Jdlrobson claimed this task.

Given the buttons are 1.2kb and with a page with a language button with JavaScript disabled the only unused css rules relating to buttons are small, I'm going to decline this as a micro-optimisation.

For the record these are the css rules we currently don't use:
.mw-ui-button.mw-ui-big
.mw-ui-button.mw-ui-block
.mw-ui-button.mw-ui-progressive.mw-ui-quiet,.mw-ui-button.mw-ui-primary.mw-ui-quiet
.mw-ui-button.mw-ui-progressive.mw-ui-quiet:hover,.mw-ui-button.mw-ui-primary.mw-ui-quiet:hover,.mw-ui-button.mw-ui-progressive.mw-ui-quiet:focus,.mw-ui-button.mw-ui-primary.mw-ui-quiet:focus
.mw-ui-button.mw-ui-progressive.mw-ui-quiet:active,.mw-ui-button.mw-ui-primary.mw-ui-quiet:active,.mw-ui-button.mw-ui-progressive.mw-ui-quiet.mw-ui-checked,.mw-ui-button.mw-ui-primary.mw-ui-quiet.mw-ui-checked
.mw-ui-button.mw-ui-progressive.mw-ui-quiet:disabled,.mw-ui-button.mw-ui-primary.mw-ui-quiet:disabled
.mw-ui-button.mw-ui-constructive
.mw-ui-button.mw-ui-constructive:hover
.mw-ui-button.mw-ui-constructive:focus
.mw-ui-button.mw-ui-constructive:focus::-moz-focus-inner
.mw-ui-button.mw-ui-constructive:active,.mw-ui-button.mw-ui-constructive.mw-ui-checked
.mw-ui-button.mw-ui-constructive:disabled
.mw-ui-button.mw-ui-constructive:disabled:hover,.mw-ui-button.mw-ui-constructive:disabled:active,.mw-ui-button.mw-ui-constructive:disabled.mw-ui-checked
.mw-ui-button.mw-ui-constructive.mw-ui-quiet
.mw-ui-button.mw-ui-constructive.mw-ui-quiet:hover,.mw-ui-button.mw-ui-constructive.mw-ui-quiet:focus
.mw-ui-button.mw-ui-constructive.mw-ui-quiet:active,.mw-ui-button.mw-ui-constructive.mw-ui-quiet.mw-ui-checked
.mw-ui-button.mw-ui-constructive.mw-ui-quiet:disabled
.mw-ui-button.mw-ui-destructive
.mw-ui-button.mw-ui-destructive:hover
.mw-ui-button.mw-ui-destructive:focus
.mw-ui-button.mw-ui-destructive:focus::-moz-focus-inner
.mw-ui-button.mw-ui-destructive:active,.mw-ui-button.mw-ui-destructive.mw-ui-checked
.mw-ui-button.mw-ui-destructive:disabled
.mw-ui-button.mw-ui-destructive:disabled:hover,.mw-ui-button.mw-ui-destructive:disabled:active,.mw-ui-button.mw-ui-destructive:disabled.mw-ui-checked
.mw-ui-button.mw-ui-destructive.mw-ui-quiet
.mw-ui-button.mw-ui-destructive.mw-ui-quiet:hover,.mw-ui-button.mw-ui-destructive.mw-ui-quiet:focus
.mw-ui-button.mw-ui-destructive.mw-ui-quiet:active,.mw-ui-button.mw-ui-destructive.mw-ui-quiet.mw-ui-checked
.mw-ui-button.mw-ui-destructive.mw-ui-quiet:disabled
.mw-ui-button.mw-ui-quiet
.mw-ui-button.mw-ui-quiet:hover,.mw-ui-button.mw-ui-quiet:focus
.mw-ui-button.mw-ui-quiet:active,.mw-ui-button.mw-ui-quiet.mw-ui-checked
.mw-ui-button.mw-ui-quiet:disabled
.mw-ui-button.mw-ui-quiet:hover,.mw-ui-button.mw-ui-quiet:focus
.mw-ui-button.mw-ui-quiet:active,.mw-ui-button.mw-ui-quiet:disabled
.mw-ui-button-group > *
.mw-ui-button-group > *:first-child
.mw-ui-button-group > *:not(:first-child)
.mw-ui-button-group > *:last-child
.mw-ui-icon.mw-ui-icon-before:before