Skip to content

Instantly share code, notes, and snippets.

@demoive
Last active December 17, 2015 16:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save demoive/5641752 to your computer and use it in GitHub Desktop.
Save demoive/5641752 to your computer and use it in GitHub Desktop.
A LESS mixin to generate vendor-specific (browser-specific/experimental) CSS properties.
.vendorify(@prop, @vals...) {
@property: e('@{prop}');
@values: `'@{arguments}'.replace(/^\[|\]$/g, '').split(', ').splice(1)`;
// v1.6.0 added interpolation allowing us to do this:
-o-@{property}: @values;
-ms-@{property}: @values;
-moz-@{property}: @values;
-webkit-@{property}: @values;
@{property}: @values;
/*
// If prior to v1.6.0, use this:
-less-vendorify: ~` ';\n' +
' -o-' + '@{property}: ' + '@{values};\n' +
' -ms-' + '@{property}: ' + '@{values};\n' +
' -moz-' + '@{property}: ' + '@{values};\n' +
' -webkit-' + '@{property}: ' + '@{values};\n' +
' @{property}: ' + '@{values}'`;
*/
}
@demoive
Copy link
Author

demoive commented May 24, 2013

This is an attempt for a simplistic solution to do what is more easily possible in SCSS, but in LESS. Since LESS doesn't support the usage of variables in properties - a.k.a interpolation - (see issue 698 and 36), there have been other solutions, such as this one. However, I have found them to be buggy or unnecessarily complicated.

To avoid creating separate mixins for each property (such as less-mixins or elements), I created this solution. Check out the usage samples below or (try it out yourself).

Things to note

  • Values with single quotes are not permitted so if a value needs to be quoted, us double quotes

  • If on version prior to v1.6.0, a useless (but harmless) -less-vendorify: ; property is included in the style definition

  • It blindly uses the property suffix with all vendor-specific prefixes, so it would not work well for properties where vendors have different suffixes, for example:

    -webkit-border-top-right-radius
    -moz-border-radius-topright
    

    or

    -webkit-gradient
    -ms-linear-gradient
    

@demoive
Copy link
Author

demoive commented May 26, 2013

Test cases

Input

@v1:  none;                                        // display
@v2:  "✓";                                         // content
@v3:  ~"none";                                     // display
@v4:  10px;                                        // width
@v5:  1px 2px 3px 4px;                             // padding
@v6:  @v4 5px;                                     // padding
@v7:  1px solid red;                               // border
@v8:  translate(10px, 10px);                       // transform
@v9:  scale(.5) translate(10px, 10px);             // transform
@v10: url("bg1.png");                              // background-image
@v11: url('bg1.png');                              // background-image
@v12: url(bg2.png) repeat, url(bg3.png) no-repeat; // background

.test-empty              { /* at least one param required: .vendorify(); */ }
.test-prop-no-val        { .vendorify(color); }
.test-simple             { .vendorify(display, @v1); }
.test-simple-as-string   { .vendorify(content, @v2); }
.test-simple-escaped     { .vendorify(display, @v3); }
.test-px                 { .vendorify(padding, @v4); }
.test-px-several         { .vendorify(padding, @v5); }
.test-px-nested          { .vendorify(padding, @v6); }
.test-mixed-type         { .vendorify(border, @v7); }
.test-complex            { .vendorify(transform, @v8); }
.test-complex-several    { .vendorify(color, @v9); }
.test-quoted-double      { .vendorify(background-image, @v10); }
.test-quoted-single      { /* singlue quotes not allowed: .vendorify(background-image, @v11); */ }
.test-compound           { .vendorify(background, @v12); }
.test-compound-several   { .vendorify(background, @v10, @v12); }

Output

