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.