Skip to main content

    Guidelines for good SCSS / CSS

    We're moving our docs!

    Find the latest version of this page on the Platform website.

    Still can't find what you're looking for? Reach out to #vfs-platform-support on Slack.

    Some guidelines for writing good CSS that scales well and doesn't make your colleagues ragey.

    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:

    #content {
      ol {
        p {}
      }
    }
    

    Compiles to:

    #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:

    .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.)

    h4 {
      color: #c09;
      font-size: 1.2rem;
      font-weight: 100;
    }
    
    label {
      @extend h4;
      cursor: pointer;
    }
    
    .footer h4 {
      display: inline;
    }
    

    Compiles to:

    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.

    Periodially 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.