Code guidelines
beta

The SCSS coding styleguide provides rules and guidance around writing and maintaining styles for projects throughout E*TRADE. It aims to establish a high standard of code, to support easy maintenance through quick understanding and code style consistency. Our standards are derived from the Design Language styles framework, reference best practices and web standards. The Design Language source code is available on Bitbucket.

Terminology: Sass or SCSS

Sass is a CSS pre-processor with syntax advancements. Sass is compiled and turned into regular CSS style sheets. The main reason for this is the addition of features that CSS painfully lacks (like variables). However, Sass does not extend the CSS standard itself. There are two syntaxes available for Sass. The first, known as SCSS, used throughout this guide, is an extension of the syntax of CSS. This syntax is enhanced through compiling the the files, allowing the use of variables, functions and more. (The second, and older syntax, known as indented syntax or simply as "Sass", uses indentation rather than brackets, and newlines instead of semicolons. This syntax is NOT used by the Design Language.)

First of all, your SCSS code must pass lint to help keep your scss files clean and readable. The Design Language linter rules are a slight modification (modifications noted below) of Sass Lint, a Node-only Sass linter for both sass and scss syntax. See linter default rules to learn more.

Design Language Linter Rules:
  1. Class names must be lowercase alpha characters and may include a hyphen.
    done Allowed:
    .good-class-name
    clear Not allowed:
    .badClassName .improper_class_
    GO BACK
  2. Mixin names must be lowercase alpha characters and may include a hyphen.
    done Allowed:
    @mixin good-mixin-name($param) {...}
    clear Not allowed:
    @mixin BADmixinName($param) {...} @mixin improper_mixin_($param) {...}
    GO BACK
  3. Placeholder names must be lowercase alpha characters and may include a hyphen.
    done Allowed:
    %good-placeholder-name
    clear Not allowed:
    %badPlaceholderName %improper_placeholder_
    GO BACK
  4. Function names must be lowercase alpha characters and may include a hyphen.
    done Allowed:
    @function good-function-name() {...}
    clear Not allowed:
    @function BADfunctionName($param) {...} @function improper_function_() {...}
  5. Variable names must be lowercase alpha characters and may include a hyphen.
    done Allowed:
    $good-var-name
    clear Not allowed:
    $badVarName $improper_variable_
    GO BACK
  6. Leading underscores and filename extensions are not allowed in @import paths. For filename _account-profile.scss:
    done Allowed:
    @import "account-profile";
    clear Not allowed:
    @import "_account-profile.scss";
    More about File Structure.
    GO BACK
  7. Extends should be before declarations.
    done Allowed:
    .some-class {
      @extend %placeholder-class;
      .add-styling {...}
    }
    
    clear Not allowed:
    .some-class {
      .add-styling {...}
      @extend %placeholder-class;
    }
    
  8. Extends should be before mixins.
    done Allowed:
    .some-class {
      @extend %placeholder-class;
      @include some-mixin() {...}
    }
    
    clear Not allowed:
    .some-class {
      @include some-mixin() {...}
      @extend %placeholder-class;
    }
    
  9. Mixins should be before declarations.
    done Allowed:
    .some-class {
      @include some-mixin() {...}
      .add-styling {...}
    }
    
    clear Not allowed:
    .some-class {
      .add-styling {...}
      @include some-mixin() {...}
    }
    
  • Rules 7, 8, and 9 (above) should be considered all together.
    done Allowed:
    .some-class {
      @extend %placeholder-class;
      @include some-mixin() {...}
      .add-styling {...}
    }
    
    clear Not allowed:
    .some-class {
      .add-styling {...}
      @extend %placeholder-class;
      @include some-mixin() {...}
    }
    
    .some-class {
      @extend %placeholder-class;
      .add-styling {...}
      @include some-mixin() {...}
    }
    
    .some-class {
      @include some-mixin() {...}
      @extend %placeholder-class;
      .add-styling {...}
    }
    
    More about Formatting SCSS.
  1. Classes shoud never be nested more than 3 deep.
    Note: Lint default is 2 deep. The Design Language allows 3 deep nesting.
    done Allowed:
    .first-level {
      width: 1px;
    }
    
    .first-level {
      .second-level {
        width: 1px;
      }
    }
    
    .first-level {
      .second-level {
        .third-level {
          width: 1px;
        }
      }
    }
    
    clear Not allowed:
    .first-level {
      .second-level {
        .third-level {
          .fourth-level {
            width: 1px;
          }
        }
      }
    }
    
    GO BACK
  2. Colors must be expressed as hexadecimal color values rather than literals.
    done Allowed:
    color: #f00; color: #ff0000;
    clear Not allowed:
    color: red;
    More about Colors.
    GO BACK
  3. All hex values must be 3 or 6 characters in length.
    done Allowed:
    $color-red: #f00; $color-red: #ff0000;
    clear Not allowed:
    $too-short: #f0; $also-short-or-long: #ff00; $too-long: #ff00f00;
    GO BACK
  4. Do not use protocols or domains in URLs.
    done Allowed:
    background-image: url('/images/some_image.png');
    clear Not allowed:
    background-image: url('https://company.com/images/some_image.png');
  5. Never use vendor prefixes.
    done Allowed:
    @keyframes anim {...} ::placeholder {...} transition: none;
    clear Not allowed:
    @-webkit-keyframes anim {...} ::-moz-placeholder {...} -ms-transition: none;
    More about Autoprefixers.
    GO BACK
  6. No misspelled/unknown CSS properties.
    done Allowed:
    border: 1px solid $border-color; padding-left: 10px;
    clear Not allowed:
    borders: 1px solid $border-color; left-padding: 10px;
  7. No duplicate CSS properties within the same block.
    done Allowed:
    .some-class {
      margin: 0;
    }
    
    .some-class {
      margin: 0;
      margin-left: 10px;
    }
    
    clear Not allowed:
    .some-class {
      margin: 0;
      margin: 0 0 0 10px;
    }
    
  8. No repeated/mergeable selectors.
    done Allowed:
    .some-class {
      margin: 0;
      width: 10px;
    }
    
    clear Not allowed:
    .some-class {
      margin: 0;
    }
    
    .some-class {
      width: 10px;
    }
    
    GO BACK
  9. No empty rulesets.
    done Allowed:
    .some-class {
      width: 10px;
    }
    
    .some-class {
      .another-class {
        width: 10px;
      }
    }
    
    clear Not allowed:
    .some-class {}
    .some-class {
    
    }
    
    .some-class {
      .another-class {
    
      }
    }
    
    GO BACK
  10. Each declaration must be on its own line.
    done Allowed:
    .some-class {
      margin: 0;
      width: 10px;
    }
    
    clear Not allowed:
    .some-class {content: 'text', content: 'more text'}
    .some-class {
      margin: 0; width: 10px;
    }
    
    GO BACK
  11. Declarations must end with a semi-colon.
    done Allowed:
    .some-class {
      margin: 0;
      width: 10px;
    }
    
    clear Not allowed:
    .some-class {
      margin: 0
      width: 10px
    }
    
    GO BACK
  12. There must be no trailing whitespace. No whitespace at the end of a line of code. (\s denotes spaces or tabs.)
    done Allowed:
    .some-class {
      margin: 0;
    }
    
    clear Not allowed:
    .some-class {\s
      margin: 0;
    }
    
    .some-class {
      margin: 0;\s
    }
    
    .some-class {
      margin: 0;
    }\s
    
  13. No trailing zeros in decimal values.
    done Allowed:
    margin: 1.5rem; opacity: 0.5;
    clear Not allowed:
    margin: 1.500rem; opacity: 0.50;
  14. Never use !important.
    done Allowed:
    .some-class {
      margin: 0;
    }
    
    form {
      .some-class-for-specificity {
        .some-class {
          margin: 0;
        }
      }
    }
    
    clear Not allowed:
    .some-class {
      margin: 0 !important;
    }
    
    More about !important and specificity.
  15. You must include a space after a comma.
    done Allowed:
    @include some-mixin(param, another-param) box-shadow: 1px 1px #000000, 1px 1px #000000;
    clear Not allowed:
    @include some-mixin(param,another-param) box-shadow: 1px 1px #000000,1px 1px #000000;
    GO BACK
  16. You must include a space after a colon.
    done Allowed:
    margin: 10px;
    clear Not allowed:
    margin:10px;
    GO BACK
  17. You must include a space before a curly bracket.
    done Allowed:
    .some-class {...} @some-mixin {...}
    clear Not allowed:
    .some-class{...} @some-mixin{...}
    GO BACK
  18. You must include a space before and after an operator.
    done Allowed:
    @if $var == $another-var {...} margin: $var + $another-var + 'px';
    clear Not allowed:
    @if $var== $another-var {...} @if $var==$another-var {...} margin: $var+ $another-var +'px'; margin: $var+$another-var+'px';
