LearnGetting Started with Stylus

David Walsh
writes on November 26, 2013

Within the web development community, we hear a lot about two popular CSS preprocessor: Sass and LESS. You don’t often, however, hear about the third big preprocessor: Stylus. When it came to redesigning the Mozilla Developer Network, I chose Stylus for a few important reasons:

  • Since Stylus is NodeJS-based, we didn’t need to add another technology to our stack (Sass would have required Ruby)
  • Stylus provides a JavaScript API so that preprocessing can be further customized
  • Stylus doesn’t require brackets, colons, or semicolons: the syntax is completely space-based. You can, however, add any of those punctuations and Stylus will still compile correctly.
  • An additional component and mixin library called Nib is also available.

Of course Stylus provides the standard CSS preprocessor abilities, like extending classes, creating mixins (functions), importing stylesheets, and setting variables, but it also provides a load of more advanced features. Before making more promises, let’s check out the basics of Stylus and get into some CSS programming!

Getting Stylus, Options, and Processing CSS

Stylus is an open source project hosted on GitHub. You can install from source or you can simply use NPM:

$ npm install stylus

Stylus CSS files should be given the .styl extension and can be placed anywhere within your project. No configuration file is needed to process, the code within stylus files — simply run the stylus utility to generate the CSS output:

$ stylus stylus/main.styl --out /css --compress

You’ll notice that the the command above compiles main.styl into a CSS file of the same name within the /css output directly. If you prefer not to manually process your styles, you can also use the --watch option:

$ stylus --watch stylus/main.styl

There are a number of other options available with Stylus, including options to convert existing CSS to Stylus, compare input and output, and more.

Stylus Syntax Basics

The basics of Stylus are very much like that of other CSS preprocessors but let’s review how to code some of these items:

/* Set a basic variable */
base-font-size = 12px

