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

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?

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;
}

Try this
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

SASS - compare vh and px with min function

I am trying to get the minimum between 7.6% of the viewport height and 55px.
min-height: min(7.6vh, 55px);
This gives me an error about incompatible units. Can this be done?
The Sass min() function only works when both values have the same unit (%, px, em, etc.). However, CSS itself has a min() function built in. Modern Dart Sass will automatically use the CSS function when possible.
For older versions of Sass, to use the CSS function you need to override min() with your own custom function like this:
// Override Sass min()
#function min($numbers...) {
#return m#{i}n(#{$numbers});
}
div {
// This now works
width: min(7.6vh, 55px);
}
Thanks to Jianqiu Xiao on GitHub for pointing out the "override" solution.
The SASS compiler can't know the viewport height of the target device(s), so it is impossible to compare vh to a fixed value given pixels.
What you can do is to set the height to either of the two numbers and set a min-height to the other number. However, the semantics are slightly different, as you now also have a max-height. In the following example, the div will take (at most) 100% of the viewport height, but at least 450px:
html, body {
height: 100%;
margin: 0;
padding: 0;
}
div {
background: darkgreen;
height: 450px;
min-height: 100vh;
}
<div>
</div>

less to sass writing a very simple function

I am switching from LESS to SASS but have some difficulties to use it
very simple less variable + function Less :
#mini :0.1rem;
#brown:#533a38;
.border(#color:#brown){border:#mini solid #color;}
I use it :
#contact-form{
.border();
}
how can I do the same with SASS ?
thank you
$mini :0.1rem;
$brown:#533a38;
#mixin border($color:$brown){border:$mini solid $color;}
Use mixin if you don't want to return anything. Now when we use border:
#contact-form{
border: #include border;
}

Using interpolation for calling compass sprite mixins

the problem that i have with this mixing is that i can't interpolation for calling different sprite mixins that compass provides.
I want to be able to have this in one place, create the sprites in different scss and them just include this shared mixing and use it.
So far seems that Sass doesn't allow me to do that. Maybe i just have a crazy and bad way of doing things ( i'm no designer really and i learn about sass a few months ago ).
Thanks for your time.
#mixin icon-button($width, $height, $icon-bg-color, $icon, $sprite-name){
.icon-base{
width: $width;
height: $height;
background-color: $icon-bg-color;
.icon{
$icon-height: #{$sprite-name}-sprite-height(#{$icon});
$icon-width: #{$sprite-name}-sprite-width(#{$icon});
#include #{$sprite-name}-sprite(#{$icon});
width: $icon-width;
height: $icon-height;
position: relative;
left: ($width - $icon-width)/2;
top: ($height - $icon-height)/2;
}
}
}
The #{something} is a ruby-way of interpolation. Compass framework uses ruby compiler to make css from scss/sass. Interpolation is just the way to insert some value (of a variable) into a string, like this: puts "I want to say #{smth}" will print "I want to say something" into irb console if you previously defined the smth = "something" variable. You also may notice the difference between ' and ". So, sometimes you would like to use standalone functions in compass like this:
headings(all) {
color: $color;
}
to compile it into css:
h1, h2, h3, h4, h5, h6 {
color: #2a2a2a;
}
Instead, it throws an error. So, to do this you need to interpolate the call of the function:
#{headings(all)} {
color: $color;
}
And it runs. But if you try to make interpolation with variables:
$color: #abc;
$color2: "#abc";
#mixin some($color) {
color: #{$color};
}
will also throw an error because in this case interpolation outputs a string "#abc".
Try to avoid using ruby syntax in compass if it is possible for cleaner style.
Note: I would appreciate if someone can explain with better compilation details because i'm not a rubyist, i'm pythonist.
Update
Check this code:
#mixin setFonting($from, $to, $size) {
$curr: $from;
$to: $to + 3;
#while $curr != $to {
h#{$curr} {
font-size: $size;
}
$curr: $curr + 1;
$size: $size + 2;
}
}
#include setFonting(1, 3, 20px);
It compiles to :
h1 {font-size: 20px;} h2 {font-size: 22px;} h3 {font-size: 24px;} h4 {font-size: 26px;} h5 {font-size: 28px;}
So as you see, #{} interpolation in compass works outside curly brackets used to define statements for selector.

SASS/SCSS: Refer to property without using an intermediate variable

Is it possible to refer to a property previously defined in a selector without introducing an intermediate variable?
I'd like to say something like:
.foo {
padding: 15px;
width: 300px - $padding;
}
I know that $padding syntactically looks for a defined variable, I only use it in the above example to illustrate what I want to achieve in functionality.
The above example would be equivalent to this:
.foo {
$padding: 15px;
padding: $padding;
width: 300px - $padding * 2;
}
No, you can't, and it would be great.
I haven't tested, but as far as I know the only css pre-processor that can do that is stylus. Look at the variable section in its documentation, where it says Property Lookup. It works that way:
.foo {
padding: 15px;
width: 300px - #padding * 2;
}
But no, in Sass you can't, as far as I'm concerned.
If its an option to use an other preprocessor then scss, I really recommend using Stylus. There is a feature called Property lookup which is exactly what you want.

sass dynamic width

I'm using
.w400 {
width: 400px;
}
.w110 {
width: 110px;
}
.w600 {
width: 600px;
}
is it possible to make dynamic class with sass?
something like
.w(size) {
width: size+px
}
If you want to be able to use arbitrary .w(something) classes, I believe (see below) that is not possible with Sass. However, if you know beforehand what sizes you need, you could use mixins with arguments to generate the classes. Something like this:
#mixin width-class($size) {
.w#{$size} {
width: $size * 1px;
}
}
You would use it like this:
#include width-class(400);
#include width-class(110);
This generates the following CSS:
.w400 {
width: 400px; }
.w110 {
width: 110px; }
Now, if you want to avoid writing a new #include line for each of the classes, you can create another mixins (or combine the two mixins into one):
#mixin dynwidths($size-list) {
#each $size in $size-list {
#include width-class($size)
}
}
Now you can pass it a list of widths. This generates the same CSS as above:
#include width-classes(400 110);
Note: This is just a guess, but wildcard class names might be possible by extending Sass with Ruby. However, I'm not sure if this is a desirable feature.

Resources