It is a sequence! It began a couple of articles in the past, once we came upon that, in accordance with the State of CSS 2025 survey, trigonometric capabilities have been the “Most Hated” CSS function.

I’ve been making an attempt to vary that perspective, so I showcased a number of makes use of for trigonometric capabilities in CSS: one for sin() and cos() and one other on tan(). Nonetheless, that’s solely half of what trigonometric capabilities can do. So at present, we’ll poke on the inverse world of trigonometric capabilities: asin(), acos(), atan() and atan2().
CSS Trigonometric Capabilities: The “Most Hated” CSS Function
sin()andcos()tan()asin(),acos(),atan()andatan2()(You might be right here!)
Inverse capabilities?
Recapping issues a bit, given an angle, the sin(), cos() and tan() capabilities return a ratio presenting the sine, cosine, and tangent of that angle, respectively. And if you happen to learn the final two components of the sequence, then you definately already know what every of these portions represents.
What if we wished to go the opposite approach round? If now we have a ratio that represents the sine, cosine or tangent of an angle, how can we get the unique angle? That is the place inverse trigonometric capabilities are available! Every inverse perform asks what the required angle is to get a given worth for a particular trigonometric perform; in different phrases, it undoes the unique trigonometric perform. So…
acos()is the inverse ofcos(),asin()is the inverse ofsin(), andatan()andatan2()are the inverse oftan().
They’re additionally known as “arcus” capabilities and written as arcos(), arcsin() and arctan() in most locations. It’s because, in a circle, every angle corresponds to an arc within the circumference.
The size of this arc is the angle instances the circle’s radius. Since trigonometric capabilities reside in a unit circle, the place the radius is the same as 1, the arc size can be the angle, expressed in radians.
Their mathy definitions are slightly boring, to say the least, however they’re easy:
y = acos(x)such thatx = cos(y)y = asin(x)such thatx = sin(y)y = atan(x)such thatx = tan(y)
acos() and asin()
Utilizing acos() and asin(), we will undo cos(θ) and sin(θ) to get the beginning angle, θ. Nonetheless, if we attempt to graph them, we’ll discover one thing odd:

The capabilities are solely outlined from -1 to 1!
Bear in mind, cos() and sin() can take any angle, however they may all the time return a quantity between -1 and 1. For instance, each cos(90°) and cos(270°) (to not point out others) return 0, so which worth ought to acos(0) return? To reply this, each acos() and asin() have their area (their enter) and vary (their output) restricted:
acos()can solely take numbers between-1and1and return angles between0°and180°.asin()can solely take numbers between-1and1and return angles between-90°and90°.
This limits so much of the conditions the place we will use acos() and asin(), since one thing like asin(1.2) doesn’t work in CSS* — in accordance with the spec, going outdoors acos() and asin() area returns NaN — which leads us to our subsequent inverse perform…
atan() and atan2()
Equally, utilizing atan(), we will undo tan(θ) to get θ. However, in contrast to asin() and acos(), if we graph it, we’ll discover a giant distinction:

This time it’s outlined on the entire quantity line! This is smart since tan() can return any quantity between -Infinity and Infinity, so atan() is outlined in that area.
atan() can take any quantity between -Infinity and Infinity and returns angles -90° and 90°.
This makes atan() extremely helpful to search out angles in all types of conditions, and much more versatile than acos() and asin(). That’s why we’ll be utilizing it, alongside atan2(), going ahead. Though don’t fear about atan2() for now, we’ll get to it later.
Discovering the right angle
Within the final article, we labored so much with triangles. Particularly, we used the tan() perform to search out one of many sides of a right-angled triangle from the next relationships:

To make it work, we wanted to know considered one of its sides and the angle, and by fixing the equation, we’d get the opposite facet. Nonetheless, usually, we do know the lengths of the triangle’s sides and what we are literally on the lookout for is the angle. In that case, the final equation turns into:

