Web Dev Tools 101: CSS Processors

You like writing CSS, right? No? Me neither. It’s a pain in the neck. My CSS is mostly trial and error. It can be made easier through the use of processors. The most common preprocessors are LESS, SASS and Stylus – these render their own syntax into raw CSS. Then you have postprocessors – these include doing things like minification, browser extension tags and conversions so you don’t have to deal with the keeping up to date with browser standards.

TL;DR

You want to use a preprocessor – pick SASS or LESS, depending on your preference.

Postprocessors are optional, but the bigger the project, the more likely you are going to want one. Pleeease packages a lot of the postprocessors into one place.

Why do you need to know?

I hate CSS. Something a simple as centering an element on the screen should not be this difficult. It’s always evolving and there is some seriously cool stuff happening, but I can’t keep up. When I play with CSS, my productivity goes way down. I’ve learned to accept it. That doesn’t mean I don’t look for ways to gain productivity back though. One of those things is using CSS processors to do some of the chore work for me.

The first thing I can do is make the syntax of CSS more sane. That means not writing it in CSS, but in something else. Preprocessors compile a better syntax into CSS for you, allowing you to concentrate on the task at hand – developing awesome UI. Once I’ve got the CSS compiled, I then need to remember to use another set of tools to handle compression, minification, conversion of images, browser extensions and any number of other tasks that are required in order to ship the CSS and have it do the right thing across Chrome, Firefox, Internet Explorer and Safari, Mobile and Desktop, for all screen sizes and all versions. Postprocessors allow me to reduce my test matrix for the CSS.

Preprocessors

CSS Preprocessors use a similar-but-not-the-same syntax to express the CSS between classes. They all have some similarities:

  • Variables: Generally I work with a color palette, specific font sizes and font families and specific pixel sizes. These can all be put in variables. Then I refer to the variable, not the specific color/font/etc. If my marketing manager changes the color palette on me, I replace the colors in one place, recompile and I’m done.
  • Mixins: How often do you write a flexbox? How about size and position? I use mixins much like macros or functions – it allows me to reduce the clutter and makes my code much more readable.
  • Calculations: All of the preprocessors can do calculations. If you want to call a mixin with a specific size, and then in the mixin say “50% of that number that was passed in”, it’s relatively easy.
  • Sourcemaps: All of the processors produce a .css.map file – this map file allows a browser or a debugger to tell you what line in the original source a particular directive is located.
  • Image Inlining: When you are using small images – for example, icons – it’s a good idea to put them inline instead of doing another round-trip to the server. The preprocessor should be able to do that for you.
  • Integration with your Task Runner: You should be able to run the preprocessor build phase using your favorite task runner – grunt or gulp.
  • Visual Studio Integration: You should be able to edit the source file with your favorite IDE – in my case, that’s Visual Studio.

For the comparison of the preprocessors, I’ll be using the CSS from the Bubble Search – you can download the source CSS from my GitHub repository. It’s 116 lines long, so it’s most definitely not long. This will allow me to see how much shorter it is.

LESS

You can get much more (and better) documentation on the LESS language at their website, including a really good tutorial. Here is my less code for my stylesheet:

@import (less) "mixins.less";

header {
	.size(100%; 50px);
	.colors(@bg-dark; @fg-light);

	ul {
		display: block;
		list-style: none;
		padding-top: 8px;
		
		li {
			display: inline;
			font-size: 28px;
		}
	}
}

.bubble {
	.colors(white; white);
	.rounded-box(1px solid @bg-border; 8px; 2px; @bg-border);
	
	&:before {
		content: '';
		.position(absolute; 20px; -16px);
		.css-up-triangle(16px; @bg-border);
	}

	.search {
		background: data-uri('../img/search-32.png') no-repeat;
		padding-left: 40px;
		height: 32px;
		margin: 8px 8px;

		&:before {
			content: '';
			.position(absolute; 22px; -14px);
			.css-up-triangle(14px; white);
		}

		input {
			font-size: 18px;
			border: 0;
			margin-top: 2px;
			.color(white; @bg-dark);
		}
	}
}

My import at the beginning contains all the definitions of the variables and mixins. For example, .position is defined like this:

.position(@pos: relative; @left: 0; @top: 0) {
    position: @pos;
    left: @left;
    top: @top;
}

Similarly, my colors are defined like this:

@bg-dark: #666666;

The rest of the code is nested. For instance, if I have something like this:

.bubble {
    .search {
        input {
            font-size: 18px;
        }
    }
}

It gets compiled like this:

.bubble .search input {
    font-size: 18px;
}

I like the former – it retains the inherent topology of the styles for me and is much easier to read. Notice also the data-uri() call for the background – this is how you do image inlining.

