Creating a Clock with the New CSS sin() and cos() Trigonometry Functions
Here’s what I have in mind. Again, it’s only supported in Firefox and Safari at the moment:
So, it’s not exactly like words forming a circular shape, but we are placing text characters along the circle to form a clock face. Here’s some markup we can use to kick things off:
Next, here are some super basic styles for the
.clock-face container. I decided to use the
<time> tag with a
It looks like some sort of modern art experiment, right? Let’s introduce a new variable,
--_r, to store the circle’s radius, which is equal to half of the circle’s width. This way, if the width (
--_w) changes, the radius value (
--_r) will also update — thanks to another CSS math function,
Now, a bit of math. A circle is 360 degrees. We have 12 labels on our clock, so want to place the numbers every 30 degrees (
360 / 12). In math-land, a circle begins at 3 o’clock, so noon is actually minus 90 degrees from that, which is 270 degrees (
360 - 90).
Let’s add another variable,
--_d, that we can use to set a degree value for each number on the clock face. We’re going to increment the values by 30 degrees to complete our circle:
OK, now’s the time to get our hands dirty with the
cos() functions! What we want to do is use them to get the X and Y coordinates for each number so we can place them properly around the clock face.
The formula for the X coordinate is
radius + (radius * cos(degree)). Let’s plug that into our new
The formula for the Y coordinate is
radius + (radius * sin(degree)). We have what we need to calculate that:
There are a few housekeeping things we need to do to set up the numbers, so let’s put some basic styling on them to make sure they are absolutely positioned and placed with our coordinates:
--_sz, which we’ll use for the
height of the numbers in a moment. Let’s see what we have so far.
This definitely looks more like a clock! See how the top-left corner of each number is positioned at the correct place around the circle? We need to “shrink” the radius when calculating the positions for each number. We can deduct the size of a number (
--_sz) from the size of the circle (
--_w), before we calculate the radius:
Much better! Let’s change the colors, so it looks more elegant:
We could stop right here! We accomplished the goal of placing text around a circle, right? But what’s a clock without arms to show hours, minutes, and seconds?
Let’s use a single CSS animation for that. First, let’s add three more elements to our markup,
Then some common markup for all three arms. Again, most of this is just make sure the arms are absolutely positioned and placed accordingly:
We’ll use the same animation for all three arms:
The seconds arm is almost the same as the minutes arm, but the duration is 60 seconds instead of 60 minutes:
Let’s update the properties we created in the common styles:
In the CSS, we need to add the
animation-delay as well:
Just one more thing. Using CSS
@supports and the properties we’ve already created, we can provide a fallback to browsers that do not supprt
cos(). (Thank you, Temani Afif!):
And, voilà! Our clock is done! Here’s the final demo one more time. Again, it’s only supported in Firefox and Safari at the moment.
Just messing around here, but we can quickly turn our clock into a circular image gallery by replacing the
<time> tags with
<img> then updating the width (
--_w) and radius (
Let’s try one more. I mentioned earlier how the clock looked kind of like a modern art experiment. We can lean into that and re-create a pattern I saw on a poster (that I unfortunately didn’t buy) in an art gallery the other day. As I recall, it was called “Moon” and consisted of a bunch of dots forming a circle.
The controls are range inputs (
<input type="range">) which we’ll wrap in a
<form> and listen for the
We’ll run this method on “input”, which will create a bunch of
<li> elements with the degree (
--_d) variable we used earlier applied to each one. We can also repurpose our radius variable (
I also want the dots to be different colors. So, let’s randomize (well, not completely randomized) the HSL color value for each list item and store it as a new CSS variable,
random() method picks a value within a defined range of numbers:
cos() functions help us position all the dots in the right spots.
Placing things around a circle is a pretty basic example to demonstrate the powers of trigonometry functions like
cos(). But it’s really cool that we are getting modern CSS features that provide new solutions for old workarounds I’m sure we’ll see way more interesting, complex, and creative use cases, especially as browser support comes to Chrome and Edge.
If you need help creating a digital marketing strategy for your business, don’t hesitate to contact one of Digidude’s consultants.