Sass

css-frameworks

Articles
Resources

// Sass:

Sass (Syntactically Awesome Style Sheets) is a CSS preprocessor. It is to CSS 
what CoffeeScript is to Javascript. Sass adds a feature set to your stylesheet 
markup that makes writing styles fun again.

There are several ways you can compile Sass:

1. The original Ruby Sass binary. Install it with gem install sass, and compile 
   it by running sassc myfile.scss myfile.css.

2. A GUI app such as Hammer, CodeKit, or Compass:
   http://hammerformac.com/
   https://incident57.com/codekit/
   http://compass.kkbox.com/

3. Use libsass, which is a blazing fast Sass compiler written in C. You can also 
   install libsass via NPM with node-sass (npm install node-sass).

Ruby Sass is a little slow when compiling large source sets. Libsass (node-sass) 
is fast, but is not in 100% feature parity with Ruby Sass.

If we aren’t a command line person, the GUI apps are great. We can set them up 
to watch scss files, so when we edit them they will compile automatically.

If we want to just screw around, we can use Sassmeister. It is a web based Sass 
playground.

When Sass first came out, the main syntax was noticably different from CSS. It 
used indentation instead of braces, didn’t require semi-colons and had shorthand 
operators. In short, it looked a lot like Haml ( http://haml.info/ )

Some folks didn’t take too kindly to the new syntax, and in version 3 Sass 
changed it’s main syntax to .scss. SCSS is a superset of CSS, and is basically 
written the exact same, but with all the fun new Sass features.

We can still use the original syntax if you want to.

Sass brings variables to CSS.  Acceptable values for variables include numbers, 
strings, colors, null, lists and maps.  Variables in Sass are scoped using the 
$ symbol:

$primaryColor: #eeffcc;

Defining variables on their own doesn’t actually output any css, it just sets it 
within the scope. You need to use it within a CSS declaration to see it:

$primaryColor: #eeffcc;
body {
    background: $primaryColor;
}

Sass has variable scope.  If you declare a variable within a selector, it is 
then scoped within that selector:

$primaryColor: #eeccff;

body {
  $primaryColor: #ccc;
  background: $primaryColor;
}

p {
  color: $primaryColor;
}

In the above code, we give $primaryColor a different value inside the body tag.

To set a variable globally from within a declaration, Sass provides a !global 
flag:

$primaryColor: #eeccff;

body {
  $primaryColor: #ccc !global;
  background: $primaryColor;
}

p {
  color: $primaryColor;
}

When the above code is compiled, our paragraph's color is #ccc.

Variables begin with $ and are declared just like CSS properties.  Variables can 
have any value that is allowed for CSS property:

$main-color: #ce4dd6

#navbar {
    border-bottom: {
        color: $main-color;
    }
}

Another helpful flag, particularly when writing mixins, is the !default flag. 
This allows us to make sure there is a default value for a variable in the event 
that one is not provided. If a value is provided, it is overwritten:

$firstValue: 62.5%;
$firstValue: 24px !default;
body {
    font-size: $firstValue;
}

When the above code is compiled, body font size = 62.5%.

You can use #{} to interpolate variables into property names and selectors:

$vert: top;
$hortz: left;
$radius: 10px;

.rounded-#{$vert}-#{$hortz} {
    border-#{vert}-#{$hortz}-radius: $radius;
}

This produces:

.rounded-top-left {
    border-top-left-radius: 10px;
}

Often when writing CSS, you'll have several selectors that all begin with the 
same thing.  For example, "#navbar ul", "#navbar li", and "#navbar li a".  It's 
a pain to repeat the beginning over and over again, especially when it gets 
long.  Sass allows you to avoid this by nesting the child selectors within the 
parent selector:

#navbar {
    width: 80%;
    height: 23px;
    ul {
        list-style-type: none;
    }
    li {
        float: left;
        a { 
            font-weight: bold;
        }
    }
}

We can also nest properties, so you do not have to repeat stuff like 
border-left- all the time:

.fakeshadow {
    border: {
        style: solid;
        left: {
            width: 4px;
            color: #888;
        }
        right: {
            width: 2px;
            color: #ccc;
        }
    }
}