In terms of coverage, there are modules for both grunt and gulp. With Web Essentials (which is really essential on Visual Studio), when you save a LESS file it automatically gets compiled as a CSS file, which bypasses the need for a separate compilation phase.

SASS

SASS and LESS are almost functionally equivalent. While LESS files have a .less extension, SASS files have a .scss extension. SASS has some really good documentation too. Here is the SASS equivalent of the LESS code:

@import 'mixins';

header {
	@include size(100%, 50px);
	@include colors($bg-dark, $fg-light);

	ul {
		display: block;
		list-style: none;
		padding-top: 8px;
		
		li {
			display: inline;
			font-size: 28px;
		}
	}
}

.bubble {
	@include colors(white, white);
	@include rounded-box(1px solid $bg-border, 8px, 2px, $bg-border);
	
	&:before {
		content: '';
		@include position(absolute; 20px, -16px);
		@include css-up-triangle(16px, $bg-border);
	}

	.search {
		background: data-uri('../img/search-32.png') no-repeat;
		padding-left: 40px;
		height: 32px;
		margin: {
			top: 8px;
			left: 8px;
		}

		&:before {
			content: '';
			@include position(absolute, 22px, -14px);
			@include css-up-triangle(14px, white);
		}

		input {
			font-size: 18px;
			border: 0;
			margin-top: 2px;
			@include color(white, $bg-dark);
		}
	}
}

There are differences in how the mixins and variables are defined and how imports are handled. But it’s remarkably similar. I prefer this syntax visually (however – watch for library support. Some libraries only support SASS or LESS) As before, we can define mixins easily – here is my mixin for the position:

@mixin position($pos: relative, $left: 0, $top: 0) {
    position: $pos;
    left: $left;
    top: $top
}

Note the margin setting in the .search block. That looks wierd. It actually gets compiled to:

margin-top: 8px;
margin-left: 8px;

The difference is that if it can be combined into the “margin”, then it will be. This is great for some others – I never remember the ordering of background or font properties for example. In fact, this feature is why I prefer SASS over LESS.

As with LESS, you’ve got support for Visual studio, although it isn’t as good as the LESS support that you get with Web Essentials. You also have a grunt package and a gulp package.

Stylus

Stylus freaks me out a little bit. As a developer, I find its lack of defining boundaries unsettling. Python lovers should love Stylus though. Stylus files end in .styl, so they are easily recognizable.

@import 'mixins'

header 
	size 100%, 50px
	colors  bg-dark, fg-light 
	ul 
		display block
		list-style none
		padding-top 8px
		li 
			display inline
			font-size 28px
.bubble 
	colors white, white 
	rounded-box 1px solid bg-border, 8px, 2px,  bg-border 
	&before 
		content ''
		position absolute 20px, -16px 
		css-up-triangle 16px,  bg-border
	.search 
		background data-uri '../img/search-32.png') no-repeat
		padding-left 40px
		height 32px
		margin 8px 8px
		&before 
			content ''
			position absolute, 22px, -14px 
			css-up-triangle 14px, white 
		input
			font-size 18px
			border 0
			margin-top 2px
			color white,  bg-dark

It’s very minimalist. Ok – who am I kidding? I didn’t like Python and I don’t like Stylus. It might appeal to your sensibilities. It has variables – can you tell which ones are variables? Nope? Neither can I. How about where a block ends? Sorry – an invisible space doesn’t cut it.

It does have good documentation, fortunately. It is not handled by Visual Studio, but it is handled by both grunt and gulp.

I’m not a fan. Let’s move on.

Postprocessors

There are a whole host of CSS postprocessors, but I’ll come on to why you shouldn’t care later. Here are two you need to know about:

  • Autoprefixer: There is a great site called caniuse.com – it basically tells the CSS designer if a property is supported by a browser. If not, do you need to use a vendor prefix? Autoprefixer takes your CSS and adds the vendor prefixes in where appropriate using the latest information on caniuse.com.
  • clean-css: Just like your Javascript, CSS needs to be minified to be efficient too. Clean-CSS does the minification for you, including working with a source map so you can debug on the minified code.

There is a bunch of other stuff you need to do at build time and there are a bunch of grunt and gulp tasks for this. But why bother? Let someone else maintain that stuff for you. That someone is Vincent De Oliveira and he has produced Pleeease – a post processor that basically does everything for you. It has grunt and gulp support too. Since it’s a post-processor, you don’t really need Visual Studio support as long as you have grunt and gulp.

The Verdict

LESS and SASS are definitely worthy of your study. For simpler cases they are equivalent. When you get to the complex cases, SASS is a little bit better – but it’s marginal and you can work around the deficiencies, such as they are. One of the big things I’ve noticed is that LESS has better support in GULP (gulp-sass seems to have issues right now), so I’m leaning towards LESS. I’d steer clear of Stylus.

For post processing, just use Pleeease.

The productivity gains are definitely worthwhile.