Requests for comment/LESS

This document proposes adopting LESS as a stylesheet language in core.

What is LESS?
LESS is a stylesheet language that compiles into CSS. LESS is a superset of CSS: any valid CSS code is also valid LESS. LESS extends CSS with variables, mixins, operations, and functions. These abstractions provide a means for writing concise and well-factored stylesheets that derive the styling of individual interface components from a core set of definitions.

Code samples
As an example, let's use LESS to refactor some actual CSS code in core:

The first thing we'll do is use LESS's ability to concisely express inheritance and cascade by nesting selectors:

If you look closely at the rules for  and , you'll notice that they share a common pattern of setting a background color on an input element and declaring a one-pixel border on that element that is painted a slightly darker shade of that color (12.5% darker, to be exact). LESS allows us to express this pattern as a mixin. At their most basic, mixins are simply a shorthand for a group of CSS rules that go together. More sophisticated mixins can take parameters:

You may also notice that the colors used to style the valid & invalid input boxes form two-thirds of a triadic color scheme. (Triadic color schemes consist of three colors that are equidistant from each other on the color wheel.) LESS allows us to assign these colors human-readable names and gives us functions we can use to derive harmonious color themes from a base color:

Because we'd like to build up a library of generic style components, we defined our mixin and variables in. To use these definitions in, we use the   directive. The final result looks like this:

Why use a CSS preprocessor?
Using any CSS preprocessor makes your code easier to write, reuse and maintain by adding features such as...


 * mixins, which allows you to embed a rule into another rule, and then extend it with further arguments;
 * variables, which let you define and then reuse values throughout a stylesheet, leading to more consistent design;
 * and nesting, which can clarify how rules inherit from each other and helps avoid unnecessary repetition. Having more concise stylesheets and clearer relationships between styles means that refactoring is easier and diffs are cleaner.

In addition to making stylesheets less of a pain for you to create, the above features can make an open source project easier to customize and extend. For a great example of this in action, check out the very popular Bootstrap project's use of LESS. By writing the core variables that define Bootstrap styles in LESS, as well as making these variables respond to each other in terms of their derived color balance, contrast, spacing, and size, the project makes it exceedingly easy to change the styles overall. Wikia, which uses Sass/SCSS, takes this strategy and runs with it. Their ThemeCustomizer GUI references and updates Sass variables to allow end users to pick text color, links, background color and few other elements of the page.

Why LESS? Why not SCSS / Sass?
LESS is one of the most popular and stable CSS preprocessors. Sass is another excellent CSS preprocessor. The E3 team made extensive use of Sass in our work to update the login and account creation interfaces and found it to be an excellent tool. Comparisons of LESS and Sass often give undue emphasis to minor differences in syntax, but it's important not to lose sight of the broad overlap that exists between these two tools. They are very similar. Our preference for LESS stems from a preference for its PHP implementation: we like its documentation and its large suite of unit tests, and we see the change log and the history of activity on its issue tracker as indicators of a healthy open-source project.

If this RFC is implemented, we will convert the existing SCSS code in core to LESS, and remove the special make process for that.

Case study: LESS in MobileFrontend
Moving to LESS from CSS was a very easy transition for the Wikimedia mobile web team working on the MobileFrontend extension &mdash; it was a simple rename:

Amongst various other reasons using LESS has helped the MobileFrontend extension in the following ways:


 * Dead code elimination
 * In this particular example there was no element with class .overlay meaning it was easy to identify and remove all the CSS that was being wasted by using the hierarchy: https://gerrit.wikimedia.org/r/#/c/74519/1/less/specials/userlogin.less.


 * Nicer diffs
 * In this particular example it was much easier to rename an element and its corresponding CSS due to the way the CSS rules were structured in LESS: https://gerrit.wikimedia.org/r/#/c/76336/1/less/common/notifications.less. Had these been written into CSS without nesting there would have been many many more instances to change.


 * Consistent colors / margins
 * Use of a variables file helps us be consistent with our colour scheme. For instance in this commit rather than introducing a new variant of the colour red we used an existing one : https://gerrit.wikimedia.org/r/#/c/73195/2/less/common/pagelist.less


 * Managing vendor prefixes and other things via mixins
 * In this patch we removed support for the vendor prefix  after realising that it didn't exist. This was a one-line LESS change but as you can see from the commit it changed a lot of CSS! . Another great example was dropping   support . Also see  as another example of where this has been useful.

