CSS coding guidelines

Our CSS is written in Sass, using the SCSS syntax.

Linting and formatting SCSS

Wagtail uses stylelint for linting, and Prettier for formatting. You’ll need Node.js and npm on your development machine. Ensure project dependencies are installed by running npm install --no-save

Tailwind CSS

Wagtail uses utility classes via Tailwind, generated based on values set in the tailwind.config.js file.

To use these utilities you will need to prefix your class names with w- to avoid interfering with other predefined styles of similar names.

Linting code

Run the linter from the wagtail project root:

$ npm run lint:css

The linter is configured to check your code for adherence to the guidelines below, plus a little more.

Formatting code

For Prettier auto-formatting, run:

$ npm run format

If you want to autofix linting errors:

$ npm run lint:css -- --fix

Changing the linter configuration

The configuration for the linting rules is managed in an external repository so that it can be easily shared across other Wagtail projects or plugins. This configuration can be found at stylelint-config-wagtail.

Styleguide Reference

Formatting

  • Use hex color codes #000 unless using rgba() in raw CSS (SCSS’ rgba() function is overloaded to accept hex colors as a param, e.g., rgba(#000, .5)).

  • Use // for comment blocks (instead of /* */).

  • Use single quotes for string values background: url('my/image.png')

  • Avoid specifying units for zero values, e.g., margin: 0; instead of margin: 0px;.

  • Strive to limit use of shorthand declarations to instances where you must explicitly set all the available values.

Sass imports

Leave off underscores and file extensions in includes:

// Bad
@import 'components/_widget.scss'

// Better
@import 'components/widget'

Pixels vs. ems

Use rems for font-size, because they offer absolute control over text. Additionally, unit-less line-height is preferred because it does not inherit a percentage value of its parent element, but instead is based on a multiplier of the font-size.

Specificity (classes vs. ids)

Always use classes instead of IDs in CSS code. IDs are overly specific and lead to duplication of CSS.

When styling a component, start with an element + class namespace, prefer direct descendant selectors by default, and use as little specificity as possible. Here is a good example:

<ul class="category-list">
    <li class="item">Category 1</li>
    <li class="item">Category 2</li>
    <li class="item">Category 3</li>
</ul>
.category-list { // element + class namespace

    // Direct descendant selector > for list items
    > li {
        list-style-type: disc;
    }

    // Minimal specificity for all links
    a {
        color: #f00;
    }
}

Class naming conventions

Never reference js- prefixed class names from CSS files. js- are used exclusively from JS files.

Use the SMACSS is- prefix for state rules that are shared between CSS and JS.

Misc

As a rule of thumb, avoid unnecessary nesting in SCSS. At most, aim for three levels. If you cannot help it, step back and rethink your overall strategy (either the specificity needed, or the layout of the nesting).

Examples

Here are some good examples that apply the above guidelines:

// Example of good basic formatting practices
.styleguide-format {
    color: #000;
    background-color: rgba(0, 0, 0, .5);
    border: 1px solid #0f0;
}

// Example of individual selectors getting their own lines (for error reporting)
.multiple,
.classes,
.get-new-lines {
    display: block;
}

// Avoid unnecessary shorthand declarations
.not-so-good {
    margin: 0 0 20px;
}
.good {
    margin-bottom: 20px;
}