This can be a sequence! It began a couple of articles in the past, once we discovered that, in keeping with the State of CSS 2025 survey, trigonometric capabilities had been the “Most Hated” CSS function.

I’ve been attempting 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(). Nevertheless, that’s solely half of what trigonometric capabilities can do. So as we speak, 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 in the event you learn the final two elements of the sequence, then you definitely already know what every of these portions represents.
What if we needed to go the opposite method round? If we have now 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 in! Every inverse perform asks what the required angle is to get a given worth for a selected 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 occasions the circle’s radius. Since trigonometric capabilities dwell 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 somewhat 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, θ. Nevertheless, 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 keeping 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 might get the opposite facet. Nevertheless, typically, we do know the lengths of the triangle’s sides and what we are literally searching for is the angle. In that case, the final equation turns into:

Triangles and Conic Gradients
Discovering the angle is useful in numerous circumstances, like in gradients, for example. In a linear gradient, for instance, if we would like it to go from nook to nook, we’ll must 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 feel that the majority typically than not, you need it to match the aspect’s dimensions.
Utilizing linear-gradient(), we will simply clear up this utilizing to prime proper or to backside left values for the angle, which robotically units the angle so the gradient goes from nook to nook.
.gradient {
background: repeating-linear-gradient(to prime proper, ghostwhite 0px 25px, darkslategray 25px 50px);
}
Nevertheless, we don’t have that kind of syntax for different gradients, like a conic-gradient(). For instance, the subsequent 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 will 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 components:
.gradient {
--angle: atan(var(--height-gradient) / var(--width-gradient));
}
Since conic-gradient() begins from the highest edge — conic-gradient(from 0deg) — we’ll must 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 might be questioning: can’t we try 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 fascinating stuff that’s distinctive to conic gradients.
I acquired the subsequent instance from Ana Tudor’s put up on “Variable Facet Ratio Card With Conic Gradients”:
Fairly cool, proper?. Sadly, Ana’s put up is from 2021, a time when trigonometric capabilities had been specced out however not applied. As she mentions in her article, it wasn’t attainable to create these gradients utilizing atan(). Fortunately, we dwell sooner or later! Let’s see how easy they turn out 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 way to make the unique gradient, so here’s a fast little step-by-step information on the way to make a type 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 normal use case, every of the conic-gradients would appear to be this in CSS:
.gradient {
background:
/* one under */
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 prime 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 method 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 advised you we might 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 go 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 elucidate, let’s backtrack a bit.
We used atan() within the context of triangles, which means that the adjoining and reverse sides had been all the time constructive. This may increasingly look like 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 airplane and choose 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 adverse and constructive coordinates. What if we needed its angle as a substitute? Measuring it, after all, from the constructive x-axis.

Nicely, keep 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 components turns into:

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

This components has one downside, although. It ought to work for any level within the x-y airplane, and since each x and y may be adverse, we will confuse some factors. Since we’re dividing the y-coordinate by the x-coordinate, within the eyes of atan(), the adverse y-coordinate seems to be the identical because the adverse x-coordinate. And if each coordinates are adverse, it will look the identical as if each had been constructive.

To compensate for this, we have now atan2(), and because it takes the y-coordinate and x-coordinate as separate arguments, it’s sensible sufficient to return the angle in every single place within the airplane!
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 try this? Meet my buddy Helpy, Clippy’s uglier brother from Microsoft.
Helpy desires to all the time be trying on the consumer’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 must let CSS know the mouse’s present x-y coordinates. And whereas I’ll not like utilizing JavaScript right here, it’s wanted as a way to go the mouse coordinates to CSS as two customized properties that we’ll name --m-x and --m-y.
const physique = doc.querySelector("physique");
// pay attention 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 models
physique.type.setProperty("--m-x", `${Math.spherical(x)}px`);
physique.type.setProperty("--m-y", `${Math.spherical(y)}px`);
});
Helpy is at present trying away from the content material, so we’ll first transfer his eyes so that they align with the constructive x-axis, i.e., to the best.
.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 consumer’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 will 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 somewhat bit away from that.
To repair this, we will translate the origin of the coordinate system immediately on Helpy by subtracting the padding and half its dimension:

Which seems to be 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
)
);
}
This can be a considerably minor enchancment, however shifting the coordinate origin might be important if we need to place Helpy in another place on the display.
Additional: Getting the viewport (and something) in numbers
I can’t end this sequence with out mentioning a trick to typecast totally different models into easy numbers utilizing atan2() and tan(). It isn’t immediately associated to trigonometry however 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 seems to be like magic, so I actually advocate studying Jane Ori’s put up to know 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 dwell within the unit circle we’ve checked out in different articles on this sequence. I made a decision to place the whole lot 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 realized 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-Methods, which is a part of the DigitalOcean household. You must get the publication.

