LESS - Documentation

What is LESS?

LESS (Leaner Style Sheets) is a dynamic stylesheet language that extends CSS with features like variables, mixins, functions, and more. It’s a preprocessor, meaning that LESS code is compiled into regular CSS that can be used by web browsers. This allows developers to write more maintainable, organized, and reusable CSS. LESS files typically have the .less extension.

Why use LESS?

LESS offers several key advantages over writing CSS directly:

LESS vs. CSS

Feature LESS CSS
Variables Supported Not supported
Mixins Supported Not supported
Functions Supported Not supported
Nesting Supported (simplifies selectors) Not supported
Operators Supported (mathematical, logical) Limited (mostly concatenation)
Compilation Requires a preprocessor No preprocessing needed
Browser Support Requires compilation to CSS first Directly supported by browsers

Setting up LESS

Setting up LESS typically involves installing a compiler and potentially integrating it into your workflow. Popular options for compiling LESS include:

Running LESS

After setting up LESS, you run it to compile your .less files into .css files. The specific method will depend on the compiler and setup you chose. Common methods include:

Remember to include the compiled CSS file (.css) in your HTML to apply the styles to your webpage.

Variables

Declaring variables

LESS variables provide a way to store and reuse values throughout your stylesheets. They’re declared using the @ symbol followed by the variable name and a colon, then the value. Variable names are typically written in lowercase with words separated by hyphens (e.g., @base-color).

@base-color: #f00;  // Declares a variable named @base-color with the value #f00 (red)
@font-size: 16px; // Declares a variable named @font-size with the value 16px
@spacing: 10px;

You can assign various CSS values to variables, including colors, lengths, font sizes, and more.

Using variables

Once a variable is declared, you can use it anywhere in your LESS code where you would normally use a CSS value. LESS will substitute the variable’s value during compilation.

body {
  color: @base-color;  // Uses the @base-color variable
  font-size: @font-size;
  margin: @spacing;
}

h1 {
  color: @base-color;
  font-size: @font-size * 2; // You can perform calculations with variables
}

This will compile to CSS where @base-color and @font-size are replaced with their respective values.

Variable scope

Variable scope in LESS determines where a variable is accessible. Variables declared within a block (e.g., inside a rule set) are only accessible within that block. Variables declared outside any block (global variables) are accessible throughout the entire LESS file.

@global-color: #00f; // Global variable

.class1 {
  @local-color: #0f0; // Local variable, only accessible within .class1
  color: @local-color;
  background-color: @global-color; // Accessing the global variable
}

.class2 {
    color: @global-color; // Accessing the global variable
    // @local-color is not accessible here
}

If a local variable has the same name as a global variable, the local variable takes precedence within its scope.

Variable interpolation

Variable interpolation allows you to embed the value of a variable within a string using the ~"" syntax (or ~'...' for single quotes). This is particularly useful for creating dynamic class names or selectors.

@prefix: "my-";
@suffix: "element";

.@{prefix}@{suffix} { // Interpolation to create a dynamic class name "my-element"
  width: 100px;
}

.some-other-class @{prefix}@{suffix} {
    color: blue;
}

This example uses variable interpolation to generate the class name my-element dynamically from the @prefix and @suffix variables. The resulting CSS will contain the .my-element class.

Mixins

Defining mixins

Mixins in LESS allow you to encapsulate reusable blocks of CSS code. They’re defined using the .mixin-name() syntax, where mixin-name is the name you choose for your mixin. The code within the mixin is enclosed in curly braces {}.

.border-radius(@radius) {
  -webkit-border-radius: @radius;
  -moz-border-radius: @radius;
  border-radius: @radius;
}

This defines a mixin named border-radius that takes a radius argument. It applies the border-radius property with vendor prefixes for cross-browser compatibility.

Calling mixins

To use (or “call”) a mixin, you use the + symbol followed by the mixin name and its arguments (if any), within a CSS rule set.

#my-element {
  +border-radius(5px);  // Calls the border-radius mixin with a 5px radius
}

.my-other-element {
    +border-radius(10px);
}

This will result in the border-radius properties being applied to both #my-element and .my-other-element.

Mixins with arguments

Mixins can accept arguments, allowing you to customize their behavior. Arguments are defined within the parentheses of the mixin definition and used within the mixin’s body.

.box-shadow(@horizontal, @vertical, @blur, @color) {
  -webkit-box-shadow: @horizontal @vertical @blur @color;
  -moz-box-shadow: @horizontal @vertical @blur @color;
  box-shadow: @horizontal @vertical @blur @color;
}