Be consistent with indentation and spacing. This makes your code more readable and therefore, easier to maintain. Using a prettifier helps maintain uniformity. (HTML Prettify for SublimeText, Beautify for Atom)
Use a space after a comma. See code examples.
Use a space after a colon. See code examples.
Use a space in front of each curly bracket. See code examples.
Use names that have meaning.
Selectors/Class Names
If your class adds a yellow background to the element:
done Good:
.background-yellow
clear Bad:
.bg-y
GO BACK
Mixin Names
If your mixin creates variations of links:
done Good:
@mixin link-variations($param) {...}
clear Bad:
@mixin myLinksMixin($param) {...}
GO BACK
Placeholder Names
If your placeholder centers an element:
done Good:
%center-block-element {...}
clear Bad:
%ctr {...}
GO BACK
Variable Names
Regarding variable names:
done Good:
$link-color $link-color-hover $card-border-width $font-weight-medium
clear Bad:
$txtLinks $hover $c-b-w $md
GO BACK
Comment your code. Sometimes meaningful names are not enough. Comment your code for understanding. It's OK to be VERY verbose regarding SCSS comments. Keep in mind that CSS comments /* comment */ are compiled into the CSS style sheet while SCSS comments // comment are not. This is important when considering page weight.
Never use an ID for styling. If you need an id for use as a selector, for instance in your JavaScript, you can also create a class if the element needs styling.
done Good:
.some-class {...}
clear Bad:
#some-id {...}
GO BACK
Never use an element or tag for styling. Always add a class when an element needs styling. This will avoid confusion, and bugs, if later more tags with the same name are added to the markup.
done Good:
div.some-class {...}
clear Bad:
div {...}
GO BACK
Don't have a class with no styling rules.
See code examples.
Keep properties together. Repeat or mergeable selectors are not allowed. Although repeat selectors will create valid CSS, it becomes difficult to maintain because it is unreadable, especially if the selector blocks are not near each other. It is bad practice to put CSS properties in different blocks for the same selector.
See code examples.
Put each declaration on its own line. See code examples.
Also, end each declaration with a semicolon. See code examples.
Put your SCSS code in consistent order. List extends first, followed by mixins. Next declare your regular styles followed by pseudo classes. Last list nested classes, keeping in mind that they should never be nested more than three deep.
Example
  .first-level-class {
    @extend %placeholder-class;
    @include some-mixin() {...}
    .add-styling {
      color: $link-color;
    }
    &:hover {
      color: $link-hover-color;
    }
    .second-level-class {
      @extend %placeholder-class;
      @include some-mixin() {...}
      .add-more-styling {
        border-color: $border-color;
      }
      &:hover {
        border-color: $border-hover-color;
      }
      .third-level-class {
        ...
      }
    }
    .another-second-level-class {
      ...
    }
  }
  
