465

Right Now I'm trying to do this in CSS3 in my LESS code:

width: calc(100% - 200px);

However, when LESS compiles it is outputting this:

width: calc(-100%);

Is there a way to tell LESS not to compile it in that manner and to output it normally?

dippas
  • 58,591
  • 15
  • 114
  • 126
AJStacy
  • 5,175
  • 4
  • 17
  • 31
  • I thought my solution was a pretty ugly hack already, but the most upvoted dupe uses virtually the same hack as mine so I guess there are not many other (cleaner) ways. `:P` – Fabrício Matté Jul 28 '13 at 01:36
  • 1
    Note that Less no longer collapses these calculations within `calc()` regardless of the `math` setting. – Matthew Dean Feb 15 '19 at 21:33

5 Answers5

826

Using an escaped string (a.k.a. escaped value):

width: ~"calc(100% - 200px)";

Also, in case you need to mix Less math with escaped strings:

width: calc(~"100% - 15rem +" (10px+5px) ~"+ 2em");

Compiles to:

width: calc(100% - 15rem + 15px + 2em);

This works as Less concatenates values (the escaped strings and math result) with a space by default.

Fabrício Matté
  • 69,329
  • 26
  • 129
  • 166
  • Note that the `~"value"` syntax has been replaced with the `e("value")` function. See here: http://lesscss.org/functions/#string-functions-e – chharvey Nov 08 '15 at 17:36
  • @chharvey are you sure? The [`~""` documentation](http://lesscss.org/features/#features-overview-feature-escaping) has no deprecation notice. In fact, if I'm reading the [`e()` function docs](http://lesscss.org/functions/#string-functions-e) correctly, it is the `e` function that has been replaced with `~""`. This [related answer](http://stackoverflow.com/a/8331285) reaffirms this point. – Fabrício Matté Nov 09 '15 at 18:44
  • @FabrícioMatté yes you're right. I misread the alert in the `e()` docs. the `~''` syntax seems to be newer. – chharvey Nov 09 '15 at 20:25
  • Hi. A Less.js language designer here. What would you think about a tweak to language syntax to interpret the entire statement as a string? As in: `width~: calc(100% - 200px);` equivalent to: `width: ~"calc(100% - 200px)";` – Matthew Dean Jan 28 '16 at 22:51
  • @MatthewDean That looks like an improvement, in my opinion. Though, I usually dislike having multiple ways to write the same thing—it is one more (unnecessary) choice you have to make, one more thing learners have to keep in mind, and leads to coding style discussions. Of course, as a language designer you most surely already know all these drawbacks, so I'd leave it to your team to discuss whether this syntax sugaring is worth it. And, to be honest, I've had little use for calc/escaped strings lately as I can usually solve the problem in a simpler and more robust way using Flexbox layout. – Fabrício Matté Feb 03 '16 at 22:56
64

Apart from using an escaped value as described in my other answer, it is also possible to fix this issue by enabling the Strict Math setting.

With strict math on, only maths that are inside unnecessary parentheses will be processed, so your code:

width: calc(100% - 200px);

Would work as expected with the strict math option enabled.

However, note that Strict Math is applied globally, not only inside calc(). That means, if you have:

font-size: 12px + 2px;

The math will no longer be processed by Less -- it will output font-size: 12px + 2px which is, obviously, invalid CSS. You'd have to wrap all maths that should be processed by Less in (previously unnecessary) parentheses:

font-size: (12px + 2px);

Strict Math is a nice option to consider when starting a new project, otherwise you'd possibly have to rewrite a good part of the code base. For the most common use cases, the escaped string approach described in the other answer is more suitable.

Community
  • 1
  • 1
Fabrício Matté
  • 69,329
  • 26
  • 129
  • 166
24

Here's a cross-browser less mixin for using CSS's calc with any property:

.calc(@prop; @val) {
  @{prop}: calc(~'@{val}');
  @{prop}: -moz-calc(~'@{val}');
  @{prop}: -webkit-calc(~'@{val}');
  @{prop}: -o-calc(~'@{val}');
}

Example usage:

.calc(width; "100% - 200px");

And the CSS that's output:

width: calc(100% - 200px);
width: -moz-calc(100% - 200px);
width: -webkit-calc(100% - 200px);
width: -o-calc(100% - 200px);

A codepen of this example: http://codepen.io/patrickberkeley/pen/zobdp

Patrick Berkeley
  • 2,206
  • 21
  • 26
  • throws `ParseError: Syntax Error on line 2` – Tom Roggero Aug 30 '14 at 03:35
  • @TomRoggero what version of less are you running? What's the rest of your environment? I've updated the original answer to include a working example. – Patrick Berkeley Aug 30 '14 at 16:54
  • 1
    I would advise against this. It's better to keep your CSS pure, and then use something like Autoprefixer to add prefix not just to `calc` but to any other attribute one might be using. – zeh Oct 01 '16 at 15:48
  • 1
    this is awesome Patrick, I've issued a PR against LESS-Prefixer for inclusion – ekkis Oct 25 '16 at 23:34
15

Example for escaped string with variable:

@some-variable-height: 10px;

...

div {
    height: ~"calc(100vh - "@some-variable-height~")";
}

compiles to

div {
    height: calc(100vh - 10px );
}
Achim Koellner
  • 913
  • 12
  • 22
6

The solutions of Fabricio works just fine.

A very common usecase of calc is add 100% width and adding some margin around the element.

One can do so with:

@someMarginVariable: 15px;

margin: @someMarginVariable;
width: calc(~"100% - "@someMarginVariable*2);
width: -moz-calc(~"100% - "@someMarginVariable*2);
width: -webkit-calc(~"100% - "@someMarginVariable*2);
width: -o-calc(~"100% - "@someMarginVariable*2);

Or can use a mixin like:

.fullWidthMinusMarginPaddingMixin(@marginSize,@paddingSize) {
  @minusValue: (@marginSize+@paddingSize)*2;
  padding: @paddingSize;
  margin: @marginSize;
  width: calc(~"100% - "@minusValue);
  width: -moz-calc(~"100% - "@minusValue);
  width: -webkit-calc(~"100% - "@minusValue);
  width: -o-calc(~"100% - "@minusValue);
}
furins
  • 4,979
  • 1
  • 39
  • 57
Sebastien Lorber
  • 89,644
  • 67
  • 288
  • 419