[FIXED] SassError undefined operation
Encountering SASS Error: undefined operation and not sure what it means? Typical causes such as performing invalid operations, mixing incompatible units, and the nuances of division in SASS
Jun 22, 2023 | Read time 10 minutesđ Table of contents
Introduction
Recently when I was working on a front-end project using Angular and SASS, I noticed this error coming up:
SassError undefined operation
Now generally this comes up when we are trying to do a math operation (add, minus, divide, multiply) in SASS and its failing.
So I ended up going through all the possibility and a give you this step by step guide on how to approach.
Generally the error looks like this when you are compiling SASS:
Error: Undefined operation "#700e70 + 15%".
â·
2 â $color: $color + $amount;
â ^^^^^^^^^^^^^^^^
â”
style\util\_functions.scss 2:13 lighten()
style\components\_buttons.scss 12:27 @forward
style\components\index.scss 2:1 @use
style\main.scss 1:1 root stylesheet
Conflicting types
The most common reason why this error pops up is that you are to do a math operation (addition, subtraction, multiplication, and division) on two incompatible types.
For example you are trying to multiply a string and a number, or a color and a number, SASS will throw an âundefined operationâ error.
Consider the following SASS code:
$var: "hello" * 10; //Invalid operation
We can see that we are mixing a string with number. This will give you the compile error.
Different unit types
One of the gotchas is that even though we are using the math operation - applying that to different types will give you âundefined operationâ error as well.
You will need to convert units like pixels (px), ems (em), rems (rem), and percentages (%).
For example converting between pixels
and em
will fail:
$var: 10px + 2em; //Invalid operation
to convert from pixels (px) to root ems (rem), youâll first need to know the root font size of your HTML document because 1 rem equals the font size of the root HTML element. The standard default in most browsers is 16px, but it can be different if a user has changed their settings or if itâs been overridden in the CSS.
Once you have the root font size, you can create a function or mixin to convert px to rem:
@function pxToRem($px, $base-font-size: 16px) {
@return ($px / $base-font-size) * 1rem;
}
Then you can use this function in your SCSS code:
body {
font-size: pxToRem(18px); // This will compile to font-size: 1.125rem if the root font-size is 16px
}
If your root font size is not 16px, you can adjust the $base-font-size parameter accordingly. For example, if your root font size is 20px:
body {
font-size: pxToRem(18px, 20px); // This will compile to font-size: 0.9rem if the root font-size is 20px
}
Review the division operator
Be careful of using the division operator ('/' forward slash) since this can have conflicts with the CSS meaning.
In CSS, the â/â forward slash can mean different things. In the following code, we can see that the forward slash is a short-hand for border-radius width (100px) and height (50px)
#oval {
width: 200px;
height: 100px;
background: red;
border-radius: 100px / 50px;
}
Consider another example:
$var: 500px/200px;
Here â/â is treated as a CSS separator, not a division operator.
This can be fixed by using parentheses or a variable:
$var: (500px/200px); // Using parentheses
$num1: 500px;
$num2: 200px;
$var: $num1/$num2; // Using variables
As of Dart Sass 1.32.0, the Sass team has introduced a new function for division: div().
This replaces the / division operator, which is being gradually phased out for division operations. The / will mainly be preserved as a CSS separator, for cases like defining font sizes (font: 16px/1.5).
To use the div() function for division, you would do something like this:
$width: div(500px, 2); // Results in 250px
This example will divide 500px by 2, resulting in 250px. The div() function works exactly the same way as the / used to work for division, but without the confusion of also being a CSS separator.
This function makes Sass more predictable and less confusing and the recommended to use div() for new work instead of the â/â (forward slash)
Remember to check your projectâs Sass version before using the div() function, as it may not be available in older versions.
The 1px trick
$numericValue: 30;
$pixelValue: $numericValue+px; // also tried $pixelValue: #{$numericValue}px;
$calc: $pixelValue * 2; // also tried $calc: unquote($pixelValue) * 2;
The trick is to use * 1px when you want to add a unit. Using +px or interpolation (#{$numericValue}px) turns it into a string.
$numericValue: 30;
$pixelValue: $numericValue * 1px;
$calc: $pixelValue * 2;
Consider the calc() CSS function
One alternative that I would recommend is using the calc() function.
This is a powerful native CSS way to perform calculations that can involve different units.
Itâs very useful when you need to perform operations with mixed units, or when you need to calculate values dynamically. Here are some examples:
Consider the following example where I need to calculate the width:
.element {
width: calc(100% - 20px); /* The width is 100% of the parent element minus 20 pixels */
}
We can also combine calc() function with CSS variables if you want to do something more dynamic:
:root {
--main-padding: 15px;
}
.element {
padding: var(--main-padding);
width: calc(100% - var(--main-padding));
}
In the above case, the width is 100% of the parent element minus the --main-padding
variable.
We can also use responsive units like vw
or vh
:
.element {
font-size: calc(1em + 1vw);
}
The font size is 1em plus 1% of the viewport width. This will allow the font size to scale responsively as the screen width.
Now keep in mind that calc() is calculated in real-time not at compile time like SASS.
This makes it especially useful for calculations that need to respond to dynamic conditions (like the size of the viewport, for example).
Be aware that older browsers may not fully support calc(), so always use feature detection or a fallback when necessary.
Browser Support
Internet Explorerâs non-standard expression() syntax can be used to somewhat simulate calc() support in its older versions. However, due to varied sub-pixel rounding handling by different browsers, layouts employing calc() may yield unexpected outcomes.
Regarding partial support: In Android Browser 4.4, the calc() function canât multiply or divide values. Internet Explorer 9 can crash when calc() is used for the background-position value. In Internet Explorer 10 and 11, calc() doesnât always work correctly in various use cases as mentioned in known issues.
- Firefox versions below 48 donât support calc() in properties like line-height, stroke-width, stroke-dashoffset, and stroke-dasharray.
- Internet Explorer (IE) does not support calc() with color functions such as hsl().
- Both IE and Edge reportedly do not support calc() within a flex property. For example, flex: 1 1 calc(50% - 20px); will not work.
- IE11 does not support transitioning values set with calc().
- Safari and iOS Safari (versions 6 and 7) do not support viewport units (vw, vh, etc) in calc().
- IE11 reportedly does not correctly support calc() in generated content.
- IE11 also has reported problems with calc() in nested expressions, e.g., width: calc((100% - 10px) / 3);, as it rounds differently.
- IE10, IE11, and Edge versions below 14 donât support using calc() within a transform property.
- IE10 experiences crashes when a div using calc() in a property has a child with the same property set to inherit.
- IE versions 9 to 11 do not render box-shadow when calc() is used for any of the values.
- IE versions 9 to 11 and Edge do not support width: calc() on table cells.
- Firefox versions below 59 do not support calc() on color functions.
- Firefox versions below 66 do not support width: calc() on table cells.
Summary
In this post, I went over the âSassError undefined operationâ error. Now this error is usually caused by incorrect use of the math operators (addition, subtraction, division, and multiplication).
The first thing to check is that we are applying the math operation on the same types (string vs colours vs numbers), check that the units are the same (eg pixels vs rems).
Also you will need to consider the division, since this can conflict with the â/â (forward slash).
Lastly, if you want to get around all of this, then consider using the native CSS calc() function.