A sassy introduction to CSS preprocessing

by Ramón Guijarro

Ramón Guijarro

Creative web developer with an eye for design and communication. JavaScript and React enthusiast. Proud @h4ckademy alumni.

What is it?

A scripting language that is interpreted into CSS, also known as CSS preprocessor

Sass

CSS

Two syntaxes

Sass

SCSS

The old syntax

Indentation and newlines

The new syntax

Brackets and semicolons

You can convert between them with sass-convert

body
  font-family: sans-serif
  color: black
body {
  font-family: sans-serif;
  color: black;
}

Why should you use it?

Extends CSS with a bunch of useful features

You can finally have variables! Hooray!

Allows better structuring and modularization

Avoids the use of non-semantic selectors

Say goodbye to .float-left

Improves legibility and maintainability

How do you set it up?

sudo apt-get install ruby-full  # Ubuntu, Debian
sudo yum install ruby           # Fedora, CentOS, RHEL
sudo pacman -S ruby             # Arch Linux
brew install ruby               # OS X (Homebrew)
format C:                       # Windows

Install Ruby

Technically, you don't need Ruby. Implementations in other languages are available thanks to libSass: http://sass-lang.com/libsass.

sudo gem install --no-user-install sass   # Globally
gem install sass                          # For your user

Install Sass

If you install the gem for your user, you'll need to add
the folder with the executable to your PATH.

sass -i

Interactive shell

Convert a file

Watch for changes

sass styles.scss styles.css
sass --watch styles.scss:styles.css   # A file
sass --watch cssFolder:scssFolder     # A folder

Run Sass

sudo gem install --no-user-install listen   # Globally
gem install listen                          # For your user

Install Listen (optional)

It prevents Sass from polling for changes in some scenarios.
You should be fine without it for now, though.

Install tools (optional)

Syntax highlighter for your editor

Auto reload plugin for your browser

Alternative setups

No setup

Fancy setups

  • Task runners / automators
    • Grunt with grunt-contrib-sass plugin
    • Gulp with gulp-sass or gulp-ruby-sass plugins
  • Handled by the server
    • Rails with sass-rails gem (default since Rails 3.1)
    • Node with node-sass package

How do you use it?

Extensions

main {
  margin: 1em auto;

  a {
    text-decoration: none;

    &:hover {
      text-decoration: underline;
    }
  }
}
main {
  margin: 1em auto;
}

main a {
  text-decoration: none;
}

main a:hover {
  text-decoration: underline;
}

Nested rules

SCSS

CSS

h1 {
  font: {
    family: sans-serif;
    size: 2em;
  }
  
  border: {
    color: #ffffff;
    width: 2px;
  }
}
h1 {
  font-family: sans-serif;
  font-size: 2em;
  border-color: #ffffff;
  border-width: 2px;
}

Nested properties

SCSS

CSS

$sans-serif-font: 'Droid Sans';
$base-size: 1em;

h1 {
  font: {
    family: $sans-serif-font;
    size: $base-size * 2;
  }
}
h1 {
  font-family: 'Droid Sans';
  font-size: 2em;
}

Variables and operations

SCSS

CSS

$col-width: 40px;
$gutter-width: 10px;

@function grid-width($cols) {
  @return $cols * $col-width +
          ($cols - 1) *
          $gutter-width;
}

.container {
  width: grid-width(3);
}
.container {
  width: 140px;
}

SCSS

CSS

Take a look at http://sass-lang.com/documentation/Sass/Script/Functions.html for all the functions included in the language

Functions

Directives

Media queries

They work just like in regular CSS, but can be nested.

$phone-bp: 320px;
$tablet-bp: 768px;

.sidebar {
  display: none;

  @media (min-width: $phone-bp) {
    display: block;
  }

  @media (min-width: $tablet-bp) {
    display: inline;
  }
}
.sidebar {
  display: none;
}

@media (min-width: 320px) {
  .sidebar {
    display: block;
  }
}

@media (min-width: 768px) {
  .sidebar {
    display: inline;
  }
}

SCSS

CSS

%error {
  color: white;
  background-color: red;
  border-color: darken(red, 10%);
}

.normal-error {
  @extend %error;
  border-width: 1px;
}

.highlighted-error {
  @extend %error;
  border-width: 3px;
}
.normal-error, .highlighted-error {
  color: #ffffff;
  background-color: #ff0000;
  border-color: #cc0000;
}

.normal-error {
  border-width: 1px;
}

.highlighted-error {
  border-width: 3px;
}

Extend and placeholders

SCSS

CSS

Extends are fixed and prevent from repetition.

@mixin banner($color) {
  background-color: $color;
  color: lighten($color, 20%);
}

.warning {
  @include banner(#ffff00);
}

.error {
  @include banner(#ff0000);
}
.warning {
  background-color: #ffff00;
  color: #ffff66;
}

.error {
  background-color: #ff0000;
  color: #ff6666;
}

Include and mixins

SCSS

CSS

Mixins can be variable and don't prevent from repetition.

@for $index from 1 through 3 {
  .item-#{$index} {
    height: 2em * $index;
  }
}
.item-1 {
  height: 2em;
}

.item-2 {
  height: 4em;
}

.item-3 {
  height: 6em;
}

Control directives (I)

SCSS

CSS

These allow you to write very fancy stuff, but are rarely used.
You probably want to use third-party libraries instead.

@each $item in new, open, save {
  .#{$item}-icon {
    background-image:
      url('#{$item}.png');
  }
}
.new-icon {
  background-image: url('new.png');
}

.open-icon {
  background-image: url('open.png');
}

.save-icon {
  background-image: url('save.png');
}

Control directives (II)

SCSS

CSS

These allow you to write very fancy stuff, but are rarely used.
You probably want to use third-party libraries instead.

Control directives (III)

$prefixes: moz, webkit, o, ms;
$prefixer-enabled: true;
  
@mixin border-radius($radius) {
  @if $prefixer-enabled {
    @each $prefix in $prefixes {
      -#{$prefix}-border-radius: $radius;
    }
  }

  border-radius: $radius;
}

button {
  @include border-radius(10px);
}
button {
  -moz-border-radius: 10px;
  -webkit-border-radius: 10px;
  -o-border-radius: 10px;
  -ms-border-radius: 10px;
  border-radius: 10px;
}

SCSS

CSS

button {
  border-radius: 10px;
}
$prefixer-enabled: true
$prefixer-enabled: false

These allow you to write very fancy stuff, but are rarely used.
You probably want to use third-party libraries instead.

Import and partials

* {
  margin: 0;
  padding: 0;
}

body {
  font-family: 'Open Sans';
  background-color: #eeeeec;
}
* { margin: 0; padding: 0; }

CSS

SCSS

$body-font: 'Open Sans';
$body-bg-color: #eeeeec;
_reset.scss
_variables.scss
@import 'reset', 'variables';

body {
  font-family: $body-font;
  background-color: $body-bg-color;
}
main.scss
main.css

All together

Code example

What else can you use?

Frameworks

Mixin libraries

Grid systems

Complements

Other preprocessors

Postprocessors

Future versions of CSS

Alternatives

Thank you

A sassy introduction to CSS preprocessing

By Ramón Guijarro

A sassy introduction to CSS preprocessing

Slides from an introductory talk to CSS preprocessing with Sass. Take a look at this GitHub repository for a code example that shows all the features of the language explained here in practice: https://github.com/soyguijarro/sass-talk

  • 1,666