2

How could I create a mixin that uses as an argument a nested mixin property?

I explain myself with the next example.

I have a 'transition-property' mixin:

.transition-property (@props){
  -webkit-transition-property: @props;
  -moz-transition-property: @props;
  -o-transition-property: @props;
  transition-property: @props;
}

From this mixin I want to use a 'transform' mixin property, so I tried to call this like:

 .transition-property(~"opacity, .transform");

The '.transform' mixin should return one of the next values:

 transform
 -ms-transform
 -webkit-transform

The thing is that I don't find the way to inject these property names to the 'transition-property' mixin, could someone shed some light on this?

FINAL DESIRED CSS

element {
  -webkit-transition-property: opacity, -webkit-transform;
  -moz-transition-property: opacity, -moz-transform;
  -o-transition-property: opacity, -o-transform;
  transition-property: opacity, transform;
}
TylerH
  • 20,799
  • 66
  • 75
  • 101
DreaMTT
  • 341
  • 2
  • 4
  • 11
  • LESS does not allow to re-use values of the properties. You need to use variables for this (Though I can't give you an example because I can't understand what `.transition-property(~"opacity, .transform");` is supposed to do actually). Also see [1](http://stackoverflow.com/questions/21010520) and [2](https://github.com/less/less.js/issues/1790) about not using escaped values as mixin parameters. – seven-phases-max Jan 11 '14 at 19:21
  • I think the easier way to get an answer would be just to post the CSS result you plan to get as result of all those mixin calls (then it becomes less or more evident what solution to suggest). – seven-phases-max Jan 11 '14 at 20:23
  • The transition-property mixin is written like this to support more than one argument, here is supporting 'opacity' and transform values. More info here: http://stackoverflow.com/questions/11419741/less-css-mixins-with-variable-number-of-arguments – DreaMTT Jan 11 '14 at 20:30
  • Read "1" and "2" links in my comment above, there're much better ways to pass a list of values to a mixin in modern LESS. – seven-phases-max Jan 11 '14 at 20:33

2 Answers2

4

OK, so first of all, a general remark: using a CSS preprocessor (e.g. LESS, SASS or whatever) to generate vendor prefixes is actually one of the greatests misuses these days (really, there's no need to bloat your code with prefixes and waste your time writing such mixins since tools like Autoprefixer, -prefix-free and similar came in).

Either way here's a (sort of) generic solution (but considering amount of code and its complexity I think it's actually an overkill, here I will use LESS 1.6.0 example because in earlier versions it would be even more verbose and hackish):

// usage:

element1 {
    .vendorize(transition-property; opacity, transform);
}

element2 {
    .vendorize(transition-property; width, box-shadow, color);
}

element3 {
    .vendorize(transition-property; height);
}

// implementation:

// prefixes we want to be used:
@prefixes: -webkit-, -moz-, -o-, ~'';

// here we specialize what values are to be prefixed:
.vendorize-value(transform)  {.true}
.vendorize-value(box-shadow) {.true}
// etc.
.vendorize-value(...) when (default()) {.false} // to handle not prefixed values

// and now the mixin that can apply all of above specializations:
.vendorize(@property, @values) {

    .-1();
    .-1(@i: length(@prefixes)) when (@i > 0) {
        .-1((@i - 1));
        @prefix: extract(@prefixes, @i);
        .-2();
    }

    .-2(@j: length(@values)) when (@j > 0) {
        .-2((@j - 1));
        @value: extract(@values, @j);
        .vendorize-value(@value);
    }

    .false() {@{prefix}@{property}+: @value}
    .true()  {@{prefix}@{property}+: ~'@{prefix}@{value}'}
}

(Of course it can be simplified a bit if you need only transform to be prefixed but still looks too crazy).

upd: fixed some errors.

seven-phases-max
  • 11,765
  • 1
  • 45
  • 57
  • I hadn't heard of these 'autoprofixer' tools. Would you suggest we transpile from LESS to CSS, then run it through autoprofixer, and then clean-css? That would add 2 extra steps to my workflow, as LESS comes bundled with clean-css. Source maps get a bit nastier too. – mpen Jan 11 '14 at 22:14
  • 1
    If I'm not mistaken Autoprefixer (version > 1.0) preserves the minified structure of CSS files. – seven-phases-max Jan 11 '14 at 22:19
  • Thanks a lot @seven-phases-max! Complex solution for a simple problem, hopefully next LESS/SASS versions will be easier to use to generate prefixes, to solve this kind of problems in a easy way! – DreaMTT Jan 13 '14 at 00:59
  • Ah.. looks like the answer to this question: http://stackoverflow.com/questions/21511508/less-a-string-lessjs-1-6-x maybe I can use it. –  Feb 02 '14 at 14:17
3

It's a simpler solution by right of before:

// prefixes we want to be used:
@prefixes: -webkit-, -moz-, -ms-, -o-, ~'';

// here we specialize what values are to be prefixed:
@prefvendor: ~'(transform|filter|box-shadow)'; // etc...

// and now the mixin that can apply all of above specializations:
.vendorize(@property, @values) {
    .-1();
    .-1(@i: length(@prefixes)) when (@i > 0) {
        .-1(@i - 1);
        @pref: extract(@prefixes, @i);
        @{pref}@{property}+: replace(~'@{values}', '@{prefvendor}', '@{pref}$1', 'gi');
    }
}

usage:

element1{
    .vendorize(transition; opacity 1s ease-out, transform 3s ease-in);
}

output:

element1 {
  -webkit-transition: opacity 1s ease-out, -webkit-transform 3s ease-in;
  -moz-transition: opacity 1s ease-out, -moz-transform 3s ease-in;
  -ms-transition: opacity 1s ease-out, -ms-transform 3s ease-in;
  -o-transition: opacity 1s ease-out, -o-transform 3s ease-in;
  transition: opacity 1s ease-out, transform 3s ease-in;
}

Tested on LessCSS 1.7.0.1

Altro
  • 31
  • 1
  • 2