RfC: Allow styling in templates
Open, HighPublic40 Story Points

Subscribers
Tokens
"Like" token, awarded by IKhitron."Like" token, awarded by Sophivorus."Mountain of Wealth" token, awarded by RandomDSdevel."Like" token, awarded by Liuxinyu970226."Like" token, awarded by MartinK."Like" token, awarded by JMinor."Mountain of Wealth" token, awarded by Mrjohncummings."Yellow Medal" token, awarded by APerson."Barnstar" token, awarded by Jdforrester-WMF.
Assigned To
Authored By
Qgil, Sep 25 2014

Description

Currently the MediaWiki markup allows the inclusion of html elements with style attributes. Mixing layout with content causes various problems with reusability, maintainability and is not future proof. Already on the mobile version of MediaWiki problems are being seen with inline styles with how pages render on smaller screens which could be solved via css3 media queries, however these cannot be done in inline styles.

It should be possible for templates to have associated stylesheets so that media queries can be applied where necessary. This is related to T37704.

This RFC was proposed in 2013, discussed at two separate RFC meetings in 2014, and the status is unclear as of 2016-03-29. More detailed status in the comments of this task

Full writeup:
Allow styling in templates RfC.

Related Objects

StatusAssignedTask
OpenJdlrobson
OpenJdlrobson
OpenNone
OpenNone
ResolvedJdlrobson
StalledNone
OpenNone
OpenNone
ResolvedTheDJ
OpenNone
ResolvedTheDJ
ResolvedJdlrobson
OpenNone
DuplicateNone
OpenNone
OpenNone
Opencoren
ResolvedAnomie
OpenNone
OpenNone
There are a very large number of changes, so older changes are hidden. Show Older Changes

Coren, can you add parserfunctions extension to your experimental wiki ?
i'd like to test a few actual en.wiki templates, and almost all of those need parserfunctions and/or scribunto

In T483#2209633, @TheDJ wrote:

Coren, can you add parserfunctions extension to your experimental wiki ?
i'd like to test a few actual en.wiki templates, and almost all of those need parserfunctions and/or scribunto

Yeah, those and a couple others really - will do so shortly.

coren added a comment.Apr 15 2016, 1:14 PM

Done. I added ParserFunctions and Scribunto, and reimported Template:Wide image recursively to make sure it worked.

TheDJ added a comment.Apr 15 2016, 2:09 PM

Some first practical experiences:
1: i quickly found a situation, where in lieu of inline styles, i'll have to use a unique (per parserrun) class or ID. we have no good options for this right now. For now, i'll keep using inline styles for those situations. (width specific to the image being transcluded)
2: the style block should probably be inserted AFTER the <meta name="ResourceLoaderDynamicStyles" content=""/>
3: These style blocks will have to be exposed in the api, so that something like LivePreview can update them.
4: The style block will need an identifying attribute, so that something like livepreview can replace it.
5: Every conditional styling option of a template will require it's own class (always included). For instance, even if I don't use the border option of http://ts.wmflabs.org/w/index.php/Template:Wide_image, I will always have to include the .noborder styling class. This might be more bytes and more unused styling classes for uses of certain templates. Not really sure what to do about that... Tried using wikimarkup inside the style block, but that doesn't seem to work (and scary if it would..)

coren added a comment.EditedApr 15 2016, 3:59 PM
In T483#2209954, @TheDJ wrote:

Some first practical experiences:
1: i quickly found a situation, where in lieu of inline styles, i'll have to use a unique (per parserrun) class or ID. we have no good options for this right now. For now, i'll keep using inline styles for those situations. (width specific to the image being transcluded)

There isn't a good option for this that I can think of. Certainly, "new" best practices would be to avoid such parametrization entirely whenever at all possible since they play poorly with window width and mobile in all cases. I expect most cases can be reduced to a smaller set of limited options, though (say, "auto, 75%, 100%").

At the very least, it then becomes possible to override such variation in a @media block with a !important; so the situation is "less bad" than it otherwise might have been.

2: the style block should probably be inserted AFTER the <meta name="ResourceLoaderDynamicStyles" content=""/>

The point of insertion is actually picked by core (in OutputPage::addInlineStyle()); we'd need to check whether that's the best spot in all contexts.

3: These style blocks will have to be exposed in the api, so that something like LivePreview can update them.
4: The style block will need an identifying attribute, so that something like livepreview can replace it.

I'm not familiar enough with LivePreview to evaluate what that entails. I'll have to look into it.

