The New CSS Math: rem() and mod()
CSS added many new Math functions to supplement the old favorites (such as calc()
). They all ultimately represent a numeric value, but the nuance in how they work is not always clear from the start. As of October 2023, these are available in the latest Safari and Firefox. They are also available in Edge/Chrome behind the Experimental Web Platform feature flag.
The basics of the CSS rem()
function
The mathematical concept of a remainder comes from division, representing what remains when a number does not divide evenly into another number. For example, with 9 ÷ 4
, 9
is not a multiple of 4
, so 4
does not divide evenly into 9
. You can add two 4
s to get 8
, but you still have a 1
left over to get to 9
, so 1
is our remainder.
In JavaScript we can do this with an operator: %
:
console.log(9 % 4); // 1
console.log(5 % 4.1); // 0.9
console.log(1003 % 5); // 3
In CSS, we now have access to the rem()
function to calculate a remainder. It takes two parameters, as JavaScript has two numbers to use with the remainder operator %
. In mathematical terms, the first number is the dividend and the second is the divisor.
The following CSS representations would be equivalent to the previous JavaScript examples:
line-height: rem(9, 4); /* 1 */
line-height: rem(5, 4.1); /* 0.9 */
line-height: rem(1003 % 5); /* 3 */
Since we are in CSS, we also have to consider units. Both parameter values need to be of the same type, such as a length or an angle representation.
rotate: rem(20deg, 5deg); /* 0deg */
rotate: rem(20deg, 7deg); /* 6deg */
rotate: rem(20deg, 3deg); /* 2deg */
You can mix units if they are of the same type. For example we can mix deg
and turn
since both of those represent angles.
rotate: rem(100deg, .25turn); /* 10deg (100 % 90) */
rotate: rem(200deg, .25turn); /* 20deg (200 % 90) */
See the Pen CSS Math functions: rem() (Visual reference) by Dan Wilson (@danwilson) on CodePen.
The value will always take the sign of the first parameter (dividend). So if the dividend is negative, the result will be negative. The sign of the second parameter (divisor) has no effect on the result.
line-height: rem(9, 4); /* 1 */
line-height: rem(-9, 4); /* -1 */
line-height: rem(9, -4); /* 1 */
line-height: rem(-9, -4); /* -1 */
The basics of the CSS mod()
function
Closely related to the concept of remainders is the modulus function. When both the dividend and divisor have the same sign, both functions have an equivalent result.
line-height: rem(9, 4); /* 1 */
line-height: mod(9, 4); /* 1 */
line-height: rem(-9, -4); /* -1 */
line-height: mod(-9, -4); /* -1 */
However, where the rem()
function takes the sign of the dividend, mod()
takes the sign of the divisor.
line-height: mod(9, 4); /* 1 */
line-height: mod(-9, 4); /* 1 */
line-height: mod(9, -4); /* -1 */
line-height: mod(-9, -4); /* -1 */
And most importantly... you have to think differently with mod()
when you have a mix of signs. Let’s start with an example:
line-height: rem(-9, 4); /* 1 */
line-height: mod(-9, 4); /* -3 */
line-height: rem(9, -4); /* -1 */
line-height: mod(9, -4); /* 3 */
If you take away the signs, for remainders, we typically think how many multiple of the divsor can fit in the dividend. In the case of rem(9, 4)
two multiples of 4
fit into 9
(because 2 * 4 = 8
), and the remainder is 1
(because 9 - 8 = 1
).
For mod()
in the case where there is one negative sign and one positive sign, I think about it like I am looking for the multiple bigger than the dividend. So for mod(9, -4)
, you look at the multiple just past the dividend (4 * 3 = 12
). And as per usual, we then look at the difference, so our answer is 12 - 9 = 3
.
See the Pen CSS Math functions: rem() and mod() (Visual reference) by Dan Wilson (@danwilson) on CodePen.