Skip to content

Less Language Operations

Mária Jurčovičová edited this page Sep 14, 2015 · 11 revisions

Operations

Less language supports four arithmetical operations plus '+', minus '-', multiplication '*', division '/' and parentheses '(' ')'. Operations are evaluated in usual order:

  • parentheses are evaluated first,
  • multiplication/division takes precedence over addition and subtraction,
  • non commutative operations are evaluated from left to right.

Only operations on numbers and colors are supported. Operations on strings, identifiers or anything else are not.

Units

Numbers in CSS can have specified units: 21px 14cm 4.56%. If it is possible, mathematical operations take units into account and convert numbers before adding, subtracting or comparing them. If the conversion is impossible or not meaningful, the numbers are taken as they are. The result has leftmost explicitly stated unit type.

Example of impossible conversion: px to cm or rad to %.

Multiplication and division do not convert numbers. It would not be meaningful in most cases - a length multiplied by a length gives an area and css does not support specifying areas. Less will operate on numbers as they are and assign explicitly stated unit type to the result.

Example - conversion:

  • Input: property: 2cm + 10mm
  • Output: property: 3cm
  • Input: property: 2 - 3cm - 5mm
  • Output: property: -1.5cm

Example - incompatible units:

  • Input: property: 2 + 5px - 3cm
  • Output: property: 4px
  • Input: property: (2 + 5px) - 3%
  • Output: property: 4px

Example - not meaningful:

  • Input: property: 2cm * 3mm
  • Output: property: 6cm

Colors

Colors are split into their red, green, blue and alpha dimensions. The operation is applied to each color dimension separately. E.g., if the user added two colors, then the green dimension of the result is equal to sum of green dimensions of input colors. The same goes for red and blue dimensions.

Alpha is treated differently. No matter what the operations is, colors alphas are always added together.

Example:

  • Input: color: #112233 + #010203;
  • Output: color: #122436;

Example with alpha:

  • Input: color: rgba(4, 5, 6, 0.2) - rgba(1, 2, 3, 0.1);
  • Output: color: rgba(3, 3, 3, 0.30000000000000004); // the rounding error in the end is the same as less.js has and unimportant

An operation on two colors always produces valid color. If some color dimension of the result ends up being bigger than 'ff' or smaller than '00', the dimension is rounded to either 'ff' or '00'. If alpha ends up being bigger than '1.0' or smaller than '0.0', the alpha is rounded to either '1.0' or '0.0'.

Example:

  • Input1: color: #fe01fe + #040404;;
  • Output1: color: #ff05ff;
  • Input2: color: #01fe01 - #040404;
  • Output2: color: #00fa00;
  • Input3: color: rgba(1, 2, 3, 0.9) * rgba(4, 5, 6, 0.8);
  • Output3: color: #040a12; // 0.9+0.8=1.7 It is then rounded to 1 which is the same as no alpha.

An operation between color and number results in color too. Similarly to the previous case, the number is applied to each dimension separately. The only exception is alpha. No matter what number and what operations, the results is always no alpha (e.g. alpha=1). Operations between colors and numbers have two limitations: it is impossible to subtract a color from the number and it is impossible to divide a number by a color.

Example:

  • Input: color: #112233 + 4;
  • Output: color: #152637;

Example with alpha:

  • Input: color: rgba(4, 5, 6, 0.2) + 0.6;
  • Output: color: #050607; // alpha resulted in 1

Incorrect Less:

  • Input: color: 4 - #112233;
  • Output: color: 4 / #112233;

The result of division by 0 is always 'ff':

Example:

  • Input1: color: #112233 / #000100;
  • Output1: color: #ff22ff;
  • Input2: color: #112233 / 0;
  • Output2: color: #ffffff;

Empty Separator and Whitespaces

Important: the content of this chapter will not be valid after less.js 1.4.0 comes out. Expressions in that language version are going to be treated in cleaner, but backward incompatible way.

Less language allows spaces inside mathematical expressions and those spaces are considered insignificant: this 10 - 5 is equivalent to 10-5.

This is very reasonable feature, but it has an unfortunate conflict with CSS separators. CSS allows spaces as separators - this is called an empty separator. For example, following declaration uses an empty separator: declaration: 10 23;. CSS allows also negative numbers as parameters and valid declaration can contain two negative numbers separated by an empty separator 10 -5.

The result is an ambiguity: a space can either represent a separator or can be just an unimportant part of the expression. Less4j solves this ambiguity in following way: a space before minus '-' represents an empty separator only if:

  • does not follow arithmetical operator 10+<not a separtor>-5,
  • is followed by minus '-',
  • that minus is not followed by another space.

Note: there is slight subtle difference between less4j and less.js handling of the space around unary minus. This difference will be dealt with in the future, see: TODO link the associated issue


selector {
  declaration: 10 - -5;//not an unary operator - compiles into "declaration: 15"
  declaration: 10 - 5;//space after '-' - compiles into "declaration: 5"
  declaration: 10- 5;//space after '-' - compiles into "declaration: 5"
  declaration: 10-5;//no space anywhere - compiles into "declaration: 5"
  declaration: 10 -5;//element space operator element no - it is an empty separator and compiles into "declaration: 10 -5"
}

Important: the same rules apply for expressions in parentheses. This may lead to unintuitive results and compile errors. The example of unintuitive result is the something: (12 (13 + 10 -23)) declaration. The space before '-' is interpreted as a separator and the expression compiles into a list of three numbers something: 12 23 -23.

Compile errors happen when user tries to perform an operation over a parentheses with a list. For example, ((13 -23) + 12) is parsed as "the list of two numbers (13 -23) plus 12". This causes compilation errors, because arithmetic operators can act only on numbers.

The above expression can be fixed either by

  • adding a space between '-' and 23 e.g., ((13 - 23) + 12),
  • removing space before '-' e.g., ((13-23) + 12).

It is possible that less.js will change this behavior in the future. Related issue and discussion on the topic: https://github.com/cloudhead/less.js/issues/952 . However, even if it changes, the space as a separator vs meaningless space ambiguity will remain in top-level expressions (those without parentheses).

Ignored In

As the font property can contain a ratio font: 12pt/14pt sans-serif, math expressions following the font property are not evaluated. Note: less4j implementation may remove some whitespaces from the font declarations. If it turns out to be a problem, we will fix it.

The same holds for aspect-ratio and device-aspect-ratio media features. As they can contain ratio, ratio expressions in them are ignored.

List of all properties and media features with ignored expressions:

  • font,
  • aspect-ratio,
  • device-aspect-ratio,
  • min-aspect-ratio,
  • max-aspect-ratio,
  • min-device-aspect-ratio,
  • max-device-aspect-ratio.

The following input remains unchanged by the translation:

@media (max-aspect-ratio: 58/80) {
  property: 3em;
}
selector {
  font: 12px/16px Arial;
}