Skip to content

dropbox/css-style-guide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 

Repository files navigation

Dropbox (S)CSS Style Guide

“Every line of code should appear to be written by a single person, no matter the number of contributors.” —@mdo

General

Don’ts

  • Avoid using HTML tags in CSS selectors
    • E.g. Prefer .o-modal {} over div.o-modal {}
    • Always prefer using a class over HTML tags (with some exceptions like CSS resets)
  • Don't use ids in selectors
    • #header is overly specific compared to, for example .header and is much harder to override
    • Read more about the headaches associated with IDs in CSS here.
  • Don’t nest more than 3 levels deep
    • Nesting selectors increases specificity, meaning that overriding any CSS set therein needs to be targeted with an even more specific selector. This quickly becomes a significant maintenance issue.
  • Avoid using nesting for anything other than pseudo selectors and state selectors.
    • E.g. nesting :hover, :focus, ::before, etc. is OK, but nesting selectors inside selectors should be avoided.
  • Don't !important
    • Ever.
    • If you must, leave a comment, and prioritise resolving specificity issues before resorting to !important.
    • !important greatly increases the power of a CSS declaration, making it extremely tough to override in the future. It’s only possible to override with another !important declaration later in the cascade.
  • Don’t use margin-top.
    • Vertical margins collapse. Always prefer padding-top ormargin-bottom on preceding elements
  • Avoid shorthand properties (unless you really need them)
    • It can be tempting to use, for instance, background: #fff instead of background-color: #fff, but doing so overrides other values encapsulated by the shorthand property. (In this case, background-image and its associative properties are set to “none.”
    • This applies to all properties with a shorthand: border, margin, padding, font, etc.

