158

I want to be able to do the following:

height: 25% - 5px;

Obviously when I do that I get the error:

Incompatible units: 'px' and '%'.
cimmanon
  • 67,211
  • 17
  • 165
  • 171
Mike Fielden
  • 10,055
  • 14
  • 59
  • 99
  • I get the `Invalid property value` error. In every browser including Chrome's Canary build. – Mike Fielden Nov 07 '12 at 17:17
  • If there is a Sass function thatd get me what I want thats cool, I was just playing with `calc` ... – Mike Fielden Nov 07 '12 at 17:17
  • Yes :) Like I said I dont care how it gets done `calc` was were I went first and it didnt work. It looks like `calc` doesnt work in any of my browsers, so a sass implementation would be best I'd guess. – Mike Fielden Nov 07 '12 at 17:23
  • 1
    Sass cannot act as a polyfill for calc(). It doesn't know how to convert 25% to px so it can do the math and generate the CSS. Depending on your exact needs, there may be an alternative, such as using the display-table family, changing your box-sizing, or using negative margins (http://jsfiddle.net/5JZGt/) – cimmanon Nov 07 '12 at 17:30

6 Answers6

303

Sass cannot perform arithmetic on values that cannot be converted from one unit to the next. Sass has no way of knowing exactly how wide "100%" is in terms of pixels or any other unit. That's something only the browser knows.

You need to use calc() instead. Check browser compatibility on Can I use...

.foo {
    height: calc(25% - 5px);
}

If your values are in variables, you may need to use interpolation turn them into strings (otherwise Sass just tries to perform arithmetic):

$a: 25%;
$b: 5px;

.foo {
  width: calc(#{$a} - #{$b});
}
chrisgonzalez
  • 4,173
  • 1
  • 16
  • 15
  • 5
    I would say that calc() does not at all work in most browsers. Mobile platforms are just as important as desktops. – dalgard Feb 07 '13 at 15:10
  • 3
    No argument there, but count the browsers! More support calc() than not, and even more will support it in the near future! – chrisgonzalez Feb 13 '13 at 17:20
  • 5
    I had issues width using a variable inside the calc functions, but found here: http://stackoverflow.com/questions/13542164/using-variables-in-sass-percentage-function that I could reference the variable like this: `calc(25% - #{$var})`. – mlunoe Feb 22 '13 at 10:52
  • To follow up on @dalgard's statement, in terms of existing, released browsers, calc does not work in more than it works in. See: http://caniuse.com/#search=calc – imjared Sep 02 '13 at 20:22
  • 3
    You can always use a fall back option by adding `width: 22%` at above all `width`s with `calc` – Hengjie Sep 03 '13 at 06:14
  • @Hengjie - you could, except that 25% - 5px will very seldom equal 22%. This approach is good though, you could definitely include a less elegant fallback when calc is not supported. – chrisgonzalez Sep 06 '13 at 18:54
  • 1
    Old thread, but apparently, you can also store the "calc()" command itself in a variable, so you don't need to repeat the arithmetic operations throughout the file. Example: $video-height: calc(#{$video-width} * #{$aspect-ratio}); .my-elements {height: $video-height; } – Stephen Kaiser Aug 13 '20 at 00:46
29

There is a calc function in both SCSS [compile-time] and CSS [run-time]. You're likely invoking the former instead of the latter.

For obvious reasons mixing units won't work compile-time, but will at run-time.

You can force the latter by using unquote, a SCSS function.

.selector { height: unquote("-webkit-calc(100% - 40px)"); }
sandstrom
  • 14,554
  • 7
  • 65
  • 62
15
$var:25%;
$foo:5px;
.selector {
    height:unquote("calc( #{$var} - #{$foo} )");
}
  • 2
    Thank you for posting an answer to this question! Code-only answers are discouraged on Stack Overflow, because a code dump with no context doesn't explain how or why the solution will work, making it difficult for the original poster (or any future readers) to understand the logic behind it. Please, edit your question and include an explanation of your code so that others can benefit from your answer. Thanks! – Maximillian Laumeister Aug 16 '15 at 03:51
  • That saved me. width: unquote("calc( 100% - #{$leftnav-width} )"); – httpete May 19 '16 at 16:04
7

IF you know the width of the container, you could do like this:

#container
  width: #{200}px
  #element
    width: #{(0.25 * 200) - 5}px

I'm aware that in many cases #container could have a relative width. Then this wouldn't work.

Design by Adrian
  • 2,185
  • 1
  • 20
  • 22
2

Sorry for reviving old thread - Compass' stretch with an :after pseudo-selector might suit your purpose - eg. if you want a div to fill width from left to (50% + 10px) of screen you could use (in SASS indented syntax):

.example
    background: red
    +stretch(0, -10px, 0, 0)
    &:after
        +stretch(0, 0, 0, 50%)
        content: ' '
        background: blue

The :after element fills 50% to the right of .example (leaving 50% available for .example's width), then .example is stretched to that width plus 10px.

  • 1
    is there a less or sass mixing for this somewhere? calc doesn't seem to work very well at all. – v3nt Jun 17 '14 at 09:18
1

Just add the percentage value into a variable and use #{$variable} for example

$twentyFivePercent:25%;
.selector {
    height: calc(#{$twentyFivePercent} - 5px);
}
Aftab Ahmed
  • 665
  • 9
  • 17