Jesse Cravens

Building Modern Web Applications and Teams that Deliver

Using Stylus’ Transparent Mixins to Hack Vendor-Specific Properties

One of the most interesting features of Stylus is transparent Mixins. One reason they are interesting is that at the time of this writing, this feature is exclusive to Stylus, other CSS metalanguages like Less and Sass do not offer Transparent Mixin support.

We already defined a mixin earlier, when we explored mixins with Jade. Here they are used similarly.

Before we begin with the transparent aspect of Stylus mixin support, let’s build a simple CSS mixin. Perhaps, the best example, as provided by TJ Holowaychuk in this beginner screencast uses vendor-specific prefixes.

How about we take his example and expand it to a slightly more challenging scenario.

In case you haven’t come across this challenge before, lets set some context. Browser makers, or vendors, implement proprietary extensions to standard CSS specifications to release and test browser features that have been developed pre ‘Candidate Recommendation’ W3C draft status. Although vendor-specific prefixes can be frustrating for web developers, they are a necessary evil, allowing new properties to be widely tested before they become available as standard CSS properties.

Each Vendor maintains a list of their proprietary CSS properties. The following table provides the extension prefixes for all the modern browsers:

Extension Rendering Engine Browser(s) Example
-moz- Camino Mozilla Firefox -moz-border-radius
-ms- Trident Internet Explorer -ms-layout-grid
-o- Presto Opera -o-border-radius
-webkit- Webkit Chrome, Safari -webkit-border-radius

And here is a few valuable resources for finding these properties:

Without a metalanguage that provides logic to CSS, these declarations can become cumbersome and repetitive. Here is an example of a div element that needs to have corners take on different size radiuses:

First, the markup in Jade.

example.html
1
2
3
4
5
6
7
header
  h1= title
  p Welcome to #{title}

div.panel panel test
div.mixin-panel mixin-panel test
div.t-mixin-panel transparent-mixin-panel test

Then, the styles in basic CSS.

example.css
1
2
3
4
5
div.panel {
  -moz-border-radius: 10px 5px;
  -webkit-border-radius: 10px 5px;
  border-radius: 10px 5px;
}

This produces the following effect:

With that context in mind, let’s leverage Stylus to help us manage our code. First, we are able to remove all parenthesis, semi-colons, and colons.

example2.css
1
2
3
4
div.panel
  -moz-border-radius 10px 5px
  -webkit-border-radius 10px 5px
  border-radius 10px 5px

Much like Jade, this simplified syntax goes along way in our ability to quickly write CSS. Now, let’s apply some logic, by creating a border-radius mixin, and pass our values as arguments to our mixin:

example3.css
1
2
3
4
5
6
7
my-border-radius-mixin (...args)
  -moz-border-radius args
  -webkit-border-radius args
  border-radius args

div.panel
  my-border-radius-mixin (10px 5px)

And we can reuse this mixin in other contexts, which continues to help reduce code bloat and keep your code DRY.

example4.css
1
2
3
4
5
6
7
8
9
10
11
12
13
my-border-radius-mixin (...args)
  -moz-border-radius args
  -webkit-border-radius args
  border-radius args

div.panel
  border-radius-mixin (10px 5px)

div.other-panel
  border-radius-mixin (3px 32px 100px 55px)

div.another-panel
  my-border-radius-mixin (5px 10px 33px 43px)

While Stylus allows us to name our mixin as we choose, we are also given the ability to apply mixins ‘transparently.’ In the case of a simple implementation of border-radius, a transparent mixin would make a lot of sense. In effect, this normalizes browser implementations and provides an abstraction layer for CSS developers.

example5.css
1
2
3
4
5
6
7
border-radius (...args)
  -moz-border-radius args
  -webkit-border-radius args
  border-radius args

div.panel
  border-radius 10px 5px

As long as a border-radius mixin is present, Stylus will find it, and apply the vendor-specific properties transparently.

Comments