Moving away from Compass

Moving away from Compass

Philipp Nowinski 16. Februar 2015 Expert Topics

1 Kommentar // Lesezeit: 6 min.

In my last post, I talked about how and why we got started with developing a build process for our frontend workflow with gulp. Today I want to talk about the next big issue we've had to face on our way to the new setup: Getting rid of Compass.

Why dump Compass?

Before we integrated a real task-based build process, we used Compass to compile our Sass files to CSS. This approach had several drawbacks. To compile a set of Sass files, you had to navigate to the directory your assets lived in, make sure you got the right path to the config.rb file and then invoke the compile command. OK - that was easy to fix. In the first version of our gulp toolchain, we included gulp-compass. Now we could pull this into our CSS task which automatically read the configuration from config.rb and we were done. But this was where we ran into the next issue.

Compass is, like Sass, written in ruby. This caused two major problems for us. First of all, we had to maintain ruby as a dependency for every project. This might not be much of a problem if you are developing a Ruby on Rails application, but if you don't know a thing about ruby, this can be a real pain. But this is nothing that bothers you every day. Updates only come once in a while, so this was OK for some time. But here is the second issue: compilation was just too slow. The compile time for the basic CSS of one of our bigger projects took over 16 seconds. This is acceptable for making your code ready for production, but if you have to wait 16 seconds, just to see if the 10 pixels you just added to the headline fix your problem, can be really annoying.

Where to go from here?

So, we needed to get away from ruby. The good news is, replacing ruby-sass is easy. There is a library called libsass that implements Sass in C. It is a lot faster than the original implementation in ruby and already the default in gulp-sass. So switching to a faster compiler was easy. But here is the bad news: there is no counterpart for Compass. Compass offers you a lot of functionality on top of Sass, so we had to make sure to find replacements for all the parts of Compass we were currently using.

CSS3 Mixins

The first Compass feature we used quite heavily are the CSS3 Mixins. Those were easy to replace. Instead of having something like this in your CSS:

.box {
  @include border-radius(5px);
}

you can safely go with just typing the W3C compliant version:

.box {
  border-radius: 5px;
}

The border-radius mixin just provides you with vendor prefixes. This can easily be replaced by passing your code through gulp-autoprefixer. Apart from that, I would highly recommend to use the version, you'll find in the spec over using a mixin. Since autoprefixer can take care of the vendor-prefixes, you don't have to care about them at this point. And I think you shouldn't either. Your CSS will look less bloated and stick more to the point. This line describes that .box has a 5px rounded corner - let the toolchain care about the different browsers

One thing you should watch out for while converting your Sass code is the linear-gradient mixin. I stumbled upon this line very often:

@include background-image(linear-gradient(top, #FFF, #DDD));

The problem here is the keyword 'top'. The linear-gradient syntax has changed since its first proposal in 2008 and the 'top' keyword is no longer supported by several browsers. This will e.g. brake your gradients in the latest version of Firefox. The Compass mixin automatically converted this for you (and again, I don't think this is the right place to do this). To avoid this, make sure to replace every occurrence with the new syntax. In this case:

background: linear-gradient(to bottom, #FFF, #DDD);

Spriting

One thing that Compass does really well is spriting. But since this was not enough reason to stick with it, we looked for a gulp task to replace it. There are a few good spite-engines out there. For our setup, we chose css-sprite. As this is no drop-in replacement for Compass, we needed to adjust our syntax a bit, but that was no big deal. One thing you might want to add here is cache-busting. The plugins gulp-hash and gulp-hash-references worked pretty well for this. You can find an example of how this looks like in a gulp-task at the bottom of this post.

image-width and image-height

Another feature we used quite often are the image-width and image-height functions. What they do is actually quite simple. You can pass them the path to an image and they return the width or height in pixels. Quite handy. There was no gulp-task that could replace this functionality, so we wrote one. As I said in the last post, it's a good thing if you understand the language your build tool is written in. It's much more easy to maintain it, or even to extend it.

So what we came up with is a gulp-task called gulp-css-image-dimensions. It works as a drop-in replacement, so just pull it into your gulp-task and you're done.

Some neat Mixins

If you want to keep some of the neat mixins Compass provides you with, you should check out this project on GitHub: compass-mixins. This is a Sass implementation of some of the ruby functions that Compass provides as Sass extensions.

Bringing the pieces together

Finally, this is what the new gulp-task can look like. The transition didn't took as long as we suspected and by doing it, we were able to drop the compile time from over 16s down to 840ms. Hooray, that's quite a number :-)

'use strict';

var gulp = require('gulp'),
  sass = require('gulp-sass'),
  cssImageDimensions = require('gulp-css-image-dimensions'),
  gulpif = require('gulp-if'),
  sprite = require('css-sprite').stream,
  imagemin = require('gulp-imagemin'),
  tap = require('gulp-tap'),
  del = require('del'),
  hash = require('gulp-hash'),
  sourcemaps = require('gulp-sourcemaps'),
  references = require('gulp-hash-references'),
  autoprefixer = require('gulp-autoprefixer'),
  minifyCss = require('gulp-minify-css');

// compile sass to css (and run hash-sprites before you start)
gulp.task('css', ['hash-sprites'], function() {
  return gulp.src('scss/**/*.scss')
    .pipe(cssImageDimensions('../images'))
    .pipe(sourcemaps.init())
    .pipe(sass())
    .pipe(autoprefixer('last 1 version', '> 1%', 'ie 8'))
    .pipe(minifyCss())
    .pipe(sourcemaps.write())
    .pipe(gulp.dest('css'));
});

// create spritesheet
gulp.task('sprites', function() {
  return gulp.src('images/sprites/**/*')
    .pipe(sprite({
      name: 'sprites',
      style: '_sprite.scss',
      cssPath: '../images',
      template: 'gulp/sprite-scss-template.mustache', // template for the generated _sprite.scss file
      orientation: 'binary-tree'
    }))
    .pipe(imagemin()) // optimize the image before writing it back to the fs
    .pipe(gulpif('*.png', gulp.dest('images'), gulp.dest('scss')));
});

// cache-busting
gulp.task('hash-sprites', ['sprites'], function() {
  return gulp.src('images/sprites.png')
    .pipe(hash())
    .pipe(gulp.dest('images')) // save the cache-busted image (sth. like sprites-b721c882.png)
    .pipe(hash.manifest('manifest.json'))
    .pipe(references(gulp.src('scss/_sprite.scss'))) // update the references
    .pipe(gulp.dest('scss))
    .pipe(tap(function() {
      del('images/sprites.png'); // delete the original image
    }));
});

1 Kommentar

Dateien hier ablegen
Dateien hochladen
  • Alex

    Alex

    am 12.04.2016

    Nice post. Compass is too slow for me. Thanks Nice post. Compass is too slow for me. Thanks

    Dateien hier ablegen
    Dateien hochladen