5: Every conditional styling option of a template will require it's own class (always included). For instance, even if I don't use the border option of http://ts.wmflabs.org/w/index.php/Template:Wide_image, I will always have to include the .noborder styling class. This might be more bytes and more unused styling classes for uses of certain templates.

I expect that's not a significant issue in practice; that duplication is probably offset by the fact that multiple inclusions of the same template cause the styles to be inlined only once and that using a class more than once within the same template removes the repetition of the inline style.

That said, it's theoretically possible to omit classes that are not in fact used on the page - the selectors for every rule are known at the point of insertion. That would, however, require non-trivial parsing of the document and is probably best left to after we have determined that there is an issue to fix.

coren added a comment.Apr 15 2016, 4:03 PM
In T483#2209954, @TheDJ wrote:

Tried using wikimarkup inside the style block, but that doesn't seem to work (and scary if it would..)

That wouldn't have worked even if the tag was parsed: the stylesheet is parsed on save and stored as a page property for use by transcluding pages, so it cannot differ from one transclusion to another.

In T483#2209954, @TheDJ wrote:

Tried using wikimarkup inside the style block, but that doesn't seem to work (and scary if it would..)

What if you used {{#tag:templatestyles}} so the wikitext is processed? I'm not sure how the extension is storing the actual styles though.

coren added a comment.Apr 15 2016, 4:34 PM
In T483#2209954, @TheDJ wrote:

Tried using wikimarkup inside the style block, but that doesn't seem to work (and scary if it would..)

What if you used {{#tag:templatestyles}} so the wikitext is processed? I'm not sure how the extension is storing the actual styles though.

It's stored as a serialized parse tree of the rules; the processing would happen exactly once on save, then parsed as CSS and stored in a fixed format.

TheDJ added a comment.Apr 15 2016, 6:08 PM

Right, found a quite important point... We are now scoping using:
mw-body-content it seems. But that is a skin specific class, amongst others not used by the mobile minerva skin.

We have #mw-content-text that contains all generated output for wikitext pages, but more importantly the classes mw-content-ltr and mw-content-rtl.

coren added a comment.Apr 16 2016, 2:01 AM
In T483#2211010, @TheDJ wrote:

Right, found a quite important point... We are now scoping using:
mw-body-content it seems. But that is a skin specific class, amongst others not used by the mobile minerva skin.

We have #mw-content-text that contains all generated output for wikitext pages, but more importantly the classes mw-content-ltr and mw-content-rtl.

Aha. Good catch. Fixing.

Change 283772 had a related patch set uploaded (by coren):
Add unit tests for CSSParse and CSSRender

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

Stryn added a subscriber: Stryn.Apr 16 2016, 6:33 PM
In T483#2211010, @TheDJ wrote:

We have #mw-content-text that contains all generated output for wikitext pages, but more importantly the classes mw-content-ltr and mw-content-rtl.

Please note that in diff views, #mw-content-text also contains the table.diff element with the actual diff, revert links etc. It should probably be avoided that templates can leak styles into that area.

I don't know of any selector that precisely catches user-generated content. Currently, #mw-content-text is just an approximation.

It should probably be avoided that templates can leak styles into that area.

Actually, plenty of templates can appear outside 'content' space, such as edit notices. Those should be able to be styled. The risk of clashing CSS classes is pretty low anyway.

Restricted Application added a subscriber: TerraCodes. · View Herald TranscriptApr 19 2016, 3:30 PM
coren added a comment.Apr 20 2016, 2:32 AM

Actually, plenty of templates can appear outside 'content' space, such as edit notices. Those should be able to be styled. The risk of clashing CSS classes is pretty low anyway.

In addition to the desirability of avoiding clashes, there is also the issue that part of the objective of placing styling in templates is to allow non-administrator the ability to edit styles - which means that we need to protect most UI elements from accidental (or malicious) alteration.

It might be worthwhile to consider alternatives by which UI elements can be styled in controlled contexts, but I think this is a good project for a future version. :-)

jayvdb added a subscriber: jayvdb.Apr 20 2016, 2:41 AM

Would it be safer to introduce this feature as only available on admin-protected templates? Then we could relax that requirement gradually once the issues are better understood and have been prevented..?

I think scoping to #mw-content-text should be enough. Any tempate appearing outside actual content is usually protected anyway.

coren added a comment.Apr 20 2016, 4:11 PM

I think scoping to #mw-content-text should be enough. Any tempate appearing outside actual content is usually protected anyway.

I would tend to agree; let's not overcomplicate the first go at this and aim for an implementation that is simple to implement and describe: template styles allow styling of contents.

I think there's a good case to be made that styling UI elements is outside the scope of this extension; it's a marginal use at best and should probably be left to some other mechanism (especially since fiddling with the UI is very skin-specific and depends a great deal on the actual interface in use).

Change 283772 merged by jenkins-bot:
Add unit tests for CSSParse and CSSRender

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

With the latest rounds of merges, the TemplateStyles extension appears to be in a reasonable state and implements the major substantive part of this RfC as discussed in Jerusalem.

An interesting side effect of the current implementation is that a <templatestyles> tag appearing on a page not appearing in the list of allowed namespaces will not - as designed - affect pages transcluding it but it does style itself regardless of namespace.

I'm not sure that shouldn't simply be documented as a feature. :-)

brion added a comment.Apr 23 2016, 3:04 PM

Note that people do like to use templates outside the template NS, for user or project pages for instance. Not sure if we want to support that explicitly/implicitly/not at all, etc. :)

coren added a comment.Apr 23 2016, 4:46 PM
In T483#2232314, @brion wrote:

Note that people do like to use templates outside the template NS, for user or project pages for instance. Not sure if we want to support that explicitly/implicitly/not at all, etc. :)

