Skip to content

Differences Between Less.js and Less4j

Mária Jurčovičová edited this page Dec 26, 2013 · 26 revisions

Expressions

Standalone Unary '-'

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.

Negative Floats Without Leading 0

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;
    }
    

Minus 0

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;
    }
    

Percentage as a Class Name

Less.js does not accept percentage as a class name. Less4j accepts it.

Illegal in less.js but legal in Less4j:

.12% {
  
}

!important Keyword

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".

Colors

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;
    }

Whitespaces

Whitespaces After Comments

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.

Comments After Declarations

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. * /:

Newlines After Comments

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;
    

nth-xxxxx(an+b) Pseudo-classes

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;
    }

Media Font Declaration

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;
      }
    }

Whitespaces in Media Queries

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 {
      ...
    }

Whitespaces in Empty Media

Empty media bodies are printed differently by less4j and less.js

Less4j:

@media screen {
}

Less.js:

@media screen {
   
}

Selector Ending With Combinator

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.

String Interpolation: Incorrect Variables Name

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}";
}

Duplicate Declaration Detection

Less.js does not detect duplicate declarations inside body of @viewport. Less4j detects them and leaves only the last declaration in place.

Media Merging

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;
  }
}

Supports At-Rule

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.

Evaluation

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) {
  /* ... */
}

Validation

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.

Formatting

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;
}
Clone this wiki locally