CSS typed arithmetic is genuinely thrilling! It opens the door to new sorts of structure composition and animation logic we may solely hack earlier than. The primary time I printed one thing that leaned on typed arithmetic was on this animation:
However earlier than we dive into what is occurring in there, let’s pause and get clear on what typed arithmetic really is and why it issues for CSS.
Browser Assist: The CSS characteristic mentioned on this article, typed arithmetic, is on the leading edge. As of the time of writing, browser assist may be very restricted and experimental. To make sure all readers can perceive the ideas, the examples all through this text are accompanied by movies and pictures, demonstrating the outcomes for these whose browsers don’t but assist this performance. Please test sources like MDN or Can I Use for the newest assist standing.
The Sorts
Should you actually wish to get what a “kind” is in CSS, take into consideration TypeScript. Now neglect about TypeScript. It is a CSS article, the place semantics really matter.
In CSS, a kind describes the unit house a worth lives in, and known as a data-type
. Each CSS worth belongs to a particular kind, and every CSS property and performance solely accepts the information kind (or varieties) it expects.
- Properties like
opacity
orscale
use a plain
with no items. width
,top
, different field metrics, and plenty of extra properties use
items likepx
,rem
,cm
, and so forth.- Features like
rotate()
orconic-gradient()
use an
withdeg
,rad
, orflip
. animation
andtransition
usefor his or her length in seconds (
s
) or milliseconds (ms
).
Word: You may determine CSS knowledge varieties within the specs, on MDN, and different official references by their angle brackets:
.
There are a lot of extra knowledge varieties like
,
, and
, however the varieties talked about above cowl most of our day by day use instances and are all we are going to want for our dialogue right this moment. The mathematical idea stays the identical for (virtually) all kinds.
I say “virtually” all kinds for one motive: not each knowledge kind is calculable. As an example, varieties like
,
, or
can’t be utilized in mathematical operations. An expression like "foo" * purple
could be meaningless. So, once we focus on arithmetic basically, and typed arithmetic specifically, it’s essential to make use of varieties which are inherently calculable, like
,
, or
.
The Guidelines of Typed Arithmetic
Even once we use calculable knowledge varieties, there are nonetheless limitations and necessary guidelines to bear in mind when performing mathematical operations on them.
Addition and Subtraction
Sadly, a mix-and-match strategy doesn’t actually work right here. Expressions like calc(3em + 45deg)
or calc(6s - 3px)
won’t produce a logical consequence. When including or subtracting, you should keep on with the identical knowledge kind.
In fact, you’ll be able to add and subtract completely different items throughout the similar kind, like calc(4em + 20px)
or calc(300deg - 1rad)
.
Multiplication
With multiplication, you’ll be able to solely multiply by a plain
kind. For instance: calc(3px * 7)
, calc(10deg * 6)
, or calc(40ms * 4)
. The consequence will all the time undertake the kind and unit of the primary worth, with the brand new worth being the product of the multiplication.
However why are you able to solely multiply by a quantity? If we tried one thing like calc(10px * 10px)
and assumed it adopted “common” math, we’d anticipate a results of 100px²
. Nonetheless, there aren’t any squared pixels in CSS, and definitely no sq. levels (although that could possibly be attention-grabbing…). As a result of such a result’s invalid, CSS solely permits multiplying typed values by unitless numbers.
Division
Right here, too, mixing and matching incompatible varieties isn’t allowed, and you may divide by a quantity simply as you’ll be able to multiply a quantity. However what occurs while you divide a kind by the identical kind?
Trace: that is the place issues get attention-grabbing.
Once more, if we have been pondering when it comes to common math, we’d anticipate the items to cancel one another out, leaving solely the calculated worth. For instance, 90x / 6x = 15
. In CSS, nevertheless, this isn’t the case. Sorry, it wasn’t the case.
Beforehand, an expression like calc(70px / 10px)
would have been invalid. However beginning with Chrome 140 (and hopefully quickly in all different browsers), this expression now returns a legitimate quantity, which winds up being 7
on this case. That is the foremost change that typed arithmetic allows.
Is that every one?!
That little division? Is that the large factor I referred to as “genuinely thrilling”? Sure! As a result of this one little characteristic opens the door to a world of inventive potentialities. Living proof: we will convert values from one knowledge kind to a different and mathematically situation values of 1 kind based mostly on one other, similar to within the swirl instance I demoed on the high.
So, to know what is occurring there, let’s have a look at a extra simplified swirl:

