Last Updated: February 25, 2016
·
4.7K
· sevenupcan

How to create a complex function in Stylus

I've been experimenting with Stylus a lot recently and each time I use it I learn more and more tricks. Below I'm going to show you how to create the calc() function without having to repeat it for each vendor prefix.

Add the prefixes

First store the vendors in a list.

vendors = webkit moz ms

Next iterate through each vendor to create the prefixes

for prefix in vendors
    s('-%s-calc()', prefix)

The s() function allows us to combine our hyphens with the items in our array as a Litteral node. This means Stylus won't try to interpret the hyphens, but will simply replace %s with the prefix in the index.

Before we forget we should also include the non-prefixed version also.

for prefix in vendors
    s('-%s-calc()', prefix)
s('calc()')

Create the function

Next we want to create a function to call this code every time we need to use it.

calc()
    for prefix in vendors
                s('-%s-calc(%s)', prefix, arguments)
            s('calc(%s)', arguments)

To capture everything that's passed through the function we use the arguments local variable. This lets us do.

calc(30% - 10px)

However you'll notice that the expression inside the brackets gets calculated and that's not what we want for browsers to interpret the CSS function correctly. Therefore we need to pass our expression through surrounded in quotes.

calc('30% - 10px')

Now our function will preserve the expression but as a result it will also print the quotes. To prevent this we must pass the arguments local variable through the unquote() function.

calc()
    for prefix in vendors
        arguments = unquote(arguments)
    s('-%s-calc(%s)', prefix, arguments)
    s('calc(%s)', arguments)

Our function is starting to take shape. Unfortunately we can't use calc() on it's own. It must be used in conjunction with a property. Luckily Stylus has another local variable called current-property[0] that allows us to look up the current property and another one add-property() which allows us to repeat the property for each vendor prefix.

calc()
    for prefix in vendors
        arguments = unquote(arguments)
        add-property(current-property[0], s('-%s-calc(%s)', prefix, arguments))
    s('calc(%s)', arguments)

Go ahead and run your function inside a class

.test
    width calc('30% - 10px')

Which should produce

test {
    width: -webkit-calc(30% - 10px);
    width: -moz-calc(30% - 10px);
    width: -ms-calc(30% - 10px);
    width: calc(30% - 10px);
}

Now I think that's pretty sweet.

Add error handling

For added reliability you might want to check the function is used within a property and output an error message if it's not.

calc()
    if current-property
        for prefix in vendors
            arguments = unquote(arguments)
            add-property(current-property[0], s('-%s-calc(%s)', prefix, arguments))
        s('calc(%s)', arguments)
    else
        error('calc() must be used within a property')

And voila! You have a calc() function.

4 Responses
Add your response

This:
s('calc()', arguments)
Should be:
s('calc(%s)', arguments)

Thanks!
naorye http://www.webdeveasy.com

over 1 year ago ·

Good spot. Thanks @naorye

over 1 year ago ·

another tweak s('-%s-calc(%s)-' has a trailing -

...and note to anyone who wants to use variables with this:

.content
    height: calc('100% - %s' % headerHeight)
over 1 year ago ·

Silly me. Thanks for spotting that. :)

over 1 year ago ·