Less.js: CSS3 calc() function doesn't work with LESS

Created on 8 Oct 2012  ·  51Comments  ·  Source: less/less.js

I know it's been reported already but bugs were closed due to insufficient information.

I have the following CSS code:

#id1 {
    position: fixed;
    left: 0; top: 0;
    width: 130px;
}
#id2 {
    position: fixed;
    right: 0; top: 0;
    width: calc(100% - 130px);
}

I wanted to transform it into LESS using 130px as a parameter but calc gets internpreted by LESS and this:

@id1width: 130px
#id1 {
    position: fixed;
    left: 0; top: 0;
    width: @id1width;
}
#id2 {
    position: fixed;
    right: 0; top: 0;
    width: calc(100% - @id1width);
}

makes the last but one line transformed to width: calc(-30%); which is clearly not what's desired. I tried using width: ~"calc(100% - @id1width)"; but it makes @id1width not interpreted.

I think LESS shouldn't use things reserved by CSS3 for its internal use...

Most helpful comment

they were probably closed as duplicates.. though I can't find one about calc.. see #146 #122 and #915

workaround: width: ~"calc(100% - @{id1width})"; - note curly brackets around variable.

We are moving to a system where only things inside brackets will be evaluated to fix this problem.

All 51 comments

they were probably closed as duplicates.. though I can't find one about calc.. see #146 #122 and #915

workaround: width: ~"calc(100% - @{id1width})"; - note curly brackets around variable.

We are moving to a system where only things inside brackets will be evaluated to fix this problem.

:+1:

@rows: 10;

@row1: 1 / @rows * 100%;

.featured1
{
  top: ~'-webkit-calc(@{row1} + 20px)';
  right: 0;
  bottom: @row5;
  left: @col9;
}

This bit of LESS will process out the value of '@row1' to be 10%, which is great. But when it is inside an escaped seciton of LESS and wrapped in curlys to retain the LESS variable it returns '10' without the '%'.

I've found a workaround that hasn't failed me yet. If you place another '%' after the closing curly of the 'row1' variable inside the escaped code it will work correctly...

~'-webkit-calc(@{row1}% + 20px)';

But that seems like quite a hack to add in another unit type that is suppose to already be in the variable.

@jonjohnjohnson this is fixed in head and will be in 1.3.2

the rest of this bug will be resolved in 1.4.0

Not sure if this is the same issue, but I'm having a problem with the following. Note there's no less-specific stuff here, less 1.3.3 is munging otherwise valid CSS.

Here's the CSS

html, body {
    margin:0, padding:0, border:0;
    height: 100%;
}

#content {
    height: -webkit-calc(100% - 40px);
    height: calc(100% - 40px);
    background-color:gray;
}

#footer {
    background-color:black;
}

And here's the HTML to include it

<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet/less" type="text/css" href="test.css" />
<script src="less-1.3.3.min.js"></script>
<body>
<div id="content"></div>
<div id="footer" style="height:40px"></div>
</body>
</html>

"content" is being set to a height of 60%, so less is parsing & incorrectly resolving the calc expression rather than passing it unchanged through to the browser. Tested in Safari 6.0.2 and Firefox.

Fixed on master for 1.4.0

height: ~"calc(100% - 50px)";

still produces:

height: calc(50%);

for me. I want:

height: calc(100% - 50px);

What’s more, it still produces height: calc(50%); even with strict math set to on.

@OliverJAsh I can't reproduce your results with Less 1.7.0 (both escaped value and --strict-math:on work as expected)... Could you please provide more details on the compiler/environment/scripts you use? (Just in case there was Bootstrap build script issue that could lead to such incorrect results: https://github.com/twbs/bootstrap/issues/13604, maybe this is your case too?).

