enigma969
enigma969

Reputation: 427

calc() with variables not possible - SyntaxError: Operation on an invalid type

I've got following LESS variables:

@dashboard-height: 90.5%;
@dashlet-header-height: 35px;
@dashboard-margin: 0px;
@dashlet-border: 1px;

and I want to calculate following classes:

.generate-dashlet-classes(6);
.generate-dashlet-classes(@n, @i: 1) when (@i =< @n) {
  &.dashlet-@{i} .dashlet-content {
    height: round((calc(@dashboard-height - (@i * (@dashlet-header-height + @dashboard-margin + @dashlet-border)))) / @i, 6);
  }
  .generate-dashlet-classes-times(@i);
  .generate-dashlet-classes(@n, (@i + 1));
}

.generate-dashlet-classes-times(@i, @times:1) when (@times < @i) {
  &.dashlet-@{times}-x-@{i} .dashlet-content {
    @dashletContainerHeight: (@dashlet-header-height + @dashboard-margin + @dashlet-border);
    height: round(((calc(@dashboard-height - (@i * @dashletContainerHeight))) / @i * @times) + (@dashletContainerHeight * (@times - 1)), 6);
  }
  .generate-dashlet-classes-times(@i, (@times + 1));
}

Now the compiler throws following error:

>> SyntaxError: Operation on an invalid type in app/styles/less/main.less on line 338, column 5:
>> 337 
>> 338     .generate-dashlet-classes(6);
>> 339     .generate-dashlet-classes(@n, @i: 1) when (@i =< @n) {

There would be no error if @dashboard-height would have a px value and no calc() would be used. But when mixing percentages and px values, we have to use calc(), don't we?

Upvotes: 3

Views: 5735

Answers (1)

Marvin
Marvin

Reputation: 10142

LESS will try to calculate everything that is not escaped until you compile with strict math on. In other words: what is the outcome of (90.5% - (3 * (35px + 0px + 1px))) / 3? Less can't know and I guess that is what Operation on an invalid type tries to tell us.

Turning strict math mode on (lessc -sm=on myfile.less myfile.css) will solve your problem immediately. But it has the unwanted side effect that also every other calculation in your other less files won't get processed (only maths that is inside un-necessary parenthesis will be processed). So this might not be an option as you probably would have to refactor your existing code base.

Escaping in general looks like this width: ~"calc(100% - 20px)";. It's a little tricky as we don't want to also escape the variables inside the calc function. A way to achieve this to interpolate the variables:
height: ~"calc(@{dashboard-height} - (@{i} * (@{dashlet-header-height} + @{dashboard-margin} + @{dashlet-border})))" / @i;
which will result in e.g. height: calc(90.5% - (2 * (35px + 0px + 1px))) / 2. At first glance this is better than a compile error, but it is invalid CSS.

Fortunately, we can only escape some of the operators (the minus in this example)
height: calc(@dashboard-height ~"-" (@i * (@dashlet-header-height + @dashboard-margin + @dashlet-border))); which will result in e.g. height: calc(90.5% - 36px);


When you are done with escaping you will get the next error, telling you that your usage of the LESS round function does not work. The function expects a floating point number as argument, so you can't mix it up with the CSS calc() function. Rounding only makes sense here if the value is known at compile time. For the same reason I removed the / @i in the above calculation, as you can't divide calc() by a number.

Upvotes: 5

Related Questions