summaryrefslogtreecommitdiffstats
path: root/docs/code-quality/coding-style/css_guidelines.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/code-quality/coding-style/css_guidelines.rst')
-rw-r--r--docs/code-quality/coding-style/css_guidelines.rst569
1 files changed, 569 insertions, 0 deletions
diff --git a/docs/code-quality/coding-style/css_guidelines.rst b/docs/code-quality/coding-style/css_guidelines.rst
new file mode 100644
index 0000000000..bfa2841800
--- /dev/null
+++ b/docs/code-quality/coding-style/css_guidelines.rst
@@ -0,0 +1,569 @@
+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)