Faced with a super-sized stylesheet, Ragnar Kurm developed a workflow for simplifying, modifying and automating his CSS. In the first instalment of this two-part guide, he explores the features of preprocessor SASS and how to optimize your selectors.

Compile Your Style: Smarter CSS
Keine Kommentare

Image licensed by Ingram Image

Have you ever written CSS for a big website with multiple layouts and found yourself lost in the growing CSS files? Even if you have structured your files, the problem lies in how to work with multiple layouts side-by-side. So far I have not found any convincing proposal of how to approach the situation.

I had a CSS project that took more than half a year and I learned a lot during that time. Because I have extensive background in programming, I took some programming tools to writing my CSS. This article covers a workflow to work with multiple layouts side-by-side. On the way we learn many new approaches to working with CSS. In all of these aspects I give only an introduction, because complete references and tutorials for each are already available. All of these methods or steps can be used independently as well.

Diagnosing an overweight stylesheet

First, let’s take a look what happens when a site style grows big. There are variety of symptoms and indications:

  • Some values repeat a lot. Maybe the most common is the site’s default color, used in backgrounds, titles, highlights, etc.
  • In many places dependent values are used. These, as the name suggests, are values which depend on some other value. For example, if the content region is 75% wide then the sidebar value will be 25% wide. So the sidebar value is derived from the content width.
  • Some bits of CSS gets repeated here and there, like rounded corners.
  • Browsers will take more time to render your page. Meaning that the page appears after a brief pause once loaded.
  • CSS files grow big which causes:
    • Hard to orient in CSS
    • Loss of overview
    • Lack of structure
  • Increasing danger that changing some value interferes something else
  • Theming for multiple layouts (mobile, narrow, normal, wide) becomes uncomfortable, because layouts live in separate files.
  • Creating graphical elements for different layouts requires extra effort.

Fortunately there is remedy for all of that.

There are few tools and few concepts to be learned, but we will go through it step-by-step. Any of these steps can be applied alone or in combination to a theme of any size.

Although it is not compulsory, I have created a small boilerplate package which I now use at every site I create. I find that it eases the job a lot.


I found that keeping the style information for multiple layouts (different designs depending on screen size or mobile device) in different files is almost unmanageable for me. So I started to look for a better way – to have good manageability and have a good overview at the same time.

The workflow I evolved is multiple layouts side-by-side, or MLSBS for short. It allows different layouts to be put into one file, side-by-side, so that styling information for a single element in different layouts is visible at same time. Over time the methodology has evolved, and nowadays if I start a new styling project I cannot imagine doing without it.

Here is an example of how our styling information may appear “side-by-side”, in this case for logo element

. Note that the syntax which is used here is a preprocessor syntax, but property values are given verbatim.

@if $LAYOUT == "all"
  display: block
  background-position: center
  background-repeat: no-repeat
@if $LAYOUT == "narrow"
  width: 100px
  height: 100px
  background-image: url(logo-narrow.png)
@if $LAYOUT == "normal"
  width: 200px
  height: 200px
  background-image: url(logo-normal.png)
@if $LAYOUT == "wide"
  width: 300px
  height: 300px
  background-image: url(logo-wide.png)

The Master Plan

What do we need to learn in order to efficiently handle multiple layouts? There are many steps, summarized below.

Master plan

In part one of the article, we will be exploring how to write smarter CSS, covering the following subjects:

  • Style Preprocessor: SASS. A style preprocessor is central tool to achieve multiple layouts side-by-side. Preprocessors give dynamics to static CSS. In the context of this article, we are specifically interested in conditionals.
  • SASS plugin: Awareness of Environment. In order to guide the preprocessor externally, there is a requirement to be able to specify preprocessor variables from the command line. Therefore we must add a custom SASS plugin.
  • Style and Evaluation: Matching and Specificity. Page rendering speed depends on many factors, and style complexity is one of them. Style complexity is determined by selectors. To write good selectors, one needs to know how the browser matches selectors. Though this is not prerequisite to have multiple layouts side-by-side, it is almost essential to know when building big theme.

In part two, we will explore ways to structure, compile and automate our style:

  • Structuring: Splitting and Joining. To keep a style modular there is a need to split the theme into smaller pieces. But in order to avoid too many pieces, these should be joined later on after compiling.
  • Automated imagework with ImageMagick. In order to minimize manual image manipulation for different screen sizes, it is convenient to use image scaling on the fly from the command line.
  • Media Queries. To be able to select between layouts, one needs to use media queries which then execute the respective style. This is not directly related to the workflow, but is just a prerequisite for choosing the layout from the client side.
  • Automatics: Make / Makefile. To use all the steps efficiently from the command line, we need to bind them somehow. Makefile keeps track what needs to be done and carries out necessary operations.

Style Preprocessor: SASS

In my theming project there were many repeated and dependent values, lots of repeated code and even more things which were “hardcoded”, “clumsy” and uncomfortable. As programmer I could identify many such problems and started to consider using things like C preprocessor or the M4 macro language.

