CSS typed arithmetic is genuinely thrilling! It opens the door to new sorts of structure composition and animation logic we might solely hack earlier than. The primary time I revealed one thing that leaned on typed arithmetic was on this animation:
However earlier than we dive into what is going on in there, let’s pause and get clear on what typed arithmetic truly is and why it issues for CSS.
Browser Help: The CSS characteristic mentioned on this article, typed arithmetic, is on the innovative. As of the time of writing, browser help 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 help this performance. Please verify assets like MDN or Can I Use for the newest help standing.
The Sorts
In the event you actually wish to get what a “kind” is in CSS, take into consideration TypeScript. Now neglect about TypeScript. This can be a CSS article, the place semantics truly matter.
In CSS, a kind describes the unit area a worth lives in, and is known as a data-type
. Each CSS worth belongs to a particular kind, and every CSS property and performance solely accepts the info kind (or varieties) it expects.
- Properties like
opacity
orscale
use a plain
with no models. width
,peak
, different field metrics, and lots of further properties use
models likepx
,rem
,cm
, and so on.- Features like
rotate()
orconic-gradient()
use an
withdeg
,rad
, orflip
. animation
andtransition
usefor his or her period in seconds (
s
) or milliseconds (ms
).
Be aware: You possibly can establish CSS information varieties within the specs, on MDN, and different official references by their angle brackets:
.
There are various extra information 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 at the moment. The mathematical idea stays the identical for (nearly) every type.
I say “nearly” every type for one motive: not each information kind is calculable. For example, varieties like
,
, or
can’t be utilized in mathematical operations. An expression like "foo" * purple
could be meaningless. So, after we talk about arithmetic on the whole, and typed arithmetic particularly, it’s essential to make use of varieties which can be inherently calculable, like
,
, or
.
The Guidelines of Typed Arithmetic
Even after we use calculable information varieties, there are nonetheless limitations and essential guidelines to remember when performing mathematical operations on them.
Addition and Subtraction
Sadly, a mix-and-match method doesn’t actually work right here. Expressions like calc(3em + 45deg)
or calc(6s - 3px)
is not going to produce a logical outcome. When including or subtracting, it’s essential to keep on with the identical information kind.
In fact, you possibly can add and subtract totally different models throughout the similar kind, like calc(4em + 20px)
or calc(300deg - 1rad)
.
Multiplication
With multiplication, you possibly can solely multiply by a plain
kind. For instance: calc(3px * 7)
, calc(10deg * 6)
, or calc(40ms * 4)
. The outcome 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 count on a results of 100px²
. Nonetheless, there are not any squared pixels in CSS, and positively no sq. levels (although that could possibly be fascinating…). 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 shouldn’t be allowed, and you’ll divide by a quantity simply as you possibly can multiply a quantity. However what occurs once you divide a kind by the identical kind?
Trace: that is the place issues get fascinating.
Once more, if we had been considering by way of common math, we’d count on the models to cancel one another out, leaving solely the calculated worth. For instance, 90x / 6x = 15
. In CSS, nonetheless, 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 Safari 18.2 and Chrome 140 (and hopefully quickly in all different browsers), this expression now returns a sound quantity, which winds up being 7
on this case. That is the foremost change that typed arithmetic permits.
Is that each one?!
That little division? Is that the large factor I known as “genuinely thrilling”? Sure! As a result of this one little characteristic opens the door to a world of artistic prospects. Living proof: we are able to convert values from one information kind to a different and mathematically situation values of 1 kind based mostly on one other, identical to within the swirl instance I demoed on the prime.
So, to know what is going on there, let’s have a look at a extra simplified swirl:
I’ve a container
parts within the markup which can be organized in a spiral with CSS. Every component 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 component utilizing
sibling-index()
and multiply it by 10deg
. So, the primary component with an index of 1
might 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 wherever. On this case, I can multiply it by a
worth (e.g. 180px
) that determines the component’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 component in a different 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 essential to make clear that when utilizing typed arithmetic this manner, 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 a substitute, the outcome could be utterly totally different — although 1turn
is equal to 360deg
, the ensuing unitless quantity would symbolize the worth in turns.
A clearer instance might be seen with
values.
Let’s say we're working with a display screen width of 1080px
. If we divide the display screen width (100vw
) by 1px
, we get the variety of pixels that match into the display screen width, which is, in fact, 1080
.
calc(100vw / 1px) /* 1080 */
Nonetheless, if we divide that very same width by 1em
(and assume a font dimension of 16px
), we get the variety of em
models that match throughout the display screen.
calc(100vw / 1em) /* 67.5 */
The ensuing quantity is unitless in each instances, however its which means is fully depending on the unit of the worth we divided by.
From Size to Angle
In fact, this conversion doesn’t need to be from a kind
to a kind
. Right here is an instance that calculates a component’s angle based mostly on the display screen width (100vw
), creating a brand new and strange sort of responsiveness.
And get this: There are not any media queries in right here! it’s all occurring 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 supplies me a brand new vary, from -400px
to 0px
.
Utilizing typed arithmetic, I then divide this vary by 400px
, which supplies me a normalized, unitless quantity between -1
and 0
. And eventually, I convert this quantity into an
by multiplying it by -90deg
.
Right here’s what that appears like in CSS after 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
information kind, corresponding to opacity
. What if I wish to decide the font’s opacity based mostly on its dimension, making smaller fonts extra opaque and due to this fact clearer? Is it potential? Completely.

On this instance, I'm setting a unique font-size
worth for every component 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 might 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 develop into totally clear, I divide it by twice that quantity (2.4rem
). This offers me a outcome 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 dimension in pixel models although the scale is outlined in rem
models. I merely use typed arithmetic to divide the font dimension by 1px
, which supplies 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 capabilities, in comparison with different approaches, is that all the pieces occurs dynamically at runtime. Right here, for instance, is a small demo the place I shade the component’s background relative to its rendered width.
p {
--hue: calc(100cqi / 1px);
background-color: hsl(var(--hue, 0) 75% 25%);
}
You possibly can drag the bottom-right nook of the component to see how the colour modifications in real-time.
Right here’s one thing neat about this demo: as a result of the component’s default width is 50% of the display screen width and the colour is immediately proportional to that width, it’s potential that the component will initially seem in utterly totally different colours on totally different gadgets with totally different screens. Once more, that is all occurring 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 prospects. Earlier than we put a bow on this, I wished to pit this idea towards 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 series, however I did surprise what would occur if we had 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 needed (possibly?), 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 peak, 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 component’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 flexibility to divide one typed worth by one other to provide a unitless quantity would possibly look like no large 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 totally different CSS information varieties, reworking 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 type a button or animate a loading spinner. It represents a basic shift in our psychological mannequin. We're not merely declaring static types, however moderately defining dynamic, mathematical relationships between properties. The width of a component can now intrinsically find out about its shade, an angle can dictate a distance, and a font’s dimension can decide its personal visibility.
That is CSS changing into self-aware, able to creating complicated behaviors and responsive designs that adapt with a precision and class that beforehand required JavaScript.
So, the subsequent time you end up reaching for JavaScript to bridge a spot between two CSS properties, pause for a second. Ask your self if there’s a mathematical relationship you possibly can outline as a substitute. You is likely to be shocked at how far you possibly can go together with just some 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 after we begin mixing these strategies with scroll-driven animations, view transitions, and different fashionable CSS options? The potential for creating intricate information visualizations, generative artwork, and really fluid person interfaces, all natively in CSS, is immense. We're being handed a brand new set of artistic instruments, and the instruction handbook remains to be being written.