Sass/SCSS

CSS with Superpowers

Created by Yogesh Kumar / @yoku_2010

Let's start...

  1. Why Sass / SCSS?
  2. The Workflow
  3. Sass Basics
  4. Sass Advanced
  5. Media Queries
  6. A Short & Lovely Demo
  7. Wrap Up

Section - I

Why Sass / SCSS?

The Trouble with CSS

  • Websites are becoming increasingly complex.
  • CSS is getting harder to maintain.
  • Writing styles is often tedious and repetitive.

Repetition

.header {
  background-color: #531946;
  border-radius: 5px;
  padding: 5px 20px;
}
.header a {
  color: #fff;
}
.header a:hover {
  color: #095169;
}

.footer {
  background-color: #30162B;
  color: #fff;
  border-radius: 5px;
  padding: 5px 20px;
}
.footer a {
  color: #095169;
}
.footer a:hover {
  color: #fff;
}

.feature a {
  background-color: #30162B;
  color: #fff;
  border-radius: 5px;
  padding: 5px 20px;
}
.feature a:hover {
  color: #531946;
}

.content {
  background-color: #fff;
  color: #222;
  border-radius: 5px;
  padding: 5px 20px;
}
DRY
Don't Repeat Yourself

HEX Colors

Border Radius

Padding

Selectors

Repetition Colors

CSS
.header {
  background-color: #531946;
}
.header a {
  color: #fff;
}
.header a:hover {
  color: #095169;
}

.footer {
  background-color: #30162B;
  color: #fff;
}
.footer a {
  color: #095169;
}
.footer a:hover {
  color: #fff;
}

.feature a {
  background-color: #30162B;
  color: #fff;
}

.feature a:hover {
  color: #531946;
}

.content {
  background-color: #fff;
  color: #222;
}
Sass Variables
$white: #ffffff;
$black: #222222;
$eggplant: #531946;
$eggplantDark: #30162B;
$teal: #095169;

.header {
  background-color: $eggplant;
}
.header a {
  color: $white;
}
.header a:hover {
  color: $teal;
}

.footer {
  background-color: $eggplantDark;
  color: $white;
}
.footer a {
  color: $teal;
}
.footer a:hover {
  color: $white;
}

.feature a {
  background-color: $eggplantDark;
  color: $white;
}

.feature a:hover {
  color: $eggplant;
}

.content {
  background-color: $white;
  color: $black;
}

Repetition Border Radius & Padding