Triangles and Conic Gradients
Discovering the angle is useful in a lot of circumstances, like in gradients, as an illustration. In a linear gradient, for instance, if we would like it to go from nook to nook, we’ll should match the gradient’s angle relying on the aspect’s dimensions. In any other case, with a hard and fast angle, the gradient received’t change if the aspect will get resized:
.gradient {
background: repeating-linear-gradient(ghostwhite 0px 25px, darkslategray 25px 50px);
}
This can be the specified look, however I believe that almost all usually than not, you need it to match the aspect’s dimensions.
Utilizing linear-gradient(), we will simply remedy this utilizing to high proper or to backside left values for the angle, which mechanically units the angle so the gradient goes from nook to nook.
.gradient {
background: repeating-linear-gradient(to high proper, ghostwhite 0px 25px, darkslategray 25px 50px);
}
Nonetheless, we don’t have that sort of syntax for different gradients, like a conic-gradient(). For instance, the following conic gradient has a hard and fast angle and received’t change upon resizing the aspect.
.gradient {
background: conic-gradient(from 45deg, #84a59d 180deg, #f28482 180deg);
}
Fortunately, we will repair this utilizing atan()! We are able to have a look at the gradient as a right-angled triangle, the place the width is the adjoining facet and the peak the other facet:

Then, we will get the angle utilizing this system:
.gradient {
--angle: atan(var(--height-gradient) / var(--width-gradient));
}
Since conic-gradient() begins from the highest edge — conic-gradient(from 0deg) — we’ll should shift it by 90deg to make it work.
.gradient {
--rotation: calc(90deg - var(--angle));
background: conic-gradient(from var(--rotation), #84a59d 180deg, #f28482 180deg);
}
You could be questioning: can’t we do this with a linear gradient? And the reply is, sure! However this was simply an instance to showcase atan(). Let’s transfer on to extra attention-grabbing stuff that’s distinctive to conic gradients.
I obtained the following instance from Ana Tudor’s submit on “Variable Side Ratio Card With Conic Gradients”:
Fairly cool, proper?. Sadly, Ana’s submit is from 2021, a time when trigonometric capabilities have been specced out however not applied. As she mentions in her article, it wasn’t doable to create these gradients utilizing atan(). Fortunately, we reside sooner or later! Let’s see how easy they grow to be with trigonometry and CSS.
We’ll use two conic gradients, every of them overlaying half of the cardboard’s background.

To avoid wasting time, I’ll gloss over precisely the best way to make the unique gradient, so here’s a fast little step-by-step information on the best way to make a kind of gradients in a square-shaped aspect:
Since we’re working with an ideal sq., we will repair the --angle and --rotation to be 45deg, however for a basic use case, every of the conic-gradients would appear like this in CSS:
.gradient {
background:
/* one beneath */
conic-gradient(
from var(--rotation) at backside left,
#b9eee1 calc(var(--angle) * 1 / 3),
#79d3be calc(var(--angle) * 1 / 3) calc(var(--angle) * 2 / 3),
#39b89a calc(var(--angle) * 2 / 3) calc(var(--angle) * 3 / 3),
clear var(--angle)
),
/* one above */
conic-gradient(
from calc(var(--rotation) + 180deg) at high proper,
#fec9d7 calc(var(--angle) * 1 / 3),
#ff91ad calc(var(--angle) * 1 / 3) calc(var(--angle) * 2 / 3),
#ff5883 calc(var(--angle) * 2 / 3) calc(var(--angle) * 3 / 3),
clear var(--angle)
);
}
And we will get these --angle and --rotation variables the identical approach we did earlier — utilizing atan(), after all!
.gradient {
--angle: atan(var(--height-gradient) / var(--width-gradient));
--rotation: calc(90deg - var(--angle));
}
What about atan2()?
The final instance was all abou atan(), however I instructed you we’d additionally have a look at the atan2() perform. With atan(), we get the angle once we divide the other facet by the adjoining facet and move that worth because the argument. On the flip facet, atan2() takes them as separate arguments:
atan(reverse/adjoining)atan2(reverse, adjoining)
What’s the distinction? To clarify, let’s backtrack a bit.
We used atan() within the context of triangles, which means that the adjoining and reverse sides have been all the time constructive. This will likely seem to be an apparent factor since lengths are all the time constructive, however we received’t all the time work with lengths.
Think about we’re in a x-y aircraft and decide a random level on the graph. Simply by taking a look at its place, we will know its x and y coordinates, which might have each unfavorable and constructive coordinates. What if we wished its angle as an alternative? Measuring it, after all, from the constructive x-axis.

Effectively, bear in mind from the final article on this sequence that we will additionally outline tan() because the quotient between sin() and cos():

Additionally recall that once we measure the angle from the constructive x-axis, then sin() returns the y-coordinate and cos() returns the x-coordinate. So, the final system turns into:

And making use of atan(), we will instantly get the angle!

This system has one downside, although. It ought to work for any level within the x-y aircraft, and since each x and y might be unfavorable, we will confuse some factors. Since we’re dividing the y-coordinate by the x-coordinate, within the eyes of atan(), the unfavorable y-coordinate appears the identical because the unfavorable x-coordinate. And if each coordinates are unfavorable, it could look the identical as if each have been constructive.

To compensate for this, now we have atan2(), and because it takes the y-coordinate and x-coordinate as separate arguments, it’s good sufficient to return the angle in all places within the aircraft!
Let’s see how we will put it to sensible use.
Following the mouse
Utilizing atan2(), we will make parts react to the mouse’s place. Why would we need to do this? Meet my good friend Helpy, Clippy’s uglier brother from Microsoft.
Helpy desires to all the time be wanting on the person’s mouse, and fortunately, we may also help him utilizing atan2(). I received’t go into an excessive amount of element about how Helpy is made, simply know that his eyes are two pseudo-elements:
.helpy::earlier than,
.helpy::after {
/* eye styling */
}
To assist Helpy, we first have to let CSS know the mouse’s present x-y coordinates. And whereas I’ll not like utilizing JavaScript right here, it’s wanted with the intention to move the mouse coordinates to CSS as two customized properties that we’ll name --m-x and --m-y.
const physique = doc.querySelector("physique");
// hear for the mouse pointer
physique.addEventListener("pointermove", (occasion) => {
// set variables for the pointer's present coordinates
let x = occasion.clientX;
let y = occasion.clientY;
// assign these coordinates to CSS customized properties in pixel items
physique.fashion.setProperty("--m-x", `${Math.spherical(x)}px`);
physique.fashion.setProperty("--m-y", `${Math.spherical(y)}px`);
});
Helpy is at the moment wanting away from the content material, so we’ll first transfer his eyes in order that they align with the constructive x-axis, i.e., to the precise.
.helpy::earlier than,
.helpy::after {
rotate: 135deg;
}
As soon as there, we will use atan2() to search out the precise angle Helpy has to show so he sees the person’s mouse. Since Helpy is positioned on the top-left nook of the web page, and the x and y coordinates are measured from there, it’s time to plug these coordinates into our perform: atan2(var(--m-y), var(--m-x)).
.helpy::earlier than,
.helpy::after {
/* rotate the eyes by it is beginning place, plus the atan2 of the coordinates */
rotate: calc(135deg + atan2(var(--m-y), var(--m-x)));
}
We are able to make one final enchancment. You’ll discover that if the mouse goes on the little hole behind Helpy, he’s unable to have a look at the pointer. This occurs as a result of we’re measuring the coordinates precisely from the top-left nook, and Helpy is positioned slightly bit away from that.
To repair this, we will translate the origin of the coordinate system instantly on Helpy by subtracting the padding and half its dimension:

Which appears like this in CSS:
.helpy::earlier than,
.helpy::after {
rotate: calc(
135deg +
atan2(
var(--m-y) - var(--spacing) - var(--helpy-size) / 2,
var(--m-x) - var(--spacing) - var(--helpy-size) / 2
)
);
}
It is a considerably minor enchancment, however transferring the coordinate origin shall be important if we need to place Helpy in another place on the display screen.
Additional: Getting the viewport (and something) in numbers
I can’t end this sequence with out mentioning a trick to typecast totally different items into easy numbers utilizing atan2() and tan(). It isn’t instantly associated to trigonometry nevertheless it’s nonetheless tremendous helpful. It was first described amazingly by Jane Ori in 2023, and goes as follows.
If we need to get the viewport as an integer, then we will…
@property --100vw {
syntax: "<size>;";
initial-value: 0px;
inherits: false;
}
:root {
--100vw: 100vw;
--int-width: calc(10000 * tan(atan2(var(--100vw), 10000px)));
}
And now: the --int-width variable holds the viewport width as an integer. This appears like magic, so I actually suggest studying Jane Ori’s submit to grasp it. I even have an article utilizing it to create animations because the viewport is resized!
What about reciprocals?
I observed that we’re nonetheless missing the reciprocals for every trigonometric perform. The reciprocals are merely 1 divided by the perform, so there’s a complete of three of them:
- The secant, or
sec(x), is the reciprocal ofcos(x), so it’s1 / cos(x). - The cosecant, or
csc(x), is the reciprocal ofsin(x), so it’s1 / sin(x). - The cotangent, or
cot(x)is the reciprocal oftan(x), so it’s1 / tan(x).
The great thing about sin(), cos() and tan() and their reciprocals is that all of them reside within the unit circle we’ve checked out in different articles on this sequence. I made a decision to place all the pieces collectively within the following demo that reveals all the trigonometric capabilities lined on the identical unit circle:
That’s it!
Welp, that’s it! I hope you discovered and had enjoyable with this sequence simply as a lot as I loved writing it. And thanks a lot for these of you who’ve shared your personal demos. I’ll be rounding them up in my Bluesky web page.
CSS Trigonometric Capabilities: The “Most Hated” CSS Function
sin()andcos()tan()asin(),acos(),atan()andatan2()(You might be right here!)
The “Most Hated” CSS Function: asin(), acos(), atan() and atan2() initially printed on CSS-Tips, which is a part of the DigitalOcean household. You need to get the publication.