GO BACK
GO BACK
SCSS filenames must always start with an underscore ( _ ). The one exception to this rule is the main SCSS file which contains the list of supporting files that will compile into CSS. The file main.scss contains no styling, just a list of imports.
Example of main.scss
@import "mixins";
@import "variables";
@import "button-group";
@import "footer";
@import "forms";
@import "typography";
The filename for the import "mixins" is _mixins.scss. Because we do not want mixins, or any supporting file, to be compiled into its own CSS, we prefix the filename with an underscore. This ensures that all supporting files are compiled into main.css. The file extension is not needed in an import.
Mixins and Large SCSS File Systems
If you have several mixins, and/or many SCSS files that can be categorized, you should organize your SCSS files into directories.
File structure example:
▾ styles
  ▾ forms
    _button.scss
    _checkbox.scss
    _dropdown.scss
  ▾ mixins
    _breakpoints.scss
    _browser-hacks.scss
    _deprecate.scss
    _grid.scss
  ▸ typography
  _button-group.scss
  _footer.scss
  _forms.scss
  _mixins.scss
  _typography.scss
  _variables.scss
  main.scss
In the above example, three folders have been created to help organize the SCSS files — forms, mixins, and typography. You'll notice that the parent directory styles contains 3 SCSS files _forms.scss, _mixins.scss, and _typography.scss. These files, like main.scss, contain a list of imports only, no styling rules.
Example content for _mixins.scss:
@import "breakpoints";
@import "browser-hacks";
@import "deprecate";
@import "grid";
The main import file, main.scss, will import the other import files _forms.scss, _mixins.scss, and _typography.scss, as in the example above. This methodology ensures that the SCSS is easy to maintain since a file or style can easily be found. Mixin files are centrally located, not scattered throughout the main.scss import statements. This is important since mixins should be at or near the top of your imports file so that they can cascade down and are reusable throughout the entire project.
Always style with classes.
Never use IDs for styling. ID selectors are to pair a specific element with JavaScript functionality, not to apply styling with SCSS. See code examples.
Never use elements/tags for styling. Always include a class on an element to add styling; never make the assumption that your elements are or will remain unique in the markup. See code examples.
Name selectors using lowercase letters with dashed separators. See code examples.
Use full English words that have meaning. See code examples.
Use variables for propery values whenever possible. Become familiar with the Design Language variables, and always use them first. When you need custom styling for a project, create your own variables. There are a couple good reasons for this. First regarding Design Language global variables, if E*TRADE decides to change its brand colors from purple and green to orange and teal, for instance, your project will update automatically with the Design Language. And second, regarding custom variables, you'll only have to change the value in one place rather than searching through your SCSS to find every instance. More about variables.
Multiple declarations that share the same properties should be combined, and stacked.
done Good:
.btn {
  &:active,
  &.active,
  &:focus,
  &.focus {
    background-color: $button-primary-active-background-color;
  }
}
clear Bad:
.btn {
  &:active, &.active {
    background-color: $button-primary-active-background-color;
  }
  &:focus, &.focus {
    background-color: $button-primary-active-background-color;
  }
}
Never use !important in your property value.
If you need to override a Bootstrap or Design Language class and are having difficulties, check its specificity. More about specificity.
GO BACK
GO BACK
Use variables in place of propery values as mentioned above in Declarations and Properties. Any time a value is repeated throughout a page or a project, a variable should be created. Use local variables in your SCSS file, even when their value is also a Design Language global variable. Use the global variable as the value for your local variable. This allows for easy maintenance of the project's SCSS files, even as the Design Language evolves and changes.
Name variables using lowercase letters with dashed separators. See code examples.
Use full English words that contain obvious and understandable meaning. See code examples.
Variable Examples
Design Language _variables.scss snippet:
$background-color: #f6f6f6;
$border-color: #dbdbdb;
$hr-border: $border-color;

