Can I define a LESS mixin to generate a transition-property with a variable number of parameters?

css, less, less-mixins, mixins

Solution

I've managed to figure it out thanks to Luke Page pointing me towards the `...` syntax.

The solution was to use the following:

- `...` to allow variable parameters

- Backticks for JavaScript evaluation

- Variable string interpolation

- A `~` prefix to escape the resulting expression (i.e. stop LESS from enclosing it in a string)

- Good old regular expressions

Phew. Here's the resulting mixin:

.transition-properties(...) {
    -webkit-transition-property: ~`"@{arguments}".replace(/[\[\]]/g, '')`;
}

And here's the full version with a complete set of browser extensions:

.transition-properties(...) {
    @props: ~`"@{arguments}".replace(/[\[\]]/g, '')`;
    -webkit-transition-property: @props;
    -moz-transition-property: @props;
    -o-transition-property: @props;
    transition-property: @props;
}

Problem

I'm introducing LESS to a large web app project to simplify my CSS. I've got a few CSS rules which apply transitions to a varying number of properties, for example: ``` .movable { transition-property: top, left; transition-duration: 0.2s; transition-timing-function: ease; } .fadeAndStretchable { transition-property: opacity, width, height, margin; transition-duration: 1.5s; transition-timing-function: ease-out; } ``` (Note: I've omitted `-webkit`, `-moz` and `-o` properties here for brevity: in reality each of these rules is 12 lines long rather than 3.) Note that the values for `transition-property` are comma-separated. This is unusual in CSS: multiple values are usually space-separated (as in `border: 1px solid #f00`). LESS mixins can use the special `@arguments` value to produce a space-separated list of all the mixin arguments - but is it possible to define a LESS mixin that takes a variable number of parameters and turns them into a comma-separated value list, suitable for `transition-property`? If necessary, I'm happy with a solution that requires two mixins: one for `transition-property` and another for `transition-duration` and `transition-timing-function`. Here's what I've tried so far: Attempt 1: using @arguments with unnamed parameters ``` .transition-property() { -webkit-transition-property: @arguments; -moz-transition-property: @arguments; -o-transition-property: @arguments; transition-property: @arguments; } .movable { .transition-property(top, left); } ``` Result: LESS error ("No matching definition was found for '.transition-property(top, left)'") Attempt 2: using @arguments with named parameters ``` .transition-property(@p1, @p2, @p3, @p4, @p5) { -webkit-transition-property: @arguments; -moz-transition-property: @arguments; -o-transition-property: @arguments; transition-property: @arguments; } .movable { .transition-property(top, left); } ``` Result: LESS error ("No matching definition was found for '.transition-property(top, left)'") Attempt 3: using named parameters with dummy default values ``` .transition-property(@p1:p1, @p2:p2, @p3:p3, @p4:p4, @p5:p5) { -webkit-transition-property: @p1, @p2, @p3, @p4, @p5; -moz-transition-property: @p1, @p2, @p3, @p4, @p5; -o-transition-property: @p1, @p2, @p3, @p4, @p5; transition-property: @p1, @p2, @p3, @p4, @p5; } .movable { .transition-property(top, left); } ``` Result: No LESS error but it generates a CSS rule `-webkit-transition-property: top, left, p3, p4, p5` that the browser ignores because of the unrecognised properties. I've tried various other approaches (e.g. passing the property as a string `'top,left'`) but all result in the same thing: either a LESS error or invalid CSS. Is there any way round this? Or do I have to bite the bullet and define a set of mixins overloaded on arity, e.g. ``` .transition-property(@p1) {...} .transition-property(@p1, @p2) {...} .transition-property(@p1, @p2, @p3) {...} .transition-property(@p1, @p2, @p3, @p4) {...} etc. ```

Original source