Blog-Archiv

Samstag, 15. November 2014

Sass Over CSS

Cascading Style Sheets have a very poor syntax. Neither variables nor constants, not even arithmetic calculations.
With CSS, you can not define your styles in a structured way like with a programming language. But redundancy is what developers want to avoid, see the agile DRY principle, or the OnceAndOnlyOnce requirement.

For that purpose CSS preprocessors have been invented.

  • Sass is such one, spelled "Syntactically Awesome Stylesheets", written in Ruby, having a fast sibling written in C++,
  • Less is another one, written in JavaScript.
Such is useful when you want to alter the background-color of your portal with just one text modification, instead of engaging a software developer for a week to carefully rewrite external, internal and inline CSS of all HTML pages :-)

Using Sass, your CSS would always be external, mixed together (preprocessed) from one or several files by the Sass interpreter.
Given that, you should try to put as much styling logic as possible into *.scss files (these are the Sass source files), and minimize the amount of styling logic in HTML (where the content should be). For example, there should be no more than one CSS class on an element. Mixing CSS classes together should happen in SCSS, not in HTML.

The stronger the separation of concerns is, the smaller the software maintenance effort will be.

If you already have an installed Sass, you may want to jump to the feature description.

Installing Sass

Visit the Sass Install Page to get going. It can be installed on WINDOWS, MAC and LINUX operating systems. The following I had to do on my Ubuntu 12.04 LINUX to get Sass/Ruby installed:


sudo apt-get install ruby-full rubygems   # install ruby
sudo gem install sass   # install Sass
sass -v   # check if it works
Sass 3.4.8 (Selective Steve)
sass --help   # read help
Usage: sass [options] [INPUT] [OUTPUT]

Description:
  Converts SCSS or Sass files to CSS.

Common Options:
    -I, --load-path PATH             Specify a Sass import path.
    -r, --require LIB                Require a Ruby library before running Sass.
        --compass                    Make Compass imports available and load project configuration.
    -t, --style NAME                 Output style. Can be nested (default), compact, compressed, or expanded.
    -?, -h, --help                   Show this help message.
    -v, --version                    Print the Sass version.

Watching and Updating:
        --watch                      Watch files or directories for changes.
                                     The location of the generated CSS can be set using a colon:
                                       sass --watch input.sass:output.css
                                       sass --watch input-dir:output-dir
        --poll                       Check for file changes manually, rather than relying on the OS.
                                     Only meaningful for --watch.
        --update                     Compile files or directories to CSS.
                                     Locations are set like --watch.
    -f, --force                      Recompile every Sass file, even if the CSS file is newer.
                                     Only meaningful for --update.
        --stop-on-error              If a file fails to compile, exit immediately.
                                     Only meaningful for --watch and --update.

Input and Output:
        --scss                       Use the CSS-superset SCSS syntax.
        --sourcemap=TYPE             How to link generated output to the source files.
                                       auto (default): relative paths where possible, file URIs elsewhere
                                       file: always absolute file URIs
                                       inline: include the source text in the sourcemap
                                       none: no sourcemaps
    -s, --stdin                      Read input from standard input instead of an input file.
                                     This is the default if no input file is specified.
    -E, --default-encoding ENCODING  Does not work in Ruby 1.8.
        --unix-newlines              Use Unix-style newlines in written files.
                                     Always true on Unix.
    -g, --debug-info                 Emit output that can be used by the FireSass Firebug plugin.
    -l, --line-numbers               Emit comments in the generated CSS indicating the corresponding source line.
        --line-comments

Miscellaneous:
    -i, --interactive                Run an interactive SassScript shell.
    -c, --check                      Just check syntax, don't evaluate.
        --precision NUMBER_OF_DIGITS How many digits of precision to use when outputting decimal numbers.
                                     Defaults to 5.
        --cache-location PATH        The path to save parsed Sass files. Defaults to .sass-cache.
    -C, --no-cache                   Don't cache parsed Sass files.
        --trace                      Show a full Ruby stack trace on error.
    -q, --quiet                      Silence warnings and status messages during compilation.

Impressive! What to do with it now?

A quick way to learn things is to read the user guide and play around with it at the same time.
But first I need to find out how to translate .scss files using the Sass compiler. The web page provides a reference where this is described (which also contains a more technical user guide).

So I create my input.scss ...

1
2
3
4
5
6
7
$fontfamily: sans-serif;
$bgcolor: #33CCFF;

body {
  font-family: $fontfamily;
  background-color: $bgcolor;
}

... run the translation ...

sass input.scss output.css   # translate input.scss to output.css

... and get my output.css:

