SASS: Incompatible units: 'vw' and 'px'

Viewed 19274

How to solve the incompatible units problem?

@mixin square-size($size, $min: $size, $max: $size) {
  $clamp-size: min(max($size, $min), $max);
  width: $clamp-size;
  height: $clamp-size;
}

The input is:

@include square-size(10vw, 40px, 70px);

Problem:

Incompatible units: 'vw' and 'px'.
node_modules\@ionic\app-scripts\dist\util\helpers.js:253.replace(/&/g, '&')

But if I use calc(1vw - 1px) it works. (no unit problem). e.g. max(calc(1vw - 1px)) does not work. Because no number for max.

In my case I want a mixin to square the size of an element. Including clamp. min-width, max-width, etc. does not work. It will be a rect or an ellipse. Because it does not keep the aspect ratio. I want a element with dynamic size but with min and max size.

I understand that the dynamic unit vw (Viewport) must be present after sass compilation. Therefore it is not possible to convert the value to a fixed unit. But is there no way?

7 Answers

I was able to fix the error in React SASS using the calc function.

font-size: calc(max(8vw, 30px));

If you're unable to work around it in any other way, SCSS has a function for ignoring things in quotes:

width: unquote("max(50px, 5rem)");

This will be compiled without the quotes and be valid CSS.

width: max(50px, 5rem);

It will be strange to have this in your scss, but it's a sure-fire way of allowing modern CSS to not interrupt your scss functions

The Problem

CSS didn't use to have its own runtime min() and max() functions, and before they existed SASS had a compile-time version. Since SASS doesn't run live it would be impossible for it to determine whether 10vw or 40px is larger - hence the error.

The Solution

Since SASS is case sensitive while CSS isn't, you can force the parser to use the CSS version of min or max by just calling MIN() or MAX() instead. If you need to resume SASS parsing inside of MAX() ( like to reference a SASS variable ) just surround the SASS code with #{...}.

Here's a fixed version of your code to demonstrate:

@mixin square-size($size, $min: $size, $max: $size) {
  /* $clamp-size: min(max($size, $min), $max); */
  $clamp-size: MIN(MAX(#{$size}, #{$min}), #{$max});
  width: $clamp-size;
  height: $clamp-size;
}

Good luck!

You would need to bypass the scss compiler & use a literal instead.

@mixin square-size($size, $min: $size, $max: $size) {
  $clamp-size: #{'min(max(#{$size}, #{$min}), #{$max})'};
  width: $clamp-size;
  height: $clamp-size;
}

when doing min or max in sass, if you get incompatible units error, you can simply put the value in a quotation, and it will let it pass.

min(10vw, 20px) to"min(10vw, 20px)"

This works for other functions too.

And if you are using variables in calculations, you use #{} on the variables to make it pass

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

.mydiv {
  width: calc(#{$a} - #{$b});
}

And the #{} converts them to string so that sass wouldn't make arithmetic using them while compiling

You could do it like this using min-width/height and max-width/height to avoid mixing units:

@mixin square-size($size, $min: $size, $max: $size) {
  min-width: $min;
  max-width: $max;    
  min-height: $min;
  max-height: $max;    
  width: $size;
  height: $size;
}
.class {
    @include square-size(10vw, 40px, 70px);
} 

For this, instead of SCSS @include

.foo {
  @include square-size(10vw, 40px, 70px);
}

use better css function "clamp":

.foo {
    width:clamp(10vw, 40px, 70px);
    height:clamp(10vw, 40px, 70px);
}
Related