569 lines
18 KiB
ReStructuredText
569 lines
18 KiB
ReStructuredText
CSS Guidelines
|
|
==============
|
|
|
|
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 to avoid:
|
|
|
|
- absolutely positioned elements
|
|
- hardcoded values such as: ``vertical-align: -2px;`` . The reason
|
|
you should avoid such "hardcoded" values is that, they don't
|
|
necessarily work for all font-size configurations.
|
|
|
|
- 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.
|
|
- Only use generic selectors such as ``:last-child``, when it is what
|
|
you mean semantically. If not, using a semantic class name is more
|
|
descriptive and usually better.
|
|
|
|
Boilerplate
|
|
~~~~~~~~~~~
|
|
|
|
Make sure each file starts with the standard copyright header (see
|
|
`License Boilerplate <https://www.mozilla.org/MPL/headers/>`__).
|
|
|
|
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. Most of the time, the common
|
|
component already follows the a11y/theme standards defined in this
|
|
guide. So, when possible, always prefer editing common components to
|
|
writing your own.
|
|
|
|
Also, it is good practice to introduce a common class when the new
|
|
element you are styling reuses some styles from another element, this
|
|
allows the maintenance cost and the amount of code duplication to be
|
|
reduced.
|
|
|
|
Formatting
|
|
----------
|
|
|
|
Spacing & Indentation
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
- 2 spaces indentation is preferred
|
|
- Add a space after each comma, **except** within color functions:
|
|
|
|
.. code:: css
|
|
|
|
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:
|
|
|
|
.. code:: css
|
|
|
|
margin: 0;
|
|
|
|
Not this:
|
|
|
|
.. code:: css
|
|
|
|
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:
|
|
|
|
.. code:: css
|
|
|
|
border-color: red;
|
|
|
|
Not this:
|
|
|
|
.. code:: css
|
|
|
|
border: red;
|
|
|
|
Put multiple selectors on different lines
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Do this:
|
|
|
|
.. code:: css
|
|
|
|
h1,
|
|
h2,
|
|
h3 {
|
|
font-family: sans-serif;
|
|
text-align: center;
|
|
}
|
|
|
|
Not this:
|
|
|
|
.. code:: css
|
|
|
|
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
|
|
~~~~~~~~~~
|
|
|
|
- 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.
|
|
- Using descendant selectors is good practice for performance when
|
|
possible:
|
|
|
|
- For example:
|
|
``.autocomplete-item[selected] > .autocomplete-item-title`` would
|
|
be more efficient than
|
|
``.autocomplete-item[selected] .autocomplete-item-title``
|
|
|
|
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, 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 overridden, you can try reducing its
|
|
specificity, either by simplifying the selector or by changing where the
|
|
rule is placed in the stylesheet. If this isn't possible, you can also
|
|
try introducing a ``:not()`` to prevent the other rule from applying,
|
|
this is especially relevant for different element states (``:hover``,
|
|
``:active``, ``[checked]`` or ``[disabled]``). However, never try to
|
|
increase the selector of the rule you are adding as it can easily become
|
|
hard to understand.
|
|
|
|
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:
|
|
|
|
#. **Is the variable value changed at runtime?**
|
|
*(Either from JavaScript or overridden by another CSS file)*
|
|
**If the answer is no**, consider using a preprocessor variable or
|
|
inlining the value.
|
|
|
|
#. **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.
|
|
|
|
#. **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.
|
|
|
|
In general, it's good to first think of how some CSS could be written
|
|
cleanly without the CSS variable(s) and then think of how the CSS
|
|
variable could improve that CSS.
|
|
|
|
Using variables
|
|
~~~~~~~~~~~~~~~
|
|
|
|
Use the variable according to its naming
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Do this:
|
|
|
|
.. code:: css
|
|
|
|
xul|tab:hover {
|
|
background-color: var(--in-content-box-background-hover);
|
|
}
|
|
|
|
Not this:
|
|
|
|
.. code:: css
|
|
|
|
#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``.
|
|
- The RTL-aware equivalents of
|
|
``border-{top/bottom}-{left/right}-radius`` are
|
|
``border-{start/end}-{start/end}-radius``
|
|
- 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 <https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties>`__
|
|
for more information.
|
|
|
|
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, | line-height, | cursor, width, | overflow, |
|
|
| \*-color, | padding, | max-width, | direction, |
|
|
| border-\*, | margin | top, | display, |
|
|
| -moz-appearance | | bottom [2]_, | \*-align, |
|
|
| [1]_ | | etc | 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:
|
|
|
|
.. code:: html
|
|
|
|
<?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.
|
|
|
|
High contrast mode
|
|
~~~~~~~~~~~~~~~~~~
|
|
|
|
Content area
|
|
^^^^^^^^^^^^
|
|
|
|
On Windows high contrast mode, in the content area, Gecko does some
|
|
automatic color adjustments regarding page colors. Part of those
|
|
adjustments include making all ``box-shadow`` invisible, so this is
|
|
something to be aware of if you create a focus ring or a border using
|
|
the ``box-shadow`` property: consider using a ``border`` or an
|
|
``outline`` if you want the border/focus ring to stay visible in
|
|
high-contrast mode. An example of such bug is `bug
|
|
1516767 <https://bugzilla.mozilla.org/show_bug.cgi?id=1516767>`__.
|
|
|
|
Another adjustment to be aware of is that Gecko removes all the
|
|
``background-image`` when high contrast mode is enabled. Consider using
|
|
an actual ``<img>`` tag (for HTML documents) or ``list-style-image``
|
|
(for XUL documents) if rendering the image is important.
|
|
|
|
If you are not using Windows, one way to test against those adjustments
|
|
on other platforms is:
|
|
|
|
- Going to about:preferences
|
|
- Clicking on the "Colors..." button in the "Fonts & Colors"
|
|
sub-section of the "Language and Appearance" section
|
|
- Under "Override the colors specified by the page with your selections
|
|
above", select the "Always" option
|
|
|
|
Chrome area
|
|
^^^^^^^^^^^
|
|
|
|
The automatic adjustments previously mentioned only apply to pages
|
|
rendered in the content area. The chrome area of Firefox uses colors as
|
|
authored, which is why using pre-defined variables, ``currentcolor`` or
|
|
inheritance is useful to integrate with the system theme with little
|
|
hassle.
|
|
|
|
If not, as a last resort, using `system
|
|
colors <https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#system_colors>`__
|
|
also works for 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. Do not use it on
|
|
text that is not disabled to desemphsize text, because it does not
|
|
guarantee a sufficient contrast ratio for non-disabled text.
|
|
- ``ThreeDShadow``: Used as border on elements.
|
|
- ``ThreeDLightShadow``: Used as light border on elements.
|
|
|
|
Using the background/text pairs is especially important to ensure the
|
|
contrast is respected in all situations. Never mix custom text colors
|
|
with a system background color and vice-versa.
|
|
|
|
Note that using system colors is only useful for the chrome area, since
|
|
content area colors are overridden by Gecko anyway.
|
|
|
|
Writing media queries
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Boolean media queries
|
|
^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Do this:
|
|
|
|
.. code:: css
|
|
|
|
@media (-moz-mac-yosemite-theme: 0) {
|
|
|
|
Not this:
|
|
|
|
.. code:: css
|
|
|
|
@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:
|
|
|
|
.. code:: css
|
|
|
|
@media (-moz-mac-yosemite-theme: 0) {
|
|
#placesList {
|
|
box-shadow: inset -2px 0 0 hsla(0,0%,100%,.2);
|
|
}
|
|
}
|
|
|
|
Not this:
|
|
|
|
.. code:: css
|
|
|
|
#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. <https://addons.mozilla.org/en-US/firefox/addon/arc-dark-theme-we/>`__
|
|
|
|
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 themed areas, though in general it's
|
|
recommended to try to avoid them and use ``light-dark()`` to get the right
|
|
colors automatically:
|
|
|
|
- ``:root[lwt-toolbar-field="light/dark"]``: explicitly light or dark address bar and
|
|
searchbar.
|
|
- ``:root[lwt-toolbar-field-focus="light/dark"]``: explicitly light or dark address bar and
|
|
searchbar in the focused state.
|
|
- ``:root[lwt-popup="light/dark"]``: explicitly light or dark arrow panels
|
|
and autocomplete panels.
|
|
- ``:root[lwt-sidebar="light/dark"]``: explicitly light or 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 behavior.
|
|
|
|
CSS selectors
|
|
~~~~~~~~~~~~~
|
|
|
|
When targeting the root element of a page, using ``:root`` is the most
|
|
performant way of doing so.
|
|
|
|
Reflows and style flushes
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
See :ref:`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 :ref:`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):
|
|
|
|
.. code:: css
|
|
|
|
@media (min-resolution: 1.1dppx)
|