Stylus

Expressive, dynamic, robust CSS

Fork me on GitHub

Mixins

Both mixins and functions are defined in the same manner, but they are applied in different ways.

For example, we have a border-radius(n) function defined below, which is invoked as a mixin (i.e., invoked as a statement, rather than part of an expression).

When border-radius() is invoked within a selector, the properties are expanded and copied into the selector.

border-radius(n)
  -webkit-border-radius n
  -moz-border-radius n
  border-radius n

form input[type=button]
  border-radius(5px)

Compiles to:

form input[type=button] {
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  border-radius: 5px;
}

When using mixins you can omit the parentheses altogether, providing fantastic transparent vendor property support!

border-radius(n)
  -webkit-border-radius n
  -moz-border-radius n
  border-radius n

form input[type=button]
  border-radius 5px

Note that the border-radius within our mixin is treated as a property, and not a recursive function invocation.

To take this further, we can utilize the automatic arguments local variable, containing the expression passed, allowing multiple values to be passed:

border-radius()
  -webkit-border-radius arguments
  -moz-border-radius arguments
  border-radius arguments

Now we can pass values like border-radius 1px 2px / 3px 4px!

Another great use of this is the addition of transparent support for vendor-specifics—such as opacity support for IE:

    support-for-ie ?= true

    opacity(n)
      opacity n
      if support-for-ie
        filter unquote('progid:DXImageTransform.Microsoft.Alpha(Opacity=' + round(n * 100) + ')')

    #logo
      &:hover
        opacity 0.5

Rendering:

    #logo:hover {
      opacity: 0.5;
      filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50);
    }

Parent References

Mixins may utilize the parent reference character &, acting on the parent instead of further nesting.

For example, let’s say we want to create a stripe(even, odd) mixin for striping table rows. We provide both even and odd with default color values, and assign the background-color property on the row. Nested within the tr we use & to reference the tr, providing the even color.

 stripe(even = #fff, odd = #eee)
   tr
     background-color odd
     &.even
     &:nth-child(even)
       background-color even

We may then utilize the mixin as shown below:

 table
   stripe()
   td
     padding 4px 10px

 table#users
   stripe(#303030, #494848)
   td
     color white

Alternatively, stripe() could be defined without parent references:

stripe(even = #fff, odd = #eee)
  tr
    background-color odd
  tr.even
  tr:nth-child(even)
    background-color even

If we wished, we could invoke stripe() as if it were a property:

stripe #fff #000

Block mixins

You can pass blocks to mixins by calling mixin with + prefix:

+foo()
  width: 10px

The passed block would be available inside the mixin as block variable, that then could be used with interpolation:

foo()
  .bar
    {block}

+foo()
  width: 10px

=> .bar {
     width: 10px;
   }

This feature is in its rough state ATM, but would be enhanced in the future.

Mixing Mixins in Mixins

Mixins can (of course!) utilize other mixins, building upon their own selectors and properties.

For example, below we create comma-list() to inline (via inline-list()) and comma-separate an unordered list.

 inline-list()
   li
     display inline

 comma-list()
   inline-list()
   li
     &:after
       content ', '
     &:last-child:after
       content ''

 ul
   comma-list()

Rendering:

ul li:after {
  content: ", ";
}
ul li:last-child:after {
  content: "";
}
ul li {
  display: inline;
}