LESS in MediaWiki core
Adding support for LESS to MediaWiki means that generating CSS from LESS files would not require a separate build step, but instead happen on the fly. ResourceLoader makes this easy to implement because it already implements a static asset pipeline. It does not generally serve JS and CSS files as they are written on disk; instead it applies a series of transformations to the raw source code that optimize it and adapt it for the client's environment, and caches the result of its transformations to avoid repeating work. It already performs minification and RTL flipping of CSS. ResourceLoader has worked extremely well for MediaWiki and we think that by extending it judiciously, LESS support could be implemented in a manner that does not degrade performance. contains a draft implementation.

Why not implement this as an extension?
MediaWiki core has over 10,000 lines of CSS code, some of it quite ancient, and we think that a tool like LESS can help us a lot with its upkeep. This will help us define and enforce a set of consistent design guidelines for MediaWiki's interface, and it's fun to write. Concentrating these generic definitions in core and providing a uniform interface for working with LESS will facilitate standardization and code reuse.

Userscript and gadget support?
Will this also support User:Yuvipanda/something.less files natively? Yuvipanda (talk) 09:21, 19 August 2013 (UTC)


 * Same question goes for gadgets I guess? Steven Walling (WMF) &bull; talk   19:41, 19 August 2013 (UTC)


 * patch #3 doesn't make .less files a known content type, so editing them on-wiki doesn't work very well.
 * Would you want MediaWiki to automatically load 'User:Yuvipanda/common.less' ? What if you already had a common.css? It seems too tricky.
 * in user CSS files seems left as is, so we'd have to reconfigure the server to transform the request.
 * Adding  to common.js doesn't work, it embeds a   in code using ResourceLoader. That was and remains the convention for reasons unrelated to this RFC. Krinkle (talk)
 * So if I include other less files via resource loader dependencies, will I be able to use variables and functions defined in those files? --Nikerabbit (talk) 18:14, 11 September 2013 (UTC)
 * You should use @import to load LESS files that contain variables and mix-ins. The compiler environment is not shared across compilations of LESS files based on ResourceLoader dependency relationships. Each top-level '.less' file that is referenced in a ResourceLoader module declaration gets a fresh environment. --Ori.livneh (talk) 10:58, 15 September 2013 (UTC)

Sample usage: MobileFrontend
Work in progress adapting MobileFrontend to use the less styles directly. A couple notes: --brion (talk) 19:16, 13 September 2013 (UTC)
 * Styles aren't quite working yet.
 * I'm having some sort of trouble where variables aren't interpolating correctly, not sure what's wrong yet. This seems to cause errors when doing math.
 * The -webkit-transform mixin needs to do a string replacement; since JS isn't available we'd have to add an internal less function to do it.
 * Errors are definitely not handled well yet. :) Waiting on some fixes to continue.
 * If using images, don't forget to move them from the css to the less directories!


 * Brion, thanks very much for this. I think the latest patch-set addresses all the issues. --Ori.livneh (talk) 10:58, 15 September 2013 (UTC)

wgLESSVars vs. imports
Perhaps it would be more modular to import a global definition file like https://github.com/twbs/bootstrap/blob/master/less/variables.less, rather than using wgLESSVars. Particular modules could add additional local files for this as well. Superm401 - Talk 00:43, 17 September 2013 (UTC)
 * You'd lose the ability to specify values dynamically, and that's a big loss -- there's a lot you can do with that. Take Wikia's ThemeCustomizer, which loads wiki-specific color schemes based on the wiki's configuration. --Ori.livneh (talk) 04:25, 17 September 2013 (UTC)

Conventions (particularly, but not only, about @import)
Besides the obvious (indenting, spacing, etc.), we will need to have some other conventions, particularly how to use more advanced functionality. The most important of this is @import. We want to allow people to take advantage of features like variables and mixins. It's not enough to say that core has one folder of definitions and mixins. Extensions definitely need to be able to have their own local definitions, and it's probably more modular if core also breaks up the LESS library in a logical way. There's probably one folder that all LESS should be allowed to @import without a special declaration.

But others should follow particular rules. One approach is to have modules depend on modules representing the LESS libraries they use. Because LESS libraries compile to empty CSS, those library modules would not contribute anything to the page unless they're library exports are used. It would be mainly for documentation purposes since currently there is no enforcement of where @import declarations can import from.

Those are just some quick thoughts. The main point is that we need to invest some time in working on this. I'll start Requests for comments/LESS/Conventions in a bit. Superm401 - Talk 22:28, 17 September 2013 (UTC)