🤯 50% Off! 700+ courses, assessments, and books

Getting To Know Stylus

    Kitty Giraudel
    Share

    If you are part of the front-end scene, you might have heard of Stylus, the distant cousin from Sass that nobody knows very well. Like Sass, Stylus is a CSS preprocessor which is written in Node.js. According to its GitHub repository, it describes itself as:

    […] a revolutionary new language, providing an efficient, dynamic, and expressive way to generate CSS.

    Okay, revolutionary might be a bit exaggerated. But everything else is true.

    What, another one!?

    Kind of. But Stylus isn’t brand new. It has been around since the beginning of 2011, but I see it as having quite a discrete community. By the way, did you know the latest Mozilla Developer Network redesign has been made with Stylus? David Walsh, who’s been involved in the project, also wrote about how to get started with Stylus.

    So what are the advantages of Stylus over Sass? Well, it is built in Node.js which sounds like a plus side to me. And while it is perfectly fine to use Sass in a Node workflow thanks to Node-Sass wrapper for LibSass, it does not make LibSass written in Node for all that.

    Also Stylus has an extremely permissive syntax, which can be a good or a bad thing depending on your project, your team and your tendency to stick to strict coding guidelines. I think a permissive syntax should be fine as long as you do not involve too much logic in the stylesheet, and lint the code before committing.

    All in all, Stylus and Sass both support pretty much the same things; you can have a look at the full list of Stylus features but don’t expect anything ground breaking (although there are some neat features). Stylus also supports multiple syntaxes although the line is much more blurry than Sass: you can write your styles pretty much how you want (indented, CSS-style) and you can mix and match within the same stylesheet (the parser for this must have been fun to write).

    So what do you think? Want to give it a try?

    Getting started

    As stated before, Stylus is written in Node.js so we can install it like any other npm package:

    $ npm install stylus -g

    From there, either you can plug it into your Node workflow using the JavaScript API, or you can use the command line executable to compile your stylesheets. For the sake of some simplicity, we will use the stylus command line tool but feel free to tackle it from a Node script, Gulp or Grunt.

    stylus ./stylesheets/ --out ./public/css

    The previous command tells stylus to compile all Stylus stylesheets (.styl) from the stylesheets folder and to generate them in public/css folder. Of course, you can also watch the directory for changes:

    stylus --watch ./stylesheets/ --out ./public/css

    Writing Stylus styles

    If you are just getting started and don’t want to feel overwhelmed with a new syntax, know that you can write plain CSS in a .styl file. Since Stylus does support the standard CSS syntax, it is perfectly fine to start with CSS code only to enhance it slowly.

    Basic syntax

    Regarding the syntax itself, almost everything is optional. Braces: why bother? Semi-colons: come on! Colons: ditch ’em too. Parentheses: please. The following is perfectly valid Stylus code:

    .foo
    .bar
      color tomato
      background deepskyblue

    Kind of disturbing at first but we could get used to it, especially when there are syntax highlighters available. As you can probably guess, the previous code compiles into:

    .foo, .bar {
      color: tomato;
      background: deepskyblue;
    }

    Variables

    The most used feature from CSS preprocessors has to be the ability to define variables. It’s not surprise that Stylus offers it as well. Although contrary to Sass, they are declared with an equal sign (=) rather than a colon (:). Also, the leading dollar sign ($) is optional and can be safely omitted.

    // Defining a `text-font-stack` variable
    text-font-stack = 'Helvetica', 'Arial', sans-serif;
    
    // Using it as part of the `font` property
    body
      font 125% / 1.5 text-font-stack

    Now there is something that Stylus does which Sass or any other preprocessor does not: property value look-up. Let’s say you want to apply a negative left margin of half the width; in Sass you’d have to store the width in a variable, but not in Stylus:

    .foo
      width 400px
      position absolute
      left 50%
      margin-left (@width / 2)

    By using @width, we tell Stylus to fetch the value of the width property of the current block, treating it as a variable. Pretty neat! Another interesting use-case for this is to conditionally output a property depending on whether or not it has already been defined:

    .foo
      // ... other styles
      z-index: 1 unless @z-index

    In this case, z-index will be set to 1 unless .foo already has a value assigned for the z-index property. Couple this with mixins and you really have something.

    Mixins

    Speaking of which, let’s define a mixin since it’s probably one of the most popular features of Sass! A mixin in Stylus needs no specific keyword; it is a mixin as long as it has the parentheses (empty or not) at the end of its name.

    size(width, height = width)
      width width
      height height

    Along the same lines, including a mixin needs no specific syntax like @include or +:

    .foo
      size(100px)

    You can even drop the parentheses if you feel so, in which case it looks like you use a completely standard (yet not) CSS property. This mechanism is referred to as transparent mixins as their inclusions are invisible.

    .foo
      size 100px

    That might look an unnecessary trick at first glance, but this feature actually allows authors to extend the default CSS syntax if you think about it. Consider the following overflow mixin:

    overflow(value)
      if value == ellipsis
        white-space nowrap
        overflow hidden
        text-overflow ellipsis
      else
        overflow: value

    If the given value is ellipsis, it prints the well-known declaration triplet needed to have a one-line ellipsis overflow. Else, it prints the given value. Here is how you’d use it:

    .foo
      overflow ellipsis

    And it will yield:

    .foo {
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    You gotta admit, that’s a pretty cool trick. While it might be confusing (and possibly dangerous), being able to extend the standard CSS properties with extra values is actually an interesting concept.

    If you want to pass some content to a mixin, in a @content fashion, it is possible through a {block} variable. During the inclusion, you only have to prefix the mixin name with + to pass it extra content.

    has-js()
      html.js &
        {block}
    
    .foo
      +has-js()
        color red

    This code will compile to:

    html.js .foo {
      color: #f00;
    }

    Last very interesting feature of Stylus mixins: they always have a arguments local variable containing all arguments (if any) passed to the mixin when included. This variable can be manipulated and treated as an array, for instance to fetch values at specific indexes using [..] like in JavaScript.

    Final thoughts

    Going through all features and syntax tricks from Stylus would be too long and I think we already had a decent introduction, enough to get started at least!

    As you can see, Stylus is extremely permissive. Of all existing tools to help writing CSS, Stylus is definitely the one bringing CSS the closest to a real programming language.

    Note that Stylus also has its own framework in the same way that Sass has Compass, and it’s called Nib. Nib is a toolbox providing extra helpers and cross-browsers support mixins for Stylus.

    Some people might like it, some people might not. My advice would be to be very rigorous with the syntax though. Dealing with such a tolerant syntax might not always be such a bliss. In any case, it’s nice to see some decent concurrence to Sass.