In addition to just using variables, you can also modify and combine them using 
math and pre-defined functions.  This allows you to compute element sizes and 
even color.

Unlike CSS, Sass allows us to use mathematical expressions! This is super 
helpful within mixins, and allows us to do some really cool things with our 
markup.  Supported operators include:

1. Addition: +
2. Subtraction: -
3. Division: / 
4. Multiplication: *
5. Modulo: %
6. Equality: ==
7: Inequality: !=

Because the / symbol is used in shorthand CSS font properties like font: 
14px/16px, if you want to use the division operator on non-variable values, 
you need to wrap them in parentheses like:

$fontDiff: (14px/16px);

We cannot mix value units:

$container-width: 100% - 20px;

The above example won’t work. Instead, for this particular example you could use 
the css calc function, as it needs to be interpereted at render time.

To create a dynamic column declaration, based upon a base container width:

$container-width: 100%;

.container {
  width: $container-width;
}

.col-4 {
  width: $container-width / 4;
}

Sass comes with a number of functions.

With the darken() function, we can pass it a color and a percentage and it will 
returns a darken color of the original color.

One of the most helpful, and also misused features of Sass, is the ability to 
nest declarations. With great power comes great responsibility.

Basic nesting refers to the ability to have a declaration inside of a 
declaration. In normal CSS we might write:

.container {
    width: 100%;
}

.container h1 {
    color: red;
}

But in Sass we can get the same result by writing:

.container {
    width: 100%;
    h1 {
        color: red;
    }
}

So what if we want to reference the parent? This is achieved by using the & 
symbol. Check out how we can leverage this to add pseudo selectors to anchor 
elements:

a.myAnchor {
    color: blue;
    &:hover {
        text-decoration: underline;
    }
    &:visited {
        color: purple;
    }
}

Now we know how to nest, but if we want to de-nest, we have to use the @at-root 
directive. Say we have a nest set up like so:

.first-component {
    .text { font-size: 1.4rem; }
    .button { font-size: 1.7rem; }
    .second-component {
        .text { font-size: 1.2rem; }
        .button { font-size: 1.4rem; }
    }
}

After realizing that the second component might be used elwhere, we have 
ourselves a pickle. Well, not really. @at-root to the rescue:

.first-component {
    .text { font-size: 1.4rem; }
    .button { font-size: 1.7rem; }
    @at-root .second-component {
        .text { font-size: 1.2rem; }
        .button { font-size: 1.4rem; }
    }
}

Nests are a really great way to save some time and make your styles readable, 
but overnesting can cause problems with overselection and file size. Always 
look at what your sass compiles to and try to follow the “inception rule”, which 
is "don’t go more than four levels deep".  See http://thesassway.com/

@import "grids";

We can import without specifying the file name extension.

Sass @import does not require HTTP requests.  It pulls in the stylesheet 
directly.  Any variables or mixins defined in @imported files are availabled to 
the files that import them.

Sass has a naming convention for files that are meant to be imported (called 
"partials").  They begin with an underscore.  Sass allows files to be imported 
without specifying a file extension.   That means we can import "rounded" rather 
than rounded.scss:

/* _rounded.scss */
@mixin rounded($vert, $horz, $radius: 10px) {
    border-#{$vert}-#{$horz}-radius: $radius;
}

/* style.scss */
@import "rounded";

Sass compilers also include a concept called “partials”. If you prefix a .sass 
or .scss file with an underscore, it will not get compiled to CSS. This is 
helpful if your file only exists to get imported into a master style.scss and 
not explicitly compiled. 

In Sass, the @extend directive is an outstanding way to inherit already existing 
styles.  Lets use an @extend directive to extend an input’s style if it has an 
input-error class:

.input {
  border-radius: 3px;
  border: 4px solid #ddd;
  color: #555;
  font-size: 17px;
  padding: 10px 20px;
  display: inline-block;
  outline: 0;
}

.error-input {
  @extend .input;
  border:4px solid #e74c3c;
}

Please note, this does not copy the styles from .input into .error-input. Take 
a look at the compiled CSS in this example to see how it is intelligently 
handled:

