css_guidelines.rst (18738B)
1 CSS Guidelines 2 ============== 3 4 This document contains guidelines defining how CSS inside the Firefox 5 codebase should be written, it is notably relevant for Firefox front-end 6 engineers. 7 8 Basics 9 ------ 10 11 Here are some basic tips that can optimize reviews if you are changing 12 CSS: 13 14 - Avoid ``!important`` but if you have to use it, make sure it's 15 obvious why you're using it (ideally with a comment). The 16 `Overriding CSS`_ section contains more information about this. 17 - Avoid magic numbers; prefer automatic sizing or alignment methods. 18 Some examples to avoid: 19 20 - absolutely positioned elements 21 - hardcoded values such as: ``vertical-align: -2px;`` . The reason 22 you should avoid such "hardcoded" values is that, they don't 23 necessarily work for all font-size configurations. 24 25 - Avoid setting styles in JavaScript. It's generally better to set a 26 class and then specify the styles in CSS. 27 - ``classList`` is generally better than ``className``. There's less 28 chance of overwriting an existing class. 29 - Only use generic selectors such as ``:last-child``, when it is what 30 you mean semantically. If not, using a semantic class name is more 31 descriptive and usually better. 32 33 Boilerplate 34 ~~~~~~~~~~~ 35 36 Make sure each file starts with the standard copyright header (see 37 `License Boilerplate <https://www.mozilla.org/MPL/headers/>`__). 38 39 Before adding more CSS 40 ~~~~~~~~~~~~~~~~~~~~~~ 41 42 It is good practice to check if the CSS that is being written is needed, 43 it can be the case that a common component has been already written 44 could be reused with or without changes. Most of the time, the common 45 component already follows the a11y/theme standards defined in this 46 guide. So, when possible, always prefer editing common components to 47 writing your own. 48 49 Also, it is good practice to introduce a common class when the new 50 element you are styling reuses some styles from another element, this 51 allows the maintenance cost and the amount of code duplication to be 52 reduced. 53 54 Formatting 55 ---------- 56 57 Spacing & Indentation 58 ~~~~~~~~~~~~~~~~~~~~~ 59 60 - 2 spaces indentation is preferred 61 - Add a space after each comma, **except** within color functions: 62 63 .. code:: css 64 65 linear-gradient(to bottom, black 1px, rgba(255,255,255,0.2) 1px) 66 67 - Always add a space before ``!important``. 68 69 Omit units on 0 values 70 ~~~~~~~~~~~~~~~~~~~~~~ 71 72 Do this: 73 74 .. code:: css 75 76 margin: 0; 77 78 Not this: 79 80 .. code:: css 81 82 margin: 0px; 83 84 Use expanded syntax 85 ~~~~~~~~~~~~~~~~~~~ 86 87 It is often harder to understand what the shorthand is doing and the 88 shorthand can also hide some unwanted default values. It is good to 89 privilege expanded syntax to make your intentions explicit. 90 91 Do this: 92 93 .. code:: css 94 95 border-color: red; 96 97 Not this: 98 99 .. code:: css 100 101 border: red; 102 103 Put multiple selectors on different lines 104 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 105 106 Do this: 107 108 .. code:: css 109 110 h1, 111 h2, 112 h3 { 113 font-family: sans-serif; 114 text-align: center; 115 } 116 117 Not this: 118 119 .. code:: css 120 121 h1, h2, h3 { 122 font-family: sans-serif; 123 text-align: center; 124 } 125 126 Naming standards for class names 127 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 128 129 - ``lower-case-with-dashes`` is the most common. 130 - But ``camelCase`` is also used sometimes. Try to follow the style of 131 existing or related code. 132 133 Other tips 134 ~~~~~~~~~~ 135 136 - Assume ``="true"`` in attribute selectors. 137 138 - Example: Use ``option[checked]``, not ``option[checked="true"]``. 139 140 - Avoid ID selectors unless it is really the wanted goal, since IDs 141 have higher specificity and therefore are harder to override. 142 - Using descendant selectors is good practice for performance when 143 possible: 144 145 - For example: 146 ``.autocomplete-item[selected] > .autocomplete-item-title`` would 147 be more efficient than 148 ``.autocomplete-item[selected] .autocomplete-item-title`` 149 150 Overriding CSS 151 -------------- 152 153 Before overriding any CSS rules, check whether overriding is really 154 needed. Sometimes, when copy-pasting older code, it happens that the 155 code in question contains unnecessary overrides. This could be because 156 the CSS that it was overriding got removed in the meantime. In this 157 case, dropping the override should work. 158 159 It is also good practice to look at whether the rule you are overriding 160 is still needed: maybe the UX spec for the component has changed and 161 that rule can actually be updated or removed. When this is the case, 162 don't be afraid to remove or update that rule. 163 164 Once the two things above have been checked, check if the other rule you 165 are overriding contains ``!important``, if that is case, try putting it 166 in question, because it might have become obsolete. 167 168 Afterwards, check the specificity of the other selector; if it is 169 causing your rule to be overridden, you can try reducing its 170 specificity, either by simplifying the selector or by changing where the 171 rule is placed in the stylesheet. If this isn't possible, you can also 172 try introducing a ``:not()`` to prevent the other rule from applying, 173 this is especially relevant for different element states (``:hover``, 174 ``:active``, ``[checked]`` or ``[disabled]``). However, never try to 175 increase the selector of the rule you are adding as it can easily become 176 hard to understand. 177 178 Finally, once you have checked all the things above, you can permit 179 yourself to use ``!important`` along with a comment why it is needed. 180 181 Using CSS variables 182 ------------------- 183 184 Adding new variables 185 ~~~~~~~~~~~~~~~~~~~~ 186 187 Before adding new CSS variables, please consider the following 188 questions: 189 190 #. **Is the variable value changed at runtime?** 191 *(Either from JavaScript or overridden by another CSS file)* 192 **If the answer is no**, consider using a preprocessor variable or 193 inlining the value. 194 195 #. **Is the variable value used multiple times?** 196 **If the answer is no and the value isn't changed at runtime**, then 197 you likely don't need a CSS variable. 198 199 #. **Is there an alternative to using the variable like inheriting or 200 using the ``currentcolor`` keyword?** 201 Using inheriting or using ``currentcolor`` will prevent repetition of 202 the value and it is usually good practice to do so. 203 204 In general, it's good to first think of how some CSS could be written 205 cleanly without the CSS variable(s) and then think of how the CSS 206 variable could improve that CSS. 207 208 Using variables 209 ~~~~~~~~~~~~~~~ 210 211 Use the variable according to its naming 212 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 213 214 Do this: 215 216 .. code:: css 217 218 xul|tab:hover { 219 background-color: var(--in-content-box-background-hover); 220 } 221 222 Not this: 223 224 .. code:: css 225 226 #certificateErrorDebugInformation { 227 background-color: var(--in-content-box-background-hover); 228 } 229 230 Localization 231 ------------ 232 233 Text Direction 234 ~~~~~~~~~~~~~~ 235 236 - For margins, padding and borders, use 237 ``inline-start``/``inline-end`` rather than ``left``/``right``. 238 *Example:* Use ``margin-inline-start: 3px;`` instead of 239 ``margin-left: 3px``. 240 - For RTL-aware positioning (left/right), use 241 ``inset-inline-start``/``inset-inline-end``. 242 - For RTL-aware float layouts, ``float: inline-start|inline-end`` can 243 be used instead of ``float: left|right``. 244 - The RTL-aware equivalents of 245 ``border-{top/bottom}-{left/right}-radius`` are 246 ``border-{start/end}-{start/end}-radius`` 247 - When there is no special RTL-aware property available, use the pseudo 248 ``:-moz-locale-dir(ltr|rtl)`` (for XUL files) or ``:dir(ltr|rtl)`` 249 (for HTML files). 250 - Remember that while a tab content's scrollbar still shows on the 251 right in RTL, an overflow scrollbar will show on the left. 252 - Write ``padding: 0 3px 4px;`` instead of 253 ``padding: 0 3px 4px 3px;``. This makes it more obvious that the 254 padding is symmetrical (so RTL won't be an issue). 255 256 .. note:: 257 258 See `CSS Logical Properties and 259 Values <https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties>`__ 260 for more information. 261 262 Writing cross-platform CSS 263 -------------------------- 264 265 Firefox supports many different platforms and each of those platforms 266 can contain many different configurations: 267 268 - Windows 7, 8 and 10 269 270 - Default theme 271 - Aero basic (Windows 7, 8) 272 - Windows classic (Windows 7) 273 - High contrast (All versions) 274 275 - Linux 276 - macOS 277 278 File structure 279 ~~~~~~~~~~~~~~ 280 281 - The ``browser/`` directory contains styles specific to Firefox 282 - The ``toolkit/`` directory contains styles that are shared across all 283 toolkit applications (Thunderbird and SeaMonkey) 284 285 Under each of those two directories, there is a ``themes`` directory 286 containing 4 sub-directories: 287 288 - ``shared`` 289 - ``linux`` 290 - ``osx`` 291 - ``windows`` 292 293 The ``shared`` directories contain styles shared across all 3 platforms, 294 while the other 3 directories contain styles respective to their 295 platform. 296 297 For new CSS, when possible try to privilege using the ``shared`` 298 directory, instead of writing the same CSS for the 3 platform specific 299 directories, especially for large blocks of CSS. 300 301 Content CSS vs. Theme CSS 302 ^^^^^^^^^^^^^^^^^^^^^^^^^ 303 304 The following directories also contain CSS: 305 306 - ``browser/base/content/`` 307 - ``toolkit/content/`` 308 309 These directories contain content CSS, that applies on all platforms, 310 which is styling deemed to be essential for the browser to behave 311 correctly. To determine whether some CSS is theme-side or content-side, 312 it is useful to know that certain CSS properties are going to lean one 313 way or the other: color - 99% of the time it will be theme CSS, overflow 314 - 99% content. 315 316 +-----------------+--------------+----------------+----------------+ 317 | 99% theme | 70% theme | 70% content | 99% content | 318 +=================+==============+================+================+ 319 | font-\*, color, | line-height, | cursor, width, | overflow, | 320 | \*-color, | padding, | max-width, | direction, | 321 | border-\*, | margin | top, | display, | 322 | -moz-appearance | | bottom [2]_, | \*-align, | 323 | [1]_ | | etc | align-\*, | 324 | | | | \*-box-\*, | 325 | | | | flex-\*, order | 326 +-----------------+--------------+----------------+----------------+ 327 328 If some CSS is layout or functionality related, then it is likely 329 content CSS. If it is esthetics related, then it is likely theme CSS. 330 331 When importing your stylesheets, it's best to import the content CSS 332 before the theme CSS, that way the theme values get to override the 333 content values (which is probably what you want), and you're going to 334 want them both after the global values, so your imports will look like 335 this: 336 337 .. code:: html 338 339 <?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?> 340 <?xml-stylesheet href="chrome://browser/content/path/module.css" type="text/css"?> 341 <?xml-stylesheet href="chrome://browser/skin/path/module.css" type="text/css"?> 342 343 .. [1] -moz-appearance is tricky. Generally, when specifying 344 -moz-appearance: foo; you're giving hints as to how something should 345 act, however -moz-appearance: none; is probably saying 'ignore 346 browser preconceptions - I want a blank sheet', so that's more 347 visual. However -moz-appearance values aren't implemented and don't 348 behave consistently across platforms, so idealism aside 349 -moz-appearance should always be in theme CSS. 350 351 .. [2] However there is probably a better way than using absolute 352 positioning. 353 354 Colors 355 ~~~~~~ 356 357 For common areas of the Firefox interface (panels, toolbar buttons, 358 etc.), mozilla-central often comes with some useful CSS variables that 359 are adjusted with the correct values for different platform 360 configurations, so using those CSS variables can definitively save some 361 testing time, as you can assume they already work correctly. 362 363 Using the ``currentcolor`` keyword or inheriting is also good practice, 364 because sometimes the needed value is already in the color or on the 365 parent element. This is especially useful in conjunction with icons 366 using ``-moz-context-properties: fill;`` where the icon can adjust to 367 the right platform color automatically from the text color. It is also 368 possible to use ``currentcolor`` with other properties like 369 ``opacity`` or ``fill-opacity`` to have different 370 opacities of the platform color. 371 372 High contrast mode 373 ~~~~~~~~~~~~~~~~~~ 374 375 Content area 376 ^^^^^^^^^^^^ 377 378 On Windows high contrast mode, in the content area, Gecko does some 379 automatic color adjustments regarding page colors. Part of those 380 adjustments include making all ``box-shadow`` invisible, so this is 381 something to be aware of if you create a focus ring or a border using 382 the ``box-shadow`` property: consider using a ``border`` or an 383 ``outline`` if you want the border/focus ring to stay visible in 384 high-contrast mode. An example of such bug is `bug 385 1516767 <https://bugzilla.mozilla.org/show_bug.cgi?id=1516767>`__. 386 387 Another adjustment to be aware of is that Gecko removes all the 388 ``background-image`` when high contrast mode is enabled. Consider using 389 an actual ``<img>`` tag (for HTML documents) or ``list-style-image`` 390 (for XUL documents) if rendering the image is important. 391 392 If you are not using Windows, one way to test against those adjustments 393 on other platforms is: 394 395 - Going to about:preferences 396 - Clicking on the "Colors..." button in the "Fonts & Colors" 397 sub-section of the "Language and Appearance" section 398 - Under "Override the colors specified by the page with your selections 399 above", select the "Always" option 400 401 Chrome area 402 ^^^^^^^^^^^ 403 404 The automatic adjustments previously mentioned only apply to pages 405 rendered in the content area. The chrome area of Firefox uses colors as 406 authored, which is why using pre-defined variables, ``currentcolor`` or 407 inheritance is useful to integrate with the system theme with little 408 hassle. 409 410 If not, as a last resort, using `system 411 colors <https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#system_colors>`__ 412 also works for non-default Windows themes or Linux. In general, the 413 following colors are used: 414 415 - ``-moz-Field``: textbox or field background colors, also used as the 416 background color of listboxes or trees. 417 - ``-moz-FieldText``: textbox or field text colors, also used as the 418 text color of listboxes or trees. 419 - ``-moz-Dialog``: window or dialog background color. 420 - ``-moz-DialogText``: window or dialog text color. 421 - ``GrayText``: used on disabled items as text color. Do not use it on 422 text that is not disabled to desemphsize text, because it does not 423 guarantee a sufficient contrast ratio for non-disabled text. 424 - ``ThreeDShadow``: Used as border on elements. 425 - ``ThreeDLightShadow``: Used as light border on elements. 426 427 Using the background/text pairs is especially important to ensure the 428 contrast is respected in all situations. Never mix custom text colors 429 with a system background color and vice-versa. 430 431 Note that using system colors is only useful for the chrome area, since 432 content area colors are overridden by Gecko anyway. 433 434 Writing media queries 435 ~~~~~~~~~~~~~~~~~~~~~ 436 437 Boolean media queries 438 ^^^^^^^^^^^^^^^^^^^^^ 439 440 Do this: 441 442 .. code:: css 443 444 @media (-moz-mac-yosemite-theme: 0) { 445 446 Not this: 447 448 .. code:: css 449 450 @media not all and (-moz-mac-yosemite-theme) { 451 452 Privilege CSS for most common configuration 453 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 454 455 It is better to put the most common configuration (latest version of an 456 OS, or default theme for example) outside of the media query. In the 457 following example, ``-moz-mac-yosemite-theme`` targets macOS 10.10 and 458 higher, so it should be privileged over the styling for macOS 10.9. 459 460 Do this: 461 462 .. code:: css 463 464 @media (-moz-mac-yosemite-theme: 0) { 465 #placesList { 466 box-shadow: inset -2px 0 0 hsla(0,0%,100%,.2); 467 } 468 } 469 470 Not this: 471 472 .. code:: css 473 474 #placesList { 475 box-shadow: inset -2px 0 0 hsla(0,0%,100%,.2); 476 } 477 478 @media (-moz-mac-yosemite-theme) { 479 #placesList { 480 box-shadow: none; 481 } 482 } 483 484 Theme support 485 ------------- 486 487 Firefox comes built-in with 3 themes: default, light and dark. The 488 built-in light/dark themes are a bit special as they load the 489 ``compacttheme.css`` stylesheet. In addition to this, Firefox supports a 490 variety of WebExtension themes that can be installed from AMO. For 491 testing purposes, `here is an example of a WebExtension 492 theme. <https://addons.mozilla.org/en-US/firefox/addon/arc-dark-theme-we/>`__ 493 494 Writing theme-friendly CSS 495 ~~~~~~~~~~~~~~~~~~~~~~~~~~ 496 497 - Some CSS variables that are pre-adjusted for different platforms are 498 also pre-adjusted for themes, so it's again a good idea to use them 499 for theme support. 500 - The text color of elements often contains valuable information from 501 the theme colors, so ``currentcolor``/inheritance is again a good 502 idea for theme support. 503 - Never write CSS specially for the built-in light/dark theme in 504 ``compacttheme.css`` unless that CSS isn't supposed to affect 505 WebExtension themes. 506 - These selectors can be used to target themed areas, though in general it's 507 recommended to try to avoid them and use ``light-dark()`` to get the right 508 colors automatically: 509 510 - ``:root[lwt-toolbar-field="light/dark"]``: explicitly light or dark address bar and 511 searchbar. 512 - ``:root[lwt-toolbar-field-focus="light/dark"]``: explicitly light or dark address bar and 513 searchbar in the focused state. 514 - ``:root[lwt-popup="light/dark"]``: explicitly light or dark arrow panels 515 and autocomplete panels. 516 - ``:root[lwt-sidebar="light/dark"]``: explicitly light or dark sidebars. 517 518 - If you'd like a different shade of a themed area and no CSS variable 519 is adequate, using colors with alpha transparency is usually a good 520 idea, as it will preserve the original theme author's color hue. 521 522 Variables 523 ~~~~~~~~~ 524 525 For clarity, CSS variables that are only used when a theme is enabled 526 have the ``--lwt-`` prefix. 527 528 Layout & performance 529 -------------------- 530 531 Layout 532 ~~~~~~ 533 534 Mixing XUL flexbox and HTML flexbox can lead to undefined behavior. 535 536 CSS selectors 537 ~~~~~~~~~~~~~ 538 539 When targeting the root element of a page, using ``:root`` is the most 540 performant way of doing so. 541 542 Reflows and style flushes 543 ~~~~~~~~~~~~~~~~~~~~~~~~~ 544 545 See :ref:`Performance best practices for Firefox front-end engineers` 546 for more information about this. 547 548 Misc 549 ---- 550 551 Text aliasing 552 ~~~~~~~~~~~~~ 553 554 When convenient, avoid setting the ``opacity`` property on 555 text as it will cause text to be aliased differently. 556 557 HDPI support 558 ~~~~~~~~~~~~ 559 560 It's recommended to use SVG since it keeps the CSS clean when supporting 561 multiple resolutions. See the :ref:`SVG Guidelines` for more information 562 on SVG usage. 563 564 However, if only 1x and 2x PNG assets are available, you can use this 565 ``@media`` query to target higher density displays (HDPI): 566 567 .. code:: css 568 569 @media (min-resolution: 1.1dppx)