.test-empty {
  /* at least one param required: .vendorify(); */
}
.test-prop-no-val {
  -o-color: ;
  -ms-color: ;
  -moz-color: ;
  -webkit-color: ;
  color: ;
}
.test-simple {
  -o-display: none;
  -ms-display: none;
  -moz-display: none;
  -webkit-display: none;
  display: none;
}
.test-simple-as-string {
  -o-content: "✓";
  -ms-content: "✓";
  -moz-content: "✓";
  -webkit-content: "✓";
  content: "✓";
}
.test-simple-escaped {
  -o-display: none;
  -ms-display: none;
  -moz-display: none;
  -webkit-display: none;
  display: none;
}
.test-px {
  -o-padding: 10px;
  -ms-padding: 10px;
  -moz-padding: 10px;
  -webkit-padding: 10px;
  padding: 10px;
}
.test-px-several {
  -o-padding: 1px 2px 3px 4px;
  -ms-padding: 1px 2px 3px 4px;
  -moz-padding: 1px 2px 3px 4px;
  -webkit-padding: 1px 2px 3px 4px;
  padding: 1px 2px 3px 4px;
}
.test-px-nested {
  -o-padding: 10px 5px;
  -ms-padding: 10px 5px;
  -moz-padding: 10px 5px;
  -webkit-padding: 10px 5px;
  padding: 10px 5px;
}
.test-mixed-type {
  -o-border: 1px solid #ff0000;
  -ms-border: 1px solid #ff0000;
  -moz-border: 1px solid #ff0000;
  -webkit-border: 1px solid #ff0000;
  border: 1px solid #ff0000;
}
.test-complex {
  -o-transform: translate(10px, 10px);
  -ms-transform: translate(10px, 10px);
  -moz-transform: translate(10px, 10px);
  -webkit-transform: translate(10px, 10px);
  transform: translate(10px, 10px);
}
.test-complex-several {
  -o-color: scale(0.5) translate(10px, 10px);
  -ms-color: scale(0.5) translate(10px, 10px);
  -moz-color: scale(0.5) translate(10px, 10px);
  -webkit-color: scale(0.5) translate(10px, 10px);
  color: scale(0.5) translate(10px, 10px);
}
.test-quoted-double {
  -o-background-image: url("bg1.png");
  -ms-background-image: url("bg1.png");
  -moz-background-image: url("bg1.png");
  -webkit-background-image: url("bg1.png");
  background-image: url("bg1.png");
}
.test-quoted-single {
  /* singlue quotes not allowed: .vendorify(background-image, @v11); */
}
.test-compound {
  -o-background: url(bg2.png) repeat, url(bg3.png) no-repeat;
  -ms-background: url(bg2.png) repeat, url(bg3.png) no-repeat;
  -moz-background: url(bg2.png) repeat, url(bg3.png) no-repeat;
  -webkit-background: url(bg2.png) repeat, url(bg3.png) no-repeat;
  background: url(bg2.png) repeat, url(bg3.png) no-repeat;
}
.test-compound-several {
  -o-background: url("bg1.png"), url(bg2.png) repeat, url(bg3.png) no-repeat;
  -ms-background: url("bg1.png"), url(bg2.png) repeat, url(bg3.png) no-repeat;
  -moz-background: url("bg1.png"), url(bg2.png) repeat, url(bg3.png) no-repeat;
  -webkit-background: url("bg1.png"), url(bg2.png) repeat, url(bg3.png) no-repeat;
  background: url("bg1.png"), url(bg2.png) repeat, url(bg3.png) no-repeat;
}

@theMikeD
Copy link

"A useless (but harmless) -less-vendorify: ; property is included in the style definition"

Why?

@demoive
Copy link
Author

demoive commented May 26, 2013

Because of the way LESS works, we are unable to simply print out the string generated by the JavaScript code without it being "attached" to an existing property. We get around this by creating the bogus -less-vendorify property (it can be anything), and tricking LESS by assigning the remaining properties as the value of this property. However, we insert semicolons and line breaks so that other properties get created as well.

If you know of a way around this, I'm all ears!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment