1

I have the following snippet of Less:

@Foo: 50px;

.someClass {
    width: calc(~'(100% - @{Foo}' - 5px);
}

This works fine. However, if I change this to:

@Foo: 50px;

.someClass {
    width: calc(~'(100% - @{Foo}' + 5px);
}

We now have a ParseError. We're on a bit older version of Less, but I've tried it on the official Less preview site and it still breaks.

Is this a bug or am I doing something silly?

Harry
  • 87,580
  • 25
  • 202
  • 214
alan
  • 870
  • 7
  • 24

1 Answers1

2

This is a very interesting case. The below code compiles fine and produces the expected output when --strict-math setting is turned on (--strict-math=on).

@Foo: 50px;
.someClass {
  width: calc(e('(100% - @{Foo}') - 5px);
}
.someClass {
  width: calc(e('(100% - @{Foo}') + 5px);
}

When strict math is turned off (which is, the default), both lines result in compiler error. Error message is given below and it is indicative of the fact that Less compiler is trying to perform math operations on values inside the calc function. This aggressive compilation is a known behavior of Less compiler.

OperationError: Operation on an invalid type

As confirmed by seven-phases-max in his comment, the behavior with the e() function (both when strict math is turned on and when it is turned off) is correct and error message also is as expected.


Ideally the same behavior as above should be seen for ~"" syntax also because it is a replacement of the e(). But unfortunately it doesn't seem to be. The code fails to compile irrespective of whether the strict math setting is enabled or not and the error message shown is the following:

ParseError: Could not parse call arguments or missing ')'

The error message indicates it is Parse Error and not an Operation Error. As seven-phases-max has indicated, it seems like the parser is not expecting an arithmetic operator to follow a value that is not a number and hence is throwing a parser error. The error message could've been more friendly :)

This problem happens only when the operator is + or * and not when it is - or /. When - or / is used, they can't always be considered as math operator (because - is used in prefixes and / is used in font property for line-height etc) and so compiler processes them as an identifier but + or * is invariably a math operator and so causes the issue. When - or / is used, it just results in string concatenation.


The below is the recommended way to fix this issue as it doesn't make the compiler to think that some kind of math operation has to be performed (and leaves it to the User Agent to handle as part of CSS):

@Foo: 50px;
.someClass {
  width: calc(~'(100% - @{Foo} - 5px');
}
.someClass {
  width: calc(~'(100% - @{Foo} + 5px');
}

Note: There is a missing close brace ()) within the calc functions but that is irrelevant to this case.

Community
  • 1
  • 1
Harry
  • 87,580
  • 25
  • 202
  • 214
  • The error is because Less (with `--strict-math=off`) tries to add a number (`5px`) to a string (`~"..."`) which is invalid operation of course. I.e. both snippets are expected to throw a error (No idea why that "older version" passes the first example - but that was incorrect anyway). – seven-phases-max Mar 25 '16 at 15:53
  • @seven-phases-max: I think the error message that was shown for the older version (the one with `e()`) with strict-math=off is correct because it says operation on invalid type. Is that not? Actually the newer one (the one with `~""`) gives an error message that could be seen as a bit misleading because it doesn't say operation on an invalid type but says parse error. – Harry Mar 25 '16 at 15:59
  • 1
    Hmm, yes, the error with `~"..."` version is unexpected (should be the same as with `e`) - so it looks like a sort of bug/bogus (the parser use slightly different parsing algo for the function/mixing argument values and in this particular case it seems like not expecting any arithmetic ops after "not a number" at all (and yes `-` passes as n identifier instead). – seven-phases-max Mar 25 '16 at 16:10
  • 1
    I.e. indeed, `@var: ~"..." + 5px` statement is parsed fine (because the property/variable value parsing is more relaxed and more tolerate to supposedly invalid values), but argument values parsing is more strict (no `not-a-number arithm-op ...` pattern there) hence the error (but it could could be more friendly error message indeed). – seven-phases-max Mar 25 '16 at 16:15
  • 1
    Either way what you suggested as a workaround is actually the correct (one of) syntax (despite of confusing error message, the original snippet is wrong in assumption the compiler is a *text*-processor, while it's not and in either `strict-math` mode the parser tries to understand the code, and in this particular case the `string + ...` value is deliberately invalid CSS which the parser never expects in this context). – seven-phases-max Mar 25 '16 at 16:28
  • @seven-phases-max: Thank you very much. Always nice to get a confirmation from an authoritative source. I have reworded my answer a bit to include the crux of your comments :) – Harry Mar 25 '16 at 16:53