It's supported via $wgTemplateStylesNamespaces; whether that is left to just Template: or not when that gets deployed to prod seems to me to be a decision best left to the individual communities.

brion added a comment.Apr 23 2016, 4:50 PM

It seems like an unnecessary burden on users to figure out why it didn't work and ask their communities for permission to change, on communities to deal with the question, and on wmf releng to handle updating the setting.

What downside is there to just having it always on everywhere?

In T483#2232450, @brion wrote:

on communities to deal with the question, and on wmf releng to handle updating the setting.

I don't know if you've been watching Wikimedia-Site-requests lately but the credit for handling that process really should go to the volunteers involved.

brion added a comment.Apr 23 2016, 6:40 PM

If volunteers are +2'ing config updates and deploying them, I'm impressed. :)

In T483#2232623, @brion wrote:

If volunteers are +2'ing config updates and deploying them, I'm impressed. :)

Regardless, it is probably worthwhile to ask what the communities around templates think before we figure it out - at least on the bigger projects. Ima do this this week.

TheDJ added a comment.EditedMay 12 2016, 5:04 PM

I was thinking a bit about variance, maintainability etc. And in the mobile-friendly content meeting we were also discussing: How do we document this so that editors know what they should do ?

Lets say we have a block like:

@media print and (min-width: 480px)

How do we make sure that not every single template has a different cutoff width and thus triggers a reflow? In every single language ?

This made me realize: We need to make this a less sheet and MediaWiki/Wikimedia should have a centralized less sheet with predefined variables, functions/mixins etc. We could properly document those variables and functions and use them in our examples. We could put complicated CSS magic in descriptively named functions/variables, so that people don't have to understand all the CSS details, they can just be "in this situation i need to use this function".

This would make templatestyles a lot more maintainable and consistent, still give lot's of flexibility to editors and also allow us to make changes from the MediaWiki/Wikimedia side.

GWicke added a subscriber: GWicke.EditedMay 12 2016, 5:17 PM

Adding the parsing team, as this would introduce page-global state, and also needs to work in Parsoid and VE.

coren added a comment.May 13 2016, 5:58 PM

Adding the parsing team, as this would introduce page-global state, and also needs to work in Parsoid and VE.

I've been pondering on that issue for a bit; clearly there needs to be an API endpoint for parsoid to hit - but I'm not certain what data would be most useful to return; would the final "merged" stylesheet be apropriate?

GWicke added a comment.EditedMay 13 2016, 7:14 PM

@coren: When implemented as proposed here, Parsoid and VisualEditor both would need to reimplement the same logic independently. Additionally, any application composing content on the client would need to implement similar aggregation passes, which would make our content a lot less modular than desirable.

There are alternatives that don't suffer from this issue:

Inline stylesheets

All modern browsers support <link rel="stylesheet"> in the body. While this was not sanctioned by the HTML4 spec, it has recently been allowed in the HTML5 spec. Chrome is explicitly working on further improvements in how it handles rendering of such styles. Among other things, the technique is used to speed up time to first paint by deferring the loading of below-fold CSS until it is needed.

While this could be used to pull in external styles, that would add some network requests. However, the styles we are talking about here should be fairly small, so inlining them would be preferable. This can be done using data URLs like this (tested in Chrome and Firefox, JSFiddle):

<body>
    <div id="mw12345">
        <link rel="stylesheet"
        href="data:text/css;base64,I213MTIzNDUgeyBjb2xvcjogcmVkIH0=">
        This text is styled red.
    </div>