Spacing

  • Four spaces for indenting code
  • Put spaces after : in property declarations
    • E.g. color: red; instead of color:red;
  • Put spaces before { in rule declarations
    • E.g. .o-modal { instead of .o-modal{
  • Write your CSS one line per property
  • Add a line break after } closing rule declarations
  • When grouping selectors, keep individual selectors on a single line
  • Place closing braces } on a new line
  • Add a new line at the end of .scss files
  • Trim excess whitespace

Formatting

  • All selectors are lower case, hyphen separated aka “spinal case” eg. .my-class-name
  • Always prefer Sass’s double-slash // commenting, even for block comments
  • Avoid specifying units for zero values, e.g. margin: 0; instead of margin: 0px;
  • Always add a semicolon to the end of a property/value declaration
  • Use leading zeros for decimal values opacity: 0.4; instead of opacity: .4;
  • Put spaces before and after child selector div > span instead of div>span

Sass Specifics

Internal order of a .scss file

  1. Imports
  2. Variables
  3. Base Styles
  4. Experiment Styles

Example:

//------------------------------
// Modal
//------------------------------

@import "../constants";
@import "../helpers";

$DBmodal-namespace: "c-modal" !default;
$DBmodal-padding: 32px;

$DBmodal-background: #fff !default;
$DBmodal-background-alt: color(gray, x-light) !default;

.o-modal { ... }

// Many lines later...

// EXPERIMENT: experiment-rule-name
.o-modal--experiment { ... }
// END EXPERIMENT: experiment-rule-name

Variables

  • Define all variables at the top of the file after the imports
  • Namespace local variables with the filename (SASS has no doc level scope)
    • eg business_contact.scss$business_contact_font_size: 14px;
  • Local variables should be $snake_lowercase
  • Global constants should be $SNAKE_ALL_CAPS

Color

  • Use the defined color constants via the color function
  • Lowercase all hex values #fffff
  • Limit alpha values to a maximum of two decimal places. Always use a leading zero.

Example:

// Bad
.c-link {
  color: #007ee5;
  border-color: #FFF;
  background-color: rgba(#FFF, .0625);
}

// Good
.c-link {
  color: color(blue);
  border-color: #ffffff;
  background-color: rgba(#ffffff, 0.1);
}

Experiments

Wrap experiment styles with comments:

// EXPERIMENT: experiment-rule-name
.stuff { ... }
// END EXPERIMENT: experiment-rule-name

Rule Ordering

Properties and nested declarations should appear in the following order, with line breaks between groups:

  1. Any @ rules
  2. Layout and box-model properties
  • margin, padding, box-sizing, overflow, position, display, width/height, etc.
  1. Typographic properties
  • E.g. font-, line-height, letter-spacing, text-, etc.
  1. Stylistic properties
  • color, background-*, animation, border, etc.
  1. UI properties
  • appearance, cursor, user-select, pointer-events, etc.
  1. Pseudo-elements
  • ::after, ::before, ::selection, etc.
  1. Pseudo-selectors
  • :hover, :focus, :active, etc.
  1. Modifier classes
  2. Nested elements

Here’s a comprehensive example:

.c-btn {
    @extend %link--plain;

    display: inline-block;
    padding: 6px 12px;

    text-align: center;
    font-weight: 600;

    background-color: color(blue);
    border-radius: 3px;
    color: white;

    &::before {
        content: '';
    }

    &:focus, &:hover {
        box-shadow: 0 0 0 1px color(blue, .3);
    }

    &--big {
        padding: 12px 24px;
    }

    > .c-icon {
        margin-right: 6px;
    }
}

Nesting

  • As a general rule of thumb, avoid nesting selectors more than 3 levels deep
  • Prefer using nesting as a convenience to extend the parent selector over targeting nested elements. For example:
    .block {
        padding: 24px;
    
        &--mini {
            padding: 12px;
        }
    }

Nesting can be really easily avoided by smart class naming (with the help of BEM) and avoiding bare tag selectors.


BEM

Block: Unique, meaningful names for a logical unit of style. Avoid excessive shorthand.

  • Good: .alert-box or .recents-intro or .button
  • Bad: .feature or .content or .btn

Element: styles that only apply to children of a block. Elements can also be blocks themselves. Class name is a concatenation of the block name, two underscores and the element name. Examples:

  • .alert-box__close
  • .expanding-section__section

Modifier: override or extend the base styles of a block or element with modifier styles. Class name is a concatenation of the block (or element) name, two hyphens and the modifier name. Examples:

  • .alert-box--success
  • .expanding-section--expanded

BEM Best practices

Don't @extend block modifiers with the block base.

  • Good: <div class="my-block my-block--modifier">
  • Bad: <div class="my-block--modifier">

Don't create elements inside elements. If you find yourself needing this, consider converting your element into a block.

  • Bad: .alert-box__close__button

Choose your modifiers wisely. These two rules have very different meaning:

.block--modifier .block__element { color: red; }
.block__element--modifier { color: red; }

Selector Naming

  • Try to use BEM-based naming for your class selectors
    • When using modifier classes, always require the base/unmodified class is present
  • Use Sass’s nesting to manage BEM selectors like so:
    .block {
        &--modifier { // compiles to .block--modifier
            text-align: center;
        }
    
        &__element { // compiles to .block__element
            color: red;
    
            &--modifier { // compiles to .block__element--modifier
                color: blue;
            }
        }
    }

Namespaced Classes

There are a few reserved namespaces for classes to provide common and globally-available abstractions.

  • .o- for CSS objects. Objects are usually common design patterns (like the Flag object). Modifying these classes could have severe knock-on effects.
  • .c- for CSS components. Components are designed pieces of UI—think buttons, inputs, modals, and banners.
  • .u- for helpers and utilities. Utility classes are usually single-purpose and have high priority. Things like floating elements, trimming margins, etc.
  • .is-, .has- for stateful classes, a la SMACSS. Use these classes for temporary, optional, or short-lived states and styles.
  • ._ for hacks. Classes with a hack namespace should be used when you need to force a style with !important or increasing specificity, should be temporary, and should not be bound onto.
  • .t- for theme classes. Pages with unique styles or overrides for any objects or components should make use of theme classes.

Separation of Concerns (One Thing Well™)

You should always try to spot common code—padding, font sizes, layout patterns—and abstract them to reusable, namespaced classes that can be chained to elements and have a single responsibility. Doing so helps prevent overrides and duplicated rules, and encourages a separation of concerns.

// Bad code
// HTML:
// <div class="modal compact">...</div>
.modal {
    padding: 32px;
    background-color: color(gray, x-light);

    &.compact {
        padding: 24px;
    }
}

// Good code
// HTML:
// <div class="c-modal u-l-island">...</div>
// <div class="c-modal u-l-isle">...</div>

// components/_modal.scss
.c-modal {
    background-color: color(gray, x-light);
}

// helpers/_layout.scss
.u-l-island {
    padding: 32px;
}

.u-l-isle {
    padding: 24px;
}

Media Queries

Media queries should be within the CSS selector as per SMACSS

.selector {
      float: left;

      @media only screen and (max-width: 767px) {
        float: none;
      }
}

Create variables for frequently used breakpoints

$SCREEN_SM_MAX: "max-width: 767px";

.selector {
      float: left;

      @media only screen and ($SCREEN_SM_MAX) {
        float: none;
      }
}