var(--width)<\/code> inside the hour hand element or any ancestor elements inside that, the value returned from our example above is 10px. This also means that if we try using any of these properties outside these elements\u2014for example inside the body element\u2014they are inaccessible to those elements outside the scope.<\/p>\n\n\n\nMoving on to the hands for seconds and minutes, we enter a different scope. That means the custom properties can be redefined with different values.<\/p>\n\n\n\n
.second {\n --width: 5px;\n --height: 140px;\n --color: var(--yellow);\n}\n.minute {\n --width: 10px;\n --height: 90px;\n --color: var(--blue);\n}\n.hour {\n --width: 10px;\n --height: 50px;\n --color: var(--dark-blue);\n}\n.hand {\n position: absolute;\n top: 50%;\n left: calc(50% - var(--width) \/ 2);\n width: var(--width);\n height: var(--height);\n background-color: var(--color);\n transform-origin: center 0;\n}<\/code><\/pre>\n\n\n\nThe great thing about this is that the .hand<\/code> class (which we assigned to all three hand elements) can reference these properties for the calculations and declarations. And each hand will receive its own properties from its own scope. In a way, we\u2019re personalizing the .hand<\/code> class for each element to avoid unnecessary repetition in our code.<\/p>\n\n\n\nOur clock is up and running and all hands are moving at the correct speed:<\/p>\n\n\n\n <\/figure>\n\n\n\nWe could stop here but let me suggest a few improvements. The hands on the clock start at 6 o\u2019clock, but we could set their initial positions to 12 o\u2019clock by rotating the clock 180 degrees. Let\u2019s add this line to the .clock<\/code> class:<\/p>\n\n\n\n.clock {\n \/* same as before *\/\n transform: rotate(180deg);\n}<\/code><\/pre>\n\n\n\nThe hands might look nice with rounded edges:<\/p>\n\n\n\n
.hand {\n \/* same as before *\/\n border-radius: calc(var(--width) \/ 2);\n}<\/code><\/pre>\n\n\n\nOur clock looks and works great! And all hands start from 12 o\u2019clock, exactly how we want it!<\/p>\n\n\n
Setting the clock<\/h3>\n\n\n Even with all these awesome features, the clock is unusable as it fails terribly at telling the actual time<\/strong>. However, there are some hard limitations to what we can do about this. It\u2019s simply not possible to access the local time with HTML and CSS to automatically set our clock. But we can prepare it for manual setup.<\/p>\n\n\n\nWe can set the clock to start at a certain hour and minute and if we run the HTML at exactly that time it will keep the time accurately afterwards. This is basically how you set a real-world clock, so I think this is an acceptable solution. 😅<\/p>\n\n\n\n
Let\u2019s add the time we want to start the clock as custom properties inside the .clock<\/code> class:<\/p>\n\n\n\n.clock {\n --setTimeHour: 16;\n --setTimeMinute: 20;\n \/* same as before *\/\n}<\/code><\/pre>\n\n\n\nThe current time for me as I write is coming up to 16:20 (or 4:20) so the clock will be set to that time. All I need to do is refresh the page at 16:20 and it will keep the time accurately.<\/p>\n\n\n\n
OK, but\u2026 how can we set the time to these positions and rotate the hands if a CSS animation is already controlling the rotation?<\/em><\/p>\n\n\n\nIdeally, we want to rotate and set the hands of the clock to a specific position when the animation starts at the very beginning. Say you want to set the hour hand to 90 degrees so it starts at 3:00 pm and initialize the rotation animation from this position:<\/p>\n\n\n\n
\/* this will not work *\/\n.hour.hand {\n transform: rotate(90deg);\n animation: rotate linear var(--hour) infinite;\n}<\/code><\/pre>\n\n\n\nWell, unfortunately, this will not work because the transform<\/code> is immediately overridden by the animation, as it modifies the very same transform<\/code> property. So, no matter what we set this to, it will go back to 0 degrees where the first keyframe of the animation starts.<\/p>\n\n\n\nWe can set the rotation of the hand independently from the animation. For example, we could wrap the hand into an extra element. This extra parent element, the \u201csetter,\u201d would be responsible for setting the initial position, then the hand element inside could animate from 0 to 360 degrees independently. The starting 0-degree position would then be relative to what we set the parent setter element to.<\/p>\n\n\n\n
This would work but luckily there\u2019s a better option! Let me amaze you!<\/strong> 🪄✨✨<\/p>\n\n\n\nThe animation-delay<\/code> property is what we usually use to start the animation with some predefined delay.<\/p>\n\n\n\nThe trick is to use a negative value,<\/strong> which starts the animation immediately, but from a specific point in the animation timeline!<\/p>\n\n\n\nTo start 10 seconds into the animation:<\/p>\n\n\n\n
animation-delay: -10s;<\/code><\/pre>\n\n\n\nIn case of the hour and minute hands, the actual value we need for the delay is calculated from the --setTimeHour<\/code> and --setTimeMinute<\/code> properties. To help with the calculation, let\u2019s create two new properties with the amount of time shifting we need:<\/p>\n\n\n\nThe hour hand needs to be the hour we want to set the clock, multiplied by an hour.<\/li> The minute hand shifts the minute we want to set the clock multiplied by a minute.<\/li><\/ul>\n\n\n\n--setTimeHour: 16;\n--setTimeMinute: 20;\n--timeShiftHour: calc(var(--setTimeHour) * var(--hour));\n--timeShiftMinute: calc(var(--setTimeMinute) * var(--minute));<\/code><\/pre>\n\n\n\nThese new properties contain the exact amount of time we need for the animation-delay<\/code> property to set our clock. Let\u2019s add these to our animation definitions:<\/p>\n\n\n\n.second.hand {\n animation: rotate steps(60) var(--minute) infinite;\n}\n.minute.hand {\n animation: rotate linear var(--hour) infinite;\n animation-delay: calc(var(--timeShiftMinute) * -1);\n}\n.hour.hand {\n animation: rotate linear calc(var(--hour) * 12) infinite;\n animation-delay: calc(var(--timeShiftHour) * -1);\n}<\/code><\/pre>\n\n\n\nNotice how we multiplied these values by -1 to convert them to a negative number.<\/p>\n\n\n\n
We have almost reached perfection with this, but there\u2019s a slight issue: if we set the number of minutes to 30, for example, the hour hand needs to already be halfway through to the next hour. An even worse situation would be to set the minutes to 59 and the hour hand is still at the beginning of the hour.<\/p>\n\n\n\n
fix this, all we need to do is add the minute shift and the hour shift values together for the hour hand:<\/p>\n\n\n\n
.hour.hand {\n animation: rotate linear calc(var(--hour) * 12) infinite;\n animation-delay: calc(\n (var(--timeShiftHour) + var(--timeShiftMinute)) * -1\n );\n}<\/code><\/pre>\n\n\n\nAnd I think with this we have fixed everything. Let\u2019s admire our beautiful, pure CSS, settable, analog clock:<\/p>\n\n\n\n <\/figure>\n\n\nLet\u2019s go digital<\/h3>\n\n\n In principle, an analog and a digital clock both use the same calculations, the difference being the visual representation of the calculations.<\/p>\n\n\n\n <\/figure>\n\n\n\nHere\u2019s my idea: we can create a digital clock by setting up tall, vertical columns of numbers and animate these instead of rotating the clock hands. Removing the overflow mask from the final version of the clock container reveals the trick:<\/p>\n\n\n\n <\/figure>\n\n\n\nThe new HTML markup needs to contain all the numbers for all three sections of the clock from 00 to 59 on the second and minute sections and 00 to 23 on the hour section:<\/p>\n\n\n\n
<main>\n <div class=\"clock\">\n <div class=\"hour section\">\n <ul>\n <li>00<\/li>\n <li>01<\/li>\n <!-- etc. -->\n <li>22<\/li>\n <li>23<\/li>\n <\/ul>\n <\/div>\n <div class=\"minute section\">\n <ul>\n <li>00<\/li>\n <li>01<\/li>\n <!-- etc. -->\n <li>58<\/li>\n <li>59<\/li>\n <\/ul>\n <\/div>\n <div class=\"second section\">\n <ul>\n <li>00<\/li>\n <li>01<\/li>\n <!-- etc. -->\n <li>58<\/li>\n <li>59<\/li>\n <\/ul>\n <\/div>\n <\/div>\n <\/main><\/code><\/pre>\n\n\n\nTo make these numbers line up, we need to write some CSS, but to get started with the styling we can copy over the custom properties from the :root<\/code> scope of the analog clock straight away, as time is universal:<\/p>\n\n\n\n:root {\n --second: 1s;\n --minute: calc(var(--second) * 60);\n --hour: calc(var(--minute) * 60);\n}<\/code><\/pre>\n\n\n\nThe outermost wrapper element, the .clock<\/code>, still has the very same custom properties for setting the initial time. All that\u2019s changed is that it becomes a flexbox container:<\/p>\n\n\n\n.clock {\n --setTimeHour: 14;\n --setTimeMinute: 01;\n --timeShiftHour: calc(var(--setTimeHour) * var(--hour));\n --timeShiftMinute: calc(var(--setTimeMinute) * var(--minute));\n\n width: 150px;\n height: 50px;\n background-color: var(--grey);\n margin: 0 auto;\n position: relative;\n display: flex;\n}<\/code><\/pre>\n\n\n\nThe three unordered lists and the list items inside them that hold the numbers don\u2019t need any special treatment. The numbers will stack on top of each other if their horizontal space is limited. Let\u2019s just make sure that there is no list styling to prevent bullet points and that we center things for consistent placement:<\/p>\n\n\n\n
.section > ul {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n.section > ul > li {\n width: 50px;\n height: 50px;\n font-size: 32px;\n text-align: center;\n padding-top: 2px;\n}<\/code><\/pre>\n\n\n\nThe layout is done!<\/p>\n\n\n\n <\/figure>\n\n\n\nOutside each unordered list is a <div><\/code> with a .section<\/code> class. This is the element that wraps each section, so we can use it as a mask to hide the numbers that fall outside the visible area of the clock:<\/p>\n\n\n\n.section {\n position: relative;\n width: calc(100% \/ 3);\n overflow: hidden;\n}<\/code><\/pre>\n\n\n\nThe structure of the clock is done and the rails are now ready to be animated.<\/p>\n\n\n
Animating the digital clock<\/h4>\n\n\n The basic idea behind the whole animation is that the three strips of numbers can be moved up and down within their masks to show different numbers from 0 to 59 for seconds and minutes, and 0 to 23 for hours (for a 24-hour format).<\/p>\n\n\n\n
We can do this by changing the translateY<\/code> transition function in CSS for the individual strips of numbers from 0 to -100%. This is because 100% on the y-axis represents the height of the whole strip. A value of 0% will show the first number, and 100% will show the last number of the current strip.<\/p>\n\n\n\nPreviously, our animation was based on rotating a hand from 0 to 360 degrees. We now have a different animation that moves the number strips from 0 to -100% on the y-axis:<\/p>\n\n\n\n
@keyframes tick {\n from { transform: translateY(0); }\n to { transform: translateY(-100%); }\n}<\/code><\/pre>\n\n\n\nApplying this animation to the seconds number strip can be done the same way as the analog clock. The only difference is the selector and the name of the animation that\u2019s referenced:<\/p>\n\n\n\n
.second > ul {\n animation: tick steps(60) var(--minute) infinite;\n}<\/code><\/pre>\n\n\n\nWith the step(60)<\/code> setting, the animation ticks between numbers like we did for the second hand on the analog clock. We could change this to ease<\/code> and then the numbers would smoothly slide up and down as if they were on a ribbon of paper.<\/p>\n\n\n\nAssigning the new tick animation to the minute and hour sections is just as straightforward:<\/p>\n\n\n\n
.minute > ul {\n animation: tick steps(60) var(--hour) infinite;\n animation-delay: calc(var(--timeShiftMinute) * -1);\n}\n.hour > ul {\n animation: tick steps(24) calc(24 * var(--hour)) infinite;\n animation-delay: calc(var(--timeShiftHour) * -1);\n}<\/code><\/pre>\n\n\n\nAgain, the declarations are very similar, what\u2019s different this time is the selector, the timing function, and the animation name.<\/p>\n\n\n\n
The clock now ticks and keeps the correct time:<\/p>\n\n\n\n <\/figure>\n\n\n