Fortunately I found there is an excellent solution for that – CSS-specific preprocessors. There are few of them available and I picked SASS. The following introduction and examples are SASS-specific. SASS syntax is the shortest of the different options, which I prefer because it means less typing, fewer errors and a better overview.

Preprocessors are built on top of CSS. Compiling your style results in plain CSS. It takes theming closer to programming instead of the continuous hardcoding of CSS.

Available preprocessors are SASS, LESS and Stylus. There is comprehensive documentation available about preprocessors so I’ll give only a very brief overview to give you an idea of how they work.

/* SASS source */

$color_main: #3bbfce
$content_width: 75%

width: $content_width
  color: $color_main
  background-color: lighten($color_main, 40%)

width: 100% - $content_width
/* CSS result */

#region-content {
width: 75%;

#region-content h1,
#region-content a {
color: #3bbfce;
background-color: white;

#region-sidebar {
width: 25%;

I personally like to keep one selector per line, though this is not a prerequisite. Having one selector per line provides a better overview and is easier to edit. For example, if there is an extra selector to be deleted, it is slightly easier to delete the entire line than a portion in the middle. In the long run, less typing matters.

Preprocessors have many powerful abilities: selector nesting, variables, multiple data types, calculations, conditions, loops, style reuse with mixins, custom functions, built-in functions and file inclusion.


How can we compile SASS to CSS? Easy.

$ sass global.sass global.css


Nesting is a way to write selectors. Child selectors are placed under parent selectors. It avoids repeating common parts of selectors and make HTML-CSS matching much easier. It saves time, less typing, less errors, gives better overview and is cleaner way targeting HTML elements.

/* SASS source */
  text-decoration: none
  color: green
/* CSS result */
#region-left a:link,
#region-left a:visited,
#region-right a:link,
#region-right a:visited {
text-decoration: none;
color: green;

Variables and data types: Numbers, colors, strings

Variables are “placeholders” for values. Values can be of many data types like numbers, colors or strings. Variables allow us to specify a value once and use this throughout the theme. They are also handy for calculations. The following example gives an idea of how to define variables and what kind of values they can hold. We’ll cover their usage in a moment.

$spacing_width: 10%
$default_font_size: 1.5em
$spacing: 16px
$content: 800px
$color_main: #aabbcc
$color_second: rgba(255, 0, 0, 0.75)
$path_img: '/files/images/'


Calculations means combining one or more values or variables to get an altered or combined value. It is possible to do arithmetic with dimensions, operations with colors, combine strings to name some of the options.

You don’t need to use a calculator to get dimensions right, nor use GIMP or ColorZilla to get a darker shade of your main color. The whole thing becomes dynamic.

/* SASS source */

  width: ($spacing + $content + $spacing)
  color: darken($color_main, 10%)
  background-image: url($path_img + 'logo.jpg')
/* CSS result */

#frame {
  width: 832px;
  color: #8aa2b9;
  background-image: url("/files/images/logo.jpg");


Conditional statements check some value and, based on that, executes one (or another) piece of code – selectively. Though not used often, they are prerequisite for MLSBS.

/* SASS source */

$page_width: 800px
$content: 800px
$sidebar: 220px

@if $content + $sidebar != $page_width
    @warn "Content #{$content} + Sidebar #{$sidebar} must match page width #{$page_width}"
/* Output error message */

WARNING: Content 800px + Sidebar 220px must match page width 800px
on line 6 of a.sass



Loops cause a certain piece of code to be executed repeatedly. Usually there is a variable that keeps track how many cycles are done. Loops are useful to generate sequences.

/* SASS source */

$size: 2em
@for $i from 1 through 6
font-size: $size
$size: 0.9 * $size
/* CSS result */

h1 { font-size: 2em; }
h2 { font-size: 1.8em; }
h3 { font-size: 1.62em; }
h4 { font-size: 1.458em; }
h5 { font-size: 1.312em; }
h6 { font-size: 1.181em; }

Style reuse – mixins

Mixins are piece of style that are incorporated into style. It allows to reuse a common code optionally based on arguments generate variations. It helps to get rid of non-semantic selectors and code repetition.

/* SASS source */

@mixin rounded($RADIUS)
  border-radius: $RADIUS
  -webkit-border-radius: $RADIUS
  -moz-border-radius: $RADIUS
  -o-border-radius: $RADIUS
  -khtml-border-radius: $RADIUS
  @include rounded(20px)
/* CSS result */