.input {
  border-radius: 3px;
  border: 4px solid #ddd;
  color: #555;
  font-size: 17px;
  padding: 10px 20px;
  display: inline-block;
  outline: 0;
}

.error-input {
  @extend .input;
  border:4px solid #e74c3c;
}

body {
  text-align: center;
  padding-top: 100px;
}

But what about if we want to extend a declaration with a set of styles that 
doesn’t already exist? Meet the placeholder selector.

%input-style {
    font-size: 14px;
}

input {
    @extend %input-style;
    color: black;
}

The placeholder selector works by prefixing a class name of your choice with 
a % symbol. It is never rendered outright, only the result of its extending 
elements are rendered in a single block.

Check out below how our previous example works with a placeholder:

%input-style {
  border-radius: 3px;
  color: #555;
  font-size: 17px;
  padding: 10px 20px;
  display: inline-block;
  outline: 0;
}

.input {
  @extend %input-style;
  border: 4px solid #ddd;
}

.error-input {
  @extend %input-style;
  border:4px solid #e74c3c;
}

body {
  text-align: center;
  padding-top: 100px;
}

Mixins.

Mixins are like variables.  However, unlike variables which allow us to define 
and re-use simple values, mixins allows us to define re-use block of styles, 
properties or even selectors.  Mixins are defined using the @mixin directive, 
which takes a block of styles that can then be included in another selector 
using the @include directive:

@mixin rounded-top-left {
    $vert: top;
    $horz: left;
    $radius: 10px;

    border-#{vert}-#{$horz}-radius: $radius;
}

#navbar li {
    @include rounded-top-left;
}

The real power of mixins comes when you pass them arguments.  Arguments are 
declared as comma-separated list of variables.  Each of those variables is 
assigned a value each time the mixin is used.  Mixin arguments can also be given 
default values just like you'd declare them normally.  When the user of the 
mixin choose not to pass that argument, it will be assigned the default value.

@mixin rounded($vert, $horz, $radius: 10px) {
    border-#{$vert}-#{horz}-radius: $radius;
}

#navbar li {
    @include rounded(top, left);
}

#footer {
    @include rounded(top, left, 5px);
}

The mixin directive is an incredibly helpful feature of Sass, in that it allows 
you to include styles the same way @extend would, but with the ability to supply 
and interperet arguments.

Sass uses the @mixin directive to define mixins, and the @include directive to 
use them. Lets build a simple mixin that we can use for media queries!

Our first step is to define our mixin:

@mixin media($queryString){
}

Notice we are calling our mixin media and adding a $queryString argument. When 
we include our mixin, we can supply a string argument that will be dynamically 
rendered. Lets put the guts in:

@mixin media($queryString){
    @media #{$queryString} {
      @content;
    }
}

Because we want our string argument to render where it belongs, we use the Sass 
interpolation syntax, #{}. When you put a variable in between the braces, it is 
printed rather than evaluated.

Another piece of our puzzle is the @content directive. When you wrap a mixin 
around content using braces, the wrapped content becomes available via the 
@content directive.  Finally, lets use our mixin with the @include directive:

.container {
    width: 900px;
    @include media("(max-width: 767px)"){
        width: 100%;
    }
}

Check out the demo below to see how our new mixin renders media queries:

@mixin media($queryString){
    @media #{$queryString} {
      @content;
    }
}

.container {
    width: 900px;
    @include media("(max-width: 767px)"){
        width: 100%;
    }
}

Function directives in Sass are similar to mixins, but instead of returning 
markup, they return values via the @return directive. They can be used to DRY 
(Don’t repeat yourself) up your code, and make everything more readable.  Lets 
go ahead and create a function directive to clean up our grid calculations from 
our grid demo:

@function getColumnWidth($width, $columns,$margin){
    @return ($width / $columns) - ($margin * 2);
}

Now we can use this function in our code below:

$container-width: 100%;
$column-count: 4;
$margin: 1%;

.container {
  width: $container-width;
}

.column {
  background: #1abc9c;
  height: 200px;
  display: block;
  float: left;
  width: getColumnWidth($container-width,$column-count,$margin);
  margin: 0 $margin;
}