CSS
.header {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.footer {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.feature a {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.content {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}
Sass Mixins
@mixin rounded-box {
  border-radius: 5px;
  padding: 5px 20px;
}

.header {
  @include rounded-box;
  // ...
}

.footer {
  @include rounded-box;
  // ...
}

.feature a {
  @include rounded-box;
  // ...
}

.content {
  @include rounded-box;
  // ...
}

Repetition Selectors

CSS
.header {
  /* ... */
}
.header a {
  /* ... */
}
.header a:hover {
  /* ... */
}

.footer {
  /* ... */
}
.footer a {
  /* ... */
}
.footer a:hover {
  /* ... */
}

.feature a {
  /* ... */
}
.feature a:hover {
  /* ... */
}

.content {
  /* ... */
}
Sass Nesting
.header {
  // ...

  a {
    // ...

    &:hover {
      // ...
    }
  }
}

.footer {
  // ...

  a {
    // ...

    &:hover {
      // ...
    }
  }
}

.feature a {
  // ...

  &:hover {
    // ...
  }
}

.content {
  // ...
}

Recap Repetition

CSS
.header {
  background-color: #531946;
  border-radius: 5px;
  padding: 5px 20px;
}
.header a {
  color: #fff;
}
.header a:hover {
  color: #095169;
}

.footer {
  background-color: #30162B;
  color: #fff;
  border-radius: 5px;
  padding: 5px 20px;
}
.footer a {
  color: #095169;
}
.footer a:hover {
  color: #fff;
}

.feature a {
  background-color: #30162B;
  color: #fff;
  border-radius: 5px;
  padding: 5px 20px;
}
.feature a:hover {
  color: #531946;
}

.content {
  background-color: #fff;
  color: #222;
  border-radius: 5px;
  padding: 5px 20px;
}
Sass
$white:        #ffffff;
$grey:         #222222;
$eggplant:     #531946;
$eggplantDark: #30162B;
$teal:         #095169;

// Mixins
@mixin rounded-box {
  border-radius: 5px;
  padding: 5px 20px;
}

// Site Stylez
.header {
  @include rounded-box;
  background-color: $eggplant;

  a {
    color: $white;
    &:hover { color: $teal; }
  }
}

.footer {
  @include rounded-box;
  background-color: $eggplantDark;
  color: $white;

  a {
    color: $teal;
    &:hover { color: $white; }
  }
}

.feature a {
  @include rounded-box;
  background-color: $eggplantDark;
  color: $white;

  &:hover { color: $eggplant; }
}

.content {
  @include rounded-box;
  background-color: $white;
  color: $grey;
}

Recap Why Sass?

  • Reduced complexity.
  • Increased maintainability.
  • Minimized repetition.
  • Supercharged CSS!

What is Sass?

Sass is an extension of CSS that adds power and elegance to the basic language. It allows you to use variables, nested rules, mixins, inline imports, and more, all with a fully CSS-compatible syntax. Sass helps keep large stylesheets well-organized, and get small stylesheets up and running quickly...

Sass Documentation

What is Sass?

CSS Extension CSS Preprocessor Sass Script Language Sass Script Interpreter

Sass CSS

Features

  • Variables ($)
  • Partials using @import
  • Nesting
  • Mixins
  • Inheritance using @extend
  • Pre-processing
  • Operators (aka math)

Two SassScript Syntaxes

.sass (Indented) Original syntax; Haml-esque
$black: #000
$white: #fff

.this
  color: $black
  background: $white

.that
  color: $white
  background: $black

.this, .that
  display: block
  &:hover
    border: 1px solid
.scss (Sassy CSS) Default syntax; Valid CSS == Valid SCSS
$black: #000;
$white: #fff;

.this {
  color: $black;
  background: $white;
}

.that {
  color: $white;
  background: $black;
}

.this, .that {
  display: block;

  &:hover {
    border: 1px solid;
  }
}

Sass

  • Original syntax
  • Used to be in the same gem as Haml (siblings)
  • Significant whitespace
    • No semi-colons
    • No brackets
  • .sass file extension
  • More concise

SCSS

  • More expressive
  • Superset of CSS
    • All CSS is valid SCSS
    • Less syntactical differences
  • More manageable/maintainable:
    • Using external CSS libs
    • Adapting legacy files
  • Encourages use of @extend and minimizes unnecessary nesting
  • Lower barrier to entry for those used to CSS

Section - II

The Workflow

Sass Installation

Ruby

OS X? Lucky you, it's preinstalled!

Windows? Try RubyInstaller

Linux? You know what to do.

Sass

$ gem install sass

More info at: sass-lang.com/install C/C++ (LibSass): LibSass.org

Running Sass

(aka Compiling Sass)

Sass CSS

$ sass source.scss output.css

$ sass source_dir output_dir

Sass Is Watching You...

$ sass --watch source.sass:output.css

This is the best thing EVER.

More Sass Options

$ sass source.scss output.css
Compile source.scss to output.css. Will fail if output directory doesn't exist.

$ sass --watch source.scss output.css
Watch source.scss for changes. Will create directory if it doesn't exist.

$ sass --style expanded source.scss:output.css
Adjusts output format. Options: nested, expanded, compact, compressed. See Example

Section - III

Sass Basics

Sass Basics

  • Nesting
  • Imports & Organization
  • Variables
  • Math & Color Utilities

Sass Basics Nesting

HTML has a clear hierarchy - elements are nested.
We can apply the same concept in Sass.
<nav class="navigation">
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#about">About</a></li>
    <li><a href="#contact">Contact</a></li>
  </ul>
</nav>
.navigation {
  float: right;

  li {
    display: inline-block;
    list-style-type: none;
    margin-left: 1.5em;
  }

  a {
    display: block;
    text-decoration: none;
  }
}

Nesting Output

Sass
.navigation {
float: right;

  li {
    display: inline-block;
    list-style-type: none;
    margin-left: 1.5em;
  }

  a {
    display: block;
    text-decoration: none;
  }
}
CSS Output
.navigation {
  float: right;
}

.navigation li {
  display: inline-block;
  list-style-type: none;
  margin-left: 1.5em;
}

.navigation a {
  display: block;
  text-decoration: none;
}

Sass gives us organization.

Sass reduces repetition.

Nesting

Mirroring HTML nesting is SUPER easy.

Sass
body {
.header {
  .navigation {
    ul {
      li {
        a {
          // ...
          }
        }
      }
    }
  }
}
CSS Output
body .header .navigation ul li a {
  /* ... */
}
Overly verbose and overly specific.
General Recommendation: no more than 3 levels deep.

Nesting Parent Selectors

allows us to reference the current parent selector(s) via the ampersand character:

Sass
a {
  color: #beedee;

  &:hover {
    color: #cbbebb;
  }

  &.btn {
    background: #deede6;
  }

  .btn {
    display: block;
  }
}
CSS Output
a {
  color: #beedee;
}

a:hover {
  color: #cbbebb;
}

a.btn {
  background: #deede6;
}

a .btn {
  display: block;
}

Nesting Parent Selectors

The & selector can follow other selectors. This will override the parent element's (&) styles when it exists within the preceding selector.

Sass
a {
  .footer & {
    text-decoration: none;

    span {
      opacity: .5;
    }
  }

  span {
    .navigation & {
      display: block;
    }
  }
}
CSS Output
.footer a {
  text-decoration: none;
}

.footer a span {
  opacity: .5;
}

.navigation a span {
  display: block;
}

Nesting Parent Selectors

The & selector can also be combined with strings.
PERFECT for BEM, child elements, states, and modifications.

Sass
.module {
  &__child {
    margin-bottom: 1em;
  }

  &--modifier {
    display: inline;
  }
}
CSS Output
.module__child {
  margin-bottom: 1em;
}

.module--modifier {
  display: inline;
}

Nesting Parent Selectors

The & contents can also be accessed as a string/list
and used in SassScript.

Sass
.thing.thang {
  .thung {
    content: &;
    content: &--mod;
    content: selector-append(&, '--mod');

    &--mod { content: 'here'; }
  }
}
CSS Output
.thing.thang .thung {
  content: .thing.thang .thung;
  content: .thing.thang .thung --mod;
  content: .thing.thang .thung--mod;
}
.thing.thang .thung--mod {
  content: 'here';
}

There are a handful of additional selector methods.

Nesting Properties

You can also nest namespaced properties

Sass
a {
  border: {
    color: #deedee;
    style: solid;
    width: 2px;
  }
}
CSS Output
a {
  border-color: #deedee;
  border-style: solid;
  border-width: 2px;
}

Sass Basics

Imports & Organization

Sass Basics Imports & Organization

CSS @import has always meant an extra file download.

Sass modifies @import to instead include the resource during compilation, rather than on the client side.

@import "vars";

@import "compass";
@import "fontawesome";

@import "utilities";

@import "grid";
@import "base";

@import "modules/all";
@import "pages/all";

Organization Imports

@import takes a path to a Sass resource, the file extension is optional.

These @imports look for resources within the main Sass file's parent directory.

@import "vars";

@import "compass";
@import "fontawesome";

@import "utilities";

@import "grid";
@import "base";

@import "modules/all";
@import "pages/all";

Imports File Structure

application.scss
@import "vars";
@import "lib/compass";
@import "lib/fontawesome";
@import "utilities";
@import "grid";
@import "base";

$ sass sass/application.scss css/application.css

  • project_awesome
    • sass
      • lib
        • compass.scss
        • fontawesome.scss
      • base.scss
      • grid.scss
      • application.scss
      • utilities.scss
      • vars.scss
    • css
      • application.css

Imports Compiling Directories

$ sass sass/ css/

  • sass
    • lib
      • compass.scss
      • fontawesome.scss
    • base.scss
    • grid.scss
    • application.scss
    • utilities.scss
    • vars.scss

  • css
    • lib
      • compass.css
      • fontawesome.css
    • base.css
    • grid.css
    • application.css
    • utilities.css
    • vars.css

Imports Partials

$ sass sass/ css/

  • sass
    • lib
      • _compass.scss
      • _fontawesome.scss
    • _base.scss
    • _grid.scss
    • print.scss
    • application.scss
    • _utilities.scss
    • _vars.scss

  • css
    • print.css
    • application.css
  • An _underscore creates a partial
  • Partials will not compile to .css on their own, they must be @imported
  • Partials allow us to break up our code into more modular, maintainable chunks!

Imports Organization

Common Practices

  • _vars.scss is a separate sheet for all your variables and settings
  • lib is a separate folder for other libraries
  • modules is a separate folder for various modules
  • pages is a separate folder for all pages css
  • _all.scss is often used to import collections of similar imports
application.scss
// Variables
@import "vars";

// Libraries
@import "lib/compass";
@import "lib/fontawesome";

// Base Styles, Utility Classes, etc.
@import "base/all";

// Individual Components
@import "modules/all";

// Page Styles
@import "pages/all";

Import Groups

You can DRY up @imports by grouping them together with comma separation.

application.scss
// Variables
@import "vars";

// Libraries
@import "lib/compass",
  "lib/fontawesome";

// Application
@import "base/all",
  "modules/all",
  "pages/all";

Sass Basics

Variables

Sass Basics Why Variables?

  • Reduce repetition
  • Improve maintainability
  • Make Find & Replace! unecessary or at least easier

Sass Basics Variables

Some Uses

  • colors
  • font sizes
  • font families
  • font paths
  • padding
  • margins
  • breakpoints

Somemore Uses

  • border-radius
  • content
  • gradients
  • shadows
  • SELECTORS!
  • LOGIC!
  • ALL THE THINGS!!!1!

Variables Assignment & Reference

Variables are defined as CSS prop/val pairs: $property: value; Variables are then referenced by their $-prefixed names.

Sass
$grey: rgba(0,0,0,.5);
$teal: #095169;
$default-padding: 1em;

a {
  color: $teal;
  padding: $default-padding;
  &:hover {
    color: $grey;
    background: $teal;
  }
}

p { padding-bottom: $default-padding; }
CSS Output
a {
  color: #095169;
  padding: 1em;
}

a:hover {
  color: rgba(0,0,0,.5);
  background: #095169;
}

p {
  padding-bottom: 1em;
}

Variable Data Types

Types

  • Numbers
  • Strings
  • Colors
  • Lists
  • Booleans
  • Null
  • Maps

Uses

$base-padding: 10px;
$line-height: 1.5;

$base-font: Verdana;
$content: "Loading...";

$feature-color: purple;
$feature-background: rgba(0, 255, 0, 0.5);

$base-margin: 20px 0 30px 10px;
$base-font: "Trebuchet MS", "Verdana", "Arial";

$bordered: true;
$shadowed: false;

$secondary: null;

$map: (key1: value1, key2: value2, key3: value3);

Variable Assignment

You can redeclare variables to override previous values

Sass
$border-width: 2px;
$border-width: 4px;

a {
  border: $border-width solid $teal;
}
CSS Output
a {
  border: 4px solid #095169;
}

Variable Scope

Sass
$border-width: 4px; // Global

a {
  $color: orange;   // Local
  border: $border-width solid $color;
}

p {
  border: $border-width solid $color;
  // ERROR!! Undefined variable "$color"
}

Variables are only available within the level of nested selectors where they're defined.

If they're defined outside of any nested selectors, they're available everywhere.

~ Sass Documentation

Variable Interpolation

Variables can be injected into selectors,
property names and values, and strings
via #{$variable}

Sass
$side: left;

.box-#{$side} {
  border-#{$side}: 1px solid #ccc;

  &:before {
    content: "It's on the #{$side} side";
  }
}
CSS
.box-left {
  border-left: 1px solid #ccc;
}

.box-left:before {
  content: "It's on the left side";
}

PROTIP Modular Naming

OK Variables
$white: #ffffff;
$black: #222222;
$eggplant: #531946;
$eggplantDark: #30162B;
$teal: #095169;

.header {
  background-color: $eggplant;
}
.header a {
  color: $white;
}
.header a:hover {
  color: $teal;
}

.footer {
  background-color: $eggplant-dark;
  color: $white;
}
.footer a {
  color: $teal;
}
.footer a:hover {
  color: $white;
}

.feature a {
  background-color: $eggplant-dark;
  color: $white;
}

.feature a:hover {
  color: $eggplant;
}

.content {
  background-color: $white;
  color: $black;
}
Better Variables
// Descriptive Colors
$white:        #ffffff;
$grey:         #222222;
$eggplant:     #531946;
$eggplantDark: #30162B;
$teal:         #095169;

// Functional Colors
$header--background:          $eggplant;
$header__logo--color:         $white;
$header__logo--color--hover:  $teal;

$footer--background:          $eggplant--dark;
$footer--color:               $white;
$footer__nav--color:          $teal;
$footer__nav--color--hover:   $white;

$content--background:         $white;
$content--color:              $grey;

$feature__link--background:   $eggplant--dark;
$feature__link--color:        $white;
$feature__link--color--hover: $eggplant;

.header {
  background-color: $header--background;
}
.header a {
  color: $header__logo--color;
}
.header a:hover {
  color: $header__logo--color--hover;
}

.footer {
  background-color: $footer--background;
  color: $footer--color;
}
.footer a {
  color: $footer__nav--color;
}
.footer a:hover {
  color: $footer__nav--color--hover;
}

.feature a {
  background-color: $feature__link--background;
  color: $feature__link--color;
}

.feature a:hover {
  color: $eggplant;
}

.content {
  background-color: $content--background;
  color: $content--color;
}

Sass Basics

Math & Color

Sass Basics Math Operators

  • Sass allows us to do basic math operations*, like:
    • + addition
    • - subtraction
    • * multiplication
    • / division
    • % modulus
      (remainder from division)
  • AND string concatenation

* Sass attempts to operate on mismatched units, but will throw an error if incompatible

Good: 20px * 2   |   Bad: 20px + 4em

$title: "yokutalks";
$base-font-size: 16px;
$padding-default: 2em;

.header {
  padding: $padding-default / 2;
  font-size: $base-font-size * 2;

  &:before {
    content: "Welcome to " + $title;
  }
}

This includes operations on numbers with units (px, em, pt, rem, etc.)*

Math Division

CSS allows / to be used for separating values.

font: normal 1.5em/1.25 Tahoma, Arial, sans-serif;

SassScript maintains this support.
There are three ways to trigger division:

  • If any part of the equation is a variable: $padding / 2
  • If the equation is surrounded by parentheses: (350 / .25)
  • If the equation involves another expression: 2 + 3 / 10

Math Utilities

Sass also comes with a set of math functions:

  • abs($num) - absolute value
  • ceil($num) - round up to closest whole number
  • floor($num) - round down to closest whole number
  • percentage($num) - convert to percentage
  • round($num) - round to closest whole number
  • max($list) - maximum list value
  • min($list) - minimum list value

Math Color

We can also use math to manipulate colors. Math operations on colors work on pieces (r, g, b).

.addition {
  color: #555555 + #112233; // => #667788
}
.subtraction {
  color: #555555 - #112233; // => #443322
}
.multiplication {
  color: #555555 * 2;       // => #aaaaaa
}
.division {
  color: (#555555 / 2);     // => #2a2a2a
}

Sass Basics Color Utilities

Sass comes with a set of color functions.

  • rgba($hex, $alpha)
    Converts HEX to RGBA and sets alpha (opacity)
  • lighten($color, $percent)
    Makes a color lighter
  • darken($color, $percent)
    Makes a color darker
  • saturate($color, $percent)
    Makes a color more saturated
  • desaturate($color, $percent)
    Makes a color less saturated
  • mix($color1, $color2)
    Mixes two colors together
  • grayscale($color)
    Converts a color to grayscale
  • invert($color)
    Inverts a color
  • complement($color)
    Returns the complement of a color
  • AND SO MUCH MORE!

Here's a tool to help color output.

Section - IV

Sass Advanced

Advanced Sass

  1. Mixins (@include)
  2. Inheritance (@extend)
  3. Directives
  4. Maps

Advanced Sass Mixins

Variables let you reuse single values.

Mixins let you reuse blocks of styles.

Mixins Use

CSS
.header {
  border-radius: 5px;
  padding: 5px 20px;
}

.footer {
  border-radius: 5px;
  padding: 5px 20px;
}

.feature a {
  border-radius: 5px;
  padding: 5px 20px;
}

.content {
  border-radius: 5px;
  padding: 5px 20px;
}
Sass
@mixin rounded-box {
  border-radius: 5px;
  padding: 5px 20px;
}

.header {
  @include rounded-box;
}

.footer {
  @include rounded-box;
}

.feature a {
  @include rounded-box;
}

.content {
  @include rounded-box;
}

Mixins Setup

@mixin rounded-box {
  border-radius: 5px;
  padding: 5px 20px;
}

.header {
  @include rounded-box;
  color: $header-color;
  // ...
}

.footer {
  @include rounded-box;
  // ...
}

.feature a {
  @include rounded-box;
  // ...
}

.content {
  @include rounded-box;
  // ...
}
  • We define a mixin with the @mixin directive.
  • We reference a mixin with the @include directive.
  • Mixins must be defined before they're referenced.
  • Mixins can be used with any other style rules.
  • You can nest within mixins just like you can elsewhere.
  • Mixins accept optional arguments.

Mixins Output

Sass
$header-color: #455667;

@mixin rounded-box {
  border-radius: 5px;
  padding: 5px 20px;
}

.header {
  @include rounded-box;
  color: $header-color;
}

.footer {
  @include rounded-box;
}

.feature a {
  @include rounded-box;
}

.content {
  @include rounded-box;
}
CSS
.header {
  border-radius: 5px;
  padding: 5px 20px;
  color: #455667;
}

.footer {
  border-radius: 5px;
  padding: 5px 20px;
}

.feature a {
  border-radius: 5px;
  padding: 5px 20px;
}

.content {
  border-radius: 5px;
  padding: 5px 20px;
}

Mixins Arguments

Mixins are great for repeated blocks of styles
where the values differ from case to case.

Sass
@mixin rounded-corners($radius) {
  -webkit-border-radius: $radius;
      -moz-border-radius: $radius;
          border-radius: $radius;
}

.header {
  @include rounded-corners(5px);
  // ...
}

.footer {
  @include rounded-corners(10px);
  // ...
}
CSS
.header {
  -webkit-border-radius: 5px;
      -moz-border-radius: 5px;
          border-radius: 5px;
  /* ... */
}

.footer {
  -webkit-border-radius: 10px;
      -moz-border-radius: 10px;
          border-radius: 10px;
  /* ... */
}

Mixins Argument Defaults

You can also set an argument's default value,
making it optional to pass one in.

Sass
@mixin rounded-corners($radius: 5px) {
  -webkit-border-radius: $radius;
      -moz-border-radius: $radius;
          border-radius: $radius;
}

.header {
  @include rounded-corners;
  // ...
}

.footer {
  @include rounded-corners(10px);
  // ...
}
CSS
.header {
  -webkit-border-radius: 5px;
      -moz-border-radius: 5px;
          border-radius: 5px;
  /* ... */
}

.footer {
  -webkit-border-radius: 10px;
      -moz-border-radius: 10px;
          border-radius: 10px;
  /* ... */
}

Mixins Multiple Arguments

Comma separated, order matters.

Sass
@mixin rounded-box($radius, $padding) {
  border-radius: $radius;
  padding: $padding;
}

.header {
  @include rounded-box(5px, 20px);
  color: $header-color;
  // ...
}

.footer {
  @include rounded-box(20px, 40px);
  // ...
}
CSS
.header {
  border-radius: 5px;
  padding: 20px;
  /* ... */
}

.footer {
  border-radius: 20px;
  padding: 40px;
  /* ... */
}

Mixins Optional Arguments

Optional arguments (ones with defaults) must be last in the set.

Sass
@mixin rounded-box($radius: 5px, $padding: 20px) {
  border-radius: $radius;
  padding: $padding;
}

@mixin content($color, $font-size: 12px) {
  color: $color;
  font-size: $font-size;
}

.header {
  @include rounded-box;
  @include content(#aaa, 24px);
  // ...
}

.footer {
  @include rounded-box(20px, 40px);
  @include content(#ccc);
  // ...
}
CSS
.header {
  border-radius: 5px;
  padding: 20px;
  color: #aaa;
  font-size: 24px;
  /* ... */
}

.footer {
  border-radius: 20px;
  padding: 40px;
  color: #ccc;
  font-size: 12px;
  /* ... */
}

Mixins Keyword Arguments

Order doesn't matter!

@mixin rounded-box($radius: 5px, $padding: 20px) {
  border-radius: $radius;
  padding: $padding;
}

.header {
  @include rounded-box($padding: 10px, $radius: 10px);
}

.footer {
  @include rounded-box($padding: 40px);
}

Mixin Variable Interpolation

Sass
@mixin toolbar-border($side, $width: 2px) {
  border-#{$side}: $width solid $toolbar-border;
}

.sidebar--left {
  @include toolbar-border("right");
}

.sidebar--right {
  @include toolbar-border("left");
}
CSS
.sidebar--left {
  border-right: 2px solid #213213;
}

.sidebar--right {
  border-left: 2px solid #213213;
}

Mixins Margin & Padding

@mixin margin--horz($left, $right: $left) {
  margin-left: $left;
  margin-right: $right;
}

@mixin margin--vert($top, $bottom: $top) {
  margin-bottom: $bottom;
  margin-top: $top;
}

.module { @include margin--vert(1em, 3em); }

Advanced Sass

Inheritance

Mixin Efficiency

Mixin Output
.header {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.footer {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.feature a {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.content {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}
Grouping Optimiztion
.header,
.footer,
.feature a,
.content {
  border-radius: 5px;
  padding: 5px 20px;
}

Advanced Sass Inheritance

@extend let's us group selectors together!

Sass
.message {
  border: 2px solid;
  margin-bottom: 1em;
  padding: 1em;
  text-align: center;
}

.message-alert {
  @extend .message;
  @include message-colors($yellow);
}

.message-error {
  @extend .message;
  @include message-colors($red);
}

.message-notice {
  @extend .message;
  @include message-colors($green);
}
CSS
.message,
.message-alert,
.message-error,
.message-notice {
  border: 2px solid;
  margin-bottom: 1em;
  padding: 1em;
  text-align: center;
}

.message-alert {
  border-color: goldenrod;
  color: goldenrod;
}

.message-error {
  border-color: darkred;
  color: darkred;
}

.message-notice {
  border-color: green;
  color: green;
}

Inheritance Setup

.message {
  border: 2px solid;
  margin-bottom: 1em;
  padding: 1em;
  text-align: center;
}

.message-alert {
  @extend .message;
  @include message-colors($yellow);
}

.message-error {
  @extend .message;
  @include message-colors($red);
}

.message-notice {
  @extend .message;
  @include message-colors($green);
}
  • Any CSS class can be extended.
  • We reference a class to extend with the @extend directive.
  • Extended classes DO NOT need to be defined before they're referenced.
  • Extensions can be used with any other style rules.
  • You can nest within extended classes just like you can elsewhere.

Inheritance Output

If we don't need to apply both .message AND .message-alert to an element, then why do we even need .message anymore?!

Sass
.message {
  border: 2px solid;
  margin-bottom: 1em;
  padding: 1em;
  text-align: center;
}

.message-alert {
  @extend .message;
  @include message-colors($yellow);
}

.message-error {
  @extend .message;
  @include message-colors($red);
}

.message-notice {
  @extend .message;
  @include message-colors($green);
}
CSS
.message,
.message-alert,
.message-error,
.message-notice {
  border: 2px solid;
  margin-bottom: 1em;
  padding: 1em;
  text-align: center;
}

.message-alert {
  border-color: goldenrod;
  color: goldenrod;
}

.message-error {
  border-color: darkred;
  color: darkred;
}

.message-notice {
  border-color: green;
  color: green;
}

Inheritance Placeholders

Placeholders are a special type of selector denoted by a %. They can be @extended but will never compile to the CSS on their own.

Sass
%message {
  border: 2px solid;
  margin-bottom: 1em;
  padding: 1em;
  text-align: center;
}

.message-alert {
  @extend %message;
  @include message-colors($yellow);
}

.message-error {
  @extend %message;
  @include message-colors($red);
}

.message-notice {
  @extend %message;
  @include message-colors($green);
}
CSS
.message-alert,
.message-error,
.message-notice, {
  border: 2px solid;
  margin-bottom: 1em;
  padding: 1em;
  text-align: center;
}

.message-alert {
  border-color: goldenrod;
  color: goldenrod;
}

.message-error {
  border-color: darkred;
  color: darkred;
}

.message-notice {
  border-color: green;
  color: green;
}

@extend Module Setup

%btn {
    // ...
}

%btn--primary {
  background: $btn--primary--bg;
  border-color: $btn--primary--border;
  color: $btn--primary--color;
}
// ...

@mixin button-setup($type) {
  @extend %btn;
  @extend %btn--#{$type};

  &:focus { @extend %btn--#{$type}; }
  &:hover { @extend %btn--#{type}--hover; }

  &.disabled {
    @extend %disabled;
    &:hover { @extend %btn--#{$type}; }
  }
}

.btn--primary { @include button-setup("primary"); }
.btn--secondary { @include button-setup("secondary"); }
.btn--tertiary { @include button-setup("tertiary"); }

// background: $btn--#{$type}--bg; => Undefined variable: "$btn--"

@mixin VS @extend

so when do I use these...?

@mixin VS @extend

Are mixins without arguments bad?
Since they duplicate code, on both sides?

Sass
@mixin rounded-box {
  border-radius: 5px;
  padding: 5px 20px;
}

.header {
  @include rounded-box;
}

.footer {
  @include rounded-box;
}

.feature a {
  @include rounded-box;
}

.content {
  @include rounded-box;
}
CSS Output
.header {
  border-radius: 5px;
  padding: 5px 20px;
}

.footer {
  border-radius: 5px;
  padding: 5px 20px;
}

.feature a {
  border-radius: 5px;
  padding: 5px 20px;
}

.content {
  border-radius: 5px;
  padding: 5px 20px;
}

@mixin VS @extend

this better?

Sass
%rounded-box {
  border-radius: 5px;
  padding: 5px 20px;
}

.header {
  @extend %rounded-box;
}

.footer {
  @extend %rounded-box;
}

.feature a {
  @extend %rounded-box;
}

.content {
  @extend %rounded-box;
}
CSS
.header,
.footer,
.feature a,
.content {
  border-radius: 5px;
  padding: 5px 20px;
}

@mixin VS @extend

Is this better?

@extend Vomit

.header, .footer, .feature header a, .content, #taco ul a, .hipster dl,
[class="btn--"], .comment .comment__body .comment__quote, .card__header,
.card--standard, .card--transFooter, .card--featured, .card--scroller,
.card--static, .card--ebook, .card--transFooter .card__content
.container .wrapper, .link--fancy, #badthing, .nope.probably a.not span.good,
article header, .article .header, [class*='rabbit'], .party .at .codemash,
#hashtag, .dot, [class*="hooligans"], [class*='making'].up.classes.is-hard,
.julie + .rocks, #made.up, .bourbon, a div i span, [id="where-the-party"],
.this .could [class*="actually-happen"], #actually.it .happens.alot,
#seriously [class*="this"].is a.problem, .it .can.get #really .out-of-hand {
  border-radius: 5px;
  padding: 5px 20px;
}

Advanced Sass

Directives

Advanced Sass Directives

  1. Functions
  2. Conditionals
  3. Loops

Directives Functions

Sass let's us define
custom functions.

@function fluidize($target, $context) {
  @return ($target / $context) * 100%;
}

.sidebar {
  width: fluidize(350px, 1000px);
  // => width: 35%;
}

  • We define a function with the @function directive.
  • We return a value with the @return directive.
  • We call a function by it's name and parens, passing arguments if needed.
  • Functions must be defined before they're referenced.
  • Functions accept arguments, they have the same rules as mixins (ie. defaults, order, keyword args, etc.)

Directives Conditionals

Sass let's us set
conditions.

$theme: light;

body {
  @if $theme == dark {
    background: #000;

  } @else if $theme == dark-mid {
    background: #4f4f4f;

  } @else if $theme == light-mid {
    background: #afafaf;

  } @else {
    background: #fff;
  }
}
  • We begin a conditon with the @if directive, then give it a comparison to evaluate
  • We have @else if for additional comparisons
  • And @else as a fallback if all prior comparisons evaluate to null or false

Comparators include:
* only compare numbers

  • == equal to
  • > greater than
  • >= greater than or equal to
  • != not equal to
  • < less than
  • <= less than or equal to

Directives Each Loops

Sass let's us
loop through lists.

$themes: dark dark-mid light-mid light;

@each $theme in $themes {
  .theme-#{$theme} {
    @include theme-colors($theme);
  }
}

// .theme-dark {
//   background: #000;
//   color: #fff;
// }
// .theme-dark-mid {
//   background: #444;
//   color: #eee;
// }
// ...

  • The @each directive takes the form of:
    • @each $var in <list>

  • $var can be any variable name
  • <list> could be a list, or a variable storing one

Directives For Loops

Sass lets us
loop through # ranges.

@for $i from 1 through 12 {
  .grid-col-#{$i} {
    width: $grid-col-width * $i;
  }
}

// .grid-col-1 {
//   width: 60px;
// }
// .grid-col-2 {
//   width: 120px;
// }
  • Two forms of @for loops;
    • @for $var from <start> through <end>
      Loop range includes start and end
    • @for $var from <start> to <end>
      Loop range excludes end

  • $var can be any variable name
  • <start> and <end> can be an integer, or a variable storing one

Directives While Loops

Sass lets us
loop conditionally.

$i: 1;

@while $i <= 12 {
  .grid-col-#{$i} {
    width: $grid-col-width * $i;
  }

  $i: $i + 1;
}

// .grid-col-1 {
//   width: 60px;
// }
// .grid-col-2 {
//   width: 120px;
// }
// ...
  • The @while directives take the form of:
    • @while <comparison>
  • It will output styles until the comparison statement returns false
  • You must manually update the variable you're comparing against
  • The <comparison> variable will often be an integer that you increment, but it could be any data type that you modify as you go

Advanced Sass

Maps

Advanced Sass Maps

Maps give us key-value pairings.

$mymap: (
  key1: value1,
  key2: value2,
  key3: value3
);
  • Maps must always be surrounded by parentheses.
  • Key-value pairs must always be comma separated.
  • Maps can be looped through or accessed via built-in map functions.

Advanced Sass Maps

Sass
$eye_color: (
  jeremy: #0989cb,
  beth: #8666ae,
  sarah: #02bba7
);

$font: (
  jeremy: Helvetica,
  beth: Verdana,
  sarah: Times
);

@each $key, $value in $eye_color {
  .#{$key} {
    background: $value;
    font-family: map-get($font, $key);
  }
}
CSS Output
.jeremy {
  background: #0989cb;
  font-family: Helvetica;
}

.beth {
  background: #8666ae;
  font-family: Verdana;
}

.sarah {
  background: #02bba7;
  font-family: Times;
}

Advanced Sass Map Functions

  • map-get($map, $key)
  • map-merge($map1, $map2)
  • map-remove($map, $keys...)
  • map-keys($map)
  • map-values($map)
  • map-has-key($map, $key)

Advanced Sass

Putting it all together.

Advanced Sass Icons

$icons: (
  checkmark: "\e600",
  plus:      "\e601",
  minus:     "\e602"
);

@each $name, $value in $icons {
  .icon--#{$name} {
    &:before { content: $value; }
  }
}

Advanced Sass Module Skins

$messages: (
  error:   (#d82d2d, #666),
  success: (#52bf4a, #fff),
  warning: (#c23435, #fff)
);

@each $name, $colors in $messages {
  $bg: nth($colors, 1);
  $color: nth($colors, 2);

  .message--#{$name} {
    background-color: $bg;
    color: $color;
  }
}

Advanced Sass Z-Indexes

$layers: (
  bottom: 1,
  middle: 5,
  top:    10
);

@mixin layer($name) {
  z-index: map-get($layers, $name);
};

.overlay {
  @include layer(middle);
}

.lightbox {
  @include layer(top);
}

Advanced Sass Font Sizes

$font--sizes: (
  ( base,  $base-font-size,     $base-line-height ),
  ( small, $base-font-size*.75, $base-line-height*.75 ),
  ( large, $base-font-size*1.5, $base-line-height*1.5 )
);

@mixin typeset($level) {
  @each $item in $font--sizes {
    @if $level == nth($item, 1) {
      font-size: nth($item, 2);
      line-height: nth($item, 3);
    }
  }
}

@each $set in $font--sizes {
  $size: nth($set, 1);
  #{"%size--" + $size} {
    @include typeset($size);
  }
}

Advanced Sass Theming

$themes: (
  gray: (
    button-bg: #ccc,
    button-color: #f2f2f2
  ),
  brown: (
    button-bg: #ab906b,
    button-color: #ecdac3
  )
);

@function setStyle($theme, $property) {
  @return map-get(map-get($themes, $theme), $property);
}

.btn {
  @each $key, $value in $themes {
    .theme--#{$key} & {
      background: setStyle($key, button-bg);
      color: setStyle($key, button-color);
    }
  }
}

Section - V

Media Queries

Media Queries CSS3

@media screen and (max-width: 500px) {
  .sidebar {
    float: none;
    width: 100%;
  }
}

Media queries allow you to conditionally load styles based on things like page width, orientation, and even environmental lighting.

Responsive Web Design!

You nest declarations within media queries.

Media Queries Sass

.sidebar {
  float: left;
  width: 35%;

  @media screen and (max-width: 800px) {
    width: 25%;
  }

  @media screen and (max-width: 500px) {
    float: none;
    width: 100%;

    a { display: block; }
  }
}

In Sass, you can nest your media queries under any declaration.

OMG THIS IS SO AWESOME.

It becomes easy to see exactly how the module is morphing through breakpoints.

Media Queries Output

Media Queries "bubble up" beyond their containing declarations.

Sass
.sidebar {
  float: left;
  width: 35%;

  @media screen and (max-width: 800px) {
    width: 25%;
  }

  @media screen and (max-width: 500px) {
    float: none;
    width: 100%;

    a { display: block; }
  }
}
CSS Output
.sidebar {
  float: left;
  width: 35%;
}
@media screen and (max-width: 800px) {
  .sidebar {
    width: 25%;
  }
}
@media screen and (max-width: 500px) {
  .sidebar {
    float: none;
    width: 100%;
  }
  .sidebar a { display: block; }
}

Media Queries Variables

Sass
$break-large: 800px;
$break-small: 500px;

.sidebar {
  float: left;
  width: 35%;

  @media screen and (max-width: $break-large) {
    width: 25%;
  }

  @media screen and (max-width: $break-small) {
    float: none;
    width: 100%;

    a { display: block; }
  }
}

Breakpoints are often obscure numbers, and we repeat them all over the place.

Of course, we should make them variables!

Media Queries Variables II

Sass
$mobile-med: "screen and (min-width: 480px)";
$tablet-port: "screen and (min-width: 768px)";

.sidebar {
  float: left;
  width: 35%;

  @media #{$tablet-port} {
    width: 25%;
  }

  @media #{$mobile-med} {
    float: none;
    width: 100%;

    a { display: block; }
  }
}

Why not make the entire media query a variable?

We have to interpolate
#{} our variables so that Sass compiles them.

Media Queries @content

@mixin respond-to($breakpoint) {
  @if $breakpoint == tablet-large {
    @media only screen and (max-width: $width-large) {
      @content;
    }
  } @else if $breakpoint == mobile-large {
    @media only screen and (max-width: $width-small) {
      @content;
    }
  }
}

.sidebar {
  width: 35%;
  @include respond-to(tablet-large) {
    width: 25%;
  }
  @include respond-to(mobile-large) {
    width: 100%;
    a { display: block; }
  }
}

The @content directive allows us to pass entire blocks of styles to a mixin, which then outputs that content back into the declaration that called the mixin.

WAT?

Section - VI

A Short & Lovely Demo

Section - VII

Wrap Up

Libraries Compass

"Compass is an open-source CSS Authoring Framework." ~ Compass

  • CSS3 mixins!
  • Typography pattern tools.
  • Lots of other utilities!

Libraries Bourbon

"A simple and lightweight mixin library for Sass." ~ Bourbon

  • CSS3 mixins!
  • Vanilla styles.
  • Super slim.
  • No configuration.

Libraries Susy

"Responsive grids for Compass." ~ Susy

  • Grid mixins!
  • Very flexible.

Libraries A Few More

Tools GUIs

  • CodeKit (OS X)
    "It's like steroids for developers."
  • Compass.app
    Compilation + live reload from the menubar.
  • Scout
    Self-contained Ruby environment.
  • More at the Sass Install page.

Important Links

Cool Stuff!

Play around with this cool stuff:

Sass Questions?

I'm here to help

yoku2010@gmail.com

@yoku_2010