diff --git a/tests/css_less/__snapshots__/jsfmt.spec.js.snap b/tests/css_less/__snapshots__/jsfmt.spec.js.snap
new file mode 100644
index 000000000..86c4237a3
--- /dev/null
+++ b/tests/css_less/__snapshots__/jsfmt.spec.js.snap
@@ -0,0 +1,3189 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`less.css 1`] = `
+@nice-blue: #5B83AD;
+@light-blue: @nice-blue + #111;
+
+#header {
+ color: @light-blue;
+}
+
+
+#header {
+ color: #6c94be;
+}
+
+
+.bordered {
+ border-top: dotted 1px black;
+ border-bottom: solid 2px black;
+}
+
+
+#menu a {
+ color: #111;
+ .bordered;
+}
+
+.post a {
+ color: red;
+ .bordered;
+}
+
+
+#header {
+ color: black;
+}
+#header .navigation {
+ font-size: 12px;
+}
+#header .logo {
+ width: 300px;
+}
+
+
+#header {
+ color: black;
+ .navigation {
+ font-size: 12px;
+ }
+ .logo {
+ width: 300px;
+ }
+}
+
+
+.clearfix {
+ display: block;
+ zoom: 1;
+
+ &:after {
+ content: " ";
+ display: block;
+ font-size: 0;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+ }
+}
+
+
+.screen-color {
+ @media screen {
+ color: green;
+ @media (min-width: 768px) {
+ color: red;
+ }
+ }
+ @media tv {
+ color: black;
+ }
+}
+
+
+@media screen {
+ .screen-color {
+ color: green;
+ }
+}
+@media screen and (min-width: 768px) {
+ .screen-color {
+ color: red;
+ }
+}
+@media tv {
+ .screen-color {
+ color: black;
+ }
+}
+
+
+#a {
+ color: blue;
+ @font-face {
+ src: made-up-url;
+ }
+ padding: 2 2 2 2;
+}
+
+
+#a {
+ color: blue;
+}
+@font-face {
+ src: made-up-url;
+}
+#a {
+ padding: 2 2 2 2;
+}
+
+
+// numbers are converted into the same units
+@conversion-1: 5cm + 10mm; // result is 6cm
+@conversion-2: 2 - 3cm - 5mm; // result is -1.5cm
+
+// conversion is impossible
+@incompatible-units: 2 + 5px - 3cm; // result is 4px
+
+// example with variables
+@base: 5%;
+@filler: @base * 2; // result is 10%
+@other: @base + @filler; // result is 15%
+
+
+@base: 2cm * 3mm; // result is 6cm
+
+
+@color: #224488 / 2; //results in #112244
+background-color: #112244 + #111; // result is #223355
+
+
+.weird-element {
+ content: ~"^//* some horrible but needed css hack";
+}
+
+
+@base: #f04615;
+@width: 0.5;
+
+.class {
+ width: percentage(@width); // returns \`50%\`
+ color: saturate(@base, 5%);
+ background-color: spin(lighten(@base, 25%), 8);
+}
+
+
+#bundle {
+ .button {
+ display: block;
+ border: 1px solid black;
+ background-color: grey;
+ &:hover {
+ background-color: white
+ }
+ }
+ .tab { /* ... */ }
+ .citation { /* ... */ }
+}
+
+
+#header a {
+ color: orange;
+ #bundle > .button;
+}
+
+
+@var: red;
+
+#page {
+ @var: white;
+ #header {
+ color: @var; // white
+ }
+}
+
+
+@var: red;
+
+#page {
+ #header {
+ color: @var; // white
+ }
+ @var: white;
+}
+
+
+/* One hell of a block
+style comment! */
+@var: red;
+
+// Get in line!
+@var: white;
+
+
+@import "library"; // library.less
+@import "typo.css";
+
+
+a,
+.link {
+ color: #428bca;
+}
+.widget {
+ color: #fff;
+ background: #428bca;
+}
+
+
+// Variables
+@link-color: #428bca; // sea blue
+@link-color-hover: darken(@link-color, 10%);
+
+// Usage
+a,
+.link {
+ color: @link-color;
+}
+a:hover {
+ color: @link-color-hover;
+}
+.widget {
+ color: #fff;
+ background: @link-color;
+}
+
+
+// Variables
+@my-selector: banner;
+
+// Usage
+.@{my-selector} {
+ font-weight: bold;
+ line-height: 40px;
+ margin: 0 auto;
+}
+
+
+.banner {
+ font-weight: bold;
+ line-height: 40px;
+ margin: 0 auto;
+}
+
+
+// Variables
+@images: "../img";
+
+// Usage
+body {
+ color: #444;
+ background: url("@{images}/white-sand.png");
+}
+
+
+// Variables
+@themes: "../../src/themes";
+
+// Usage
+@import "@{themes}/tidal-wave.less";
+
+
+@property: color;
+
+.widget {
+ @{property}: #0ee;
+ background-@{property}: #999;
+}
+
+
+.widget {
+ color: #0ee;
+ background-color: #999;
+}
+
+
+@fnord: "I am fnord.";
+@var: "fnord";
+content: @@var;
+
+
+content: "I am fnord.";
+
+
+.lazy-eval {
+ width: @var;
+}
+
+@var: @a;
+@a: 9%;
+
+
+.lazy-eval-scope {
+ width: @var;
+ @a: 9%;
+}
+
+@var: @a;
+@a: 100%;
+
+
+.lazy-eval-scope {
+ width: 9%;
+}
+
+
+@var: 0;
+.class {
+ @var: 1;
+ .brass {
+ @var: 2;
+ three: @var;
+ @var: 3;
+ }
+ one: @var;
+}
+
+
+.class {
+ one: 1;
+}
+.class .brass {
+ three: 3;
+}
+
+
+// library
+@base-color: green;
+@dark-color: darken(@base-color, 10%);
+
+// use of library
+@import "library.less";
+@base-color: red;
+
+
+nav ul {
+ &:extend(.inline);
+ background: blue;
+}
+
+
+nav ul {
+ &:extend(.inline);
+ background: blue;
+}
+.inline {
+ color: red;
+}
+
+
+nav ul {
+ background: blue;
+}
+.inline,
+nav ul {
+ color: red;
+}
+
+
+.a:extend(.b) {}
+
+// the above block does the same thing as the below block
+.a {
+ &:extend(.b);
+}
+
+
+.c:extend(.d all) {
+ // extends all instances of ".d" e.g. ".x.d" or ".d.x"
+}
+.c:extend(.d) {
+ // extends only instances where the selector will be output as just ".d"
+}
+
+
+.e:extend(.f) {}
+.e:extend(.g) {}
+
+// the above an the below do the same thing
+.e:extend(.f, .g) {}
+
+
+.big-division,
+.big-bag:extend(.bag),
+.big-bucket:extend(.bucket) {
+ // body
+}
+
+
+pre:hover,
+.some-class {
+ &:extend(div pre);
+}
+
+
+pre:hover:extend(div pre),
+.some-class:extend(div pre) {}
+
+
+.bucket {
+ tr { // nested ruleset with target selector
+ color: blue;
+ }
+}
+.some-class:extend(.bucket tr) {} // nested ruleset is recognized
+
+
+.bucket tr,
+.some-class {
+ color: blue;
+}
+
+
+.bucket {
+ tr & { // nested ruleset with target selector
+ color: blue;
+ }
+}
+.some-class:extend(tr .bucket) {} // nested ruleset is recognized
+
+
+tr .bucket,
+.some-class {
+ color: blue;
+}
+
+
+.a.class,
+.class.a,
+.class > .a {
+ color: blue;
+}
+.test:extend(.class) {} // this will NOT match the any selectors above
+
+
+*.class {
+ color: blue;
+}
+.noStar:extend(.class) {} // this will NOT match the *.class selector
+
+
+*.class {
+ color: blue;
+}
+
+
+link:hover:visited {
+ color: blue;
+}
+.selector:extend(link:visited:hover) {}
+
+
+link:hover:visited {
+ color: blue;
+}
+
+
+:nth-child(1n+3) {
+ color: blue;
+}
+.child:extend(:nth-child(n+3)) {}
+
+
+:nth-child(1n+3) {
+ color: blue;
+}
+
+
+[title=identifier] {
+ color: blue;
+}
+[title='identifier'] {
+ color: blue;
+}
+[title="identifier"] {
+ color: blue;
+}
+
+.noQuote:extend([title=identifier]) {}
+.singleQuote:extend([title='identifier']) {}
+.doubleQuote:extend([title="identifier"]) {}
+
+
+[title=identifier],
+.noQuote,
+.singleQuote,
+.doubleQuote {
+ color: blue;
+}
+
+[title='identifier'],
+.noQuote,
+.singleQuote,
+.doubleQuote {
+ color: blue;
+}
+
+[title="identifier"],
+.noQuote,
+.singleQuote,
+.doubleQuote {
+ color: blue;
+}
+
+
+.a.b.test,
+.test.c {
+ color: orange;
+}
+.test {
+ &:hover {
+ color: green;
+ }
+}
+
+.replacement:extend(.test all) {}
+
+
+.a.b.test,
+.test.c,
+.a.b.replacement,
+.replacement.c {
+ color: orange;
+}
+.test:hover,
+.replacement:hover {
+ color: green;
+}
+
+
+@variable: .bucket;
+@{variable} { // interpolated selector
+ color: blue;
+}
+.some-class:extend(.bucket) {} // does nothing, no match is found
+
+
+.bucket {
+ color: blue;
+}
+.some-class:extend(@{variable}) {} // interpolated selector matches nothing
+@variable: .bucket;
+
+
+.bucket {
+ color: blue;
+}
+
+
+.bucket {
+ color: blue;
+}
+@{variable}:extend(.bucket) {}
+@variable: .selector;
+
+
+.bucket, .selector {
+ color: blue;
+}
+
+
+@media print {
+ .screenClass:extend(.selector) {} // extend inside media
+ .selector { // this will be matched - it is in the same media
+ color: black;
+ }
+}
+.selector { // ruleset on top of style sheet - extend ignores it
+ color: red;
+}
+@media screen {
+ .selector { // ruleset inside another media - extend ignores it
+ color: blue;
+ }
+}
+
+
+@media print {
+ .selector,
+ .screenClass { /* ruleset inside the same media was extended */
+ color: black;
+ }
+}
+.selector { /* ruleset on top of style sheet was ignored */
+ color: red;
+}
+@media screen {
+ .selector { /* ruleset inside another media was ignored */
+ color: blue;
+ }
+}
+
+
+@media screen {
+ .screenClass:extend(.selector) {} // extend inside media
+ @media (min-width: 1023px) {
+ .selector { // ruleset inside nested media - extend ignores it
+ color: blue;
+ }
+ }
+}
+
+
+@media screen and (min-width: 1023px) {
+ .selector { /* ruleset inside another nested media was ignored */
+ color: blue;
+ }
+}
+
+
+@media screen {
+ .selector { /* ruleset inside nested media - top level extend works */
+ color: blue;
+ }
+ @media (min-width: 1023px) {
+ .selector { /* ruleset inside nested media - top level extend works */
+ color: blue;
+ }
+ }
+}
+
+.topLevel:extend(.selector) {} /* top level extend matches everything */
+
+
+@media screen {
+ .selector,
+ .topLevel { /* ruleset inside media was extended */
+ color: blue;
+ }
+}
+@media screen and (min-width: 1023px) {
+ .selector,
+ .topLevel { /* ruleset inside nested media was extended */
+ color: blue;
+ }
+}
+
+
+.alert-info,
+.widget {
+ /* declarations */
+}
+
+.alert:extend(.alert-info, .widget) {}
+
+
+.alert-info,
+.widget,
+.alert,
+.alert {
+ /* declarations */
+}
+
+
+.animal {
+ background-color: black;
+ color: white;
+}
+
+
+.animal {
+ background-color: black;
+ color: white;
+}
+.bear {
+ background-color: brown;
+}
+
+.animal {
+ background-color: black;
+ color: white;
+}
+.bear {
+ &:extend(.animal);
+ background-color: brown;
+}
+
+
+.my-inline-block() {
+ display: inline-block;
+ font-size: 0;
+}
+.thing1 {
+ .my-inline-block;
+}
+.thing2 {
+ .my-inline-block;
+}
+
+
+.thing1 {
+ display: inline-block;
+ font-size: 0;
+}
+.thing2 {
+ display: inline-block;
+ font-size: 0;
+}
+
+
+.my-inline-block {
+ display: inline-block;
+ font-size: 0;
+}
+.thing1 {
+ &:extend(.my-inline-block);
+}
+.thing2 {
+ &:extend(.my-inline-block);
+}
+
+
+.my-inline-block,
+.thing1,
+.thing2 {
+ display: inline-block;
+ font-size: 0;
+}
+
+
+li.list > a {
+ // list styles
+}
+button.list-style {
+ &:extend(li.list > a); // use the same list styles
+}
+
+
+.a, #b {
+ color: red;
+}
+.mixin-class {
+ .a();
+}
+.mixin-id {
+ #b();
+}
+
+
+.a, #b {
+ color: red;
+}
+.mixin-class {
+ color: red;
+}
+.mixin-id {
+ color: red;
+}
+
+
+// these two statements do the same thing:
+.a();
+.a;
+
+
+.my-mixin {
+ color: black;
+}
+.my-other-mixin() {
+ background: white;
+}
+.class {
+ .my-mixin;
+ .my-other-mixin;
+}
+
+
+.my-mixin {
+ color: black;
+}
+.class {
+ color: black;
+ background: white;
+}
+
+
+.my-hover-mixin() {
+ &:hover {
+ border: 1px solid red;
+ }
+}
+button {
+ .my-hover-mixin();
+}
+
+
+button:hover {
+ border: 1px solid red;
+}
+
+
+#outer {
+ .inner {
+ color: red;
+ }
+}
+
+.c {
+ #outer > .inner;
+}
+
+
+// all do the same thing
+#outer > .inner;
+#outer > .inner();
+#outer .inner;
+#outer .inner();
+#outer.inner;
+#outer.inner();
+
+
+#my-library {
+ .my-mixin() {
+ color: black;
+ }
+}
+// which can be used like this
+.class {
+ #my-library > .my-mixin();
+}
+
+
+#namespace when (@mode=huge) {
+ .mixin() { /* */ }
+}
+
+#namespace {
+ .mixin() when (@mode=huge) { /* */ }
+}
+
+
+#sp_1 when (default()) {
+ #sp_2 when (default()) {
+ .mixin() when not(default()) { /* */ }
+ }
+}
+
+
+.foo (@bg: #f5f5f5, @color: #900) {
+ background: @bg;
+ color: @color;
+}
+.unimportant {
+ .foo();
+}
+.important {
+ .foo() !important;
+}
+
+
+.unimportant {
+ background: #f5f5f5;
+ color: #900;
+}
+.important {
+ background: #f5f5f5 !important;
+ color: #900 !important;
+}
+
+
+.border-radius(@radius) {
+ -webkit-border-radius: @radius;
+ -moz-border-radius: @radius;
+ border-radius: @radius;
+}
+
+
+#header {
+ .border-radius(4px);
+}
+.button {
+ .border-radius(6px);
+}
+
+
+.border-radius(@radius: 5px) {
+ -webkit-border-radius: @radius;
+ -moz-border-radius: @radius;
+ border-radius: @radius;
+}
+
+
+#header {
+ .border-radius;
+}
+
+
+.wrap() {
+ text-wrap: wrap;
+ white-space: -moz-pre-wrap;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+pre { .wrap }
+
+
+pre {
+ text-wrap: wrap;
+ white-space: -moz-pre-wrap;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+
+.mixin(@color) {
+ color-1: @color;
+}
+.mixin(@color; @padding: 2) {
+ color-2: @color;
+ padding-2: @padding;
+}
+.mixin(@color; @padding; @margin: 2) {
+ color-3: @color;
+ padding-3: @padding;
+ margin: @margin @margin @margin @margin;
+}
+.some .selector div {
+ .mixin(#008000);
+}
+
+
+.some .selector div {
+ color-1: #008000;
+ color-2: #008000;
+ padding-2: 2;
+}
+
+
+.mixin(@color: black; @margin: 10px; @padding: 20px) {
+ color: @color;
+ margin: @margin;
+ padding: @padding;
+}
+.class1 {
+ .mixin(@margin: 20px; @color: #33acfe);
+}
+.class2 {
+ .mixin(#efca44; @padding: 40px);
+}
+
+
+.class1 {
+ color: #33acfe;
+ margin: 20px;
+ padding: 20px;
+}
+.class2 {
+ color: #efca44;
+ margin: 10px;
+ padding: 40px;
+}
+
+
+.box-shadow(@x: 0; @y: 0; @blur: 1px; @color: #000) {
+ -webkit-box-shadow: @arguments;
+ -moz-box-shadow: @arguments;
+ box-shadow: @arguments;
+}
+.big-block {
+ .box-shadow(2px; 5px);
+}
+
+
+.big-block {
+ -webkit-box-shadow: 2px 5px 1px #000;
+ -moz-box-shadow: 2px 5px 1px #000;
+ box-shadow: 2px 5px 1px #000;
+}
+
+
+.mixin(/* ... */) {} // matches 0-N arguments
+.mixin() {} // matches exactly 0 arguments
+.mixin(@a: 1) {} // matches 0-1 arguments
+.mixin(@a: 1; /* ... */) {} // matches 0-N arguments
+.mixin(@a; /* ... */) {} // matches 1-N arguments
+
+
+.mixin(@a; @rest...) {
+ // @rest is bound to arguments after @a
+ // @arguments is bound to all arguments
+}
+
+
+.mixin(@s; @color) { /* ... */ }
+
+.class {
+ .mixin(@switch; #888);
+}
+
+
+.mixin(dark; @color) {
+ color: darken(@color, 10%);
+}
+.mixin(light; @color) {
+ color: lighten(@color, 10%);
+}
+.mixin(@_; @color) {
+ display: block;
+}
+
+
+@switch: light;
+
+.class {
+ .mixin(@switch; #888);
+}
+
+
+.class {
+ color: #a2a2a2;
+ display: block;
+}
+
+
+.mixin(@a) {
+ color: @a;
+}
+.mixin(@a; @b) {
+ color: fade(@a; @b);
+}
+
+
+.mixin() {
+ @width: 100%;
+ @height: 200px;
+}
+
+.caller {
+ .mixin();
+ width: @width;
+ height: @height;
+}
+
+
+.caller {
+ width: 100%;
+ height: 200px;
+}
+
+
+.average(@x, @y) {
+ @average: ((@x + @y) / 2);
+}
+
+div {
+ .average(16px, 50px); // "call" the mixin
+ padding: @average; // use its "return" value
+}
+
+
+div {
+ padding: 33px;
+}
+
+
+.mixin() {
+ @size: in-mixin;
+ @definedOnlyInMixin: in-mixin;
+}
+
+.class {
+ margin: @size @definedOnlyInMixin;
+ .mixin();
+}
+
+@size: globally-defined-value; // callers parent scope - no protection
+
+
+.class {
+ margin: in-mixin in-mixin;
+}
+
+
+.unlock(@value) { // outer mixin
+ .doSomething() { // nested mixin
+ declaration: @value;
+ }
+}
+
+#namespace {
+ .unlock(5); // unlock doSomething mixin
+ .doSomething(); //nested mixin was copied here and is usable
+}
+
+
+#namespace {
+ declaration: 5;
+}
+
+
+// declare detached ruleset
+@detached-ruleset: { background: red; };
+
+// use detached ruleset
+.top {
+ @detached-ruleset();
+}
+
+
+.top {
+ background: red;
+}
+
+
+.desktop-and-old-ie(@rules) {
+ @media screen and (min-width: 1200px) { @rules(); }
+ html.lt-ie9 & { @rules(); }
+}
+
+header {
+ background-color: blue;
+
+ .desktop-and-old-ie({
+ background-color: red;
+ });
+}
+
+
+header {
+ background-color: blue;
+}
+@media screen and (min-width: 1200px) {
+ header {
+ background-color: red;
+ }
+}
+html.lt-ie9 header {
+ background-color: red;
+}
+
+
+@my-ruleset: {
+ .my-selector {
+ background-color: black;
+ }
+ };
+
+
+@my-ruleset: {
+ .my-selector {
+ @media tv {
+ background-color: black;
+ }
+ }
+ };
+@media (orientation:portrait) {
+ @my-ruleset();
+}
+
+
+@media (orientation: portrait) and tv {
+ .my-selector {
+ background-color: black;
+ }
+}
+
+
+// detached ruleset with a mixin
+@detached-ruleset: {
+ .mixin() {
+ color:blue;
+ }
+};
+// call detached ruleset
+.caller {
+ @detached-ruleset();
+ .mixin();
+}
+
+
+.caller {
+ color: blue;
+}
+
+
+@detached-ruleset: {
+ @color:blue; // this variable is private
+};
+.caller {
+ color: @color; // syntax error
+}
+
+
+@detached-ruleset: {
+ caller-variable: @caller-variable; // variable is undefined here
+ .caller-mixin(); // mixin is undefined here
+};
+
+selector {
+ // use detached ruleset
+ @detached-ruleset();
+
+ // define variable and mixin needed inside the detached ruleset
+ @caller-variable: value;
+ .caller-mixin() {
+ variable: declaration;
+ }
+}
+
+
+selector {
+ caller-variable: value;
+ variable: declaration;
+}
+
+
+@variable: global;
+@detached-ruleset: {
+ // will use global variable, because it is accessible
+ // from detached-ruleset definition
+ variable: @variable;
+};
+
+selector {
+ @detached-ruleset();
+ @variable: value; // variable defined in caller - will be ignored
+}
+
+
+selector {
+ variable: global;
+}
+
+
+@detached-1: { scope-detached: @one @two; };
+.one {
+ @one: visible;
+ .two {
+ @detached-2: @detached-1; // copying/renaming ruleset
+ @two: visible; // ruleset can not see this variable
+ }
+}
+
+.use-place {
+ .one > .two();
+ @detached-2();
+}
+
+
+ERROR 1:32 The variable "@one" was not declared.
+
+
+#space {
+ .importer-1() {
+ @detached: { scope-detached: @variable; }; // define detached ruleset
+ }
+}
+
+.importer-2() {
+ @variable: value; // unlocked detached ruleset CAN see this variable
+ #space > .importer-1(); // unlock/import detached ruleset
+}
+
+.use-place {
+ .importer-2(); // unlock/import detached ruleset second time
+ @detached();
+}
+
+
+.use-place {
+ scope-detached: value;
+}
+
+
+.foo {
+ background: #900;
+}
+@import "this-is-valid.less";
+
+
+@import "foo"; // foo.less is imported
+@import "foo.less"; // foo.less is imported
+@import "foo.php"; // foo.php imported as a less file
+@import "foo.css"; // statement left in place, as-is
+
+
+.navbar:extend(.navbar all) {}
+
+
+@import (less) "foo.css";
+
+
+@import (css) "foo.less";
+
+
+@import "foo.less";
+
+
+@import (once) "foo.less";
+@import (once) "foo.less"; // this statement will be ignored
+
+
+// file: foo.less
+.a {
+ color: green;
+}
+// file: main.less
+@import (multiple) "foo.less";
+@import (multiple) "foo.less";
+
+
+.a {
+ color: green;
+}
+.a {
+ color: green;
+}
+
+
+.mixin (@a) when (lightness(@a) >= 50%) {
+ background-color: black;
+}
+.mixin (@a) when (lightness(@a) < 50%) {
+ background-color: white;
+}
+.mixin (@a) {
+ color: @a;
+}
+
+
+.class1 { .mixin(#ddd) }
+.class2 { .mixin(#555) }
+
+
+.class1 {
+ background-color: black;
+ color: #ddd;
+}
+.class2 {
+ background-color: white;
+ color: #555;
+}
+
+
+.truth (@a) when (@a) { /* ... */ }
+.truth (@a) when (@a = true) { /* ... */ }
+
+
+.class {
+ .truth(40); // Will not match any of the above definitions.
+}
+
+
+@media: mobile;
+
+.mixin (@a) when (@media = mobile) { /* ... */ }
+.mixin (@a) when (@media = desktop) { /* ... */ }
+
+.max (@a; @b) when (@a > @b) { width: @a }
+.max (@a; @b) when (@a < @b) { width: @b }
+
+
+.mixin (@a) when (isnumber(@a)) and (@a > 0) { /* ... */ }
+
+
+.mixin (@a) when (@a > 10), (@a < -10) { /* ... */ }
+
+
+.mixin (@b) when not (@b > 0) { /* ... */ }
+
+
+.mixin (@a; @b: 0) when (isnumber(@b)) { /* ... */ }
+.mixin (@a; @b: black) when (iscolor(@b)) { /* ... */ }
+
+
+.mixin (@a) when (@a > 0) { /* ... */ }
+.mixin (@a) when (default()) { /* ... */ } // matches only if first mixin does not, i.e. when @a <= 0
+
+
+.my-optional-style() when (@my-option = true) {
+ button {
+ color: white;
+ }
+}
+.my-optional-style();
+
+
+button when (@my-option = true) {
+ color: white;
+}
+
+
+& when (@my-option = true) {
+ button {
+ color: white;
+ }
+ a {
+ color: blue;
+ }
+}
+
+
+.loop(@counter) when (@counter > 0) {
+ .loop((@counter - 1)); // next iteration
+ width: (10px * @counter); // code for each iteration
+}
+
+div {
+ .loop(5); // launch the loop
+}
+
+
+div {
+ width: 10px;
+ width: 20px;
+ width: 30px;
+ width: 40px;
+ width: 50px;
+}
+
+
+.generate-columns(4);
+
+.generate-columns(@n, @i: 1) when (@i =< @n) {
+ .column-@{i} {
+ width: (@i * 100% / @n);
+ }
+ .generate-columns(@n, (@i + 1));
+}
+
+
+.column-1 {
+ width: 25%;
+}
+.column-2 {
+ width: 50%;
+}
+.column-3 {
+ width: 75%;
+}
+.column-4 {
+ width: 100%;
+}
+
+
+.mixin() {
+ box-shadow+: inset 0 0 10px #555;
+}
+.myclass {
+ .mixin();
+ box-shadow+: 0 0 20px black;
+}
+
+
+.myclass {
+ box-shadow: inset 0 0 10px #555, 0 0 20px black;
+}
+
+
+.mixin() {
+ transform+_: scale(2);
+}
+.myclass {
+ .mixin();
+ transform+_: rotate(15deg);
+}
+
+
+.myclass {
+ transform: scale(2) rotate(15deg);
+}
+
+
+a {
+ color: blue;
+ &:hover {
+ color: green;
+ }
+}
+
+
+a {
+ color: blue;
+}
+
+a:hover {
+ color: green;
+}
+
+
+.button {
+ &-ok {
+ background-image: url("ok.png");
+ }
+ &-cancel {
+ background-image: url("cancel.png");
+ }
+
+ &-custom {
+ background-image: url("custom.png");
+ }
+}
+
+
+.button-ok {
+ background-image: url("ok.png");
+}
+.button-cancel {
+ background-image: url("cancel.png");
+}
+.button-custom {
+ background-image: url("custom.png");
+}
+
+
+.link {
+ & + & {
+ color: red;
+ }
+
+ & & {
+ color: green;
+ }
+
+ && {
+ color: blue;
+ }
+
+ &, &ish {
+ color: cyan;
+ }
+}
+
+
+.link + .link {
+ color: red;
+}
+.link .link {
+ color: green;
+}
+.link.link {
+ color: blue;
+}
+.link, .linkish {
+ color: cyan;
+}
+
+
+.grand {
+ .parent {
+ & > & {
+ color: red;
+ }
+
+ & & {
+ color: green;
+ }
+
+ && {
+ color: blue;
+ }
+
+ &, &ish {
+ color: cyan;
+ }
+ }
+}
+
+
+.grand .parent > .grand .parent {
+ color: red;
+}
+.grand .parent .grand .parent {
+ color: green;
+}
+.grand .parent.grand .parent {
+ color: blue;
+}
+.grand .parent,
+.grand .parentish {
+ color: cyan;
+}
+
+
+.header {
+ .menu {
+ border-radius: 5px;
+ .no-borderradius & {
+ background-image: url('images/button-background.png');
+ }
+ }
+}
+
+
+.header .menu {
+ border-radius: 5px;
+}
+.no-borderradius .header .menu {
+ background-image: url('images/button-background.png');
+}
+
+
+p, a, ul, li {
+ border-top: 2px dotted #366;
+ & + & {
+ border-top: 0;
+ }
+}
+
+
+p,
+a,
+ul,
+li {
+ border-top: 2px dotted #366;
+}
+p + p,
+p + a,
+p + ul,
+p + li,
+a + p,
+a + a,
+a + ul,
+a + li,
+ul + p,
+ul + a,
+ul + ul,
+ul + li,
+li + p,
+li + a,
+li + ul,
+li + li {
+ border-top: 0;
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+@nice-blue: #5b83ad;
+@light-blue: @nice-blue + #111;
+
+#header {
+ color: @light-blue;
+}
+
+#header {
+ color: #6c94be;
+}
+
+.bordered {
+ border-top: dotted 1px black;
+ border-bottom: solid 2px black;
+}
+
+#menu a {
+ color: #111;
+ .bordered;
+}
+
+.post a {
+ color: red;
+ .bordered;
+}
+
+#header {
+ color: black;
+}
+#header .navigation {
+ font-size: 12px;
+}
+#header .logo {
+ width: 300px;
+}
+
+#header {
+ color: black;
+ .navigation {
+ font-size: 12px;
+ }
+ .logo {
+ width: 300px;
+ }
+}
+
+.clearfix {
+ display: block;
+ zoom: 1;
+
+ &:after {
+ content: " ";
+ display: block;
+ font-size: 0;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+ }
+}
+
+.screen-color {
+ @media screen {
+ color: green;
+ @media (min-width: 768px) {
+ color: red;
+ }
+ }
+ @media tv {
+ color: black;
+ }
+}
+
+@media screen {
+ .screen-color {
+ color: green;
+ }
+}
+@media screen and (min-width: 768px) {
+ .screen-color {
+ color: red;
+ }
+}
+@media tv {
+ .screen-color {
+ color: black;
+ }
+}
+
+#a {
+ color: blue;
+ @font-face {
+ src: made-up-url;
+ }
+ padding: 2 2 2 2;
+}
+
+#a {
+ color: blue;
+}
+@font-face {
+ src: made-up-url;
+}
+#a {
+ padding: 2 2 2 2;
+}
+
+// numbers are converted into the same units
+@conversion-1: 5cm + 10mm; // result is 6cm
+@conversion-2: 2 - 3cm - 5mm; // result is -1.5cm
+
+// conversion is impossible
+@incompatible-units: 2 + 5px - 3cm; // result is 4px
+
+// example with variables
+@base: 5%;
+@filler: @base * 2; // result is 10%
+@other: @base + @filler; // result is 15%
+
+@base: 2cm * 3mm; // result is 6cm
+
+@color: #224488 / 2; //results in #112244
+background-color: #112244 + #111; // result is #223355
+
+.weird-element {
+ content: ~"^//* some horrible but needed css hack";
+}
+
+@base: #f04615;
+@width: 0.5;
+
+.class {
+ width: percentage(@width); // returns \`50%\`
+ color: saturate(@base, 5%);
+ background-color: spin(lighten(@base, 25%), 8);
+}
+
+#bundle {
+ .button {
+ display: block;
+ border: 1px solid black;
+ background-color: grey;
+ &:hover {
+ background-color: white;
+ }
+ }
+ .tab {
+ /* ... */
+ }
+ .citation {
+ /* ... */
+ }
+}
+
+#header a {
+ color: orange;
+ #bundle > .button;
+}
+
+@var: red;
+
+#page {
+ @var: white;
+ #header {
+ color: @var; // white
+ }
+}
+
+@var: red;
+
+#page {
+ #header {
+ color: @var; // white
+ }
+ @var: white;
+}
+
+/* One hell of a block
+style comment! */
+@var: red;
+
+// Get in line!
+@var: white;
+
+@import "library"; // library.less
+@import "typo.css";
+
+a,
+.link {
+ color: #428bca;
+}
+.widget {
+ color: #fff;
+ background: #428bca;
+}
+
+// Variables
+@link-color: #428bca; // sea blue
+@link-color-hover: darken(@link-color, 10%);
+
+// Usage
+a,
+.link {
+ color: @link-color;
+}
+a:hover {
+ color: @link-color-hover;
+}
+.widget {
+ color: #fff;
+ background: @link-color;
+}
+
+// Variables
+@my-selector: banner;
+
+// Usage
+.@{my-selector} {
+ font-weight: bold;
+ line-height: 40px;
+ margin: 0 auto;
+}
+
+.banner {
+ font-weight: bold;
+ line-height: 40px;
+ margin: 0 auto;
+}
+
+// Variables
+@images: "../img";
+
+// Usage
+body {
+ color: #444;
+ background: url("@{images}/white-sand.png");
+}
+
+// Variables
+@themes: "../../src/themes";
+
+// Usage
+@import "@{themes}/tidal-wave.less";
+
+@property: color;
+
+.widget {
+ @{property}: #0ee;
+ background-@{property}: #999;
+}
+
+.widget {
+ color: #0ee;
+ background-color: #999;
+}
+
+@fnord: "I am fnord.";
+@var: "fnord";
+content: @@var;
+
+content: "I am fnord.";
+
+.lazy-eval {
+ width: @var;
+}
+
+@var: @a;
+@a: 9%;
+
+.lazy-eval-scope {
+ width: @var;
+ @a: 9%;
+}
+
+@var: @a;
+@a: 100%;
+
+.lazy-eval-scope {
+ width: 9%;
+}
+
+@var: 0;
+.class {
+ @var: 1;
+ .brass {
+ @var: 2;
+ three: @var;
+ @var: 3;
+ }
+ one: @var;
+}
+
+.class {
+ one: 1;
+}
+.class .brass {
+ three: 3;
+}
+
+// library
+@base-color: green;
+@dark-color: darken(@base-color, 10%);
+
+// use of library
+@import "library.less";
+@base-color: red;
+
+nav ul {
+ &:extend(.inline);
+ background: blue;
+}
+
+nav ul {
+ &:extend(.inline);
+ background: blue;
+}
+.inline {
+ color: red;
+}
+
+nav ul {
+ background: blue;
+}
+.inline,
+nav ul {
+ color: red;
+}
+
+.a:extend(.b) {
+}
+
+// the above block does the same thing as the below block
+.a {
+ &:extend(.b);
+}
+
+.c:extend(.d all) {
+ // extends all instances of ".d" e.g. ".x.d" or ".d.x"
+}
+.c:extend(.d) {
+ // extends only instances where the selector will be output as just ".d"
+}
+
+.e:extend(.f) {
+}
+.e:extend(.g) {
+}
+
+// the above an the below do the same thing
+.e:extend(.f, .g) {
+}
+
+.big-division,
+.big-bag:extend(.bag),
+.big-bucket:extend(.bucket) {
+ // body
+}
+
+pre:hover,
+.some-class {
+ &:extend(div pre);
+}
+
+pre:hover:extend(div pre),
+.some-class:extend(div pre) {
+}
+
+.bucket {
+ tr {
+ // nested ruleset with target selector
+ color: blue;
+ }
+}
+.some-class:extend(.bucket tr) {
+} // nested ruleset is recognized
+
+.bucket tr,
+.some-class {
+ color: blue;
+}
+
+.bucket {
+ tr & {
+ // nested ruleset with target selector
+ color: blue;
+ }
+}
+.some-class:extend(tr .bucket) {
+} // nested ruleset is recognized
+
+tr .bucket,
+.some-class {
+ color: blue;
+}
+
+.a.class,
+.class.a,
+.class > .a {
+ color: blue;
+}
+.test:extend(.class) {
+} // this will NOT match the any selectors above
+
+*.class {
+ color: blue;
+}
+.noStar:extend(.class) {
+} // this will NOT match the *.class selector
+
+*.class {
+ color: blue;
+}
+
+link:hover:visited {
+ color: blue;
+}
+.selector:extend(link:visited:hover) {
+}
+
+link:hover:visited {
+ color: blue;
+}
+
+:nth-child(1n + 3) {
+ color: blue;
+}
+.child:extend(:nth-child(n + 3)) {
+}
+
+:nth-child(1n + 3) {
+ color: blue;
+}
+
+[title="identifier"] {
+ color: blue;
+}
+[title="identifier"] {
+ color: blue;
+}
+[title="identifier"] {
+ color: blue;
+}
+
+.noQuote:extend([title="identifier"]) {
+}
+.singleQuote:extend([title="identifier"]) {
+}
+.doubleQuote:extend([title="identifier"]) {
+}
+
+[title="identifier"],
+.noQuote,
+.singleQuote,
+.doubleQuote {
+ color: blue;
+}
+
+[title="identifier"],
+.noQuote,
+.singleQuote,
+.doubleQuote {
+ color: blue;
+}
+
+[title="identifier"],
+.noQuote,
+.singleQuote,
+.doubleQuote {
+ color: blue;
+}
+
+.a.b.test,
+.test.c {
+ color: orange;
+}
+.test {
+ &:hover {
+ color: green;
+ }
+}
+
+.replacement:extend(.test all) {
+}
+
+.a.b.test,
+.test.c,
+.a.b.replacement,
+.replacement.c {
+ color: orange;
+}
+.test:hover,
+.replacement:hover {
+ color: green;
+}
+
+@variable: .bucket;
+@{variable} {
+ // interpolated selector
+ color: blue;
+}
+.some-class:extend(.bucket) {
+} // does nothing, no match is found
+
+.bucket {
+ color: blue;
+}
+.some-class:extend(@{variable}) {
+} // interpolated selector matches nothing
+@variable: .bucket;
+
+.bucket {
+ color: blue;
+}
+
+.bucket {
+ color: blue;
+}
+@{variable}:extend(.bucket) {
+}
+@variable: .selector;
+
+.bucket,
+.selector {
+ color: blue;
+}
+
+@media print {
+ .screenClass:extend(.selector) {
+ } // extend inside media
+ .selector {
+ // this will be matched - it is in the same media
+ color: black;
+ }
+}
+.selector {
+ // ruleset on top of style sheet - extend ignores it
+ color: red;
+}
+@media screen {
+ .selector {
+ // ruleset inside another media - extend ignores it
+ color: blue;
+ }
+}
+
+@media print {
+ .selector,
+ .screenClass {
+ /* ruleset inside the same media was extended */
+ color: black;
+ }
+}
+.selector {
+ /* ruleset on top of style sheet was ignored */
+ color: red;
+}
+@media screen {
+ .selector {
+ /* ruleset inside another media was ignored */
+ color: blue;
+ }
+}
+
+@media screen {
+ .screenClass:extend(.selector) {
+ } // extend inside media
+ @media (min-width: 1023px) {
+ .selector {
+ // ruleset inside nested media - extend ignores it
+ color: blue;
+ }
+ }
+}
+
+@media screen and (min-width: 1023px) {
+ .selector {
+ /* ruleset inside another nested media was ignored */
+ color: blue;
+ }
+}
+
+@media screen {
+ .selector {
+ /* ruleset inside nested media - top level extend works */
+ color: blue;
+ }
+ @media (min-width: 1023px) {
+ .selector {
+ /* ruleset inside nested media - top level extend works */
+ color: blue;
+ }
+ }
+}
+
+.topLevel:extend(.selector) {
+} /* top level extend matches everything */
+
+@media screen {
+ .selector,
+ .topLevel {
+ /* ruleset inside media was extended */
+ color: blue;
+ }
+}
+@media screen and (min-width: 1023px) {
+ .selector,
+ .topLevel {
+ /* ruleset inside nested media was extended */
+ color: blue;
+ }
+}
+
+.alert-info,
+.widget {
+ /* declarations */
+}
+
+.alert:extend(.alert-info, .widget) {
+}
+
+.alert-info,
+.widget,
+.alert,
+.alert {
+ /* declarations */
+}
+
+.animal {
+ background-color: black;
+ color: white;
+}
+
+.animal {
+ background-color: black;
+ color: white;
+}
+.bear {
+ background-color: brown;
+}
+
+.animal {
+ background-color: black;
+ color: white;
+}
+.bear {
+ &:extend(.animal);
+ background-color: brown;
+}
+
+.my-inline-block() {
+ display: inline-block;
+ font-size: 0;
+}
+.thing1 {
+ .my-inline-block;
+}
+.thing2 {
+ .my-inline-block;
+}
+
+.thing1 {
+ display: inline-block;
+ font-size: 0;
+}
+.thing2 {
+ display: inline-block;
+ font-size: 0;
+}
+
+.my-inline-block {
+ display: inline-block;
+ font-size: 0;
+}
+.thing1 {
+ &:extend(.my-inline-block);
+}
+.thing2 {
+ &:extend(.my-inline-block);
+}
+
+.my-inline-block,
+.thing1,
+.thing2 {
+ display: inline-block;
+ font-size: 0;
+}
+
+li.list > a {
+ // list styles
+}
+button.list-style {
+ &:extend(li.list > a); // use the same list styles
+}
+
+.a,
+#b {
+ color: red;
+}
+.mixin-class {
+ .a();
+}
+.mixin-id {
+ #b();
+}
+
+.a,
+#b {
+ color: red;
+}
+.mixin-class {
+ color: red;
+}
+.mixin-id {
+ color: red;
+}
+
+// these two statements do the same thing:
+.a();
+.a;
+
+.my-mixin {
+ color: black;
+}
+.my-other-mixin() {
+ background: white;
+}
+.class {
+ .my-mixin;
+ .my-other-mixin;
+}
+
+.my-mixin {
+ color: black;
+}
+.class {
+ color: black;
+ background: white;
+}
+
+.my-hover-mixin() {
+ &:hover {
+ border: 1px solid red;
+ }
+}
+button {
+ .my-hover-mixin();
+}
+
+button:hover {
+ border: 1px solid red;
+}
+
+#outer {
+ .inner {
+ color: red;
+ }
+}
+
+.c {
+ #outer > .inner;
+}
+
+// all do the same thing
+#outer > .inner;
+#outer > .inner();
+#outer .inner;
+#outer .inner();
+#outer.inner;
+#outer.inner();
+
+#my-library {
+ .my-mixin() {
+ color: black;
+ }
+}
+// which can be used like this
+.class {
+ #my-library > .my-mixin();
+}
+
+#namespace when (@mode=huge) {
+ .mixin() {
+ /* */
+ }
+}
+
+#namespace {
+ .mixin() when (@mode=huge) {
+ /* */
+ }
+}
+
+#sp_1 when (default()) {
+ #sp_2 when (default()) {
+ .mixin() when not(default()) {
+ /* */
+ }
+ }
+}
+
+.foo (@bg: #f5f5f5, @color: #900) {
+ background: @bg;
+ color: @color;
+}
+.unimportant {
+ .foo();
+}
+.important {
+ .foo() !important;
+}
+
+.unimportant {
+ background: #f5f5f5;
+ color: #900;
+}
+.important {
+ background: #f5f5f5 !important;
+ color: #900 !important;
+}
+
+.border-radius(@radius) {
+ -webkit-border-radius: @radius;
+ -moz-border-radius: @radius;
+ border-radius: @radius;
+}
+
+#header {
+ .border-radius(4px);
+}
+.button {
+ .border-radius(6px);
+}
+
+.border-radius(@radius: 5px) {
+ -webkit-border-radius: @radius;
+ -moz-border-radius: @radius;
+ border-radius: @radius;
+}
+
+#header {
+ .border-radius;
+}
+
+.wrap() {
+ text-wrap: wrap;
+ white-space: -moz-pre-wrap;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+pre {
+ .wrap;
+}
+
+pre {
+ text-wrap: wrap;
+ white-space: -moz-pre-wrap;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+.mixin(@color) {
+ color-1: @color;
+}
+.mixin(@color; @padding: 2) {
+ color-2: @color;
+ padding-2: @padding;
+}
+.mixin(@color; @padding; @margin: 2) {
+ color-3: @color;
+ padding-3: @padding;
+ margin: @margin @margin @margin @margin;
+}
+.some .selector div {
+ .mixin(#008000);
+}
+
+.some .selector div {
+ color-1: #008000;
+ color-2: #008000;
+ padding-2: 2;
+}
+
+.mixin(@color: black; @margin: 10px; @padding: 20px) {
+ color: @color;
+ margin: @margin;
+ padding: @padding;
+}
+.class1 {
+ .mixin(@margin: 20px; @color: #33acfe);
+}
+.class2 {
+ .mixin(#efca44; @padding: 40px);
+}
+
+.class1 {
+ color: #33acfe;
+ margin: 20px;
+ padding: 20px;
+}
+.class2 {
+ color: #efca44;
+ margin: 10px;
+ padding: 40px;
+}
+
+.box-shadow(@x: 0; @y: 0; @blur: 1px; @color: #000) {
+ -webkit-box-shadow: @arguments;
+ -moz-box-shadow: @arguments;
+ box-shadow: @arguments;
+}
+.big-block {
+ .box-shadow(2px; 5px);
+}
+
+.big-block {
+ -webkit-box-shadow: 2px 5px 1px #000;
+ -moz-box-shadow: 2px 5px 1px #000;
+ box-shadow: 2px 5px 1px #000;
+}
+
+.mixin(/* ... */) {
+} // matches 0-N arguments
+.mixin() {
+} // matches exactly 0 arguments
+.mixin(@a: 1) {
+} // matches 0-1 arguments
+.mixin(@a: 1; /* ... */) {
+} // matches 0-N arguments
+.mixin(@a; /* ... */) {
+} // matches 1-N arguments
+
+.mixin(@a; @rest...) {
+ // @rest is bound to arguments after @a
+ // @arguments is bound to all arguments
+}
+
+.mixin(@s; @color) {
+ /* ... */
+}
+
+.class {
+ .mixin(@switch; #888);
+}
+
+.mixin(dark; @color) {
+ color: darken(@color, 10%);
+}
+.mixin(light; @color) {
+ color: lighten(@color, 10%);
+}
+.mixin(@_; @color) {
+ display: block;
+}
+
+@switch: light;
+
+.class {
+ .mixin(@switch; #888);
+}
+
+.class {
+ color: #a2a2a2;
+ display: block;
+}
+
+.mixin(@a) {
+ color: @a;
+}
+.mixin(@a; @b) {
+ color: fade(@a; @b);
+}
+
+.mixin() {
+ @width: 100%;
+ @height: 200px;
+}
+
+.caller {
+ .mixin();
+ width: @width;
+ height: @height;
+}
+
+.caller {
+ width: 100%;
+ height: 200px;
+}
+
+.average(@x, @y) {
+ @average: ((@x + @y) / 2);
+}
+
+div {
+ .average(16px, 50px); // "call" the mixin
+ padding: @average; // use its "return" value
+}
+
+div {
+ padding: 33px;
+}
+
+.mixin() {
+ @size: in-mixin;
+ @definedOnlyInMixin: in-mixin;
+}
+
+.class {
+ margin: @size @definedOnlyInMixin;
+ .mixin();
+}
+
+@size: globally-defined-value; // callers parent scope - no protection
+
+.class {
+ margin: in-mixin in-mixin;
+}
+
+.unlock(@value) {
+ // outer mixin
+ .doSomething() {
+ // nested mixin
+ declaration: @value;
+ }
+}
+
+#namespace {
+ .unlock(5); // unlock doSomething mixin
+ .doSomething(); //nested mixin was copied here and is usable
+}
+
+#namespace {
+ declaration: 5;
+}
+
+// declare detached ruleset
+@detached-ruleset: {
+ background: red;
+}
+
+// use detached ruleset
+.top {
+ @detached-ruleset();
+}
+
+.top {
+ background: red;
+}
+
+.desktop-and-old-ie(@rules) {
+ @media screen and (min-width: 1200px) {
+ @rules();
+ }
+ html.lt-ie9 & {
+ @rules();
+ }
+}
+
+header {
+ background-color: blue;
+
+ .desktop-and-old-ie({
+ background-color: red;
+ });
+}
+
+header {
+ background-color: blue;
+}
+@media screen and (min-width: 1200px) {
+ header {
+ background-color: red;
+ }
+}
+html.lt-ie9 header {
+ background-color: red;
+}
+
+@my-ruleset: {
+ .my-selector {
+ background-color: black;
+ }
+}
+
+@my-ruleset: {
+ .my-selector {
+ @media tv {
+ background-color: black;
+ }
+ }
+}
+@media (orientation: portrait) {
+ @my-ruleset();
+}
+
+@media (orientation: portrait) and tv {
+ .my-selector {
+ background-color: black;
+ }
+}
+
+// detached ruleset with a mixin
+@detached-ruleset: {
+ .mixin() {
+ color: blue;
+ }
+}
+// call detached ruleset
+.caller {
+ @detached-ruleset();
+ .mixin();
+}
+
+.caller {
+ color: blue;
+}
+
+@detached-ruleset: {
+ @color: blue; // this variable is private
+}
+.caller {
+ color: @color; // syntax error
+}
+
+@detached-ruleset: {
+ caller-variable: @caller-variable; // variable is undefined here
+ .caller-mixin(); // mixin is undefined here
+}
+
+selector {
+ // use detached ruleset
+ @detached-ruleset();
+
+ // define variable and mixin needed inside the detached ruleset
+ @caller-variable: value;
+ .caller-mixin() {
+ variable: declaration;
+ }
+}
+
+selector {
+ caller-variable: value;
+ variable: declaration;
+}
+
+@variable: global;
+@detached-ruleset: {
+ // will use global variable, because it is accessible
+ // from detached-ruleset definition
+ variable: @variable;
+}
+
+selector {
+ @detached-ruleset();
+ @variable: value; // variable defined in caller - will be ignored
+}
+
+selector {
+ variable: global;
+}
+
+@detached-1: {
+ scope-detached: @one @two;
+}
+.one {
+ @one: visible;
+ .two {
+ @detached-2: @detached-1; // copying/renaming ruleset
+ @two: visible; // ruleset can not see this variable
+ }
+}
+
+.use-place {
+ .one > .two();
+ @detached-2();
+}
+
+ERROR 1:32 The variable "@one" was not declared. #space {
+ .importer-1() {
+ @detached: {
+ scope-detached: @variable;
+ } // define detached ruleset
+ }
+}
+
+.importer-2() {
+ @variable: value; // unlocked detached ruleset CAN see this variable
+ #space > .importer-1(); // unlock/import detached ruleset
+}
+
+.use-place {
+ .importer-2(); // unlock/import detached ruleset second time
+ @detached();
+}
+
+.use-place {
+ scope-detached: value;
+}
+
+.foo {
+ background: #900;
+}
+@import "this-is-valid.less";
+
+@import "foo"; // foo.less is imported
+@import "foo.less"; // foo.less is imported
+@import "foo.php"; // foo.php imported as a less file
+@import "foo.css"; // statement left in place, as-is
+
+.navbar:extend(.navbar all) {
+}
+
+@import (less) "foo.css";
+
+@import (css) "foo.less";
+
+@import "foo.less";
+
+@import (once) "foo.less";
+@import (once) "foo.less"; // this statement will be ignored
+
+// file: foo.less
+.a {
+ color: green;
+}
+// file: main.less
+@import (multiple) "foo.less";
+@import (multiple) "foo.less";
+
+.a {
+ color: green;
+}
+.a {
+ color: green;
+}
+
+.mixin (@a) when (lightness(@a) >= 50%) {
+ background-color: black;
+}
+.mixin (@a) when (lightness(@a) < 50%) {
+ background-color: white;
+}
+.mixin (@a) {
+ color: @a;
+}
+
+.class1 {
+ .mixin(#ddd);
+}
+.class2 {
+ .mixin(#555);
+}
+
+.class1 {
+ background-color: black;
+ color: #ddd;
+}
+.class2 {
+ background-color: white;
+ color: #555;
+}
+
+.truth (@a) when (@a) {
+ /* ... */
+}
+.truth (@a) when (@a = true) {
+ /* ... */
+}
+
+.class {
+ .truth(40); // Will not match any of the above definitions.
+}
+
+@media: mobile;
+
+.mixin (@a) when (@media = mobile) {
+ /* ... */
+}
+.mixin (@a) when (@media = desktop) {
+ /* ... */
+}
+
+.max (@a; @b) when (@a > @b) {
+ width: @a;
+}
+.max (@a; @b) when (@a < @b) {
+ width: @b;
+}
+
+.mixin (@a) when (isnumber(@a)) and (@a > 0) {
+ /* ... */
+}
+
+.mixin (@a) when (@a > 10), (@a < -10) {
+ /* ... */
+}
+
+.mixin (@b) when not (@b > 0) {
+ /* ... */
+}
+
+.mixin (@a; @b: 0) when (isnumber(@b)) {
+ /* ... */
+}
+.mixin (@a; @b: black) when (iscolor(@b)) {
+ /* ... */
+}
+
+.mixin (@a) when (@a > 0) {
+ /* ... */
+}
+.mixin (@a) when (default()) {
+ /* ... */
+} // matches only if first mixin does not, i.e. when @a <= 0
+
+.my-optional-style() when (@my-option = true) {
+ button {
+ color: white;
+ }
+}
+.my-optional-style();
+
+button when (@my-option = true) {
+ color: white;
+}
+
+& when (@my-option = true) {
+ button {
+ color: white;
+ }
+ a {
+ color: blue;
+ }
+}
+
+.loop(@counter) when (@counter > 0) {
+ .loop((@counter - 1)); // next iteration
+ width: (10px * @counter); // code for each iteration
+}
+
+div {
+ .loop(5); // launch the loop
+}
+
+div {
+ width: 10px;
+ width: 20px;
+ width: 30px;
+ width: 40px;
+ width: 50px;
+}
+
+.generate-columns(4);
+
+.generate-columns(@n, @i: 1) when (@i =< @n) {
+ .column-@{i} {
+ width: (@i * 100% / @n);
+ }
+ .generate-columns(@n, (@i + 1));
+}
+
+.column-1 {
+ width: 25%;
+}
+.column-2 {
+ width: 50%;
+}
+.column-3 {
+ width: 75%;
+}
+.column-4 {
+ width: 100%;
+}
+
+.mixin() {
+ box-shadow+: inset 0 0 10px #555;
+}
+.myclass {
+ .mixin();
+ box-shadow+: 0 0 20px black;
+}
+
+.myclass {
+ box-shadow: inset 0 0 10px #555, 0 0 20px black;
+}
+
+.mixin() {
+ transform+_: scale(2);
+}
+.myclass {
+ .mixin();
+ transform+_: rotate(15deg);
+}
+
+.myclass {
+ transform: scale(2) rotate(15deg);
+}
+
+a {
+ color: blue;
+ &:hover {
+ color: green;
+ }
+}
+
+a {
+ color: blue;
+}
+
+a:hover {
+ color: green;
+}
+
+.button {
+ &-ok {
+ background-image: url("ok.png");
+ }
+ &-cancel {
+ background-image: url("cancel.png");
+ }
+
+ &-custom {
+ background-image: url("custom.png");
+ }
+}
+
+.button-ok {
+ background-image: url("ok.png");
+}
+.button-cancel {
+ background-image: url("cancel.png");
+}
+.button-custom {
+ background-image: url("custom.png");
+}
+
+.link {
+ & + & {
+ color: red;
+ }
+
+ & & {
+ color: green;
+ }
+
+ && {
+ color: blue;
+ }
+
+ &,
+ &ish {
+ color: cyan;
+ }
+}
+
+.link + .link {
+ color: red;
+}
+.link .link {
+ color: green;
+}
+.link.link {
+ color: blue;
+}
+.link,
+.linkish {
+ color: cyan;
+}
+
+.grand {
+ .parent {
+ & > & {
+ color: red;
+ }
+
+ & & {
+ color: green;
+ }
+
+ && {
+ color: blue;
+ }
+
+ &,
+ &ish {
+ color: cyan;
+ }
+ }
+}
+
+.grand .parent > .grand .parent {
+ color: red;
+}
+.grand .parent .grand .parent {
+ color: green;
+}
+.grand .parent.grand .parent {
+ color: blue;
+}
+.grand .parent,
+.grand .parentish {
+ color: cyan;
+}
+
+.header {
+ .menu {
+ border-radius: 5px;
+ .no-borderradius & {
+ background-image: url("images/button-background.png");
+ }
+ }
+}
+
+.header .menu {
+ border-radius: 5px;
+}
+.no-borderradius .header .menu {
+ background-image: url("images/button-background.png");
+}
+
+p,
+a,
+ul,
+li {
+ border-top: 2px dotted #366;
+ & + & {
+ border-top: 0;
+ }
+}
+
+p,
+a,
+ul,
+li {
+ border-top: 2px dotted #366;
+}
+p + p,
+p + a,
+p + ul,
+p + li,
+a + p,
+a + a,
+a + ul,
+a + li,
+ul + p,
+ul + a,
+ul + ul,
+ul + li,
+li + p,
+li + a,
+li + ul,
+li + li {
+ border-top: 0;
+}
+
+`;
diff --git a/tests/css_less/jsfmt.spec.js b/tests/css_less/jsfmt.spec.js
new file mode 100644
index 000000000..7d3726c81
--- /dev/null
+++ b/tests/css_less/jsfmt.spec.js
@@ -0,0 +1 @@
+run_spec(__dirname, ["css"]);
diff --git a/tests/css_less_docs/less_docs.css b/tests/css_less/less.css
similarity index 96%
rename from tests/css_less_docs/less_docs.css
rename to tests/css_less/less.css
index 0229682bd..30f9d9311 100644
--- a/tests/css_less_docs/less_docs.css
+++ b/tests/css_less/less.css
@@ -159,8 +159,8 @@ background-color: #112244 + #111; // result is #223355
background-color: white
}
}
- .tab { ... }
- .citation { ... }
+ .tab { /* ... */ }
+ .citation { /* ... */ }
}
@@ -663,9 +663,6 @@ link:hover:visited {
}
-Bear
-
-
.animal {
background-color: black;
color: white;
@@ -674,10 +671,6 @@ link:hover:visited {
background-color: brown;
}
-
-Bear
-
-
.animal {
background-color: black;
color: white;
@@ -981,11 +974,11 @@ pre {
}
-.mixin(...) {} // matches 0-N arguments
+.mixin(/* ... */) {} // matches 0-N arguments
.mixin() {} // matches exactly 0 arguments
.mixin(@a: 1) {} // matches 0-1 arguments
-.mixin(@a: 1; ...) {} // matches 0-N arguments
-.mixin(@a; ...) {} // matches 1-N arguments
+.mixin(@a: 1; /* ... */) {} // matches 0-N arguments
+.mixin(@a; /* ... */) {} // matches 1-N arguments
.mixin(@a; @rest...) {
@@ -994,7 +987,7 @@ pre {
}
-.mixin(@s; @color) { ... }
+.mixin(@s; @color) { /* ... */ }
.class {
.mixin(@switch; #888);
@@ -1345,8 +1338,8 @@ ERROR 1:32 The variable "@one" was not declared.
}
-.truth (@a) when (@a) { ... }
-.truth (@a) when (@a = true) { ... }
+.truth (@a) when (@a) { /* ... */ }
+.truth (@a) when (@a = true) { /* ... */ }
.class {
@@ -1356,28 +1349,28 @@ ERROR 1:32 The variable "@one" was not declared.
@media: mobile;
-.mixin (@a) when (@media = mobile) { ... }
-.mixin (@a) when (@media = desktop) { ... }
+.mixin (@a) when (@media = mobile) { /* ... */ }
+.mixin (@a) when (@media = desktop) { /* ... */ }
.max (@a; @b) when (@a > @b) { width: @a }
.max (@a; @b) when (@a < @b) { width: @b }
-.mixin (@a) when (isnumber(@a)) and (@a > 0) { ... }
+.mixin (@a) when (isnumber(@a)) and (@a > 0) { /* ... */ }
-.mixin (@a) when (@a > 10), (@a < -10) { ... }
+.mixin (@a) when (@a > 10), (@a < -10) { /* ... */ }
-.mixin (@b) when not (@b > 0) { ... }
+.mixin (@b) when not (@b > 0) { /* ... */ }
-.mixin (@a; @b: 0) when (isnumber(@b)) { ... }
-.mixin (@a; @b: black) when (iscolor(@b)) { ... }
+.mixin (@a; @b: 0) when (isnumber(@b)) { /* ... */ }
+.mixin (@a; @b: black) when (iscolor(@b)) { /* ... */ }
-.mixin (@a) when (@a > 0) { ... }
-.mixin (@a) when (default()) { ... } // matches only if first mixin does not, i.e. when @a <= 0
+.mixin (@a) when (@a > 0) { /* ... */ }
+.mixin (@a) when (default()) { /* ... */ } // matches only if first mixin does not, i.e. when @a <= 0
.my-optional-style() when (@my-option = true) {