The Firefox codebase: CSS Guidelines

Draft
This page is not complete.

This document contains guidelines defining how CSS inside the Firefox codebase should be written, it is notably relevant for Firefox front-end engineers.

Basics

Here are some basic tips that can optimize reviews if you are changing CSS:

  • Avoid !important but if you have to use it, make sure it's obvious why you're using it (ideally with a comment). The Overriding CSS section contains more information about this.
  • Avoid magic numbers; prefer automatic sizing or alignment methods. Some examples:
    • absolutely positioned elements
    • vertical-align: -2px;
  • Avoid setting styles in JavaScript. It's generally better to set a class and then specify the styles in CSS.
  • classList is generally better than className. There's less chance of overwriting an existing class.

Boilerplate

Make sure each file starts with the standard copyright header (see License Boilerplate).

Before adding more CSS

It is good practice to check if the CSS that is being written is needed, it can be the case that a common component has been already written could be reused with or without changes. Always prefer editing common components to writing your own.

Formatting

Spacing & Indentation

  • 2 spaces indentation is preferred
  • Add a space after each comma, except within color functions:
linear-gradient(to bottom, black 1px, rgba(255,255,255,0.2) 1px)
  • Always add a space before !important.

Omit units on 0 values

Do this:

  margin: 0;

Not this:

  margin: 0px;

Use expanded syntax

It is often harder to understand what the shorthand is doing and the shorthand can also hide some unwanted default values. It is good to privilege expanded syntax to make your intentions explicit.

Do this:

  border-color: red;

Not this:

  border: red;

Put multiple selectors on different lines

Do this:

h1,
h2,
h3 {
  font-family: sans-serif;
  text-align: center;
}

Not this:

h1, h2, h3 {
  font-family: sans-serif;
  text-align: center;
}

Naming standards for class names

  • lower-case-with-dashes is the most common.
  • But camelCase is also used sometimes. Try to follow the style of existing or related code.

Other tips

TODO: most of this section is probably inaccurate

  • Assume ="true" in attribute selectors.
    • Example: Use option[checked], not option[checked="true"].
  • Avoid ID selectors unless it is really the wanted goal, since IDs have higher specificity and therefore are harder to override.
  • TODO: efficient selectors, is https://developer.mozilla.org/en-US/docs/CSS/Writing_Efficient_CSS still relevant ?

Overriding CSS

Before overriding any CSS rules, check whether overriding is really needed. Sometimes, when copy-pasting older code, it happens that the code in question contains unnecessary overrides. This could be because the CSS that it was overriding got removed in the meantime. In this case, simply dropping the override should work.

It is also good practice to look at whether the rule you are overriding is still needed: maybe the UX spec for the component has changed and that rule can actually be updated or removed. When this is the case, don't be afraid to remove or update that rule.

Once the two things above have been checked, check if the other rule you are overriding contains !important, if that is case, try putting it in question, because it might have become obsolete.

Afterwards, check the specificity of the other selector; if it is causing your rule to be overriden, you can try reducing its specificity. However, never try to increase the selector of the rule you are writing as it can easily become hard to understand.

TODO: Add rules for handling :hover/:active/[disabled] overrides

TODO: Maybe mention :not() to prevent one rule from applying

Finally, once you have checked all the things above, you can permit yourself to use !important along with a comment why it is needed.

Using CSS variables

Adding new variables

Before adding new CSS variables, please consider the following questions:

  1. Is the variable value changed at runtime?
    (Either from JavaScript or overriden by another CSS file)

    If the answer is no, consider using a preprocessor variable or simply inlining the value.
     
  2. Is the variable value used multiple times?

    If the answer is no and the value isn't changed at runtime, then you likely don't need a CSS variable.
     
  3. Is there an alternative to using the variable like inheriting or using the currentColor keyword?
    Using inheriting or using currentColor will prevent repetition of the value and it is usually good practice to do so.

Using variables

Use the variable according to its naming

Do this:

xul|tab:hover {
  background-color: var(--in-content-box-background-hover);
}

Not this:

#certificateErrorDebugInformation {
  background-color: var(--in-content-box-background-hover);
}

Localization