I was having this issue in 1.6.3 (for some reason, WinLESS is barfing on compile when I upgrade to 1.7.x, so I'm sticking to 1.6.x for now)

My quickfix was just to escape one part of the equation like:

height: calc(~"100%" - unit(@var, px));

This even works for variables, like @var: 50. Or you could escape the whole calculation like calc(~"100% - 50px");

@twiginteractive If you have to use escaping with --strict-math option off (default setting) then it's not an issue but expected behaviour. See --strict-math.

@seven-phases-max Hmmm - according to the docs, with SM off (default) then this _should_ get parsed correctly (i.e. untouched)
height: calc(100% - 10px);

But it doesn't. The output CSS is height: calc(90%);, which isn't the desired result. Maybe this is fixed in 1.7, but as I say I can't use that version right now until I figure out what is breaking the WinLESS compile.

(Unless I am mis-reading the docs when it says "will be processed correctly"... LESS couldn't know the value of 100%, so it shouldn't do a mathematical computation on '100% - 10px')

@twiginteractive

according to the docs, with SM off (default) then this should get parsed correctly (i.e. untouched)

No, the word there is currently not correctly (i.e. "will _be processed_ currently").

@seven-phases-max Ah - my bad, it makes sense now. Thanks for the clarification.

height: ~"calc(100% - 50px)"; Worked for me.

This is where Less.js begins to mess with your code. Supposedly v2.0 will have the option to prefix its functions like so:

height: _calc(50%);
height: calc(100% - 50%); /* browser-native */

@stevenvachon

Supposedly v2.0 will have the option to prefix its functions like so:

This won't affect calc in any way. There's no built-in calc function, Less is just evaluating a math expression accordingly to its (Less's) rules. That's it. If you don't want this "mess" use --strict-math.

P.s. the solution to this problem is strict maths. And maybe we should
force strict maths on when in a call to calc?

The problem extends when using Myth after Less. Even with strictMath, we need to ~"calc(...)" so that Less ignores it.

Why? Does myth remove parentheses? Strict math makes less a proper superset
of css.

And maybe we should force strict maths on when in a call to calc?

We've discussed this in #1872 and there're a few arguments against "local strict-math:on" workarounds. The proposed solution (not quite decided yet) is in #1880.

@stevenvachon

Even with strictMath, we need to ~"calc(...)" so that Less ignores it.

Example? I.e. a snippet where Less screws an expression inside calc with --strict-math=on.

Since when will v2 prefix functions? Did we decide that and I forgot?

Since when will v2 prefix functions? Did we decide that and I forgot?

No. I guess this was just slightly overestimated https://github.com/less/less.js/issues/2102#issuecomment-50286985.

Yes, sorry, not "the option to" but "the ability write a plugin providing the option to". I'll have to test some code again with and without ~"" on calc(). I must've been mistaken a while back and just kept moving forward with that misunderstanding. I have some older code that I'll have to modify now.

I've noticed something weird happening with calc when used in-conjunction with width. I've put it all into a codepen just to make it easier: http://codepen.io/anon/pen/OVpJvP

@alenb

So what is strange there? The code in your codepen is compiled as expected...

@seven-phases-max

It's compiled, but it's not what's expected. Check the CSS code a little more closely.

It's strange because it still has a gap on the far right even though it should stretch fully with the 3 columns. First two columns should be 33.33% minus 20px with the last column being 33.33%. The first 2 columns would have a padding-right of 20px, but this is not reflected as there is obviously a gap on the far right.

I've played more with it last night and margin-right instead of the padding-right does the trick and resolves the problem.

@alenb

It's compiled, but it's not what's expected. Check the CSS code a little more closely.

Sure, I did. So if you expect something different - please specify.

The first 2 columns would have a padding-right of 20px, but this is not reflected

padding does not affect width in any way (unless you set specific [box-sizing](https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing)), consult [CSS specs](http://www.w3.org/TR/REC-CSS2/box.html). So you simply get : (33% - 20px) + (33% - 20px) + 33% = 99% - 40px->40px` gap as expected.

Either way this is related solely to CSS and has nothing to do with how Less compiles calc. Click "view compiled" button in the codepen code and there you see your calc statements are compiled by Less exactly to what you specified).

@seven-phases-max

I would have thought the codepen would make this apparent, but no problem at all.

Thanks for the info!

Today it still doesn't work with default installation of less (using npm).

I had to use:
min-height: ~"calc(100% - 262px)"; //calc(100% - 262px);

I don't know if it is normal, as the bug is marked "closed", but just wanted to let you know.

@RenaudParis --strict-math

Okay I will try that, thank you! But wouldn't it be better that it is by
default? Because it is quite surprising, when you don't know about this
parameter.

Thanks anyway!

Le ven. 8 avr. 2016 à 20:48, Max Mikhailov [email protected] a
écrit :

@RenaudParis https://github.com/RenaudParis --strict-math
http://lesscss.org/usage/#command-line-usage-strict-math


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
https://github.com/less/less.js/issues/974#issuecomment-207553212

But wouldn't it be better that it is by default?

Making it to be default will break a lot of existing Less code-bases. Once (at ~v1.4.0) there was an attempt to make it to be default actually, but then it's reversed because of legacy backward-compatibility... A newer, less-intrusive method was developed at #1880 (but it's not implemented yet).

Okay, thank you for taking the time to explain it to me Max!

Le sam. 9 avr. 2016 13:46, Max Mikhailov [email protected] a
écrit :

But wouldn't it be better that it is by
default?

Making it to be default will break a lot of existing Less code-bases. Once
(at ~v1.4.0) there was an attempt to make it to be default actually, but
then it's reversed because of legacy backward-compatibility... A newer,
less-intrusive method was developed at #1880
https://github.com/less/less.js/issues/1880 (but it's not implemented
yet)).


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
https://github.com/less/less.js/issues/974#issuecomment-207776654

