Manual:Coding conventions/CSS

From MediaWiki.org
Jump to: navigation, search
shortcut: CC/CSS

Naming[edit]

Name classes and IDs the same way: all lowercase and broken up by dashes. In MediaWiki core, use the mw- prefix to avoid conflicts with IDs generated by the wikitext parser to mark section headings. In extensions, use a ext-myextensioncodename- prefix.

Some examples:

/* Site-wide elements */
.mw-body,
.mw-headline,
.mw-label,
.mw-input,
#mw-panel,
#mw-jsmessage {
}

/* Special pages */
.mw-body-content,
/* - Special:AllPages */
.mw-allpages-table-form,
.mw-allpages-nav,
/* - Special:BlockIp */
#mw-bi-target {
}

Whitespace[edit]

We whitespace:

  • One selector per line.
  • One property declaration per line.
  • Opening braces for the CSS declaration block on the same line as the (last) selector.
  • Indent each property declaration with a tab.
  • No space before the colon (:).
  • One space after the colon and before the value.
  • One space after commas (, ) in multi-value properties.
  • One space after a starting and before an ending parentheses (( and )) in selectors (ex. :not()) and properties (ex. rgba()).
  • A semi-colon (;) after each declaration (including the last one).
  • Closing braces unindented back to the left.
  • Annotation for CSSJanus and CSSMin should be on their own line, above the CSS declaration they're for.
  • An empty line between one CSS rule set and the next.
.mw-selector,
#mw-some-element {
	background-color: #fff;
	color: #252525;
	float: right;
	font-family: Arial, Helvetica, sans-serif;
	text-align: left;
	transform: scale( 1.2 );
}

/* Example that uses CSSJanus and CSSMin annotations */
#mw-look-at-the-left {
	/* @noflip */
	float: left;
	/* @embed */
	background-image: url( images/foobar.png );
}

Quotes[edit]

Quotes are unnecessary in the url() parameter of a background-image declaration. The only case where this could cause problems is when an unescaped closing parenthesis occurs in the path; instead you should URL-escape such characters.

Color property values[edit]