Now that we have all these tools at our disposal, how about we build our own 
configurable grid framework? Lets roll:

Lets begin by creating a map of settings:

$settings: (
    maxWidth: 800px,
    columns: 12,
    margin: 15px,
    breakpoints: (
        xs: "(max-width : 480px)",
        sm: "(max-width : 768px) and (min-width: 481px)",
        md: "(max-width : 1024px)  and (min-width: 769px)",
        lg: "(min-width : 1025px)"
    )   
);

Next lets write a mixin that renders our framework:

@mixin renderGridStyles($settings){
}

We are going to need to render markup for each breakpoint, so lets iterate 
through our breakpoints and call our media mixin. Lets use the map-get method to 
get our breakpoint values, and our @each directive to iterate through our 
breakpoints:

@mixin renderGridStyles($settings){
  $breakpoints: map-get($settings, "breakpoints");
  @each $key, $breakpoint in $breakpoints {
    @include media($breakpoint) {

    }
  }
}

We need to render the actual grid markup within our iteration, so lets create a 
renderGrid mixin. Lets use the map-get method to get our map values, and our 
@while directive to iterate through columns with $i as our index. We render our 
class name using interpolation.

@mixin renderGrid($key, $settings) {
  $i: 1;
  @while $i <= map-get($settings, "columns") {
    .col-#{$key}-#{$i} {
      float: left;
      width: 100% * $i / map-get($settings,"columns");
    }
    $i: $i+1;
  }
}

Next, lets add container and row styles:

.container {
    padding-right: map-get($settings, "margin");
    padding-left: map-get($settings, "margin");
    margin-right: auto;
    margin-left: auto;
}

.row {
    margin-right: map-get($settings, "margin") * -1;
    margin-left: map-get($settings, "margin") * -1;
}

------

$settings: (
    maxWidth: 800px,
    columns: 12,
    margin: 15px,
    breakpoints: (
        xs: "(max-width : 480px)",
        sm: "(max-width : 768px) and (min-width: 481px)",
        md: "(max-width : 1024px)  and (min-width: 769px)",
        lg: "(min-width : 1025px)"
    )   
);

@mixin renderGridStyles($settings){
  .container {
    padding-right: map-get($settings, "margin");
    padding-left: map-get($settings, "margin");
    margin-right: auto;
    margin-left: auto;
    max-width: map-get($settings,"maxWidth");
  }

  .row {
    margin-right: map-get($settings, "margin") * -1;
    margin-left: map-get($settings, "margin") * -1;
  }
  $breakpoints: map-get($settings, "breakpoints");
  @each $key, $breakpoint in $breakpoints {
    @include media($breakpoint) {
      @include renderGrid($key, $settings);
    }
  }
}

@mixin renderGrid($key, $settings) {
  $i: 1;
  @while $i <= map-get($settings, "columns") {
    .col-#{$key}-#{$i} {
      float: left;
      width: 100% * $i / map-get($settings,"columns");
    }
    $i: $i+1;
  }
}

@mixin media($queryString){
    @media #{$queryString} {
      @content;
    }
}

@include renderGridStyles($settings);

p {
  padding: 20px;
  color: white;
  background: #9b59b6;
  margin: 20px;
}

What are the differences between the .scss format and the .sass format?

Sass has two formats (.scss and .sass). The .scss is just like regular CSS file. This format use curly braces and semi-colons. The .sass format is for people who prefer to use indentation to format the code like Python.

How can we install Sass?

gem install sass

How can we convert from .scss to .sass and from .sass to .scss?

sass-convert style.scss style.sass
sass-convert style.sass style.scss

How can we turn .scss file into a .css file?

sass input.scss output.css

How can we watch a single file?

sass --watch style.scss:style

Now, whenever you change style.scss, Sass will automatically update style.css with the changes.

How can we watch the entire directory?

sass --watch stylesheets/sass:stylesheets/css

How can we reference parent selector?

a {
    color: #ce4dd6;
    &:hover {
        color: #ffb3ff;
    }
    &:visited {
        color: #c458cb;
    }
}

Why use &:hover ? Why not just :hover?

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License