SCSS in a Nutshell2015/07/20

The complete Sass/SCSS reference is located here.

Installation

Install Sass using Ruby

gem install sass

Have Sass watch over a file, and specify the output destination

sass --watch main.scss:main.css

You will almost never use this command. Instead we use Grunt to handle this.

Install Sass syntax highlighting in Sublime Text via Package Control https://packagecontrol.io/packages/Syntax%20Highlighting%20for%20Sass

  • Enable Package Control
  • Install the Syntax Highlighting for Sass package
    • Open the Command Pallete. ctrl+shift+p (Win/Linux) OR cmd+shift+p (OSX)
    • Select Package Control: Install Package (and wait a bit)
    • Select Syntax Highlighting for Sass

Partials

All .scss files are compiled into their respective .css file. Partials which are prefixed with an underscore will not generate their own .css file. They exist for inclusion from other files.

// _partial.scss
@import 'partial'; // underscore and extension omitted

CSS Compliant

All CSS rules and syntax work in Sass. CSS in a Nutshell: /css-in-a-nutshell

Nesting

Selectors can be nested within others and are equivalent to CSS’s space separated selectors.

ul {
  list-style-type: none;

  li { // equivalent to the selector 'ul li'
    display: block;
  }
}

Parent Selector

The & character represents the current parent selector and allows selectors to be made relative to it.

.button {
  background-color: blue;

  &:hover { // .button:hover
    background-color: red;
  }
  footer & { // footer .button
    background-color: green;
  }
  &-black { // .button-black
    background-color: black;
  }
}

Nested Properties

Certain properties can also be nested.

blockquote {
  font: {
    family: "Times New Roman", serif; // font-family
    style: italics; // font-style
    size: 2rem; // font-size
  }
}

Extend/Inheritance

Selectors can inherit from other selectors using @extend. If the !optional tag is included, @extend will be ignored if it were to cause an error (e.g. the selector doesn't exist or is conflictory). The % selector is similar to ./# for classes/id's, but exists for the purpose of inheritance and won't be rendered into the output css.

p%awesome { // This ruleset won't be rendered explicitly
  font-weight: bold;
}
.message {
  border: 1px solid #CCCCCC;
  color: #333333;
}
.message-success {
  @extend .message;
  border-color: green;
  p {
    @extend %awesome; // @extend successfully runs
    @extend .something !optional; // .something doesn't exist; @extend is ignored.
  }
  a {
    @extend %awesome !optional;
    // %awesome is defined only for p
    // @extend is ignored.
  }
}

Variables

Variables' scopes are within the level of selectors they are defined in, unless given the !global flag. The !default flag will set the variable if it isn't already defined.

$size: 15px;
$size: 30px !default; // $size is still 15px
html {
  $color: #335544 !global;
  background-color: $color;
}
div {
  background-color: white;
  color: $color;
}

Allowed variable types:

  • Numbers: 1.2, 13, 10px
  • Strings: "foo", 'bar', baz
  • Colors: blue, #04A3F9, rgba(255, 0, 0, .5)
  • Booleans: true, false
  • Nulls: null
  • Lists (space or comma separated): 1.5em 0 2em, Helvetica, Arial, san-serif
  • Maps: (key1: value1, key2: value2)

Interpolation

Interpolation is mainly for using variables in selectors or strings.

$name: foo;
$attr: border;
p.#{$name} { // p.foo
  #{$attr}-color: blue; // border-color
}
$text: "#{$name}#{$attr}"; // "fooborder"

Operations

Take care that agreeable units are in the arguments.

Numbers and Colors: + - * / % < > <= >= == !=

80px / 320px * 100% == 25%
#010203 + #040506 == #050709 // computed piecewise
16px + 1em // Invalid operation
10px * 10px == 100px*px // Note px*px is not a CSS unit

Strings: + == !=

"Foo " + Bar == "Foo Bar"
sans + -serif == sans-serif

Booleans: and or not == !=

Mixins

Mixins are reusable groups of CSS declarations which allow variable parameters. (Also accepts the parameters as lists and maps).

@mixin border($width, $style, $color, $radius: 0px) {
  // $radius uses default value of 0px if not passed
  border: {
    color: $color;
    style: $style;
    width: $width;
  }
  -webkit-border-radius: $radius;
     -moz-border-radius: $radius;
      -ms-border-radius: $radius;
          border-radius: $radius;
  }
}
@mixin box-shadow($shadows...) { // supports var-args
  -webkit-box-shadow: $shadows;
     -moz-box-shadow: $shadows;
          box-shadow: $shadows;
}

.box {
  @include border(1px, solid, blue);
  @include box-shadow(0px 4px 5px #666, 2px 6px 10px #999);
}
.circle {
  @include border(
    $width: 5px,
    $color: green,
    $style: dashed,
    $radius: 50%
  );
  // keyword arguments
}

Mixins using a Content Block

@mixin apply-to-main {
  #main {
    @content;
  }
}
@include apply-to-main {
  background-color: blue; // #main
  #logo { // #main #logo
    background-image: url(/logo.gif);
  }
}

Functions

Functions supports var-args and keyword arguments similar to mixins. For the list of built-in Sass functions: http://sass-lang.com/documentation/Sass/Script/Functions.html

$grid-width: 40px;
$gutter-width: 10px;
@function grid-width($n) {
  @return $n * $grid-width + ($n - 1) * $gutter-width;
}
#sidebar {
  width: grid-width(5); // 240px
}

Control Directives

All values are "truthy" except for false and null.

The @if, @else if, and @else directives:

p {
  @if 1 + 1 == 2 { border: 1px solid; }  // true
  @if "cheese"   { border: 2px solid; }  // true
  @if 5 < 3      { border: 2px dotted; } // false
  @if null       { border: 3px double; } // false
  @if $type == ocean {
    color: blue;
  } @else if $type == matador {
    color: red;
  } @else {
    color: black;
  }
}

The @for directive loops (incrementally or decrementally) a variable through a range of integers.

@for $i from 1 through 3 {
  .size-#{$i} { width: 2em * $i; }
}

The @each directive loops through lists or maps. Also supports multiple assignment.

@each $animal in puma, sea-slug, egret, salamander {
  .#{$animal}-icon {
    background-image: url('/images/#{$animal}.png');
  }
}
@each $animal, $color, $cursor in (puma, black, default),
                                  (sea-slug, blue, pointer),
                                  (egret, white, move) {
  .#{$animal}-icon {
    background-image: url('/images/#{$animal}.png');
    border: 2px solid $color;
    cursor: $cursor;
  }
}

The @while directive loops while a condition is true.

$i: 6;
@while $i > 0 {
  .item-#{$i} { width: 2em * $i; }
  $i: $i - 2;
}