#my-element {
  +box-shadow(2px, 2px, 5px, #888);
}

Named arguments

For mixins with multiple arguments, you can use named arguments to improve readability and reduce the chance of errors. Named arguments are specified within the mixin call using the @argument-name: syntax.

.button-style(@padding: 10px, @background-color: #444, @color: white) {
  padding: @padding;
  background-color: @background-color;
  color: @color;
}

.my-button {
  +button-style(@background-color: blue, @padding: 15px); // Using named arguments
}

Here, only @background-color and @padding are explicitly set; @color will use its default value (white).

Default values for arguments

You can provide default values for mixin arguments. If a value isn’t passed when calling the mixin, the default value is used.

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

.element1 { +rounded-corners(); } // Uses default 5px radius
.element2 { +rounded-corners(10px); } // Uses 10px radius

Mixins and variable scope

Variables declared within a mixin are local to that mixin and are not accessible outside of it. However, variables declared outside the mixin are accessible inside the mixin.

@global-color: blue;

.my-mixin() {
  @local-color: red;
  color: @local-color;  // Accesses local variable
  background-color: @global-color; // Accesses global variable
}

.my-element {
  +my-mixin();
  // @local-color is not accessible here
}

Local variables within a mixin help prevent naming conflicts and maintain better organization.

Functions

Built-in functions

LESS provides a number of built-in functions for manipulating values, such as colors, strings, and numbers. These functions simplify common tasks and improve code readability. Some examples include:

For a comprehensive list and detailed documentation of built-in functions, refer to the official LESS documentation.

User-defined functions

LESS allows you to define your own custom functions to encapsulate reusable logic. User-defined functions are defined using the @function keyword followed by the function name, parameters, and a body enclosed in curly braces. The @return keyword specifies the value returned by the function.

@function calculate-width(@width, @padding) {
  @result: @width + (@padding * 2);
  @return @result;
}

#element {
  width: calculate-width(100px, 10px); //Calls the function.
}

This defines a function calculate-width which takes width and padding as arguments and returns the calculated total width.

Function arguments

Function arguments are similar to mixin arguments. They are defined within the parentheses of the function declaration and used within the function’s body. You can use named arguments for better clarity and maintainability, especially with multiple arguments.

@function create-box-shadow(@horizontal: 0, @vertical: 2px, @blur: 5px, @color: #888) {
  @return ~"(~`@horizontal`px ~`@vertical`px ~`@blur`px ~`@color`)";
}

#element {
  box-shadow: create-box-shadow(); // Uses default values
  box-shadow: create-box-shadow(@color: #000); //Override color
}

Returning values from functions

Functions use the @return keyword to specify the value that should be returned to the caller. The returned value can be any valid LESS expression, such as a number, color, string, or list.

@function add(@a, @b) {
  @return @a + @b;
}

@function string-concat(@str1, @str2) {
  @return ~"@{str1}@{str2}"; //string interpolation
}

#element {
  width: add(10px, 20px);  // Returns 30px
  height: string-concat("prefix-", "suffix"); // Returns "prefix-suffix"
}

Remember that the return value should be a valid CSS value or something that can be seamlessly integrated into CSS. The ~"" (string interpolation) is very useful when returning strings to correctly handle spacing and other special characters.

Operators

LESS supports various operators for performing calculations and comparisons within your stylesheets.

Arithmetic operators

LESS provides standard arithmetic operators for numerical calculations.

Operator Description Example Result
+ Addition 10px + 5px 15px
- Subtraction 20px - 5px 15px
* Multiplication 5px * 2 10px
/ Division 10px / 2 5px
% Modulus (remainder) 11 % 5 1

Note that units are automatically handled in addition and subtraction operations, while multiplication and division require consistent units for predictable results.

Logical operators

Logical operators allow for conditional evaluations.

Operator Description Example Result (if @x is 10 and @y is 20)
and Logical AND @x > 5 and @y > 15 true
or Logical OR @x < 5 or @y > 15 true
not Logical NOT not (@x > 5) false

These operators return either true or false, which can be used within conditional statements (discussed later).

Comparison operators

Comparison operators are used to compare values.

Operator Description Example Result (if @x is 10)
= Equal to @x = 10 true
!= Not equal to @x != 10 false
> Greater than @x > 5 true
< Less than @x < 15 true
>= Greater than or equal @x >= 10 true
<= Less than or equal @x <= 10 true

These also return boolean true or false values.

String operators

The primary string operator in LESS is concatenation using the + operator.

@prefix: "my-";
@suffix: "element";
@className: @prefix + @suffix; // Results in "my-element"

.@{className} {
  width: 100px;
}

String interpolation (~"" or ~'') is used to embed variable values within strings, and is not strictly a string operator but a crucial technique related to string manipulation. More sophisticated string manipulation would generally require user-defined functions.

Nested Rules

Nesting selectors

LESS allows you to nest CSS selectors, making your stylesheets more organized and easier to read. Nested selectors create a hierarchical structure that mirrors the HTML structure they style. A nested selector is simply placed inside another selector’s block.

#header {
  background-color: #f0f0f0;
  h1 {
    color: #333;
    font-size: 2em;
  }
  p {
    font-size: 1em;
    line-height: 1.5;
  }
}

.navigation {
  ul {
    list-style: none;
    li {
      display: inline-block;
      a {
        color: blue;
        text-decoration: none;
      }
    }
  }
}

This LESS code will compile into CSS with the selectors correctly combined (e.g., #header h1, .navigation ul li a).

Advantages of nesting

Nesting offers several benefits:

Best practices for nesting

While nesting enhances readability, excessive nesting can make the code difficult to understand and maintain. Here are some best practices:

By adhering to these guidelines, you can leverage the benefits of LESS nesting while avoiding potential drawbacks.

Selectors

LESS supports a wide range of CSS selectors, allowing you to target specific HTML elements with your styles. The selectors in LESS are largely identical to those in standard CSS, offering the same specificity and functionality.

Basic selectors

Basic selectors target elements based on their tag name, class, or ID.

Combinators

Combinators define the relationship between selectors.

Pseudo-classes

Pseudo-classes modify the selection of elements based on their state or position.

Many other pseudo-classes exist, offering fine-grained control over element selection.

Pseudo-elements

Pseudo-elements create additional elements that are not part of the HTML structure.

These are often used for styling purposes like adding icons or decorative elements. Note the double colon (::) is the modern standard.

Attribute selectors

Attribute selectors target elements based on their attributes.

LESS supports all standard CSS attribute selectors providing precise targeting capabilities. Remember to escape special characters within attribute values as necessary.

Extends

Extending selectors

The @extend directive in LESS allows you to reuse existing styles by extending one selector with another. This is different from mixins; @extend actually inlines the styles from the extended selector into the extending selector during compilation, creating a more efficient CSS output than using mixins for the same purpose. However, overuse can negatively impact CSS specificity and maintainability.

.button {
  padding: 10px 20px;
  border: 1px solid #ccc;
}

.primary-button {
  @extend .button;
  background-color: #444;
  color: white;
}

This code will generate CSS where .primary-button inherits all the styles of .button without creating separate rules. It results in a single CSS rule set containing all the properties for .primary-button.

Extending multiple selectors

A single selector can extend multiple selectors.

.base-style {
  font-size: 16px;
  line-height: 1.5;
}

.paragraph-style {
  @extend .base-style;
  text-align: justify;
}

.link-style {
  @extend .base-style;
  color: blue;
}

Here, both .paragraph-style and .link-style inherit the styles of .base-style.

Extends and inheritance

@extend is a powerful tool for inheritance in LESS, but it differs significantly from traditional CSS inheritance. While CSS inheritance involves properties cascading down the element tree from parent to child, @extend in LESS works by replacing the extending selector entirely with the extended styles during compilation. This means the extending selector is effectively removed as an independent entity.

Important Considerations:

Best Practice: Use @extend judiciously for simple inheritance scenarios where a selector needs to inherit a small set of properties from another. For more complex reusability, favor mixins. Avoid using @extend on selectors that use pseudo-classes or pseudo-elements as this can lead to unintended consequences with specificity.

Importing Files

LESS allows you to import other LESS files into your main stylesheet, promoting modularity and organization.

Using @import

The @import directive is used to import external LESS files. It’s placed at the top level of your LESS file, outside any rulesets.

@import "variables.less";
@import "mixins.less";
@import "buttons.less";
@import "typography.less";

This imports four separate LESS files: variables.less, mixins.less, buttons.less, and typography.less. The content of these files will be incorporated into the main stylesheet during compilation.

File paths

The @import statement usually takes a file path as an argument. The path can be relative to the location of the main LESS file or an absolute path. LESS will resolve these paths during compilation to locate and import the specified files.

Import order

The order in which you import files matters. LESS processes imports sequentially. Variables and mixins defined in an earlier import will be available to later imports. Organize your imports to ensure dependencies are resolved correctly. For example, if buttons.less uses variables defined in variables.less, you need to import variables.less before buttons.less.

Using relative and absolute paths

Important Note: The @import directive in LESS functions differently than in CSS. In LESS, it is preprocessed; it doesn’t generate separate <link> elements for each file in the final CSS output. Instead, all imported content is combined into a single CSS file after compilation. This results in fewer HTTP requests compared to importing multiple CSS files directly in HTML.

Comments

Comments in LESS are used to annotate your code, making it easier to understand and maintain. LESS supports both single-line and multi-line comments. These comments are removed during compilation, so they don’t affect the generated CSS.

Single-line comments

Single-line comments begin with // and extend to the end of the line.

// This is a single-line comment
.my-class {
  color: blue; // This is another single-line comment
}

Multi-line comments

Multi-line comments begin with /* and end with */. They can span multiple lines.

/*
This is a multi-line comment.
It can span multiple lines
and is useful for documenting larger sections of code.
*/

.another-class {
  /* This is a multi-line comment inside a ruleset */
  background-color: red;
}

Both single-line and multi-line comments are ignored by the LESS compiler, and therefore do not appear in the final compiled CSS. Use comments liberally to explain complex logic, document variable usage, or provide context for your styles. Well-commented code is much easier to maintain and understand, especially in larger projects.

Data Types

LESS supports several data types that can be used in variables, functions, and other parts of your stylesheets. Understanding these data types is crucial for writing effective and predictable LESS code.

Numbers

Numbers in LESS represent numerical values. They can be integers (e.g., 10, 255) or floating-point numbers (e.g., 3.14, 10.5). Numbers can optionally include units (e.g., 10px, 2em, 10%). Units are automatically handled by LESS in addition and subtraction operations, but multiplication and division require consistent units.

@width: 100px;
@height: 50%;
@ratio: @width / 2; // Result will be 50px

Strings

Strings in LESS are sequences of characters enclosed in either single quotes ('...') or double quotes ("..."). Strings are used for representing text values, such as font names or URLs. String interpolation, using the ~"" or ~'' syntax, allows embedding the values of variables directly into a string.

@font-family: "Arial", sans-serif;
@url: url('https://example.com/image.jpg');
@greeting: ~"Hello, @{userName}!"; // Interpolation

Colors

Colors in LESS are represented using various notations, such as hexadecimal (#RRGGBB), RGB (rgb(r, g, b)), RGBA (rgba(r, g, b, a)), HSL (hsl(h, s, l)), and HSLA (hsla(h, s, l, a)). LESS provides built-in functions for manipulating colors (e.g., lighten, darken, saturate).

@base-color: #007bff; // Blue
@lighter-color: lighten(@base-color, 20%);
@darker-color: darken(@base-color, 10%);

Lists

Lists in LESS are ordered sequences of values separated by commas and enclosed in parentheses. They are useful for representing multiple values associated with a single property (e.g., multiple background images or box-shadows). List items can be of any data type.

@background-images: url('image1.jpg'), url('image2.png');
@box-shadow: 2px 2px 5px #888, 5px 5px 10px #ccc;

Maps

Maps in LESS are unordered collections of key-value pairs. They are similar to JavaScript objects or dictionaries. Keys are strings (usually enclosed in quotes), and values can be of any data type. Maps are helpful for organizing related styles or options.

@button-styles: (
  primary: #444,
  secondary: #888,
  danger: #f00
);

.button (@type) {
  background-color: @button-styles[@type];
}

.button(primary); // Uses the value associated with "primary" key

Understanding these data types and how they interact with LESS’s features is crucial for building robust and maintainable stylesheets. They allow for a level of abstraction and code reuse that significantly improves the development process.

Control Directives

LESS provides control directives that allow you to write conditional and iterative code within your stylesheets, adding dynamic behavior to your styles.

@if

The @if directive allows you to conditionally include or exclude blocks of code based on a boolean condition.

@is-large-screen: true;

@if @is-large-screen {
  .container {
    width: 1200px;
  }
}

This code will only include the styles for .container if the variable @is-large-screen is true. You can combine multiple conditions using and and or operators.

@else

The @else directive provides an alternative block of code to be executed if the @if condition is false.

@is-dark-mode: false;

@if @is-dark-mode {
  body {
    background-color: #333;
    color: #eee;
  }
} @else {
  body {
    background-color: #eee;
    color: #333;
  }
}

This will apply either the dark mode or light mode styles based on the value of @is-dark-mode. You can also use @elseif for multiple conditional branches.

@for

The @for directive allows you to loop through a range of numbers. It has two forms:

@for @i from 1 through 5 {
  .size-@{i} {
    width: @i * 10px;
  }
}

This will generate styles for .size-1, .size-2, .size-3, .size-4, and .size-5.

@for @i from 1 to 5 {
  .item@{i} {
    margin-left: @i * 5px;
  }
}

Note the difference between through (inclusive of the final number) and to (exclusive).

@each

The @each directive iterates over the items in a list or a map.

@colors: red, green, blue;

@each @color in @colors {
  .box-@{color} {
    background-color: @color;
  }
}
@sizes: (small: 10px, medium: 20px, large: 30px);

@each @name, @size in @sizes {
  .size-@{name} {
    font-size: @size;
  }
}

@while

The @while directive repeats a block of code as long as a given condition is true.

@i: 1;
@max: 5;

@while (@i <= @max) {
    .level@{i} {
        padding-left: @i * 10px;
    }
    @i: @i + 1;
}

Be cautious with @while loops as an infinite loop could cause errors during compilation. Ensure your loop condition will eventually evaluate to false. @for loops are generally safer and often preferred for numerical iteration over @while.

These control directives allow you to add logic and dynamic behavior to your LESS code, enabling more sophisticated stylesheets. Use them judiciously to avoid overly complex stylesheets that may reduce maintainability.

JavaScript Integration

LESS doesn’t directly execute JavaScript code. However, you can leverage JavaScript functions within your LESS files under certain conditions, primarily when using a LESS compiler that supports this feature (such as the Node.js less compiler). This is typically used for more complex calculations or manipulation that are difficult to achieve with just the built-in LESS functions. Directly embedding JavaScript within LESS for client-side compilation with less.js is generally not recommended.

Using JavaScript in LESS

To use JavaScript in LESS, you need a server-side environment or a LESS compiler capable of handling JavaScript expressions. Typically, you would embed JavaScript code within backticks (``). The Javascript expression enclosed in backticks is evaluated by the LESS compiler before the file is compiled to CSS.

@function my-js-function() {
  @result: `var myVar = 10; myVar * 2;`;
  @return @result;
}

.my-class {
  width: my-js-function(); //this passes the Javascript result to a LESS variable
}

This LESS code includes a function which contains a JavaScript expression. The result is passed back to LESS which can then be used as needed. Remember that the JavaScript expression must result in a value that is compatible with LESS. This usually means that the result should be a valid CSS value (e.g., a number, a color, a string, etc.).

Important Considerations:

Accessing JavaScript variables

You can’t directly access JavaScript variables defined outside the LESS file unless you use a custom plugin or a server-side solution that passes data from the JavaScript environment into your LESS compiler’s context. The backtick method described above only allows for Javascript code to be run within the LESS file, not external variables.

In essence, using JavaScript within LESS should be a deliberate choice made only when the functionality cannot be accomplished more cleanly and efficiently using the built-in LESS features. It requires a certain level of familiarity with Javascript and caution to prevent issues. For simple calculations or string manipulations, the built-in LESS functions should always be the preferred option.

Advanced Techniques

This section covers advanced techniques to improve the efficiency and maintainability of your LESS projects.

Creating reusable components

Reusable components are fundamental to maintainable and scalable LESS projects. Here are strategies for creating them:

Managing large LESS projects

As projects grow, management becomes critical:

Optimizing LESS code

Optimizing your LESS code improves performance and reduces the size of the resulting CSS:

Debugging LESS code

Debugging LESS code requires attention:

By combining sound design principles and utilizing advanced tools, you can efficiently manage large-scale LESS projects and create well-optimized, maintainable code.

Best Practices

Following best practices is crucial for writing clean, efficient, and maintainable LESS code. This section outlines key guidelines to help you achieve this.

Code style guidelines

Consistent code style enhances readability and collaboration. Consider adopting the following guidelines:

Maintaining readability

Readability is paramount for long-term maintainability. Here are some tips:

Writing maintainable LESS code

Maintainable LESS code is easy to understand, modify, and extend. These principles are key:

By adhering to these best practices, you’ll create LESS code that is easier to read, maintain, extend, and collaborate on, improving the long-term success of your projects.