1
2
3
4
5
body {
  font-family: sans-serif;
  background-color: #33CCFF; }

/*# sourceMappingURL=output.css.map */

You can also tell Sass to watch the .scss file (or whole directory trees) for changes. It then blocks and translates any time a file is saved.

sass --watch input.scss:output.css   # translate input.scss to output.css
>>> Sass is watching for changes. Press Ctrl-C to stop.
[Listen warning]:
  Listen will be polling for changes. Learn more at https://github.com/guard/listen#polling-fallback.

>>> Change detected to: input.scss
      write output.css
      write output.css.map

The output.css.map JSON file and .sass-cache directory, created and updated when the compiler runs, seem to be Sass-internals.

The command to translate all .sccs files in current directory is:

sass --update .:.

But this works too:

sass --update .

Mind that, by default, for a file input.scss, a file input.css is generated (same name, different extension).

$ ls -l
-rwxrwx--- 1 root plugdev  98 Nov 15 17:18 _partial.scss
-rwxrwx--- 1 root plugdev 166 Nov 15 17:28 test1.scss
$ sass --update .
      write ./test1.css
      write ./test1.css.map
$ ls -l
-rwxrwx--- 1 root plugdev  98 Nov 15 17:18 _partial.scss
-rwxrwx--- 1 root plugdev 157 Nov 15 17:42 test1.css
-rwxrwx--- 1 root plugdev 232 Nov 15 17:42 test1.css.map
-rwxrwx--- 1 root plugdev 166 Nov 15 17:28 test1.scss

Sass Features

The Sass guide is easy to read and understand, although it is quite short and lacks links to deeper insights.
For example, what happens when I define a variable several times? Is this a compile error?

Any valid CSS code is valid SCSS code, but not vice versa. SCSS is spelled "Superset of Cascading Style Sheets".

Here is a short outline of Sass features.

Both Types of Comment

One nice thing I mentioned is that both slash-star and slash-slash comments can be used, in contrary to CSS where slash-slash does not work (and could lead to undetected errors).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/* This comment
 * will appear in the CSS output. */
body {
  color: black;
}

// This comment won't appear in the CSS output
a {
  color: green;
}

$Variables

1
2
3
4
5
$fontfamily: sans-serif;

body {
  font-family: $fontfamily;
}

These are really variables and not constants. They can get a new value at any time.
For instance, when you define a variable, and then after it import a file that contains another definition of that variable, the import wins. But when you import it before the local variable definition, the local definition wins.

A variable is known only within the { context } it is defined. Variables outside of any context are visible everywhere. Local variables can be made global by a !global suffix.

Nestings

Instead of writing CSS path expressions like

1
2
3
4
5
6
7
ul li {
  list-style-type: none;
}

ul li a {
  color: green;
}

you nest the path parts into each other:

1
2
3
4
5
6
7
8
ul {
  li {
    list-style-type: none;
    a {
      color: green;
    }
  }
}

@Import

Sass introduces the component-concept of partials. Such is a shared/reused SCSS file that has a leading underscore in its name:

_mypartial.scss

The underscore tells the Sass compiler to not translate this file because it will be imported.
The import then happens without the underscore:

1
2
3
4
5
6
7
@import "mypartial";

body {
  font-family: $fontfamily;
  background-color: $bgcolor;
  color: $fgcolor;
}

@Mixin

Another name would have been "Parameterizable Macro". It is mixed-in by an include statement.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@mixin border-radius($radius) {
  -webkit-border-radius: $radius;
  -moz-border-radius: $radius;
  -ms-border-radius: $radius;
  border-radius: $radius;
}

.roundedborder {
  @include border-radius(10px);
}

@Extend

The declarations block of another rule set can be included by addressing it via a single identifier (no complex selectors are possible here):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
.message {
  border: 1px solid #ccc;
}

.success {
  @extend .message;
  border-color: green;
}

.error {
  @extend .message;
  border-color: red;
}

&Parent Selector

This is a shortcut that avoids to repeat the parent selector. This ...

1
2
3
4
5
6
a {
  font-weight: bold;
  &:hover {
    color: red;
  }
}

... is compiled to:

1
2
3
4
5
6
7
a {
  font-weight: bold;
}

a:hover {
  color: red;
}

Arithmetic operations

You can write arithmetic calculations, even using $variables. Possible operators are:

 + - * / % 

Thus you can make your layout algorithm a little more transparent.

More

Of course there is more in it:


SASS versus SCSS Syntax

The SASS syntax is a different from SCSS syntax in that it leaves out the curly braces. It replaces them by precise indentation, like Python does.

When you go to the Sass guide page you can look at examples in both shapes, look out for the switch on top right corner of any example panel.

The Sass compiler recognizes the syntax by the file's extension. If you really want to leave out the curly braces, name your files .sass. Staying save means setting curly braces and naming the files .scss.




Keine Kommentare: