Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Clocks and Watches in CSS
Mads Stoumann
Mads Stoumann

Posted on • Edited on

     

Clocks and Watches in CSS

A couple of years ago, when CSS trigonometry functions became baseline, Iwrote an article about them. One of the examples I did, was a CSS-only analog clock:

Since then, CSS has introduced abunch of new features — one beingoffset-path, which is perfect for creating indices on a clock (I sound like an horology expert, but I Googled that).

So, without further ado, let's expand my old example with some more, cool features! We'll wrap it within a Web Component for easier customization, but you can stick with CSS-only, if you want.


First, we set up a simple grid, divided into 3 rows:

Main Grid

:host{aspect-ratio:1;background:#f2f2f2;border-radius:50%;display:grid;grid-template-rows:repeat(3,1fr);}
Enter fullscreen modeExit fullscreen mode

The indices are a bunch of<li> elements within a<ul>, usingoffset-distance / path to place them around the circle:

li{display:inline-block;list-style:none;offset-distance:var(--_d);offset-path:content-box;width:fit-content;}
Enter fullscreen modeExit fullscreen mode

Each<li> has a degree (actually a percentage), defined in the--_d custom property:

<listyle="--_d:0%">|</li>
Enter fullscreen modeExit fullscreen mode

This gets us:

Indices

By default,offset-rotate automatically rotates elements to follow the path direction. This behavior is exactly what we need for the indices, so we don't need to set any additional rotation.

Now, for the numerals, we'll also use<li>, but this time within anordered list,<ol>:

<ol><listyle="--_d:300deg">1</li></ol>
Enter fullscreen modeExit fullscreen mode

We'll usecos() andsin() to place the numerals, like in my original example.

li{--_r:calc((100%-15cqi)/2);--_x:calc(var(--_r)+(var(--_r)*cos(var(--_d))));--_y:calc(var(--_r)+(var(--_r)*sin(var(--_d))));aspect-ratio:1;display:grid;left:var(--_x);place-content:center;position:absolute;top:var(--_y);width:15cqi;}
Enter fullscreen modeExit fullscreen mode

And we get:

Numerals

Now, let's create the markup for the hands and date. The cap will be added as a pseudo-element. I had a hard time trying to wrap my head around what good, semantic markup would be here? I gave up, and just used a bunch of<div>s 😄

<navpart="hands"><divpart="seconds"></div><divpart="minutes"></div><divpart="hours"></div><timepart="date"></time></nav>
Enter fullscreen modeExit fullscreen mode

We position the<nav> in the middle row of the main grid, and create a 3-column grid:

:host::part(hands){display:grid;grid-area:2/1/3/1;grid-template-columns:repeat(3,1fr);}
Enter fullscreen modeExit fullscreen mode

This gives us:
Hands

Finally, we place the label at the top center of the last row of the main grid:

Label


Animating the hands

To animate the hands, we just need a single animation:

@keyframesturn{to{transform:rotate(1turn);}}
Enter fullscreen modeExit fullscreen mode

However, it needs to becalled in 3 very distinct ways:

:host::part(hours){animation:turn43200slinearinfinite;animation-delay:var(--_dh,0ms);}:host::part(minutes){animation:turn3600ssteps(60,end)infinite;animation-delay:var(--_dm,0ms);}:host::part(seconds){animation:turn60slinearinfinite;animation-delay:var(--_ds,0ms);}
Enter fullscreen modeExit fullscreen mode

And that's it! ... if you don't mind the clock always starting at noon!

To initialize the clock with theactual time, we need to update the delay properties:--_dh,--_dm and--_ds — and for that, we need a small snippet of #"http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24">Enter fullscreen modeExit fullscreen mode

Variants

Styling variants is dead simple (see the final demo at the end of the article).

How about a SAIKO:

SAIKO

Or a ROBEX (sorry for my unimaginative names!):

ROBEX

... or how about somereally colorful examples:

Burmese, Thai and Indian

The latter can, of course, be done by adding the labels manually, but if we wrap it in a web component, it becomes a bit easier to maintain:

<analog-clocklabel="မြန်မာ"system="mymr"timezone="+6.5"class="burmese"indicesmarker="•"></analog-clock><analog-clocklabel="ประเทศไทย"system="thai"timezone="+7"class="thai"indicesmarker="·"marker-hour="•"></analog-clock><analog-clocklabel="अरुणाचल"system="wcho"timezone="+5.5"class="indian"></analog-clock>
Enter fullscreen modeExit fullscreen mode

Let's look into that.


Web Component

Wrapping the code in a<analog-clock> web component offers a simple way to add an analog clock to your web projects. It's customizable through various attributes and CSS custom properties.

Installation & Usage

Install via npm:

npm i @browser.style/analog-clock
Enter fullscreen modeExit fullscreen mode

Or use directly via CDN:

<scriptsrc="https://browser.style/ui/analog-clock/index.js"type="module"></script>
Enter fullscreen modeExit fullscreen mode

Then, simply add the component to your HTML:

<analog-clock></analog-clock>
Enter fullscreen modeExit fullscreen mode

Basic Examples

Here are some common use cases:

<!-- Simple clock for New York time --><analog-clocklabel="New York"timezone="-4"></analog-clock><!-- Clock with date display and minute markers --><analog-clockindicesdate="day month"label="Current Time"></analog-clock><!-- Clock with custom markers and Roman numerals --><analog-clockindices="hours"system="roman"marker="•"marker-hour="●"label="Roma"></analog-clock>
Enter fullscreen modeExit fullscreen mode

Styling Examples

The component can be styled using CSS custom properties:

/* Gold luxury theme */.luxury{--analog-clock-bg:radial-gradient(circleat50%50%,#f4e5c350%,#e2ca7d51%,#5c4d2895%);--analog-clock-c:#2a2317;--analog-clock-ff:"Didot",serif;--analog-clock-second:#8b0000;--analog-clock-cap:#403428;}/* Minimalist theme */.minimal{--analog-clock-bg:#fff;--analog-clock-c:#333;--analog-clock-indices-c:#ddd;--analog-clock-second:#ff4444;--analog-clock-cap-sz:4cqi;}
Enter fullscreen modeExit fullscreen mode

Number Systems

Thesystem attribute supports variousnumber systems, as we saw in the colorful examples earlier:

<analog-clocksystem="mymr"></analog-clock><analog-clocksystem="thai"></analog-clock>
Enter fullscreen modeExit fullscreen mode

Timezone Support

You can display different timezones using thetimezone attribute:

<analog-clocklabel="New York"timezone="-4"></analog-clock><analog-clocklabel="London"timezone="0"></analog-clock><analog-clocklabel="Tokyo"timezone="+9"></analog-clock><analog-clocklabel="Mumbai"timezone="+5.5"></analog-clock>
Enter fullscreen modeExit fullscreen mode

Attributes

  • date: Display date. Values: "day", "month", "year" or any combination
  • indices: Show tick marks. Values: empty (60 marks) or "hours" (12 marks)
  • label: Text label below the clock
  • marker: Character used for indices (default: "|")
  • marker-hour: Character used for hour indices (defaults to marker value)
  • numerals: Number of numerals to display (1-12, default: 12)
  • steps: Use stepping animation for seconds hand
  • system: Number system. Values: "roman", "romanlow", or any validIntl numberingSystem
  • timezone: UTC offset in hours (e.g., "-4", "+1", "+5.5")

Demo

Here's a Codepen with all the clocks and watches, we've coded:

Now go teach kids how to read an analog clock!

Top comments(40)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
crosschainer profile image
crosschainer
blockchain dev
  • Email
  • Location
    Germany
  • Work
    Co-Founder at Xian.org
  • Joined

sick

CollapseExpand
 
artydev profile image
artydev
  • Joined
• Edited on• Edited

Awesome, thank you ;-)

CollapseExpand
 
madsstoumann profile image
Mads Stoumann
I'm a tech director, web developer, graphic designer, musician, blogger, comicbook-geek, LEGO-collector, food lover … as well as husband and father!
  • Location
    Copenhagen, Denmark
  • Pronouns
    He/him
  • Work
    Technical Director at AKQA
  • Joined

Thanks!

CollapseExpand
 
deathcrafter profile image
Shaktijeet Sahoo

Holy CSS!

CollapseExpand
 
stantheman70 profile image
StanTheMan70
  • Joined

Thank you! This is awesome! However, there's a small issue causing the script to work incorrectly with fractional time zones. For example, when the timezone is set to +9.5, the clock displays the time half an hour earlier than it should.
To fix this, simply replaceparseInt with** parseFloat** when retrieving the timezone value from the element attribute. This will ensure that fractional offsets are handled correctly.
This error exists even in the CDN.

CollapseExpand
 
madsstoumann profile image
Mads Stoumann
I'm a tech director, web developer, graphic designer, musician, blogger, comicbook-geek, LEGO-collector, food lover … as well as husband and father!
  • Location
    Copenhagen, Denmark
  • Pronouns
    He/him
  • Work
    Technical Director at AKQA
  • Joined
• Edited on• Edited

Ah, didn't think about that — thanks for letting me know!
I've added this method, so it rounds the timezone to nearest quarter of an hour:

#roundTzOffset(offset){returnMath.round((parseFloat(offset)||0)*4)/4};
Enter fullscreen modeExit fullscreen mode

And since you're called StanTheMan70 — here's Stan The Man and me, 25 years ago ;-)

StanTheMan

CollapseExpand
 
stantheman70 profile image
StanTheMan70
  • Joined

Image description

CollapseExpand
 
plutonium239 profile image
plutonium239
  • Education
    IIT Delhi
  • Work
    ML Researcher
  • Joined

Nice, but you can just name the variable--d without the underscore, neater.

CollapseExpand
 
madsstoumann profile image
Mads Stoumann
I'm a tech director, web developer, graphic designer, musician, blogger, comicbook-geek, LEGO-collector, food lover … as well as husband and father!
  • Location
    Copenhagen, Denmark
  • Pronouns
    He/him
  • Work
    Technical Director at AKQA
  • Joined

That's to indicate the variable should be considerend "private".

CollapseExpand
 
ezpieco profile image
Ezpie
Creator of the open-source social media app lambda.
  • Joined

next I want an overly complicated button made using only CSS. Now that's a keeper

CollapseExpand
 
tmnt-12 profile image
Théo Marceau
  • Joined

🕖

CollapseExpand
 
madhurima_rawat profile image
Madhurima Rawat
🚀 Passionate about tech & growth | 💻 Data Scientist & Frontend Dev | C, C++, Python, R | 📊 InfluxDB, Grafana | 🤖 ML Enthusiast | 🐙 GitHub & Open Source | 📚 Learning & Sharing
  • Location
    Bhilai, Chhattisgarh, India
  • Education
    Shiva Public School
  • Pronouns
    She/her
  • Work
    B.Tech at CSVTU
  • Joined

This looks so good🌟Thanks for sharing!

CollapseExpand
 
madsstoumann profile image
Mads Stoumann
I'm a tech director, web developer, graphic designer, musician, blogger, comicbook-geek, LEGO-collector, food lover … as well as husband and father!
  • Location
    Copenhagen, Denmark
  • Pronouns
    He/him
  • Work
    Technical Director at AKQA
  • Joined

Thanks!

CollapseExpand
 
bigol profile image
José Santos Silva
I explore new tech as a hobby.
  • Location
    Vila Real, Portugal
  • Joined

Great work thanks.

CollapseExpand
 
madsstoumann profile image
Mads Stoumann
I'm a tech director, web developer, graphic designer, musician, blogger, comicbook-geek, LEGO-collector, food lover … as well as husband and father!
  • Location
    Copenhagen, Denmark
  • Pronouns
    He/him
  • Work
    Technical Director at AKQA
  • Joined

Thanks!

CollapseExpand
 
michael_phillips_356cb1ff profile image
Michael Phillips
  • Joined

So nice!

CollapseExpand
 
madsstoumann profile image
Mads Stoumann
I'm a tech director, web developer, graphic designer, musician, blogger, comicbook-geek, LEGO-collector, food lover … as well as husband and father!
  • Location
    Copenhagen, Denmark
  • Pronouns
    He/him
  • Work
    Technical Director at AKQA
  • Joined

Thanks!

View full discussion (40 comments)

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Mads Stoumann
I'm a tech director, web developer, graphic designer, musician, blogger, comicbook-geek, LEGO-collector, food lover … as well as husband and father!
  • Location
    Copenhagen, Denmark
  • Pronouns
    He/him
  • Work
    Technical Director at AKQA
  • Joined

More fromMads Stoumann

Charts in CSS
#css#tutorial#webdev#showdev
Guitar Chords in CSS
#css#webdev#showdev#tutorial
Phases of the Moon in CSS
#css#webdev#tutorial#showdev
DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp