LESS

css-frameworks

Articles
Resources

What is LESS?

LESS is a CSS pre-processor.

What are some of LESS' features?

  • nested declaration
  • variables
  • mixins
  • operations
  • color functions

Why should we use LESS?

I NEED TO COMPLETE THIS.

Why should we not use LESS?

I NEED TO COMPLETE THIS.

How can we install less?

npm install -g less@beta
npm install -g less

How can we convert .less file into .css file?

lessc style.less > styles.css

How can we convert .less file into .css file with compression and minification?

lessc style.less -x --yui-compress > style.csss

How can we define a variable?

Variables starts with @:

@color: #4D926F;

#header {
    color: @color;
}

Do we have to define a variable before using it?

No. Variables are lazy-loaded and do not have to be declared before being used. These are valid:

lazy-eval {
    width: @var;
}

@var: @a;
@a: 9%;

How can we define variables that reference another variable?

It is possible to define variables with a variable name:

@fnord: "I am fnord.";
@var: 'fnord';
content: @@var;  // which compiles to content: "I am fnord."

How can we implement string interpolation?

Variables can be embedded inside strings (similar to Ruby or PHP) using the @{name} construct:

@base-url: "http://assets.fnord.com";
background-image: url("@{base-url}/images/bg.png");

How can we implement selector interpolation?

String interpolation also works on selector. If you want to use LESS variables inside selectors, you can:

@name: blocked;
.@{name} {
    color: black;
}

will produce:

.blocked {
    color: black;
}

How can we implement string escaping?

Sometimes we need to output a CSS value which is either not valid CSS syntax or uses proprietary syntax (Microsoft IE) which LESS do not understand. To output such value, place it inside a string prefixed with ~. For example:

.class {
    filter: ~"ms:alwaysHasItOwnSyntax.For.Stuff()";
}

will produce:

.class {
    filter: ms:alwaysHasItOwnSyntax.For.Stuff();
}

This is called an "escaped value". Escaped values can use the interpolation exactly the same way as strings:

.class {
    @what: "Stuff";
    filter: ~"ms:alwaysHasItOwnSyntax.For.@{what}()";
}

How can we use less variables inside media queries?

If you want to use LESS variables inside media, you can do this using the usual variable referencing syntax. For example:

@singleQuery: ~"(max-width: 500px)";
@media screen, @singleQuery {
    set {
        padding: 3;
    }
}

will produce:

@media screen, (max-width: 500px) {
    set {
        padding: 3;
    }
}

The variable must contain whole media query. In v1.4.0, without strict maths off, you can also include variables in media values, such as:

@media screen, (max-width: @width) { ... }

What is a mixin?

Mixins allow you to embed the properties of a CSS class into another CSS class by simply including the class name as one of its properties. It is just like variables, but for the whole classes. Mixins can also behave like functions, and take arguments:

.rounded-corners (@radius: 5px) {
    border-radius: @radius;
}

#header {
    .rounded-corners;
}

#footer {
    .rounded-corners(10px);
}

What is a parametric mixin?

Mixins can takes multiple parameters. Parameters are separated by either semicolon or comma. It is recommended to use semicolon, because comma has double meaning: it can be interpreted either as a mixin parameter separator or css list separator. Using comma as a mixin separator makes it impossible to create comma separated lists as an argument. On the other hand, if the compiler sees at least one semicolon inside mixin call or declaration, it assumes that arguments are separated by semicolon and all commas belong to css lists:

  • two arguments, and each contains comma-separated list: .name(1, 2, 3; something, else)
  • three arguments and each contains one number: .name(1, 2, 3)
  • use dummy semicolon to create mixin call with one argument containing comma separated css list: .name(1, 2, 3;)
  • comma separated default value: .name(@param1: red, blue)

Can we define multiple mixins with the same name and number of parameters?

Yes. It is legal to define multiple mixins with the same name and number of parameters. Less will use properties of all that can apply. If you used the mixin with one parameter, then properties of all mixins with exactly one mandatory parameter will be used.

The @arguments variable:

The @arguments varable has a special meaning inside mixins. It contains all the arguments passed, when the mixin was called. This is useful if you don't want to deal with individual parameters:

.box-shadow (@x: 0; @y: 0; @blur: 1px; @color: #000) {
    box-shadow: @arguments;
}

.box-shadow(2px; 5px);

which results in:

box-shadow: 2px 5px 1px #000;

Variable arguments:

You can use … if you want your mixin to take a variable number of arguments. Using this after a variable name will assign those arguments to the variable:

  • .mixin (…) { } // Your mixin can have 0 through N arguments
  • .mixin () { } // Your mixin can have exactly 0 argument
  • .mixin (@a: 1) { } // Your mixin can have 0 or 1 arguments
  • .mixin (@a: 1; …) { } // Your mixin can have 0 through N arguments
  • .mixin (@a; …) { } // Your mixin can have 1 through N arguments

Furthermore:

.mixin (@a; @rest...) {
    // @rest is bound to arguments after @a
    // @arguments is bound to all arguments
}

Pattern-matching and Guarded mixins:

Sometimes we may want to change the behavior of a mixin based on the parameters you pass to it:

.mixin (dark; @color) {
    color: darken(@color, 10%);
}

.mixin (light; @color) {
    color: lighten(@color, 10%);
}

.mixin (@_; @color) {
    display: block;
}

@switch: light;

.class {
    .mixin(@switch; #888);
}

will produce:

.class {
    color: #a2a2a2;
    display: block;
}

It is legal to define multiple mixins with the same name and number of parameters. Less will use properties of all that can apply. If you used the mixin with one parameter, then properties of all mixins with exactly one mandatory parameter will be used.

Notice that the definition of the mixin, the first parameter is a value, and is not a variable (variable starts with @).

Here is what happens:

  • The first mixin definition didn't match because it expected the value dark as the first argument
  • The second mixin definition matched because it expected light
  • The third mixin defintion matched because it expected any value

Only mixin definitions which matched were used. Variables match and bind to any value. Anything other than a variable matches only with a value equal to itself. In the above example, light is not a variable (it doesn't start with @), therefore, it only match the value light.

We can also match on arity. For example:

.mixin (@a) {
    color: @a;
}

.mixin (@a; @b) {
    color: fade(@a; @b);
}

If we call .mixin with a single argument, we will get the output of the first definition, but if we call it with two arguments, we will get the second definitions.

Guards are useful when you want to match on expression, as opposed to simple values or arity:

.mixin (@a) when (lightness(@a) >= 50%) {
    background-color: black;
}
.mixin (@a) when (lightness(@a) < 50%) {
    background-color: white;
}
.mixin (@a) {
    color: @a;
}

The full list of comparison operators usable in guards are: >, >=, =, =<, and <.

The keyword true is the only truthy value. These two mixins are equivalent:

.truth (@a) when (@a) { ... }
.truth (@a) when (@a = true) { ... }

Any value other than the keyword true is falsey. Therefore, .truth(40) will not match any of the above definitions.

Guards can be separated with a comma. If any of the conditions evaluated to true, it's considered as a match:

.mixin (@a) when (@a > 10), (@a < - 10) { ... }

Notice that we can compare arguments with each other, or with non-arguments:

@media: mobile;

.mixin (@a) when (@media = mobile) { ... }
.mixin (@a) when (@media = desktop) { ... }

.max (@a; @b) when (@a > @b) { ... }
.max (@a; @b) when (@a < @b) { ... }

We can also match mixins based on value type by using the is* function:

.mixin (@a; @b: 0) when (isnumber(@b)) { ... }
.mixin (@a; @b: black) when (iscolor(@b)) { ... }

The available is* functions are: iscolor, isnumber, isstring, iskeyword, isurl. If you wan to check if a value, in addition to being an umber, is in specific unit, you can use one of ispixel, ispercentage, isem.

We can also use the and keyword:

.mixin (@a) when (isnumber(@a)) and (@a > 0) { ... }

and the not keyword to negate conditions:

.mixin (@b) when not (@b > 0) { ... }

The !important keyword:

Use the !important keyword after a mixin call will mark all properties brought by it as !important.

Nested Rules:

#header {
    h1 {
        font-size: 26px;
        font-weight: bold;
    }
    p {
        font-size: 12px;
        a {
            text-decoration: none;
            &:hover {
                border-width: 1px;
            }
        }
    }
}

Nested Media Queries:

.one {
    @media (width: 400px) {
        font-size: 1.2em;
        @media print and color {
            color: blue;
        }
    }
}

will output:

@media (width: 400px) {
    .one {
        font-size: 1.2em;
    }
}

@media (width: 400px) and print and color {
    .one {
        color: blue;
    }
}

Functions & Operations:

Operations let you add, substract, divide, and multiply property values and colors. Operations should be performed within parentheses. Functions map one-to-one with JavaScript code allowing you to manipulate values however you want.

@the-border: 1px;
@base-color: #111;
@red: #842210;

#header {
    color: (@base-color * 3);
    border-left: @the-border;
    border-right: (@the-border * 2);
}