.block {
  border-radius: 20px;
  -webkit-border-radius: 20px;
  -moz-border-radius: 20px;
  -o-border-radius: 20px;
  -khtml-border-radius: 20px;

Custom functions

Functions are piece of code that calculate some value and return it. They are more useful for calculations rather than defining styles.

/* SASS source */

@function gallery-width($cols, $width, $padding)
@return $cols * ($padding + $width + $padding)

  width: gallery-width(5, 100px, 10px)

  width: gallery-width(10, 400px, 5px)
/* CSS result */

.gallery-1 { width: 600px; }
.gallery-2 { width: 4100px; }

Built-in functions

Built-in functions are provided by the preprocessor for data manipulation. There is a load of different kinds of built-in functions, for example color manipulation, transparency manipulation, arithmetic function, list functions etc.

/* SASS source */

$color: #123456

  color: grayscale($color)
  background-color: rgba($color, 0.5)
  width: round(100px/3)
  color: $color
/* CSS result */
.element {
  color: #343434;
  background-color: rgba(18, 52, 86, 0.5);
  width: 33px;

.element:hover {
  color: #123456

File inclusion

File inclusion means loading the contents of one file into another. The most common use-case is probably to have a file with global definitions.

@import "colors.sass"
@import url("http://fonts.googleapis.com/css?family=Droid+Sans");

SASS plugin: Awareness of Environment

In order to achieve MLSBS, there is a need to be able to read the context in which it is being compiled — specifically, to access environment variables to distinguish which layout is currently being compiled.

A custom plugin is the best way to achieve this, and it is relatively easy to create your own plugins. Here’s an example plugin which imports and uses environment variables.

First, create the file env.rb (this Ruby script is the entire plugin).

module Sass::Script::Functions
def env(var)
  assert_type var, :String

To include the plugin, SASS needs to be executed like this:

$ sass … --require env.rb …

How could it be useful? For example, if you have a different color scheme for the development site and for the production site. It helps to be more aware where you are doing your changes and not to mix them up.

Assume that you have set the environment variable STAGE=devel:

/* SASS source */

@if $STAGE == "devel"
  background-color: blue

@if $STAGE == "live"
  background-color: green
/* CSS result */

body {
background-color: blue;

Compilation in this case would be:

$ STAGE=devel sass --require env.rb tags.sass tags.css

This is one way to feed an environment variable to SASS, but there are other options as well like specifying environment variables from the shell login profile.

CSS evaluation by browser

As a theme or CSS file grows, it starts to require more browser resources for rendering, and the browser may hang for a moment before the page appears. How can we combat that? First, there are many sophisticated tools which help you analyze CSS evaluation. In addition to that, there are two concepts which are worth understanding – selector matching and selector specificity. As there is already lots of information available on this, I will provide only the most essential tips.

Selector matching

How does a browser match selectors against HTML? Browsers read selectors from right to left. I repeat, right to left. This might be a bit counter-intuitive at first glance, but this is most practical way.

Processing each element in a selector takes resources. Therefore the fewer elements, the better. Also, failing rules are quicker than matching rules.

#main-navigation { }       /* ID (Fastest) */
body.home #page-wrap { }   /* ID */
.main-navigation { }       /* Class */
ul li a.current { }        /* Class *
ul { }                     /* Tag */
ul li a { }                /* Tag */
* { }                      /* Universal (Slowest) */
#content [title='home']    /* Universal */
#main-nav > li { }         /* Slower than it might seem */
ul#main-navigation { }     /* Don't */
html body ul li a { }      /* Worst */
/* Credit: Chris Coyier, http://css-tricks.com/efficiently-rendering-css/ */

Selector specificity

In order to write good selectors it helps to know about selector specificity. If selectors have too low specificity, they will match too many elements. If a selector is too specific it will be difficult to be overridden later on if necessary.

According to the CSS3 specification:

A selector’s specificity is calculated as follows:

  • count the number of ID selectors in the selector (= a)
  • count the number of class selectors, attributes selectors, and pseudo-classes in the selector (= b)
  • count the number of type selectors and pseudo-elements in the selector (= c)
  • ignore the universal selector

Concatenating the three numbers a-b-c (in a number system with a large base) gives the specificity.

Often it is easier to understand these rules just by looking at examples. The following is also from the CSS3 spec:

*               /* a=0 b=0 c=0 -> specificity =   0 */
LI              /* a=0 b=0 c=1 -> specificity =   1 */
UL LI           /* a=0 b=0 c=2 -> specificity =   2 */
UL OL+LI        /* a=0 b=0 c=3 -> specificity =   3 */
H1 + *[REL=up]  /* a=0 b=1 c=1 -> specificity =  11 */
UL OL LI.red    /* a=0 b=1 c=3 -> specificity =  13 */
LI.red.level    /* a=0 b=2 c=1 -> specificity =  21 */
#x34y           /* a=1 b=0 c=0 -> specificity = 100 */
#s12:not(FOO)   /* a=1 b=0 c=1 -> specificity = 101 */


How can we apply these concepts to our own work? Most of the time, the selectors I use consist of one element which is usually an ID or a Class.

Here’s an example:

... ...

Here is a style example that matches above HTML:

.my-grid-td { padding: 10px; }
.my-grid-tr:hover { background-color: grey; }
.my-grid { width: 100%; }
#the-grid { border: 3px solid red; }

Next month

In this first part, we’ve looked at writing smarter CSS with use of preprocessor(s), custom plugin(s) and performance-aware selectors. In the next issue, we’ll consider how best to structure our SASS files, and how to automate every aspect of our style – from SASS compilation to image formatting. Finally we see how all these methods fit together to have multiple layouts, side-by-side.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Benachrichtige mich bei
Inline Feedbacks
View all comments
- Gib Deinen Standort ein -
- or -