I have solved this :

.calc(@prop, @val) {
    @{prop}: ~"calc(~'@{val}')";
    @{prop}: ~"-moz-calc(~'@{val}')";
    @{prop}: ~"-webkit-calc(~'@{val}')";
    @{prop}: ~"-o-calc(~'@{val}');"
}
.calc(width, "80% - 36px");

When I use command line it is correct . Only less-loader is not correct. So I found this solution on stackoverflow

I copy it to my code, Sadly it also not correct. So I modified something. It works!

Unfortunately, command line is not correct!!😂 😂 😂

Not sure why this issue is closed. It doesn't make sense that Less would change a native CSS behavior.

... Less would change a native CSS behavior.

It would not. Just set --strict-math=on (not enabled by default because of compatibility with a gigantic amount of Less projects depending on --strict-math=off, plus a few considerations mentioned at #1880).

In a UIkit 3 theme I am using this in my_theme.less:

height: ~"calc(100vh - 20px)";

And it works.

It worked for me when writing in *.less file https://github.com/less/less.js/issues/974#issuecomment-9229470

Thank @lukeapage ! 🥇

Hi @mqliutie thanks for adding the mixin suggestion for calc, but, there is an extra ~ in your Mixin that was breaking the compilation:

the mixin should be

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

Input as follows:
.calc(width, "100% - 60px");

Output as follows:
width: calc(100% - 60px);

Why is this issue closed?! It's not fixed.

I'm still getting calc(30%) when I write calc(50% - 20px). This is never what anyone wants. Apart from the fact that it's wrong to blindly calculate with different units, it should leave it as-is in a calc(), unless it can be calculated with 100% reliability (e.g. same units). I'm using LESS 2.7.3.

Please reopen this issue.

@thany
Refer to these comments, they describe how this isn't exactly an issue, as much as the default setting of processing math is a byproduct of history, and you can always change the default setting.
https://github.com/less/less.js/issues/974#issuecomment-207553212
https://github.com/less/less.js/issues/974#issuecomment-207776654

@jonjohnjohnson That's just stating the problem again. If strict mode fixes it (haven't tried yet, shouldn't be neccesary to enable all kinds of nondefault flags in order to work around bugs) then it should be on by default.

No matter how you put it, this issue is not fixed by any definition.

@thany I was just trying to help you understand that the developers decided it's not an issue according to them. Those comments don't just restate the problem, they describe the developers stance on the issue. Good luck.

@thany

then it should be on by default.

It can't be because this would immediately break zillion projects out there. So if you treat the default behaviour as an issue just set the documented option and be done. By any definition.

Why is this issue closed?!

Because the uptodate disscussion of how to improve the default behaviour is here.

@thany As @seven-phases-max, if you want to see this solved, contribute to #1880. I think the solution is there, but there hasn't been enough community weigh-in to come to a decision that is ready to implement. It's a long thread, but that's what solution-finding takes: reviewing proposals and weighing in one way or another. And then: someone to take on the work to implement.

 width: 15%;
 height: ~"calc(width)";

how to make height=width

@xiaomizhou66
That's got nothing to do with LESS, nor with this issue. It's purely a CSS question. Please search for something like "css keep aspect" and you'll find some answers.

So this is still broken. calc(100vh - 138px) comes out to -38px.

@willatathena

If you expirience this problem with Less 3.x, please create a separate bug report.
For earlier Less versions this is expected behavior by default (read the posts above to find how to handle it).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

BrianMulhall picture BrianMulhall  ·  4Comments

seven-phases-max picture seven-phases-max  ·  6Comments

rejas picture rejas  ·  6Comments

xblakestone picture xblakestone  ·  3Comments

yggi49 picture yggi49  ·  7Comments