Get affordable and hassle-free WordPress hosting plans with Cloudways — start your free trial today.
The CSS sin() trigonometric function takes a value and returns its sine. Specifically, it takes an <angle> or <number> and returns the result’s sine, which is always a number between -1 and 1. It’s incredibly good for drawing waves or laying things out in waves.
.ball {
transform: translateY(calc(sin(20deg * var(--i)) * 100px));
}
The sin() function is defined in the CSS Values and Units Module Level 4 specification. The cos() function is similar, but its result is a shift of sin(), so the two are closely related.
Syntax
sin( <calc-sum> )
…where <calc-sum> is either an <angle> unit (e.g. 45deg) or a <number> unit (e.g. 100px). But if you look at the next section, you’ll see that <calc-sum> can also be a nested calc()-ulation that returns an <angle> or a <number>, which is then calculated into the sin() of that result.
Arguments
/* Angles */
width: calc(sin(30deg) * 100px);
width: calc(sin(0.45turn) * 100px);
/* Numbers (expressed as radians) */
width: calc(sin(1.57) * 100px);
width: calc(sin(0.5) * 100px);
/* Mathematical symbols (pi, e) */
width: calc(sin(pi / 2) * 100px);
width: calc(sin(e) * 100px);
/* Nested calc() within the function */
width: calc(sin(max(30deg, 0.25turn)) * 100px);
What’s sin()?
You’ll often see the sin() function graphed as a wave that goes up and down infinitely between -1 and 1, but where exactly do all those values come from? Well, to figure it out, we’ll need to look at one (of the many) definitions of sin(): the unit circle.
The unit circle is a circle of radius one that’s placed on the origin (center) of an X-Y coordinate system, meaning its top side has positive Y-coordinates and its bottom side negative Y-coordinates.

We can describe each point of the unit circle by an angle that is measured from the positive side of the X-axis moving counter-clockwise.
However, most of the time we don’t describe points using angles, but by their X and Y coordinates. So, how can we switch between them? Well, sin() (and it’s inverse, cos()) do exactly that! Given an angle, the function returns the Y and X coordinate, respectively, in the unit circle.
From here, it’s easy to see why, when graphed, sin() returns a wave that goes from 1 to -1: it’s describing the Y-coordinate as we go around the unit circle! This also means sin() is tightly related to the cos() function, since it describes the X-coordinate instead.
Basic usage
Talking about circles, sin() allows us to create circular layouts in CSS without the headache of figuring out the exact points by hand. Let’s start with an unordered list of elements in HTML and set a flexbox layout on the container to put them all on the same line:
<ul style="--total: 12">
<li style="--i: 1">⛎</li>
<li style="--i: 2">♈</li>
<li style="--i: 3">♉</li>
<li style="--i: 4">♊</li>
<li style="--i: 5">♋</li>
<li style="--i: 6">♌</li>
<li style="--i: 7">♍</li>
<li style="--i: 8">♎</li>
<li style="--i: 9">♐</li>
<li style="--i: 10">♑</li>
<li style="--i: 11">♒</li>
<li style="--i: 12">♎</li>
</ul>
You’ll notice each element has a hard-coded index (i.e., --i: 1, --i-2, etc.), and that we also set aside the total number of elements (--total: 12). This is necessary to place each element around a circle, but you may skip this step if your browser supports the sibling-index() and sibling-count() functions, which automatically calculate an element’s index and the total count of elements in a series.
Right now, the list items are placed in a boring straight line. If we want to place them around a circle, we’ll need to first position each element at the center.
li {
position: absolute;
top: calc(50% - var(--icon-size) / 2);
left: calc(50% - var(--icon-size) / 2);
}
Then, we’ll want to evenly space each element away from the center by a certain angle. To get that angle, we can divide 360deg (a full turn around the circle) by the total amount of elements, and then place each element by a multiple of that angle:
li {
--offset: calc(360deg / var(--total) * var(--i));
/* alternatively */
--offset: calc(360deg / sibling-count() * sibling-index());
}
We’ll also need to define a certain radius to move each element away from the center:
ul {
--radius: 10rem;
}
Now each element has an angle around the circle and a radius from the center. What’s left is to use sin() (and cos()) to convert those values to X and Y coordinates, which, when multiplied by the radius, give us the values to translate each element by.
li {
transform:
translateX(calc(cos(var(--offset)) * var(--radius)))
translateY(calc(sin(var(--offset)) * var(--radius)));
}
Making waves
The sin() with cos() functions are often used together to create circular layouts like the one we saw above, but that doesn’t have to be always the case because we can use either sin() or cos() alone to place elements along a wavy line.
We’ll start once again with an unordered list of indexed list items displayed in a flexbox layout:
<ul style="--total: 20">
<li style="--i: 1"></li>
<li style="--i: 2"></li>
<li style="--i: 3"></li>
<li style="--i: 4"></li>
<!-- etc. -->
<li style="--i: 20"></li>
</ul>
That gives us our straight line. If we want to place the indexed list items along a sine wave, we’ll have to set their vertical position following the sin() function. So, we’ll multiply the element’s index (--i) by an angle (20deg) and pass it to the sin() function, and to actually move the element, we’ll multiply it by a distance (100px) and translate it along the Y-axis (translateY()) by the result.
li {
transform: translateY(calc(sin(20deg * var(--i)) * 100px));
}
Demo
Specification
The sin() function is defined in the CSS Values and Units Module Level 4 specification, which is currently in Editor’s Draft. That means the information can change between now and when the feature formally becomes a Candidate Recommendation.
Browser support
More information
- Trigonometric functions in CSS (Bramus)
- Trigonometric Functions (Una Kravets and Adam Argyle)
Related tricks!
The “Most Hated” CSS Feature: cos() and sin()
Creating a Clock with the New CSS sin() and cos() Trigonometry Functions
How to Wait for the sibling-count() and sibling-index() Functions
Typecasting and Viewport Transitions in CSS With tan(atan2())
3D Layered Text: Interactivity and Dynamicism
Related
calc()
.element { height: calc(100vh - 90px); }
cos()
.element { transform: translateY(calc(cos(20deg * var(--i)) * 100px)); }
tan()
.element { transform: translateY(calc(tan(15deg * var(--i)) * 5dvh)); }
sibling-count()
ul li { width: calc(100% / sibling-count()); }
sibling-index()
ul li { transform: translateX(calc(sibling-index() * 10px)); }