$text-muted: #767676; /// Override Bootstrap's $text-muted.
$body-text-color: #444;
$text-color: $body-text-color; /// Override Bootstrap's default text color.
$header-text-color: #242424;

$font-weight-light: 300;
$font-weight-normal: 400;
$font-weight-regular: $font-weight-normal;
$font-weight-bold: 700;

$spacing-sm: 15px;
$spacing-md: 25px;
$spacing-lg: 30px;
$spacing-xl: 40px;
SCSS using the variables above:
done Good:
$special-acct-text-color: $text-color;
$special-acct-header-color: $border-color;
$special-acct-font-weight: $font-weight-bold;
$special-acct-custom-orange-background-color: #e7c69b;

.special-acct-container {
  width: 100%;
  max-width: 700px;
  padding: $spacing-md;
  color: $special-acct-text-color;
  font-weight: $special-acct-font-weight;
  background-color: $special-acct-custom-orange-background-color;
  h3.special-acct {
    color: $special-acct-header-color;
  }
}
clear Bad:
$special-acct-text-color: #444;
$headerTextColor: $border-color;

.special-acct-container {
  width: 100%;
  max-width: 700px;
  padding: 25px;
  color: $special-acct-text-color;
  font-weight: $font-weight-bold;
  background-color: #e7c69b;
  h3.special-acct {
    color: #dbdbdb;
  }
}
Mixins
First, become familiar with the Design Language Mixins to ensure that you do not repeat existing functionality. Next, ask yourself, "Will my mixin need variables?" If the answer is "No", use a placeholder instead. If you need to write a mixin:
Name mixins using lowercase letters with dashed separators. See code examples.
Use full English words that contain obvious and understandable meaning. See code examples.
Example from the Design Language
@mixin vertical-offset($size, $spacing) {
  $spacing-decimal: $spacing / ($spacing * 0 + 1);
  $spacing-scale-decimal: ($spacing-scale / ($spacing-scale * 0 + 1)) / 100;
  .vertical-offset-#{$size} {...}
}
Using the above mixin
@include vertical-offset("base", $spacing-base);
@include vertical-offset("xxs", $spacing-xxs);
@include vertical-offset("xs", $spacing-xs);
...
@include vertical-offset("xxxl", $spacing-xxxl);
@include vertical-offset("clear", $spacing-clear);
Placeholders
Placeholders are classes that produce no CSS output unless they are referenced. If you need to write a placeholder:
Name placeholders using lowercase letters with dashed separators. See code examples.
Use full English words that contain obvious and understandable meaning. See code examples.
Example from the Design Language
%link {
  color: $link-color;
  font-weight: $font-weight-normal;
  ...
  &.focus .material-icons {
    color: $link-active-color;
  }
}
Using the above placeholder
.btn-link {
  @extend %link;
}
Mixins vs Placeholders
It is always preferable to use a placeholder over a mixin because of selector grouping. Consider the following examples:
Referenced mixin
@mixin center-block-element {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

.container {
  @include center;
}

.image-cover {
  @include center;
}
The above SCSS will compile into the following CSS
.container {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

.image-cover {
  display: block;
  margin-left: auto;
  margin-right: auto;
}
Referenced placeholder
%center-block-element {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

.container {
  @extend %center;
}

.image-cover {
  @extend %center;
}
The above SCSS will compile into the following CSS
.container, .image-cover {
  display: block;
  margin-left: auto;
  margin-right: auto;
}
Include and Extends
Anytime that you use @include or @extend in your SCSS, be mindful of the CSS output. There are tools like SassMeister that will compile your SCSS so you can adjust your code if it's repeating too much.
Maximum nesting should only be three levels deep. See code examples.
Nesting more than three levels deep can cause problems or be symptomatic of a larger problem in the markup.
  1. Too much nesting causes specificity issues or classes that are hard to override.
  2. Overly complex nesting is not reusable.
  3. Overly complex nesting is unreadable.
  4. Deep nesting suggests a fragile html structure.
  5. The Design Language is not being executed properly.
Nest media queries at the top of your class definition.
This way the code is more readable and easy to maintain since there is no rewrite of the class somewhere else in the file.
.material-icons {
  @include breakpoint-sm {
    font-size: 16px;
  }
  font-size: 23px;
  margin: 0;
}
GO BACK
Always use the Design Language variables.
This ensures correct branding and consistency across E*TRADE sites, and will also keep your site up-to-date automatically when there are design changes regarding color. All variable names are easily accessible on the Colors page of the documentation. Hovering over a color swatch, then clicking, allows you to copy the variable name to your clipboard. The hex value is also available for copying in case you need it for your JavaScript.
Never use hex strings as a property value.
If a color you need is not represented in the Design Language's variables, rethink your choice or question the requirement for that color. If you find that the requirement is mandatory, create a variable in your SCSS file with the proper hex value and inform the Design Language team so they can evaluate whether or not to add this color as a global variable.
Keep in mind that colors can only be represented as hex strings or variables, not literals. See code examples.
Also note that hex values must be either 6-characters or 3-characters long. See code examples.
GO BACK
Never write vendor prefixes.
Use an autoprefixer instead. See code examples.
Always use an autoprefixer for your SCSS in your build process, not in your editor. Make sure the settings target the correct browsers. Browser vendors — like Chrome, Safari, Firefox, IE, Edge, and Opera — are continually deprecating their prefixes as various properties become standardized. Using an autoprefixer ensures that vendor prefixes only will be used as necessary.
Locally, compile with source maps.
Source maps will help identify where a specific selector is located in the source code. It will tell you in which file and what line number a selector is located. On a project with many imports this tool is indispensable.
Sometimes, as a developer, your deadline trumps writing perfect, or even correct code. If you have a hack that needs to get in, create a _hacks.scss file and add it as the last import. Then you can easily come back and fix it later.