4

How do i escape the following:

.prefix(@rule, @prop) {
  -webkit-@{rule}: @{prop};
  -moz-@{rule}: @{prop};
  -o-@{rule}: @{prop};
  -ms-@{rule}: @{prop};
  @{rule}: @{prop};
}

I've tried a bunch of different ways, wrapping it in ~"stuff", wrapping the variables in @{var}, backslashing the -'s... no success!

Edit: There's a pull req for it on Github: https://github.com/cloudhead/less.js/pull/698

qwerty
  • 5,166
  • 17
  • 56
  • 77
  • It seems related to http://stackoverflow.com/questions/12537474/adding-vendor-prefixes-with-less-mixin. As existing less prefixers use a mixin for each rule I don't think it's possible too. – MatTheCat Feb 17 '13 at 14:17
  • Well, shit. Is it possible with SASS? Might be reason enough to switch for me, everybody keeps telling me it's better anyways. – qwerty Feb 17 '13 at 14:19
  • Don't know SASS enough to answer, hope anyone do. – MatTheCat Feb 17 '13 at 14:21

3 Answers3

7

Update for LESS 1.6+

Your original plan almost works with the LESS 1.6 update. This is the syntax needed:

LESS

.prefix(@rule, @prop) {
  -webkit-@{rule}: @prop;
  -moz-@{rule}: @prop;
  -o-@{rule}: @prop;
  -ms-@{rule}: @prop;
  @{rule}: @prop;
}

.test {
  .prefix(box-sizing, border-box);
}

CSS Output

.test {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  -o-box-sizing: border-box;
  -ms-box-sizing: border-box;
  box-sizing: border-box;
}

Nevertheless my original answer about other preprocessing of the property values still holds.

Original Answer (pre 1.6)

LESS does not allow dynamic properties (and yes, I believe SASS does).

However, it is not entirely a bad thing that pattern matching needs to be used for LESS instead, as it forces one to think through the differences that might be needed for pattern matching, and accommodating those differences in your code.

Take the following as an example. It requires two variables, and (at present) allows for two others (here, for the gradients with a background image). It could be expanded to allow for more extra variables if needed.

Note how each nested mixin expects different types of things to be passed to the second and later variables, and each one can preprocess those variables in different ways. The example below allows for opacity to be passed as either a decimal value or the numeric integer (though a value of 1 will assume a decimal value of 1.0 (i.e. 100%) not 0.01. It allows for padding in the box-sizing property, but filters that out for non-mozilla browsers (which according to this page is not supported in other browsers). So you can see that "thinking" through what each property may need is beneficial, and thus having to set up different pattern matched mixins for each can be valuable.

LESS

.prefix(@prop, @v1, @v2:~'', @v3:~'') {
  .prop(opacity) {
    @decValue: `(@{v1} > 1 ? @{v1}/100 : @{v1})`;
    @intValue: `(@{v1} <= 1 ? @{v1}*100 : @{v1})`;
    filter: alpha(opacity=@intValue);
    -webkit-opacity: @decValue;
    -moz-opacity: @decValue;
    opacity: @decValue;
  }
  .prop(boxSize) {
    @filteredSupport: ~`("@{v1}" == "padding" ? "border" : "@{v1}")`;
    -webkit-box-sizing: (~"@{filteredSupport}-box");
    -moz-box-sizing: (~"@{v1}-box"); 
    box-sizing: (~"@{filteredSupport}-box");
  }
  .prop(bkgGradient) {
    .filterFirstTwoArgs(@type, @color, @gradient) {
      background-color: @color; 
      background-image: ~"-webkit-@{type}-gradient(@{gradient})";
      background-image: ~"   -moz-@{type}-gradient(@{gradient})";
      background-image: ~"    -ms-@{type}-gradient(@{gradient})";
      background-image: ~"     -o-@{type}-gradient(@{gradient})";
      background-image: ~"        @{type}-gradient(@{gradient})";
    }
    .filterFirstTwoArgs(@v1, @v2, @v3);
  }
  .prop(@prop);
}

Use it:

.myClass {
  .prefix(opacity, 10);
  .prefix(boxSize, padding);
  .prefix(bkgGradient, linear, #F07575, "top, hsl(0, 80%, 70%), #bada55"); 
}

CSS Output

.myClass {
  filter: alpha(opacity=10);
  -webkit-opacity: 0.1;
  -moz-opacity: 0.1;
  opacity: 0.1;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: padding-box;
  box-sizing: border-box;
  background-color: #f07575;
  background-image: -webkit-linear-gradient(top, hsl(0, 80%, 70%), #bada55);
  background-image:    -moz-linear-gradient(top, hsl(0, 80%, 70%), #bada55);
  background-image:     -ms-linear-gradient(top, hsl(0, 80%, 70%), #bada55);
  background-image:      -o-linear-gradient(top, hsl(0, 80%, 70%), #bada55);
  background-image:         linear-gradient(top, hsl(0, 80%, 70%), #bada55);
}

Gradient output example taken from example found here.

Community
  • 1
  • 1
ScottS
  • 71,703
  • 13
  • 126
  • 146
  • your answer is brilliant, +1 form me. I just wanted to share, that I was just looking yesterday at a very similar question ... and thought of a bit dirty but working semi-solution, where I used string interpolation to inject the vendor properties into another properties value ... it is a messy and lazy shortcut, cause you get the extra property in front of the vendors block - but might be interesting for someone. – Martin Turjak Mar 16 '13 at 10:26
  • I played around with it a little more and updated the answer with a solution that doesn't produce unnecessary additional properties: http://stackoverflow.com/questions/14868042/using-an-argument-for-tag-name-in-less/15443008#15443008. – Martin Turjak Mar 16 '13 at 15:49
4

I just wanted to share a thing that I just tried and it worked ... injecting dynamicaly created vendor properties (with string interpolation) into another property value.

.vendors(@property, @value) {
    -inj:~"ect; -webkit-@{property}: @{value}; -moz-@{property}: @{value}; -ms-@{property}: @{value}; -o-@{property}: @{value}; @{property}: @{value}";
}

It is a hackish solution, but compiled into working css (with the one extra property in front that we were injecting to) ... itried it at less2css.org

I wrote some more about it answering this question, that is nearly an exact replicate:

Using variables in property names in LESS (dynamic properties / property name interpolation)


Edit: I figured out an more elegant solution where we inject the dynamically generated properties of one class into the name of the following class. I show how on an example in the answer to the replicate question. This way we don't generate additional unnecessary properties.

Community
  • 1
  • 1
Martin Turjak
  • 20,896
  • 5
  • 56
  • 76
2

I just wanted to add that you can use 'minus' as a propery name and the parser will ignore it but add the rest of the string. That way you won't get an empty inject:; or inj propery. It's still hacky but hey... :)

.prefix(@property, @value) {
    -:~";-webkit-@{property}: @{value}; -moz-@{property}: @{value}; -ms-@{property}: @{value}; -o-@{property}: @{value}; @{property}: @{value}";
}

Example:

.prefix(transition, "all .2s, color 0s");

Will output:

-webkit-transition: all .2s, color 0;
-moz-transition: all .2s, color 0;
-ms-transition: all .2s, color 0;
-o-transition: all .2s, color 0;
transition: all .2s, color 0;
Miro
  • 8,402
  • 3
  • 34
  • 72