I’ve a container
components within the markup which are organized in a spiral with CSS. Every ingredient has an angle relative to the middle level, rotate(var(--angle))
, and a distance from that middle level, translateX(var(--distance))
.
The angle calculation is kind of direct. I take the index of every ingredient utilizing
sibling-index()
and multiply it by 10deg
. So, the primary ingredient with an index of 1
can be rotated by 10 levels (1 * 10deg
), the second by 20 levels (2 * 10deg
), the third by 30 levels (3 * 10deg
), and so forth.
i { --angle: calc(sibling-index() * 10deg); }
As for the gap, I need it to be immediately proportional to the angle. I first use typed arithmetic to divide the angle by 360 levels: var(--angle) / 360deg
.
This returns the angle’s worth, however as a unitless quantity, which I can then use anyplace. On this case, I can multiply it by a
worth (e.g. 180px
) that determines the ingredient’s distance from the middle level.
i {
--angle: calc(sibling-index() * 10deg);
--distance: calc(var(--angle) / 360deg * 180px);
}
This manner, the ratio between the angle and the gap stays fixed. Even when we set the angle of every ingredient in another way, or to a brand new worth, the weather will nonetheless align on the identical spiral.
The Significance of the Divisor’s Unit
It’s necessary to make clear that when utilizing typed arithmetic this fashion, you get a unitless quantity, however its worth is relative to the unit of the divisor.
In our simplified spiral, we divided the angle by 360deg
. The ensuing unitless quantity, due to this fact, represents the worth in levels. If we had divided by 1turn
as an alternative, the consequence could be utterly completely different — despite the fact that 1turn
is equal to 360deg
, the ensuing unitless quantity would signify the worth in turns.
A clearer instance may be seen with
values.
Let’s say we're working with a display width of 1080px
. If we divide the display width (100vw
) by 1px
, we get the variety of pixels that match into the display width, which is, after all, 1080
.
calc(100vw / 1px) /* 1080 */
Nonetheless, if we divide that very same width by 1em
(and assume a font measurement of 16px
), we get the variety of em
items that match throughout the display.
calc(100vw / 1em) /* 67.5 */
The ensuing quantity is unitless in each instances, however its which means is totally depending on the unit of the worth we divided by.
From Size to Angle
In fact, this conversion doesn’t must be from a kind
to a kind
. Right here is an instance that calculates a component’s angle based mostly on the display width (100vw
), creating a brand new and weird sort of responsiveness.
And get this: There aren't any media queries in right here! it’s all taking place in a single line of CSS doing the calculations.
To find out the angle, I first outline the width vary I wish to work inside. clamp(300px, 100vw, 700px)
offers me a closed vary of 400px
, from 300px
to 700px
. I then subtract 700px
from this vary, which provides me a brand new vary, from -400px
to 0px
.
Utilizing typed arithmetic, I then divide this vary by 400px
, which provides me a normalized, unitless quantity between -1
and 0
. And at last, I convert this quantity into an
by multiplying it by -90deg
.
Right here’s what that appears like in CSS once we put all of it collectively:
p {
rotate: calc(((clamp(300px, 100vw, 700px) - 700px) / 400px) * -90deg);
}
From Size to Opacity
In fact, the ensuing unitless quantity can be utilized as-is in any property that accepts a
knowledge kind, reminiscent of opacity
. What if I wish to decide the font’s opacity based mostly on its measurement, making smaller fonts extra opaque and due to this fact clearer? Is it potential? Completely.

