Skip to main content
FreddieMac.com

SCSS Code Standards

Use only lowercase, and separate terms in class names by hyphens, not underscores. Name single-purpose classes using SMACSS naming scheme: container-element-modifier.

 // Good
.grid-block {}
.grid-block-title {}

// Not this
.CustomButton {}
.menu_bar {}

Avoid using #ids in selectors. Stick with classes.

 // Good
.primary-nav {}

// Not This
#primary-nav {}

Name multipurpose or modifier classes without block or element designation.

.uppercase {}
.weight-black {}
.vertical-baseline {}

Write for readability – use line breaks between declarations and selectors and use 2 spaces for each level of indention. The compiler will condense spaces and strip out line returns in the minified css.

 figure {
  margin: 0;
  img {
    width: 100%;
    &:hover,
    &:focus {
      opacity: 0.9;
    }
  }
}

When styling sub-elements of a component, prefer writing a new class over using a tag selector where possible. This reduces selector specificity, making it easier for the user to override default styles. It also reduces the risk that tag styles will leak into other elements.

 // Okay, and occasionally necessary to override Foundation's defaults
.menu-bar > li {}

// Better
.menu-bar-item {}

Keep selectors shallow

Whenever possible, avoid nesting a selector inside its parent. The purpose of nesting is to create scope, but by including the parent's class name in the child class, you've already effectively scoped it.

The deeper you nest, the more bandwidth it takes to serve your CSS and the more work it takes the browser to render it, because browsers evaluate each css rule from right to left, starting from the rightmost selector.

 // Avoid Whenever Possible
.menu-bar {
  .menu-bar-item {}
}
.menu-bar .menu-bar-item {}

// Better
.menu-bar {}
.menu-bar-item {}

When you write deeply nested css such as the following, you are forcing the browser to

  1. Find all anchor elements
  2. Check to see if they are in an li element
  3. If so, check to see if those are in a ul element
  4. If so, check to see if those are in a nav element
  5. If so, check to see if those are in an element with class .header
  6. If so, check to see if that element is a div element
  7. If so, change color in the anchor element to #666
 // Do Not Deeply Nest
div.header nav ul li a {
  color: #666;
}

When styling a tag, consider using the child selector to prevent conflicts, especially for structural components that could include any HTML inside of it.

 // Problematic, because now *every* <li> inside tabs will be styled this way
.tabs li {}
// Better, because you've restricted the reach of the selector
.tabs > li {}
// Even better, because you've reduced specificity
.tabs-item {}

For really generic class names (such as .large or .small), or class names that are used in multiple components, chain them to the main class. Foundation often re-uses the same class names for different components, so each instance needs to be isolated from the others. It's also possible that other libraries or styles could clash with a generic word.

 // Good
.button.primary {}
.callout.large {}

// Not this
.large {}
.primary {}

Avoid meaningless concatenation

Avoid meaningless concatenation and write for findability. Keep in mind that other developers will be sharing the same SCSS files.

 // Good -- clear without needing concatenation
.image-portrait {}
.image-square {}

// Meaningless Concatenation
// If another developer searched all scss files for class names that started with "image-", they’d fail to find these styles.
  .image {
    &-portrait {}
    &-square {}
  }

Use meaningful concatenation when generating class names based on a map of values (breakpoints, sizes, palettes) to

  • speed up development
  • ensure consistent naming
  • ensure that changes to a map (such as the addition of a new breakpoint, size, or palette color) are immediately available in class names.
 // Meaningful Concatenation
// this code uses interpolation to create a class for each color in $orbit-palette.
  @each $name, $color in   $orbit-palette {
    $current-contrast: color-contrast($color, $white);
    .background-#{$name} {
      background-color: $color;
      @if ($current-contrast > 1.6) {
        color: $white;
      }
    }
  }

Comment heavily!

Use comments to document mixins, functions, variables, placeholders, magic numbers, and changes to the Foundation's defaults.

 // This single-line comment won't be included in the generated CSS.

/* In fact, even this multiline comment won't be
included in the generated CSS. */

span /* Multi-line comments can be written anywhere
    * whitespace is allowed. */ .sans {
  font: Helvetica, sans-serif;  // So can single-line commments.
}

Media Queries

Use media queries inside the selector whenever possible.

 // Good
.container {
  background-color: $white;
  color: $black;
  @include breakpoint(small) {
    max-width: 100%;
  }
  @include breakpoint(large) {
    max-width: 50%;
    float: left;
  }
}

// Not this.
.container {
  background-color: $white;
  color: $black;
}
@include breakpoint(small) {
  .container {
    max-width: 100%;
  }
}
@include breakpoint(large) {
  .container {
    max-width: 50%;
    float: left;
  }
}

Dynamic classes modified by JavaScript

Dynamic classes modified by JavaScript should be prefixed with the word .is-. This sets them apart as a special kind of CSS class, and also ensures that UnCSS doesn't strip them out.

Some dynamic classes modify the state of an element temporarily.

 // Basic tab pane
.tab-pane {
  display: none;
}

// Tab pane made visible
.tab-pane.is-active {
  display: block;
}

Other dynamic classes apply structural logic necessary for a plugin to function. The menu plugins are a good example of this.

 // Applied to the top-level <ul> of a dropdown menu
.is-dropdown-menu {}

// Applied to nested <ul>s in a dropdown menu
.is-dropdown-submenu {}

// Applied to <li>s that house a nested <ul>
.is-dropdown-submenu-parent {}

Font sizes and Line-Heights

Use rem-calc() for font sizes and unitless ratios for line height.

Comps from the design studio typically have pixel-based sizes and line heights. By using rem-calc() you can maintain their px value in the SCSS while outputting standard rem units. For line height ratios, divide the desired line-height by the font-size (such as 52/43)

Some dynamic classes modify the state of an element temporarily.

 // Good
h1 {
  font-size: rem-calc(43);
  line-height: 1.21;
}

// Not This
h1 {
  font-size: 43px;
  line-height: 52px;
}