Writing raw CSS is not a pleasure nowadays. Pure CSS has a very simple and, as a side effect, very inflexible syntax that doesn’t always suited our needs in building high quality products. The overall complexity of systems are increasing day by day and modern web developers need more and that’s why CSS preprocessors exist.
The Overall Structure
In order to explain what a CSS preprocessor is and why we should use this kind of tools I’ll build a little demo with raw CSS. After that I’ll take this further by translating it in sass, the preprocessor of our choice for this article. This demo will be big enough to see the difference between each tool. I’ll try also to explain along the way some new concepts about preprocessors pretty quickly, so that you can start using those right now.
For the rest of this article I’ll use this HTML structure:
<section id=“main”> <figure> <article> <img src="..." alt=""> </article> <figcaption> ... </figcaption> </figure> </section>
I’ll skip the repetition from the code, just to be clear. You can taste full code listing and the demo in this codepen. Later we’ll discuss about implementing this demo using sass, the preprocessor we used to talk about in this article.
See the Pen yyvBVZ by Andrei Glingeanu (@andreiglingeanu) on CodePen.
Sass: Syntactically Awesome Style Sheets
Installation
We have 2 options: to use command line or a GUI application.
If you have ruby installed on your system, be it windows, osx or linux, you can type into command line this line to install sass:
gem install sass
Now you should have sass binary on your computer. You can compile a file named input.sass
into corresponding output.css
using command below. We have --watch
switch to indicate that we want to recompile automatically as we change the input.sass
file.
sass --watch input.sass:output.css
Another option will be to use a tool like Prepros to compille sass
files for you. Many other options at Official Installation Page.
Nesting rules
The most used feature that preprocessor gives us is rules nesting, just like we nest elements in each other in HTML. For example, when we write a rule like this:
#main-content { h1 { em { text-transform: uppercase; } } }
it will generate the following CSS:
#main-content h1 em { text-transform: uppercase; }
Using variables
We can treat variables as a named container, where we can put several things. For example we can store a color in a variable and use this color in multiple places. Storing a size in a variable, be it in pixels, percents or ems, is also a good idea. Let’s see a demo using variables next.
$itemBackground: #867e7e; $itemPadding: 5px; ul.menu { list-style: none; padding: 0; li { display: inline-block; background: $itemBackground; transition: background .5s ease-in; // we can use several functions to modify our colors // here we lighten $itemBackground by 50% in order to ensure // that we are able to read the text color: lighten($itemBackground, 50%); padding: $itemPadding; // we can use arithmetic operations, if variable is a number margin-right: $itemPadding * 2; cursor: pointer; font-size: 2em; } } See the Pen MYQwXM by Andrei Glingeanu (@andreiglingeanu) on CodePen.
See how I defined variable $itemBackground
in order to store background color for our menu? This is a very common pattern to define our palette of colors at the top and then use this colors throughout the file by explicit name. In this way we can change all colors very easily. In this demo we also have used rules nesting.
Another trick about storing colors in variables is that we can modify them using several predefined functions like:
- lighten
- darken
- saturate
- alternate
You can see full list of them and their usage on this great resource.
Parent reference
Sometimes, when using rules nesting we need a way to reference the element inside we nest rules. Let’s say we need a way to target paragraphs inside an article, but only those who have the class special
. We can express it this way:
article { p { color: #333; &.special { color: #f00; } } }
The key idea here is to use &
in order to reference the current element. Sass will give us back the following css:
article p { color: #333; } article p.special { color: #f00; }
We can use this trick in order to target all the pseudo elements and pseudo classes of current element together. In this demo you’ll see how I target :last-child
in order to give it margin-right: 0;
and also how to style :hover
pseudo class for lis using &
.
$itemBackground: #867e7e; $itemPadding: 5px; ul.menu { list-style: none; padding: 0; li { display: inline-block; background: $itemBackground; transition: background .5s ease-in; // we can use several functions to modify our colors // here we lighten $itemBackground by 50% in order to ensure // that we are able to read the text color: lighten($itemBackground, 50%); padding: $itemPadding; // we can use arithmetic operations, if variable is a number margin-right: $itemPadding * 2; cursor: pointer; font-size: 2em; &:hover { // another function which modifies color background: darken($itemBackground, 10%); } &:last-child { margin-right: 0; } } } See the Pen jEZwKb by Andrei Glingeanu (@andreiglingeanu) on CodePen.
Mixins and extending rules
In a nutshell, mixins are a way to encapsulate many useful properties into one block, and then using @include
insert this properties into our rule. This is somewhat a similar concept to functions in JavaScript and PHP. The main idea is that you can pass different parameters to the mixin, and it will return you the right properties, depending on the parameters you passed. Let’s see an example where we define a mixin in order to write vendor prefixes for transform property.
@mixin transform($transformation) { -webkit-transform: $transformation; transform: $transformation; } div { width: 100px; height: 100px; background: red; @include transform(translate(40px)); } See the Pen yyvEgQ by Andrei Glingeanu (@andreiglingeanu) on CodePen.
Let’s see, here we have transform
mixin, and we include it into div
, using @include
. As a named parameter $transformation
we receive translate(40px)
. The generated css for this mixin will look like this:
-webkit-transform: translate(40px); transform: translate(40px);
Another way of reusing existing styles is to @include
already existing rules. This one is not so common as mixins, because it does not have the ability to pass parameters to it, therefore it is not so flexible. You’ll have an example on using this technique in the final demo for sass.
Hence, we have many ways to not repeat ourselves by defining mixins and including already existing rules. There is available online many collections of predefined mixins for sass, which provide many neat things. Most popular ones are bourbon and susy. You can read about them by clicking on the links I provided for you. Among the others, susy is a great alternative to bootstrap grids and it will prevent your html being polluted with unsemantic classes like col-md-4
. You definitely should check them out.
Reimplementing demo
Now let me give you a full reimplementation of our kitties using sass, you can skim through code on codepen, it is very simple. Try to reveal all the new concepts we’ve covered here in the code for this demo.
See the Pen JopZRj by Andrei Glingeanu (@andreiglingeanu) on CodePen.
Conclusion
As a conclusion, all the preprocessors and sass specifically gives us a more flexible way to structure our styles, in comparison to pure css. Now all the nesting from HTML is expressed very naturally in our stylesheets. We also do’nt repeat ourselves by writing colors and scalar values, which is highly error prone and is very easily to commit a mistake by using sass variables. The abillity to group multiple rules under one named mixin is also a beautiful and readable way of structuring css.
These little explanations should really get you started on using sass. If you really want more you can go ahead and read official guide for this preprocessor. You may find useful documentation, which gives many more ideas and insights on using and integrating sass on different platforms and development stacks.
Ralph Feb 24, 2015, 9:08 pm
Raw CSS is not a problem… the problem is if you select elements like this:
#main figure figcaption span
If your CSS output is like that after preprocessing as well, then you’re creating problems in your CSS, not CSS itself.
There are also postprocessors by the way which can save you al lot of time as well, but you just write CSS as it was meant to be and you can use CSS variables and calc() too.
Andrei Glingeanu Mar 18, 2015, 6:26 pm
Thank you Ralph, good point.
But the main idea of this feature is not to nest our rules as deeply as possible, in order to generate selectors with dozens of lines in length.
Selectors nesting was created in order to simplify styles for complex widgets, and also to reflect html structure in css.
The problem with writing selectors in a way or another is tackled by various CSS methodologies, about which you can read about on the WEB.
At the end of the day, that’s just a description of a tool that should help you. You should master and use it wisely in a way that suits your personal needs.
By the way, I’ve recently found out a way to separate completely layout issues from visual styles: http://gridstylesheets.org/. That’s also a great way to improve the way we write our projects, but it introduces one more layer of complexity over our already so complex workflow.
Andrea Ballerino Mar 18, 2015, 3:25 am
Hey Andrei, very nice article, thanks :)
Andrei Glingeanu Mar 18, 2015, 6:27 pm
You’re welcome, Andrea!