</body>

This solves the primary issue of avoiding global state, but still requires styles to be explicitly prefixed to enforce scoping, for example by prefixing CSS selectors as in this example: #mw12345 { color: red }.

Shadow DOM

The Shadow DOM spec is aiming to fully encapsulate styling and DOM behavior of components. It is pushed by Google & others as the successor to <style scoped>. In recent months the spec has been shaping up quickly, but I expect it to still take some time until implementations are consistent enough & polyfills have caught up.

In summary, we might be able to leverage Shadow DOM for cleaner style isolation in the future, but for now inline stylesheets with selector prefixing should get us what we need while keeping page components self-contained.

coren added a comment.May 13 2016, 7:47 PM

All modern browsers support <link rel="stylesheet"> in the body

It's not immediately clear to me what the fundamental difference is between that and the current scheme (a <style> tag in the header)?

GWicke added a comment.EditedMay 13 2016, 7:53 PM

It's not immediately clear to me what the fundamental difference is between that and the current scheme (a <style> tag in the header)?

The <style> tag in the header requires a page-global aggregation pass to collect styles, which would need to be implemented in the PHP parser, Parsoid, VisualEditor, and any other application composing wiki content (such as apps).

The inline stylesheet on the other hand keeps each template expansion self-contained, and avoids the complexity of global passes. It is both easier to implement, and easier to consume.

In T483#2289858, @TheDJ wrote:

I was thinking a bit about variance, maintainability etc. And in the mobile-friendly content meeting we were also discussing: How do we document this so that editors know what they should do ?

Lets say we have a block like:

@media print and (min-width: 480px)

How do we make sure that not every single template has a different cutoff width and thus triggers a reflow? In every single language ?

This made me realize: We need to make this a less sheet and MediaWiki/Wikimedia should have a centralized less sheet with predefined variables, functions/mixins etc. We could properly document those variables and functions and use them in our examples. We could put complicated CSS magic in descriptively named functions/variables, so that people don't have to understand all the CSS details, they can just be "in this situation i need to use this function".

This would make templatestyles a lot more maintainable and consistent, still give lot's of flexibility to editors and also allow us to make changes from the MediaWiki/Wikimedia side.

👍 This seems very reasonable to me. From user experience _and_ developer perspective it makes sense to choose the media query breakpoints wisely and provide them in a central stylesheet. Less and future CSS offers this capability!

href="data:text/css;base64,I213MTIzNDUgeyBjb2xvcjogcmVkIH0=">

Just as side-note: Why would you base64 text? That might result in more data over the wire –after gzipping– like with SVGs laid out here.

Just as side-note: Why would you base64 text? That might result in more data over the wire –after gzipping– like with SVGs laid out here.

Good point! The following seems to work just as well:

<div id="mw12345">
  <link rel="stylesheet"
    href="data:text/css,#mw12345 { color: red }">
  This text is styled red.
</div>

The main limitation with data URLs is limited support in IE8. Only IE9+ supports stylesheets in data URLs. If we care about IE8, then we could create some JS for a read-only fix-up. VisualEditor does not support IE8, so there is no need to support the more complex editing scenarios.

We do care about IE 8, and even IE 6, as allowing users to view the site with correct styling is a basic core feature of MediaWiki, and therefore we should strive to support grade C browsers here. See https://www.mediawiki.org/wiki/Compatibility#Basic for details.

@GWicke Are you suggesting that we duplicate the template stylesheet for every template invocation? That's crazy, and it would be literally the opposite of what this feature is being developed for.

GWicke added a comment.EditedMay 13 2016, 10:52 PM

@matmarex, do you expect a drastic increase in the size of the CSS associated with templates? If anything, being able to migrate some inline styles to rules should reduce CSS size somewhat, and compression would pick up repetitions & avoid a significant impact on download sizes.

Less styles in the <head> can also unblock rendering of above-fold content more quickly, which matters especially on mobile (see T124966).

In any case, I would expect very frequently used transclusions like cite to still be predominantly styled globally. Changing some linked / global CSS is a lot cheaper than re-rendering all of Wikipedia to update a detail in citation styling.

We do care about IE 8, and even IE 6

The read-only JS fix for IE8 would work in earlier IE versions as well.

We do care about IE 8, and even IE 6, as allowing users to view the site with correct styling is a basic core feature of MediaWiki, and therefore we should strive to support grade C browsers here. See https://www.mediawiki.org/wiki/Compatibility#Basic for details.