CSS3 supports many different kinds of color values for CSS properties like background-color, color, border-color, et al. For consistency and compatibility, only use these three:

  • Hex color values like #fff and #fefefe. (Use lowercase for better gzip compression[1]! Use shorthand notation when possible.)
  • rgba() values if an alpha transparency is required like rgba( 255, 255, 255, 0.5 ). (Attention: IE8 doesn't support rgba() notation, so always provide a matching declaration before this one with a hex color value as fallback.)
  • transparent color keyword. (Attention: IE 7-8 supports it only for background-color and border. It draws color: transparent; as black.[2])

Prefer all values in lowercase for consistency and optimized file compression.[3]. See also Talk page section.
Avoid other color values (including color names/keywords – think i18n while picturing burlywood, rgb(), hsl(), and hsla() notations). Also make sure that your color contrast ratio of foreground and background (incl. background gradients, and fallback colors) reaches at least Level AA, ideally Level AAA, of WCAG 2.0[4].

Read further at MDN.

Vendor prefixes[edit]

Always put the standardized versions of CSS properties after vendor-prefixed versions. It is important for avoiding bugs in old implementation, like in the following example of -webkit-border-radius. See also https://css-tricks.com/ordering-css3-properties/.

Right: Wrong:
.bar {
	-webkit-border-radius: 30px 10px;
	border-radius: 30px 10px;
}
.foo {
	background-color: #444;
	background-image: -webkit-gradient( linear, left top, left bottom, from( #444 ), to( #999 ) );
	background-image: -webkit-linear-gradient( top, #444, #999 );
	background-image: -moz-linear-gradient( top, #444, #999 );
	background-image: linear-gradient( to bottom, #444, #999 );
}

/* Annotated version */
.foo {
	/* Fallback color in case background-image gradient is not supported */
	background-color: #444;
	/* Safari 4, Chrome 2, iOS 2 */
	background-image: -webkit-gradient( linear, left top, left bottom, from( #444 ), to( #999 ) );
	/* Safari 5.1+, Chrome 10+, iOS 5 */
	background-image: -webkit-linear-gradient( top, #444, #999 );
	/* Firefox 3.6 - 15 */
	background-image: -moz-linear-gradient( top, #444, #999 );
	/* Standard syntax supported by Firefox 16+, Opera 12.5+, IE10+ */
	background-image: linear-gradient( to bottom, #444, #999 );
}
.bar {
	border-radius: 30px 10px;
	-webkit-border-radius: 30px 10px;
}

.foo {
	background-image: linear-gradient(top, #444444, #999999);
	background-image: -moz-linear-gradient(top, #444444, #999999);
	background-image: -webkit-linear-gradient(top, #444444, #999999);
	background-image: -webkit-gradient(linear, left top, left bottom, from(#444444), to(#999999));
}

.client-js and .client-nojs[edit]

MediaWiki outputs class client-nojs on the <html> element on every page. At runtime, JavaScript code replaces this with class client-js. Hence you can use this class in your selector to conditionally show, hide, or customize certain elements depending on whether the browser has JavaScript enabled and is supported by ResourceLoader. Note that for this to be useful, the stylesheet in question must be loaded with OutputPage::addModuleStyles(), not mw.loader (see Developing with ResourceLoader)

Anti-patterns[edit]

z-index[edit]

Avoid using z-index when possible. Instead, try to use the natural stacking order in the DOM. Known exceptions include:

!important[edit]

Avoid using !important (with the exception of working around upstream code running on the same page that also uses !important, because only !important can override !important).

In most cases you don't need it at all. In other cases it may be the result of a bug elsewhere in the program. In general, to override a rule you use the same selector as the original style rule. Since CSS cascades, this works naturally (styles applied later override styles applied earlier, selectors don't need to be of higher specificity[5]).

If the overriding styles apply before the original styles, the styles got loaded in the wrong order. That should be addressed, but you may resort to workarounds to artificially increase the specificity:

  • Repeat the same selector to increase weight, like .foo.foo.[6]
  • Add or repeat attribute selectors, like [class].
  • Use default elements as ancestor selector (e.g. body .foo, html body .foo).

Add however many points you need. It will still allow multiple stylesheets to use the same technique and each express their specificity. Better than adding in ancestors classes not related to your code. (And more maintainable as they won't change.)

Less[edit]

shortcut: CC/LESS

Starting with MediaWiki 1.22, there is native support in ResourceLoader for transparently using Less (with file extension .less) in place of CSS. Most of the Less syntax can be formatted using the CSS conventions:

  • Indent nested blocks with 1 tab (same as for indenting declarations inside CSS rules).
  • Don't space-align declarations values inside mixins (same as for CSS rules).
  • No spaces on the outside of the parameter lists in function invocations, mixin uses and mixin definitions (same as for url( image.png ) in CSS).
  • No quotes around parameter values (same as for url( image.png ) in CSS).

Example:

/*
 * You do not need to copy `.background-image` into your code.
 * It is provided by mediawiki core (in mediawiki.less).  It is
 * here as an example of guard syntax.
 */
.background-image( @url ) when ( embeddable( @url ) ) {
	background-image: embed( @url );
	background-image: url( @url )!ie;
}

.background-image( @url ) when not ( embeddable( @url ) ) {
	background-image: url( @url );
}

.mw-example {
	.background-image( images/example.png );
	padding: 0.2em 0.5em;
	border: 1px solid #aaa;
	font-size: 1em;

	.mw-example-thing {
		display: inline-block;
		/* @noflip */
		float: left;
		border: 1px solid #ddd;
		border-radius: 2px;
		padding: 1px 4px;
	}
}

There's a few new concepts that don't map to CSS conventions, outlined below.

Structure[edit]

  • Separate nested CSS rules from the parent declarations by 1 empty line.
  • @noflip tags must be on the immediate line above the declaration, as shown in the example above.

Import of Less/CSS files[edit]

  • The filename of an import statement should omit the .less file extension.
  • Use @import to load mixins and variables so that they may be used by the current Less stylesheet; these are processed synchronously by phpless and are not present in the generated CSS output.
  • Don't use @import to bundle stylesheets that are related to one another only conceptually; instead, reference the set of files in the styles array of a ResourceLoader module.

Troubleshooting Import

If your Less @import doesn't work, here some things to check:

MediaWiki Less library[edit]

resources/src/mediawiki.less/mediawiki.mixins.less is a common Less mixins library for MediaWiki. The directory is in $wgResourceLoaderLESSImportPaths, so you don't need to provide the full path to it. For example:

@import "mediawiki.mixins";

.my-create-link {
    .background-image-svg( 'images/create_normal.svg', 'images/create_normal.png' );
    /* As `.background-image-svg` is taking two parameters, they have to be enclosed in quotes `''` */
}

Mixins[edit]

Mixin names should use hyphen-case, just like CSS properties.

They should be prefixed with mixin- to avoid confusing developers who are familiar with CSS, but not Less and distinguish them from classes, the syntax for which is similar.

As mentioned above, no spaces on the outside of the parameter list and avoid quoting values.

If you need to call a mixin with one or more arguments that contain a comma use a semicolon ; in Less to separate the arguments. This allows you to use commas in the literal value.

.mixin-example( @function, @properties ) {
	transition-timing-function: @function;
	transition-property: @property;
}
Applied right: Applied wrong:
.mw-example {
	.mixin-example( ease-in-out; opacity, color );

	/* Expands to: */
	transition-timing-function: ease-in-out;
	transition-property: opacity, color;
}
.mw-example {
	.mixin-example( 'ease-in-out', 'opacity, color' );

	/* Expands to: */
	transition-timing-function: 'ease-in-out';
	transition-property: 'opacity, color';

	/* Values include the quotes, this is invalid CSS
	 * and results in the browser ignoring these properties
	 */
}

/* Another bad example: */
.mw-example {
	.mixin-example( ~'ease-in-out', ~'opacity, color' );

	/* Expands to: */
	transition-timing-function: ease-in-out;
	transition-property: opacity, color;

	/* The ~ operator instructs Less to unquote the values.
	 * This produces good CSS but we avoid this pattern
	 * in favour of using ';' consistently.
	 */
}

Automated linting[edit]

You should use the node module grunt-stylelint to lint your CSS or LESS; MediaWiki and some extensions run it as part of Continuous integration. If you combine it with stylelint-config-wikimedia, your code will also be checked for consistency with these coding conventions, with exceptions where you don't yet meet the standards. For example, as of July 2016 the TemplateData extension's .stylelintrc file just uses the shared rules; MediaWiki's doesn't yet use the shared rules; VisualEditor's uses them and adds some over-rides for compatibility checking of its different browser support.

References[edit]

  1. http://www.websiteoptimization.com/speed/tweak/lowercase/
  2. Color value browser compatibility, see notes
  3. Lowercase markup has smaller gzip output, HTML5 Boilerplate 2015
  4. WCAG 2.0 Understanding Contrast
  5. Specifics on CSS Specificity, css-tricks.com
  6. 3.14 things I didn’t know about CSS, CSS Day Conference 2014


Coding conventionsManual:Coding conventions
General All languagesManual:Coding conventions#Code structure· Development policyDevelopment policy · Security for developersSecurity for developers · Pre-commit checklistManual:Pre-commit checklist · Performance guidelinesPerformance guidelines (draft) · Style guideStyle guide · Accessibility guide for developersAccessibility guide for developers (draft)
PHP Code conventionsManual:Coding conventions/PHP · PHPUnit test conventionsManual:PHP unit testing/Writing unit tests#Test_conventions · Security checklist for developersSecurity checklist for developers
JavaScript Code conventionsManual:Coding conventions/JavaScript · Learning JavaScriptLearning JavaScript
CSS Code conventionsManual:Coding conventions/CSS
Database Code conventionsManual:Coding conventions/Database· Database policyDevelopment policy#Database policy
Python Code conventionsManual:Coding conventions/Python
Ruby Code conventionsManual:Coding conventions/Ruby
Selenium/Cucumber Code conventionsManual:Coding conventions/Selenium
Java Code conventionsManual:Coding conventions/Java
API client code Standards for API client librariesAPI:Client code/Gold standard