Skip to main content
Skip table of contents

Guidelines for good SCSS / CSS

Use low-specificity selectors

The more specific the selector is, the less reusable the accompanying CSS is and/or the longer a selector you need to override it. (Or you add !important in places you shouldn't.)

The following should be used sparingly in CSS

  • id selectors.

  • Complex element/type selectors with attributes such as button[type=button] and input[type=text].

  • Descendant combinators such as #main ol li ul or .process p a.

  • Chaining class names. button and button.lg)

High specificity selectors are more likely to create side effects, that have to be undone with more CSS rules or longer selectors.

Avoid nesting SCSS selectors prematurely

SCSS compiles nested selectors into descendant combinators. For example:

CODE
#content {
  ol {
    p {}
  }
}

Compiles to:

CODE
#content ol p {}

There's a high likelihood, however that your selectors don't need to be that long; ol p would provide the same styling. If the worry is being overly broad, you can get the same results using a class name. This is related to the previous point. Specific selectors are often caused by SCSS nesting.

Nesting selectors can be useful, however, when creating variants. For example:

CODE
.button {
  &-link {
  }
}

Compiles to button-link.

Restrict class names to a single pattern or component type.

For example, don't use .process for lists and as a div or section type. Rules you introduce for div.process probably aren't related to those for ol.process. Instead use .list-process and .section-process.

Favor descriptive class names that describe what the class does or the kind of content it affects

Class names such as .primary, or .section are confusing and more likely to be misused by a colleague than .intro-text or .sidebar.

Use a product-specific prefix to avoid class name collisions

This keeps selector specificity low, while also restricting the side-effects of any one selector.

Don't use @extend

SCSS @extend repeats every instance of the extended selector for the extendee selector. (This will be flagged by our Sass-lint configuration.)

CODE
h4 {
  color: #c09;
  font-size: 1.2rem;
  font-weight: 100;
}

label {
  @extend h4;
  cursor: pointer;
}

.footer h4 {
  display: inline;
}

Compiles to:

CODE
h4, label {
  color: #c09;
  font-size: 1.2rem;
  font-weight: 100; }

label {
  cursor: pointer; }

.footer h4, .footer label {
  display: inline; }

Every instance of h4 will also be applied to label. This is usually not the behavior we want, particularly across an entire code base.

CHECK. YOUR. OUTPUT.

Periodically check your generated CSS files (JavaScript too!) to ensure that you didn't introduce bloat with your selectors or asset imports.

True story: we reduced the size of our home page CSS by ~400K by removing SVG fonts. Our Webpack configuration included base64-encoded versions of SVG fonts which dramatically inflated our file size. This fact was discovered only after viewing the generated CSS files.


JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.