I'm not sure about this requirement. Right now we are just talking about template styles. Would it be a travesty if these styles didn't apply but an IE6 browser could still use the content? If we were talking about disabling skin styles I would understand but an unstyled infobox is not the end of the world.

Jdforrester-WMF set the point value for this task to 40.May 16 2016, 8:30 AM

Hi @coren. We're looking at goal options for Reading Infrastructure in Q1 FY 2016-2017.

The question arose: is the following something that's still relevant and that you were thinking to pursue?

Safety/security notes:

  • need to parse/validate CSS rules for safety anyway -- avoid external refs, scary things
    • probably have to do a 'real' CSS parse rather than blacklisting a few keywords like we do on inline styles
    • doing this reliably may be the hardest part!

@coren, if it's not on your list (yet still in scope), we were thinking this might be something Reading Infrastructure could work on starting July 2016. If it's already on your list, we would consider a different Reading Infrastructure goal for Q1 FY 2016-2017.

CC @JKatzWMF, @Tgr, @Anomie

JMinor added a subscriber: JMinor.May 19 2016, 7:42 PM
In T483#2239190, @coren wrote:

Regardless, it is probably worthwhile to ask what the communities around templates think before we figure it out - at least on the bigger projects. Ima do this this week.

Is there any follow-up to this? I agree with Brion that restricting TemplateStyles to the Template namespace seems unnecessary. I'm pretty wary of global configuration variables, so if we can kill $wgTemplateStylesNamespaces, I think that's a win.

It's not immediately clear to me what the fundamental difference is between that and the current scheme (a <style> tag in the header)?

The <style> tag in the header requires a page-global aggregation pass to collect styles, which would need to be implemented in the PHP parser, Parsoid, VisualEditor, and any other application composing wiki content (such as apps).

The inline stylesheet on the other hand keeps each template expansion self-contained, and avoids the complexity of global passes. It is both easier to implement, and easier to consume.

I looked at T124966 a bit recently. The TemplateStyles extension is scheduled for a security review the week of May 30, according to T133408#2281285. Do you think your implementation concerns are hard blockers to deploying the TemplateStyles extension to Wikimedia wikis in the next few months?

In T483#2289858, @TheDJ wrote:

This made me realize: We need to make this a less sheet and MediaWiki/Wikimedia should have a centralized less sheet with predefined variables, functions/mixins etc. We could properly document those variables and functions and use them in our examples. We could put complicated CSS magic in descriptively named functions/variables, so that people don't have to understand all the CSS details, they can just be "in this situation i need to use this function".

It's funny, when I was skimming T133408 and starting to consider the various security concerns, one thought I had was "thank God we're not trying to start with a CSS preprocessor, variables and functions and a whole embedded programming language would make this crazy difficult to review." If we get really comfortable with being able to fully sanitize CSS output, I suppose adding a preprocessor wouldn't be totally insane. You'd still need to either do the processing client-side in JavaScript or do sandboxing server-side, the latter being similar to how we deal with embedded Lua, I believe.

I don't think we need to block the deployment of TemplateStyles over preprocessor support, though. Support for a preprocessor would probably happen in this extension at around the same time or after it happens for MediaWiki core (cf. T56864).

I'm hoping to find some time to play around with TemplateStyles this week. I'm curious whether features such as url() will be totally banned or only banned for non-Wikimedia domains. If we're going to disallow certain kinds of CSS (i.e., if we're only going to allow a subset of CSS), we'll want to make sure that the documentation and user interface both make this clear early and often to prevent headaches and frustration.

I'm hoping to find some time to play around with TemplateStyles this week. I'm curious whether features such as url() will be totally banned or only banned for non-Wikimedia domains. If we're going to disallow certain kinds of CSS (i.e., if we're only going to allow a subset of CSS), we'll want to make sure that the documentation and user interface both make this clear early and often to prevent headaches and frustration.

I presume that anything banned inline is banned in TemplateStyles as well, as they are both 'public access' so to speak. What would be cool is to have some directive to import stylesheets from MediaWiki: space, where CSS is unrestricted.

Bonvol added a subscriber: Bonvol.Jun 24 2016, 4:01 PM
MartinK added a subscriber: MartinK.
Tgr changed the status of subtask T133410: Deploy TemplateStyles to WMF production from Stalled to Open.Dec 9 2016, 11:58 PM
mxn added a subscriber: mxn.Jun 9 2017, 3:57 PM
Sophivorus added a subscriber: Sophivorus.
IKhitron added a subscriber: IKhitron.
This comment was removed by IKhitron.