#footer {
    color: (@base-color + #003300);
    border-color: desaturate(@red, 10%);
}

Namespaces:

Sometimes you may want to group your variable or mixins for organizational purposes, or just to offer some encapsulation. For example, you want to bundle your mixins and variables under #bundle for later re-use, you can:

#bundle {
    .button () {
        display: block;
        border: 1px solid black;
        background-color: grey;
        &:hover {
            background-color: white;
        }
    }
    .tab { ... }
    .citation { ... }
}

Now, if we want to use the .button mixin in our "#header a", we can:

#header a {
    color: orange;
    #bundle > .button;
{

Importing:

You can import both CSS and LESS files. Only LESS files import statements are processed. If you want to import a CSS file, and do not want LESS to process it, just use the .css extension:

@import "lib.css";

LESS file import can be placed inside rulesets, mixins, or other LESS structures. For example:

pre {
    @import "library.less";
    color: @importedColor;
}

which output:

pre {
    color: #ff0000;  // Variable defined in library.less was available
}

pre h1 { // ruleset defined in library.less was nested into 'pre' ruleset
    color: green;
}

Top-level imports (import statements that do not appear inside any ruleset or any LESS structure) are automatically moved to the top, right after @charset declarations.

Content of imported LESS file is copied into importing style sheet and compiled together with it. Importing and imported files share all mixins, namespaces, variables and other structures. Additionall, if the import statement has media queries specified in it, imported content is enclosed in the @media declaration. For example:

// library.less
@imported-color: red;
h1 { color: green; }

// Main file imports library.less
@import "library.less" screen and (max-width: 400px); // import with media query
@import "library.less"; // import without media query

.class {
    color: @importedColor;  // use imported variable
}

will produce:

// Corresponds to import with media queries
@media screen and (max-width: 400px) {
    h1 { color: green; }
}

// Corresponds to import without media queries
h1 { color: green; }
.class {
    color: #ff0000;
}

Any file that does not end with .css is considered as LESS file and is processed. If the file name has no extension or parameters, the ".less" suffix is added on the end. Both of these are equivalent:

@import "lib.less";
@import "lib";

In v1.4.0, you can force a file to be interpreted as a particular type by specifying an option:

@import (css) "lib";
@import (less) "lib";
@import (less) "lib.css";

JavaScript Evaluation:

JavaScript expressions can be evaluated as values inside LESS files. However, this should be avoided because the LESS file will not be compilable by ports and make LESS harder to maintain. If possible, try to think of a function that can be added to achieve the same purpose and ask for it on github. The LESS team has plans to allow expanding the default functions available. However, if you still want to use JavaScript in LESS file, this can be done by wrapping the expression inside back-ticks:

@var: `"hello".toUpperCase() + "!"`;

will produce:

@var: "HELLO!";

You may also use interpolation and escaping as with strings:

@str: "hello";
@var: ~`"@{str}".toUpperCase() + "!"`;

will produce:

@var: "HELLO!";
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License