Text Direction

  • For margins, padding and borders, use inline-start/inline-end rather than left/right.
    Example: Use margin-inline-start: 3px; instead of margin-left: 3px.
  • For RTL-aware positioning (left/right), use inset-inline-start/inset-inline-end.
  • For RTL-aware float layouts, float: inline-start|inline-end can be used instead of float: left|right.
  • When there is no special RTL-aware property available, use the pseudo :-moz-locale-dir(ltr|rtl) (for XUL files) or :dir(ltr|rtl) (for HTML files).
  • Remember that while a tab content's scrollbar still shows on the right in RTL, an overflow scrollbar will show on the left.
  • Write padding: 0 3px 4px; instead of padding: 0 3px 4px 3px;. This makes it more obvious that the padding is symmetrical (so RTL won't be an issue).

Note: See CSS Logical Properties and Values for more information.

 

Testing

To test for RTL layouts, you can go to about:config and set intl.uidirection to -1.

Writing cross-platform CSS

Firefox supports many different platforms and each of those platforms can contain many different configurations:

  • Windows 7, 8 and 10
    • Default theme
    • Aero basic (Windows 7, 8)
    • Windows classic (Windows 7)
    • High contrast (All versions)
  • Linux
  • macOS

File structure

  • The browser/ directory contains styles specific to Firefox
  • The toolkit/ directory contains styles that are shared across all toolkit applications (Thunderbird and SeaMonkey)

Under each of those two directories, there is a themes directory containing 4 sub-directories:

  • shared
  • linux
  • osx
  • windows

The shared directories contain styles shared across all 3 platforms, while the other 3 directories contain styles respective to their platform.

For new CSS, when possible try to privilege using the shared directory, instead of writing the same CSS for the 3 platform specific directories, especially for large blocks of CSS.

Content CSS vs. Theme CSS

The following directories also contain CSS:

  • browser/base/content/
  • toolkit/content/

These directories contain content CSS, that applies on all platforms, which is styling deemed to be essential for the browser to behave correctly. To determine whether some CSS is theme-side or content-side, it is useful to know that certain CSS properties are going to lean one way or the other: color - 99% of the time it will be theme CSS, overflow - 99% content.

99% theme 70% theme 70% content 99% content
font-*, color, *-color, border-*, -moz-appearance [1] line-height, padding, margin cursor, width, max-width, top, bottom [2], etc overflow, direction, display, *-align, align-*, *-box-*, flex-*, order

If some CSS is layout or functionality related, then it is likely content CSS. If it is esthetics related, then it is likely theme CSS.

When importing your stylesheets, it's best to import the content CSS before the theme CSS, that way the theme values get to override the content values (which is probably what you want), and you're going to want them both after the global values, so your imports will look like this:

<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/path/module.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/path/module.css" type="text/css"?>

[1] -moz-appearance is tricky. Generally, when specifying -moz-appearance: foo; you're giving hints as to how something should act, however -moz-appearance: none; is probably saying 'ignore browser preconceptions - I want a blank sheet', so that's more visual. However -moz-appearance values aren't implemented and don't behave consistently across platforms, so idealism aside -moz-appearance should always be in theme CSS.

[2] However there is probably a better way than using absolute positioning.

 

Colors

For common areas of the Firefox interface (panels, toolbar buttons, etc.), mozilla-central often comes with some useful CSS variables that are adjusted with the correct values for different platform configurations, so using those CSS variables can definitively save some testing time, as you can assume they already work correctly.

Using the currentColor keyword or inheriting is also good practice, because sometimes the needed value is already in the color or on the parent element. This is especially useful in conjunction with icons using -moz-context-properties: fill; where the icon can adjust to the right platform color automatically from the text color. It is also possible to use currentColor with other properties like opacity or fill-opacity to have different opacities of the platform color.

If none of the options above are adequate, it is good practice to use system colors, especially on non-default Windows themes or Linux. In general, the following colors are used:

  • -moz-Field: textbox or field background colors, also used as the background color of listboxes or trees.
  • -moz-FieldText: textbox or field text colors, also used as the text color of listboxes or trees.
  • -moz-Dialog: window or dialog background color.
  • -moz-DialogText: window or dialog text color.
  • GrayText: used on disabled items as text color.
  • ThreeDShadow: Used as border on elements.
  • ThreeDLightShadow: Used as light border on elements.

Writing media queries

Boolean media queries

Do this:

@media (-moz-mac-yosemite-theme: 0) {

Not this:

@media not all and (-moz-mac-yosemite-theme) {

Privilege CSS for most common configuration

It is better to put the most common configuration (latest version of an OS, or default theme for example) outside of the media query. In the following example, -moz-mac-yosemite-theme targets macOS 10.10 and higher, so it should be privileged over the styling for macOS 10.9.

Do this:

@media (-moz-mac-yosemite-theme: 0) {
  #placesList {
    box-shadow: inset -2px 0 0 hsla(0,0%,100%,.2);
  }
}

Not this:

#placesList {
  box-shadow: inset -2px 0 0 hsla(0,0%,100%,.2);
}

@media (-moz-mac-yosemite-theme) {
  #placesList {
    box-shadow: none;
  }
}

Theme support

Firefox comes built-in with 3 themes: default, light and dark. The built-in light/dark themes are a bit special as they load the compacttheme.css stylesheet. In addition to this, Firefox supports a variety of WebExtension themes that can be installed from AMO. For testing purposes, here is an example of a WebExtension theme.

Writing theme-friendly CSS

  • Some CSS variables that are pre-adjusted for different platforms are also pre-adjusted for themes, so it's again a good idea to use them for theme support.
  • The text color of elements often contains valuable information from the theme colors, so currentColor/inheritance is again a good idea for theme support.
  • Never write CSS specially for the built-in light/dark theme in compacttheme.css unless that CSS isn't supposed to affect WebExtension themes.
  • These selectors can be used to target dark areas:
    • :-moz-lwtheme-brighttext: dark window frame.
    • :root[lwt-toolbar-field-brighttext]: dark address bar and searchbar.
    • :root[lwt-popup-brighttext]: dark arrow panels and autocomplete panels.
    • :root[lwt-sidebar-brighttext]: dark sidebars.
  • If you'd like a different shade of a themed area and no CSS variable is adequate, using colors with alpha transparency is usually a good idea, as it will preserve the original theme author's color hue.

Variables

For clarity, CSS variables that are only used when a theme is enabled have the --lwt- prefix.

Layout & performance

Layout

Mixing XUL flexbox and HTML flexbox can lead to undefined behaviour.

Reflows and style flushes

See Performance best practices for Firefox front-end engineers for more information about this.

Misc

Text aliasing

When convenient, avoid setting the opacity property on text as it will cause text to be aliased differently.

HDPI support

It's recommended to use SVG since it keeps the CSS clean when supporting multiple resolutions. See the SVG Guidelines for more information on SVG usage.

However, if only 1x and 2x PNG assets are available, you can use this @media query to target higher density displays (HDPI):

@media (min-resolution: 1.1dppx).

Document Tags and Contributors

Contributors to this page: ExE-Boss, ntim, chrisdavidmills, alberts+
Last updated by: ExE-Boss,