On this instance, I'm setting a distinct font-size
worth for every ingredient utilizing a
--font-size
customized property. and because the vary of this variable is from 0.8rem
to 2rem
, I first subtract 0.8rem
from it to create a brand new vary of 0
to 1.2rem
.
I may divide this vary by 1.2rem
to get a normalized, unitless worth between 0
and 1
. Nonetheless, as a result of I don’t need the textual content to grow to be totally clear, I divide it by twice that quantity (2.4rem
). This offers me a consequence between 0
and 0.5
, which I then subtract from the utmost opacity of 1
.
p {
font-size: var(--font-size, 1rem);
opacity: calc(1 - (var(--font-size, 1rem) - 0.8rem) / 2.4rem);
}
Discover that I'm displaying the font measurement in pixel items despite the fact that the scale is outlined in rem
items. I merely use typed arithmetic to divide the font measurement by 1px
, which provides me the scale in pixels as a unitless worth. I then inject this worth into the content material
of the the paragraph’s ::after
pseudo-element.
p::after {
counter-reset: px calc(var(--font-size, 1rem) / 1px);
content material: counter(px) 'px';
}
Dynamic Width Colours
In fact, the actual great thing about utilizing native CSS math features, in comparison with different approaches, is that the whole lot occurs dynamically at runtime. Right here, for instance, is a small demo the place I shade the ingredient’s background relative to its rendered width.
p {
--hue: calc(100cqi / 1px);
background-color: hsl(var(--hue, 0) 75% 25%);
}
You may drag the bottom-right nook of the ingredient to see how the colour adjustments in real-time.
Right here’s one thing neat about this demo: as a result of the ingredient’s default width is 50% of the display width and the colour is immediately proportional to that width, it’s potential that the ingredient will initially seem in utterly completely different colours on completely different gadgets with completely different screens. Once more, that is all taking place with none media queries or JavaScript.
An Excessive Instance: Chaining Conversions
OK, so we’ve established that typed arithmetic is cool and opens up new and thrilling potentialities. Earlier than we put a bow on this, I wished to pit this idea in opposition to a extra excessive instance. I attempted to think about what would occur if we took a
kind, transformed it to a
kind, then to an
kind, again to a
kind, and, from there, again to a
kind.
Phew!
I couldn’t discover a real-world use case for such a sequence, however I did marvel what would occur if we have been to animate a component’s width and use that width to find out the peak of one thing else. All of the calculations may not be vital (perhaps?), however I believe I discovered one thing that appears fairly cool.
On this demo, the animation is on the strong line alongside the underside. The vertical place of the ball, i.e. its top, relative to the road, is proportional to the road’s width. So, as the road expands and contracts, so does the trail of the bouncing ball.
To create the parabolic arc that the ball strikes alongside, I take the ingredient’s width (100cqi
) and, utilizing typed arithmetic, divide it by 300px
to get a unitless quantity between 0
and 1
. I multiply that by 180deg
to get an angle that I take advantage of in a sin()
operate (Juan Diego has a nice article on this), which returns one other unitless quantity between 0
and 1
, however with a parabolic distribution of values.
Lastly, I multiply this quantity by -200px
, which outputs the ball’s vertical place relative to the road.
.ball {
--translateY: calc(sin(calc(100cqi / 300px) * 180deg) * -200px) ;
translate: -50% var(--translateY, 0);
}
And once more, as a result of the ball’s place is relative to the road’s width, the ball’s place will stay on the identical arc, regardless of how we outline that width.
Wrapping Up: The Daybreak of Computational CSS
The power to divide one typed worth by one other to provide a unitless quantity would possibly appear to be no huge deal; extra like a minor footnote in the grand historical past of CSS.
However as we’ve seen, this single characteristic is a quiet revolution. It dismantles the long-standing partitions between completely different CSS knowledge varieties, remodeling them from remoted silos right into a linked, interoperable system. We’ve moved past easy calculations, and entered the period of true Computational CSS.
This isn’t nearly discovering new methods to model a button or animate a loading spinner. It represents a elementary shift in our psychological mannequin. We're not merely declaring static types, however reasonably defining dynamic, mathematical relationships between properties. The width of a component can now intrinsically learn about its shade, an angle can dictate a distance, and a font’s measurement can decide its personal visibility.
That is CSS changing into self-aware, able to creating advanced behaviors and responsive designs that adapt with a precision and class that beforehand required JavaScript.
So, the following time you end up reaching for JavaScript to bridge a niche between two CSS properties, pause for a second. Ask your self if there’s a mathematical relationship you'll be able to outline as an alternative. You could be shocked at how far you'll be able to go along with only a few traces of CSS.
The Future is Calculable
The examples on this article are simply the primary steps right into a a lot bigger world. What occurs once we begin mixing these methods with scroll-driven animations, view transitions, and different trendy CSS options? The potential for creating intricate knowledge visualizations, generative artwork, and really fluid person interfaces, all natively in CSS, is immense. We're being handed a brand new set of inventive instruments, and the instruction handbook remains to be being written.