-
Notifications
You must be signed in to change notification settings - Fork 47
Differences Between Less.js and Less4j
Less.js does not allow space between unary minus and a number behind it. It produces incorrect CSS in such case. Less4j produces correct - but very different style sheet.
Example Input:
something {
margin: - -2;
margin: - 2 -2 -2 -2;
margin: -1 - 1;
parentheses: 12 - 23;
simple: - 23;
}
Less.js:
inExpression {
margin: - 1- 1- 1- 1;
margin: - 2 -2 -2 -2;
margin: -1 - - 1;
parentheses: (12) (- 23);
simple: - 23;
}
Less4j:
inExpression {
margin: -4;
margin: -2 -2 -2 -2;
margin: 0;
parentheses: 12 -23;
simple: -23;
}
Note: This is considered less4j bug and will be fixed later on. Related issue: https://github.com/SomMeri/less4j/issues/11.
Less.js adds leading 0 to negative floats, Less4j keeps the number as it was. Positive floats behave the same way in both compilers.
- Input:
selector { property : -.3 .3; }
- Less.js output:
selector { property: -0.3 .3; }
- Less4j output:
selector { property: -.3 .3; }
Less.js removes unary '-' from 0, Less4j keeps it there.
Example:
- Input:
selector { property : -0 -0% -0px; }
- Less.js output:
selector { property: 0 0% 0px; }
- Less4j output:
selector { property: -0 -0% -0px; }
Less.js does not accept percentage as a class name. Less4j accepts it.
Illegal in less.js but legal in Less4j:
.12% {
}
Less.js prints the !important keyword as it was in the input. E.g., if the input contained "! important", less.js prints it as "! important" . If the input contained "!important", less.js leaves it that way. Less.js also puts an empty space before the important keyword only if it was there in the input.
Less4j always puts a space before it and prints it as "!important".
If the input in contains a color name (red, blue, ...), then we place the color name into the output.
Less.js behavior is bit more complicated:
- if the color name is followed by ;, then less.js preserves the name
- if the color name is NOT followed by ;, then less.js translates color into the code.
Example:
- Input:
li,p { background-color : lime } li,p { background-color : lime; }
- Less.js output:
li, p { background-color: #00ff00; } li, p { background-color: lime; }
- Less4j output:
li, p { background-color: lime; } li, p { background-color: lime; }
If a comment is located inside an expression, Less4j always puts a space after it. Less.js puts it there only if original file had it.
If the comment after ruleset is not preceded by an empty line, less.js does not put new line before it. We handle comments differently, a comment is preceded by a new line if it was preceded by it in the input.
- Input with an empty line:
p ~ * { background: lime; } /* let's try some pseudos that are not valid CSS but are likely to be implemented as extensions in some UAs. These should not be recognised, as UAs implementing such extensions should use the :-vnd-ident syntax. * /
- Less4j & Less.js output::
p ~ * { background: lime; } /* let's try some pseudos that are not valid CSS but are likely to be implemented as extensions in some UAs. These should not be recognised, as UAs implementing such extensions should use the :-vnd-ident syntax. * /:
- Input without the empty line:
p ~ * { background: lime; } /* let's try some pseudos that are not valid CSS but are likely to be implemented as extensions in some UAs. These should not be recognised, as UAs implementing such extensions should use the :-vnd-ident syntax. * /
- Less.js output:
p ~ * { background: lime; } /* let's try some pseudos that are not valid CSS but are likely to be implemented as extensions in some UAs. These should not be recognised, as UAs implementing such extensions should use the :-vnd-ident syntax. * /:
- Less4j output:
p ~ * { background: lime; } /* let's try some pseudos that are not valid CSS but are likely to be implemented as extensions in some UAs. These should not be recognised, as UAs implementing such extensions should use the :-vnd-ident syntax. * /:
No matter how many new lines follow directly after the comment, less4j prints only one after that comment. Less.js will keep the original number of new lines.
Example:
- Input:
/* A C-style comment */ padding: 2;
- Less.js output:
/* A C-style comment */ padding: 2;
- Our output:
/* A C-style comment */ padding: 2;
Less4j translates whitespaces inside the :nth-xxxxx(an+b) pseudo-classes differently than less.js. Less4j strips them out while less.js does not.
Example:
- Input:
:nth-child( 3n + 1 ) :nth-child( +3n - 2 ) :nth-child( -n+ 6) :nth-child( +6 ) :nth-child( -6 ) { padding: 2; }
- Less.js output:
:nth-child( 3n + 1 ):nth-child( +3n - 2 ):nth-child( -n+ 6):nth-child( +6 ):nth-child( -6 ) { padding: 2; };
- Our output:
:nth-child(3n+1) :nth-child(+3n-2) :nth-child(-n+6) :nth-child(+6) :nth-child(-6) { padding: 2; }
If the "serif" part of font declaration does not have a leading space, less.js will not give it one. For some weird reason, sans-serif works differently. Less4j always places a space after comma ",".
Example:
- Input:
@media screen { p.test {font-family:verdana,sans-serif;font-size:14px;} } @media print { p.test {font-family:times, serif;font-size:10px;} } @media print { p.test {font-family:times,serif;font-size:10px;} }
- Less.js output:
@media screen { p.test { font-family: verdana, sans-serif; font-size: 14px; } } @media print { p.test { font-family: times, serif; font-size: 10px; } } @media print { p.test { font-family: times,serif; font-size: 10px; } }
- Les4j output:
@media screen { p.test { font-family: verdana, sans-serif; font-size: 14px; } } @media print { p.test { font-family: times, serif; font-size: 10px; } } @media print { p.test { font-family: times, serif; font-size: 10px; } }
Less.js keeps whitespaces in media and Less4j is not.
Example:
- Input:
@media screen , screen { ... } @media media screen,print { ... }
- Less.js output:
@media screen , screen { ... } @media media screen,print { ... }
- Les4j output:
@media screen, screen { ... } @media media screen, print { ... }
Empty media bodies are printed differently by less4j and less.js
Less4j:
@media screen {
}
Less.js:
@media screen {
}
If the selector ends up with a combinator, less.js ignores the last combinator. Less4j throws an exception on it.
Example:
- Input:
h1 + {
declaration: value;
}
- less.js:
h1 {
declaration: value;
}
- Less4j: syntax error.
Less4j and less.js behave differently if parentheses contains valid variable name, but such variable does not exist. Less4j leaves the expression as it is and less.js throws an exception.
Incorrect in less.js and compilable in less4j:
@variable: 32;
#stringInterpolation {
text: "@{doesNotExists}";
}
Less4j result:
#stringInterpolation {
text: "@{doesNotExists}";
}
Workaround for less.js:
@variable: 32;
#stringInterpolation {
@workaround: "doesNotExists";
text: "@{workaround}";
}
Less.js does not detect duplicate declarations inside body of @viewport. Less4j detects them and leaves only the last declaration in place.
CSS specification allows only one media type inside each media query. That media type can be followed by any number of media expressions joined by "and".
Media merging uses and
to combine queries of nested media declarations. This leads to invalid css if inner media query starts with media type. Such input is treated differently by less4j and less.js.
Sample input:
@media print {
.class {
@media screen and (max-width: 117px){
margin: 1 1 1 1;
}
}
}
Less.js combines inner and outer media queries as they are and thus produce invalid CSS:
@media print and screen and (max-width: 117px) {
.class {
margin: 1 1 1 1;
}
}
Less4j ignores media type in inner media query and produces a warning.:
@media print and (max-width: 117px) {
.class {
margin: 1 1 1 1;
}
}
Less.js does not parse nor translates supports condition found in @supports at-rule. It prints it into output as is. Less4j parses and translates it.
Less.js does not support expression evaluation inside supports conditions. Supports at rule in less will be unchanged by less.js:
@size: (3+4);
@supports (width: (@size+1)) {
/* ... */
}
Less.js output:
@supports (width: (@size+1)) {
/* ... */
}
Less4j output:
@supports (width: 8) {
/* ... */
}
CSS specification does not allow mixing of 'and', 'or', and 'not' supports condition operators without a layer of parentheses. Both less.js and less4j are able to translate such input, but less4j throws a warning on it.
Less example:
@supports (color: #ff00ff) and (size: 2) or (padding: 3) {
/* ... */
}
Less4j warning:
WARNING 1:42 CSS specification does not allow mixing of 'and', 'or', and 'not' operators without a layer of parentheses. Operators 'or' at 1:42' and 'and' at 1:28 are in the same layer of parentheses.
Less.js prints supports condition as is, less4j may change its formatting.
Less.js makes no modification to this input:
@supports ( color: #ff00ff ) {
width: 397px;
}
Less4j formats it:
@supports (color: #ff00ff) {
width: 397px;
}