I have written about units in Sass in the past for my own blog, and not so long ago as a CSS-Tricks Sass snippet, but given how often I notice confusion and misconception about the way units work in our beloved preprocessor, I thought a full length article would not be such a bad idea after all.
After two years of writing and reading Sass code every day, I must say that snippets, articles and library code misusing Sass units are beyond counting. I have been guilty of this myself in the past, and I have witnessed Sass core designers trying to teach developers to properly use Sass units more than once.
This battle is obviously not over so let’s hope this article will be the coup de grace, in some way.
Units in real life
Before considering code, I think it is important to understand how numbers and units behave in real life. You may not have noticed this yet, but there are very few numbers we use in our daily life that do not have a unit. When we say “speed limit is 50”, we implicitly mean “50 kilometers per hour”; in this case the unit is km/h. When we say “look, eggs! I’ll have a dozen of those”, the unit is eggs: a dozen of eggs. There are exceptions of course but most usages of numbers in our daily routine usually involve a unit.
Along the same lines, running mathematical operations on numbers with units follow some rules. For instance, there are reasons why an area of 5 meters per 5 meters gives 25 square meters (m²
). Same for a cube of 1 meter side: it has a volume of 1m3 because 1 meter per 1 meter per 1 meter doesn’t give 3 meters, but 1 cubic meter.
I like how Chris Eppstein puts it:
2ft ^ 2 is 4 square feet (an area), not 4 ft (which would be a length). The correct thing to do in this calculation is let the units multiply along with the number. The easiest way to think how to properly do math with units is to think of a unit like it is an unknown quantity in algebra.
(2 * x) ^ 2 is 4 * x2. If the units at the end of a calculation don’t cancel out to become the dimension you’re expecting, this is a good sign that a mathematical error was made.
We also have to understand that some units are literally incompatible. For instance, what would the result of 2 bananas + 3 apples be? Well, it turns out we cannot compute anything more than 2 bananas + 3 apples, because apples and bananas are not compatible units. On the other hand, the result of 1 meter + 10 centimeters gives 1.1 meter or 110 centimeters. This is because meters and centimeters are both part of the metric system and thus are compatible.
Of course units do not have to be part of the metric system to be compatible with each others. For instance, light-years and inches are compatible units since they both serve the same purpose: measuring distances. Of course, there is no way an equation would involve both light-years and inches, since both units live at different edges of the distance units spectrum. Still, they are compatible.
Units in Sass
Now that we have fully grasped the way units work in real life, it’s time to tackle units in Sass. I hope I will not surprise you when I say that units in Sass behave exactly like units in real life. Some units are compatible, some are not. Two numbers with the same unit that are multiplied together will produce square units, and so on.
Let’s deal with one thing at a time, and start with comparing units. Sass has a table of compatible units which makes it possible to figure out whether two units are comparable and compatible or not. For instance, turn
(turns) and deg
(degrees) are compatible; s
(seconds) and pt
(points) are not.
This means that 12px + 1in
is a perfectly valid operation that will result in 108px
. Why 108px? you ask. Because 1 inch equals 96 pixels, and the result of the operation is expressed in the first member’s unit, which in this case is pixels. If we had written 1in + 12px
, the result would have been 1.125in
.
Now, square units. While it is true that multiplying two numbers with the same unit should produce square units, in practice Sass does not allow square units because they do not make sense in CSS. When such a case occurs, Sass simply throws an error like so:
4px*px isn’t a valid CSS value.
It took me some time to understand that this message does not mean that we tried to execute 4px * px
. In the aforementioned error message, px*px
means px²
, so the message could as well be:
4px² isn’t a valid CSS value.
It all makes sense: any value using px²
as a unit, or basically any square unit for that matter, is not a valid CSS value. CSS does not support square units since it does not make any sense to have those. Now, just for the record, if you tried to run 4px * px
, Sass would throw a different error message:
Undefined operation: “4px times px”.
What’s the matter?
Okay, so this has already been pretty long and perhaps you still don’t know what is the point of all that. This is the moment where I make it, don’t worry.
When you have a unitless number, and you want to convert it to a specific unit, do not append the unit as a string. Please, I am begging you to stop this nonsense. A unit should always be coupled with a numeric value as it doesn’t make any sense in itself. cm
is not a unit per se, it is a string; 1cm
is a unit, if that makes any sense.
When applying logical arithmetic principles to Sass, multiplying our value by 1 item of the desired unit is enough.
$value: 42;
.foo {
font-size: ($value * 1px); // {number} 42px
}
Now you probably ask yourself what’s the problem with simply appending the unit as a string given it works the same and you would you be plain right in most scenarios. Now consider this:
$value: 13.37;
.foo {
font-size: round($value + em); // {string} 13.37em
}
Can you guess what will happen if we tried compiling this code? If your answer is 13em
, I am sorry to inform you that you’re wrong. The correct answer is:
$value: “13.37em” is not a number for `round’
This happens because simply adding the unit on the right of a number implicitly casts the value to a string, resulting in an incorrect parameter for the round
function (which expects a number).
Of course if you don’t plan on running extra mathematical operations on the new value, you will never notice the difference and neither will CSS. Yet, it seems quite poor to work like this with units when you know how clever Sass is with them. For the sake of consistency, elegance and meaningful code, I highly recommend that you properly convert your unitless numbers.
Actually, it all makes sense when you turn the problem upside down and want to remove the unit of a number. If the solution that immediately comes to your mind is something such as:
$value: 42px;
$unitless-value: str-slice($value + ', 1, 2); // {string} 42
… then I am afraid you are doing this wrong. Removing the unit is as simple as dividing by one member of the unit. Again, it’s like in real life. If you want to get 25 from 25m, you have to divide 25m per 1m.
$value: 42px;
$unitless-value: (42px / 1px); // {number} 42
Then we have a number, not a string. It is completely logical, elegant and prevent any weird behaviour that might be surprising.
The case of 0
Before leaving, there is one thing I would like to extrapolate on. Earlier in this article, you may have read that the result of an addition or subtraction between two numbers of different units is expressed in the first member’s unit.
We can use this to our advantage when we want to convert one unit to another (compatible) unit for a reason or another. For instance, let’s say you want to convert seconds to milliseconds. I suppose you could multiply the value by 1000 in order to have milliseconds. On the other hand, you could leave this to Sass by adding the value to 0 millisecond, like so:
$value: 42s;
transition-duration: (0ms + $value); // {number} 42000ms
For such a case, I agree that we could as well compute the value ourselves. But when it comes to translating degrees into radians, or dots per centimeters (dpcm
) to dot per pixels (dppx
), it might be better to leave it to Sass rather than engage some fairly complex calculations.
$resolution: 0dppx + 42dpcm; // {string} 1587.40157dppx
$angle: 0rad + 42deg; // {string} 0.73304rad
If you are afraid that this little trick looks too “hacky” to be used as is, you can create a short function to make the API a bit more friendly. I am not sure whether this is worth the trouble, but I’ll let you be the judge of that. Here is my take on this function:
/// Convert one unit into another
/// @author Kitty Giraudel
/// @param {Number} $value - Initial value
/// @param {String} $unit - Desired unit
/// @return {Number}
/// @throw Error if `$unit` does not exist or if units are incompatible.
@function convert-unit($value, $unit) {
$units: (
'px': 0px,
'cm': 0cm,
'mm': 0mm,
'%': 0%,
'ch': 0ch,
'in': 0in,
'em': 0em,
'rem': 0rem,
'pt': 0pt,
'pc': 0pc,
'ex': 0ex,
'vw': 0vw,
'vh': 0vh,
'vmin': 0vmin,
'vmax': 0vmax,
'deg': 0deg,
'turn': 0turn,
'rad': 0rad,
'grad': 0grad,
's': 0s,
'ms': 0ms,
'Hz': 0Hz,
'kHz': 0kHz,
'dppx': 0dppx,
'dpcm': 0dpcm,
'dpi': 0dpi,
);
@if map-has-key($units, $unit) {
@return map-get($units, $unit) + $value;
}
@error "Unknown unit `#{$unit}`.";
}
Rewriting our previous example:
$resolution: convert-unit(42dpcm, 'dppx'); // {string} 1587.40157dppx
$angle: convert-unit(42deg, 'rad'); // {string} 0.73304rad
Final thoughts
So if we sum up what we’ve seen in this article:
- Units in Sass work exactly the same as units in real life;
- To give a number a unit, multiply the value per one member of the desired unit (e.g.
42 * 1px
); - To remove unit from a number, divide by one member of the relevant unit (e.g.
42px / 1px
); - When adding or subtracting two numbers with different compatible units, result is expressed in the unit of the first member;
- To convert a value from one unit to another (compatible), add the value to 0 member of the final unit (e.g.
0px + 42in
).
That’s it. I hope we’ll see less and less unit aberrations for more elegant unit handling from now on. As Chris says:
I think Sass’s math is really nice, once the light bulb goes on!
Frequently Asked Questions about Understanding Sass Units
What are the different types of Sass units?
Sass units are a fundamental aspect of CSS that allows you to specify dimensions, such as length, width, and height. There are several types of Sass units, including relative units like em, rem, vh, vw, vmin, vmax, and ex, and absolute units like px, cm, mm, in, pt, and pc. Each unit type has a specific use case and can be used to create responsive and scalable designs.
How do Sass units interact with each other?
Sass allows you to perform arithmetic operations with different units. However, it’s important to note that operations can only be performed between compatible units. For example, you can add or subtract pixels from pixels, but not pixels from inches. If you try to perform an operation between incompatible units, Sass will throw an error.
How can I convert between different Sass units?
Sass provides a function called unit()
that allows you to check the unit of a number. You can also use the unitless()
function to check if a number has no unit. To convert between units, you can use division and multiplication. For example, to convert pixels to ems, you can divide the pixel value by the base font size.
What is the difference between relative and absolute Sass units?
Relative units in Sass are based on another value, such as the size of the parent element or the size of the viewport. On the other hand, absolute units are fixed and do not change based on the context. For example, a pixel is an absolute unit because it always represents the same size, regardless of the context.
How can I use Sass units to create responsive designs?
Sass units can be used to create responsive designs by using relative units like percentages, ems, and viewport units. These units allow your design to scale based on the size of the viewport or the parent element, making it adaptable to different screen sizes.
What are the best practices for using Sass units?
It’s generally recommended to use relative units for responsive designs, and absolute units for fixed sizes. It’s also important to be consistent with your unit usage to avoid confusion. Additionally, you should avoid mixing units in calculations to prevent errors.
How does Sass handle unitless numbers?
In Sass, unitless numbers are treated as if they have a compatible unit. This means you can perform operations between unitless numbers and numbers with units. For example, you can multiply a unitless number by a number with a unit to get a result with that unit.
Can I define my own Sass units?
No, Sass does not support user-defined units. The available units in Sass are defined by the CSS specification and cannot be extended or modified.
How can I debug issues with Sass units?
If you’re having issues with Sass units, you can use the unit()
function to check the unit of a number. You can also use the @debug
directive to output the value of a variable to the console, which can help you identify issues.
What are the limitations of Sass units?
One limitation of Sass units is that they cannot be used in string interpolation. Additionally, Sass does not support calc() expressions with units, which can limit your ability to perform complex calculations.
Non-binary trans accessibility & diversity advocate, frontend developer, author. Real life cat. She/her.