The below explains how our CSS patterns are built. Follow the repository readme to setup a development enviroment. For our general SCSS and CSS style guidelines, see this repo.

Setup

The name, description, variables, mixins and placeholders specific to the pattern come first.

// -----------------------------------------------------------
// IMAGE SLIDER
// -----------------------------------------------------------
// A simple image slider.

$image-slider-thumb-border: 3px solid;

%image-slider-thumb-rollover {
  opacity: 1;
  border: $image-slider-thumb-border $c-blue;
}

Block mixin

The block mixin creates both a class and a SCSS placeholder so the pattern can be extended (for rationale read this article) . It also adds the name to a global list and gives a warning if there is a name conflict. The passed name will be used to prefix to all the element and modifer mixins.

File structure

There should be only one block definition per file. Big patterns, ie. comments should be split into separate files (and blocks) with a single index file importing them and setting up any variables, placeholders etc.

Pattern context

A common problem is the context of patterns. If some content is in a pod, it might have slightly different styling. Sometimes a modifier to the pattern will be enough, ie. ".-inside-pod" but sometimes the context itself need extra properties to accomadate the pattern.

@include block(image-slider) {
  margin-bottom: $bottom-push;
}

Output

.image-slider {
  margin-bottom: 36px;
}

Element mixin

The element mixin creates a class (and placeholder) prepended with a "__" and the name passed to the block. Elements are tied to the purpose of the pattern; creating patterns should follow the Single responsibility principle. If you have nested HTML within those, you can:

  1. Create another pattern
  2. Use element selectors, but avoid exceeding 2 levels of nesting (not always suitable)

Outside of the mixins, avoid writing classes, the cascade and specificity - although core to CSS, using those extensivily on big projects leads poor to maintainability and hard to debug problems.

@include element(slide) {
  display: block;
  margin-bottom: 10px;
  max-height: 450px;

  > img {
    border: $border;
    border-radius: $border-radius-regular;
  }
}

@include element(thumb) {
  width: 80px;
  height: 80px;

  &:hover {
    @extend %image-slider-thumb-rollover;
  }
}

Output

.image-slider__slide {
  display: block;
  margin-bottom: 10px;
  max-height: 450px;
}

.image-slider__slide > img {
  border: 1px solid #e9e8e4;
  border-radius: 3px;
}

.image-slider__thumb {
  width: 80px;
  height: 80px;
}

Modifier mixin

The modifier creates a selector prepended by the pattern class and prefixed with a "-", ie. ".media.-large". For elements, they should always be nested - for blocks, they can be either nested or at root level.

Modifiers are never meant to be used alone; in HTML they should always accompany a block/element.

<div class="image-slider__thumb -active"></div>
@include element(thumb) {
  width: 80px;
  height: 80px;

  &:hover {
    @extend %image-slider-thumb-rollover;
  }

  @include modifier(active) {
    @extend %image-slider-thumb-rollover;
  }
}

Output

.image-slider__thumb {
  width: 80px;
  height: 80px;
}

.image-slider__thumb:hover,
.image-slider__thumb.-active {
  opacity: 1;
  border: 3px solid #2976b2;
}
// Note: the :hover comes from the element(slide) mixin