/* Set a variable based on result of mixin call */
body-background = invert(#ccc)

/* Set some basic rules */
body
    color #333
    background #fff

/* Nest rules */
nav
    margin 10px

    ul
        list-style-type none

        > li
            display inline-block

            &.current
                background-color lightblue

/* Use calculated values */
div.column
    margin-right (grid-spacing / 2)
    margin-top (grid-spacing * 2)

/* Use an already-set value for this element */
div.center-column
    width 200px
    margin-left -(@width / 2)

/* Get styles for this element from the result of a mixin */
.promo
    apply-promo-styles()
    apply-width-center(400px)

/* Iterate over a loop! */
table
    for row in 1 2 3 4 5
        tr:nth-child({row})
            height: 10px * row

    /* or.... */
    for row in (1..5)
        tr:nth-child({row})
            height: 10px * row


/* Import another Stylus stylesheet */
@import 'links.styl'

/* Extend an existing class */
.warning
    @extend .noticeBlock

These features are fairly consistent throughout all CSS preprocessors. Don’t let the lack of braces, colons, and semicolons throw you off — if you’d prefer to have that structure, you can do so and Stylus will accommodate!

Creating and Using Mixins

Mixins are incredibly useful within CSS preprocessors for a number of reasons. They allow us to use logic to generate CSS but they also allow us to organize our CSS. Mixins are easy to create with Stylus and their syntax is exactly as you’d expect:

/* 
    Basic mixin which vendorizes a propery.  Usage:

    vendorize(box-sizing, border-box)
*/
vendorize(property, value)
    -webkit-{property} value
    -moz-{property} value
    -ms-{property} value
    {property} value

You can also assign default values to arguments:

/* Generates a CSS triangle */
generate-arrow(arrow-width = 10px)
    &:before, &:after
        content ' '
        height: 0
        position absolute
        width: 0
        border arrow-width solid transparent

Mixins can return a value with the return keyword or the styles defined within the mixin can simply be applied to the the elements that call it:

/* Adds styles for the current and child elements */
special-homepage-styles(background = '#ccc')
    background-color background

    a
        color lightblue

        &:visited
            color navy

And of course you can use conditionals within your mixins (or anywhere within Stylus, really):

/* Generates a grid based on min/max and increment */
generate-grid(increment, start, end, return-dimension=false)
    total = start
    for n, x in 0..((end - start) / increment)
        if return-dimension
            if x+1 is return-dimension
                return total
        else
            .column-{x+1}
                width total
        total = total + increment

The mixin above generates a grid based on min (the smallest column width), max, and column increment amount. The last argument represents if the dimension should simply be returned, and not set as a CSS class. The example above serves as an example flexible mixin with iteration, conditionals, and return values.

Useful Stylus Mixins

MDN needed a number of Stylus mixins to support the wide requirements of the project, like RTL support, localization support, and wide browser support. Here are a few of the mixins that are tried and test on MDN — maybe some of them would be good for your project!

RTL Property Reversals

Some properties and values need to be manually reversed for RTL (right-to-left) support. Instead of duplicating the nested CSS structure in another block, you can simply use a mixin to set both the LTR and RTL properties and values:

/*
    Usage: bidi-style(left, 20px, right, auto)

    Element will be left: 20px but in RTL will be right: 20px and left: auto to offset the LTR property value
*/
bidi-style(ltr-prop, value, inverse-prop, inverse-value, make-important = false)
    make-important = unquote(make-important ? '!important' : '')

    {ltr-prop} value make-important

    html[dir='rtl'] &
        {inverse-prop} value make-important
        {ltr-prop} inverse-value make-important

/* 
    Same as bidi-style but changes the value of the same property 

    Usage: bidi-value(float, left, right);
*/
bidi-value(prop, ltr, rtl, make-important = false) {
    bidi-style(prop, ltr, prop, rtl, make-important);
}

These mixins are used often within the MDN redesign codebase as RTL is important to our readers.

Last Child Spacing

This mixin is created to nullify a value for the last child element of a parent, usually padding-bottom or margin-bottom:

/* prevents spacing of a given element if it's the last child */
prevent-last-child-spacing(element = '*', property = 'padding-bottom')
if element is '*'
    element = unquote(element)

& > {element}:last-child
    {property} 0

With this mixin, we can set a global padding or margin on a parent, and simply remove a conflicing margin or padding on the last child element of said parent.

Placeholder Styling

Placeholders tend to have a funky selector so styling them via a mixin just makes life easier:

/* Sets an input tag's placeholder styles; called within the INPUT itself */
set-placeholder-style(prop, value)
    &::-webkit-input-placeholder
            {prop} value
    &::-moz-input-placeholder
            {prop} value

You can see the other important MDN mixins within the MDN source. Give them a look over and see if they could be useful in your projects!

Where Next?

Now that you have enough information about Stylus to get you started, have a look at the advanced features that Stylus has to offer:

Stylus is an outstanding CSS preprocessor and offers a wide array of basic and advanced features. Installation is super quick and it’s incredibly fun to write your CSS so quickly and effortlessly. Give Stylus a try — it may be perfect for you!

19 Responses to “Getting Started with Stylus”

  1. Kishan on May 8, 2018 at 7:09 am said:

    Hi,
    Great Article! But how do you increment in a for loop in a stylus? Cant find anywhere!
    Since it doesnt have while loop,there should be a way right!

    Thanks!

  2. Are MDN stylus mixins available now? The old link is broken.

    By the way – thanks a lot, this article is very useful!

  3. Johny Why on August 21, 2016 at 3:49 pm said:

    hello! thx for this great info. Question, does stylus only work with sites fully-implemented in node.js? or can it work with, say, a python or php backend? thx!

  4. エルバーキンコピーエルメスバーキン30コピーエルメス ボリード47,エルメス バッグ 名前,エルメス ネクタイ ピンク エルメス クラッチバッグ,エルメス バッグ コピー,エルメス バーキン コピー エルメス 財布 ダミエ オークション,エルメス ヨーロッパ,エルメス エールライン エルメス クラッチ激安通販、高い品質、送料無料。バーキン25コピー、バーキン30コピー、バーキン35コピー、バーキン40コピーなど世界中有名なブランドレプリカを格安で通販しております。N級品スーパーコピーブランドは ブランドスーパーコピー超N品エルメスバッグ,エルメス バーキン25 , バーキン30.バーキン35.バーキン40. エルメス(HERMES) ケリー|エルメス ケリー激安|激安エルメス ケリー, エルメスN品 ボリード|エルメス ボリードスーパーコピー.ブランド直営店.ブランド,エルメス激安通販,業界で最高な品質に挑戦します!”ブランドN級品ブランドコピー 代引き,スーパーコピー時計,ブランドN級品,楽天コピーブランド,,偽物ブラン日本最大級の最高のスーパーコピーブランド財布激安代引き販売店,スーパーコピー時計の激安老舗.!国内No.1時計コピー工房,アフターサービスも自ら製造したスーパーコピー時計なので、技術力でお客様に安心のサポー トをご提供させて頂きます。スーパーコピー 代引きN品をご 購入の方は、こちらへ.弊社は正規品と同等品質のコピー品を低価で お客様に提供します!すべての商品は品質2年無料保証です。100%実物写真ですし、品質が完璧です!”スーパーコピーブランド財布激安 偽物財布激安コピー ルイヴィトン財布偽物,偽物財布コピー
    2015年の新素材-新作!高品質 腕時計高品質の追求 超N品を良心価格で提供詳しくは以下のようなブランドがあります。HERMES(バッグ、財布、時計) CHANEL(バッグ、財布、時計)LOUIS VUITTON(バッグ、小物、財布、時計) BVLGARI(財布、時計)Christian Dior(バッグ、財布) COACH(バッグ、財布)GUCCI(バッグ、財布) ROLEX(時計)OMEGA(時計) IWC(時計)FRANCK MULLER(時計) HUBLOT(時計)クロエ CHLOE バッグなどです。ご不明点が ございましたらお気軽にお問い合わせください http://www.okakaku.com/brand-8-copy-0-cheap-0-max0-attr0-3-sort_order%20Desc%2cgoods_id-DESC.html

  5. スーパーコピー、スーパーコピーブランド(N級品)激安通販専門店世界一流ブランドコピー 財布、スーパーコピー 商品、激安ブランドコピー 。 ヴィトンコピー 、 ミョウミョウコピー 、シャネルコピー 、エル メスコピー 品格安通販。商品は全て最高な材料 と優れた技術で造られて、正規と比べて、品質が無差別です!人気ブランド..
    日本最高級スーパーコピーブランド時計激安通販専門店,高品質時計コピー,2015最新作、国際ブランド腕時計コピー、業界唯一無二.世界一流の高品質ブランドコピー時計,当店はスーパーコピー時計専門店,販売以下世界一流ブランドコピー時計:ロレックスコピー、ウブロコピー、オメガコピー、シャネルコピー…ンプルに見えて目を奪われてしまう独創的なブルガリのラインアップです。1884年ブルガリの創始者ソティリオ?ブルガリが銀細工師の一族としてイタリ アにオープン。ブルガリ?ブルガリシリーズ。古代ローマの円形競技場をモチーフにした時計「アンフィテアトロ」、若い世代向けの腕時計「ソロテンポ」を発 表。2000年には新会社ダニエル?ロード&ジェラルド?ジェンダ オート?オルロジュリー社を設立しました。本物ブランド時計に間違える程のスーパーコピー時計通販!スーパーコピーは業界n級品最高品質に挑戦!ロレックスコピー,パネライコピー,ウブロコピー,オメガコピー,ルイ?ヴィトンコピー,エルメスコピーを初め世界中有名なスーパーコピーブランドを激安で通販しております!HERMES(バッグ、時計) CHANEL(バッグ、時計)LOUIS VUITTON(バッグ、時計) BVLGARI時計Christian Dior(バッグ、小物) COACH(バッグ)GUCCI(バッグ、小物) ROLEX(時計)OMEGA(時計) IWC(時計) http://www.ooowatch.com/tokei/chanel/index.html

  6. Thanks for the great article! I’ve recently been switching from LESS to Stylus, and I have to say I’m really liking it. The “transparent” mixin feature is what sold it for me, but I also really like the more flexible syntax and the easy integration with Node projects. I’m surprised more people aren’t using Stylus; hopefully more articles like this will help! 🙂

  7. Can really recommend http://roots.cx/axis/ on top of stylus and nib.

    It’s like Bootstrap for stylus

  8. I was expecting this to be a post about tablets and drawing stuff. I’m happy I still took your link bait and decided to have a read! Nice post David. Stylus looks to be a neat little item in your toolbelt.

    Question.
    How do you manage this as part of your version control. Do you manage the stylus files in a separate repo from your project and then add in the compiled (built) CSS to the main project repo?

    • Hi Steve,
      You would commit your `.styl` files into the main project. In fact they are more important to commit than the compiled `.css` files. Typically there will be many more `.styl` files than `.css` files, because best practice is to create individual files (I think of them as cascading modules) per site section and/or per component or functionality type.

      A common setup (with any CSS pre-processor, not only Stylus) is to have `variables.styl`, `mixins.styl`, various module files, and then an `app.styl` into which all of the others are imported. The `app.styl` should consist _only_ of imports; this is how you control your cascade, and it allows you to easily add/remove entire component sets when experimenting or debugging.

      I like all the CSS pre-processors, but Stylus is my personal favorite. I’m very grateful to TJ Holowaychuk for developing it (along with all of his other incredibly powerful and useful tools).

  9. just a heads up that the preprocessor you’re referring to is Sass, not SASS. See: http://sass-lang.com/

  10. Jon Rimmer on November 27, 2013 at 11:36 am said:

    Does Stylus have working Source Map support? I can’t live without it for debugging. It’s why I’ve had to stick with Ruby SASS rather than switching to node-sass/libsass.

  11. I just got started with SASS, but I definitely like the idea of less punctuations. haha.

  12. Hello,
    Simple, easy to read description.
    Thank you!

  13. hi Dave,

    Great post in very nicely written simple language. First thing i agree with peter that your link is not working and second please tell me can i use Stylus in windows ?

    • Of course. Stylus is just a Node module. Node.js works great on Windows. I haven’t tried Stylus, but if you’re going to give it a try, definitively consider the grunt-contrib-stylus Grunt plugin which enables you to easily set up an automatic build process for your CSS.

  14. Walsh, have you tried implementing Sass in your stack w/ libsass? I personally haven’t been able to get to it, but it seems to resolve your first point.

  15. It’s rather a nice and handy item of facts. I am just glad that you just distributed this convenient information around. Make sure you continue to be all of us up to date in this way. Appreciate your spreading.

  16. hi Dave,

    The Stylus link in the first paragraph mislinks a bit 🙂

Leave a Reply

You must be logged in to post a comment.

Want to learn more about CSS?

Learn how CSS allows you to apply visual styling to HTML elements with colors, fonts, layouts, and more.

Learn more