This is the sixth day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

This day to visit the blog to see a lot of big guy’s website have a clock thief pull style, I want to own a whole, think of as a front-end developer, reflect the front-end development technology moment to <())>, with CSS draw a! Let me show you the results:

Front knowledge

Here’s a summary of the knowledge points used:

rotateZ()function

RotateZ () The CSS function rotateZ() defines how to rotate elements on the Z axis without distorting them. The degree of its motion is defined by the specified Angle; If it is positive, it rotates clockwise, if it is negative, it rotates counterclockwise.

rotate()function

transform-originattribute

The transform-origin CSS property lets you change the origin of an element’s deformation.

The clock to achieve

  1. Draw the center of the circle

    Here I’m using the background vertical horizontal center +before pseudo-class drawn directly on the background

  2. Draw the hour, minute and second hands and give them a scheduled task to make them spin

    This is where rotateZ() is used, and the core code is as follows

    <template> <div class="clock"> <! - clockwise - > < div class = "hour" > < div ref = "hr" class = "hr" > < / div > < / div > <! - the minute hand -- -- > < div class = "min" > < div ref = "mn" class = "mn" > < / div > < / div > <! - the second hand -- -- > < div class = "SEC" > < div ref = "sc" class = "sc" > < / div > < / div > < / div > < / template > < script lang = "ts" > import {ref, onMounted, onUnmounted } from 'vue' export default { setup() { const hr = ref<HTMLElement | null>(null) const mn = ref<HTMLElement | null>(null) const sc = ref<HTMLElement | null>(null) const timeChange = () => { let day = new Date() let hh = Day.gethours () * 30 // one hour to 30 degrees let mm = day.getminutes () * 6 // one scale let ss = day.getseconds () * 6 // one scale; (hr.value as HTMLElement).style.transform = `rotateZ(${hh + mm / 12}deg)` ; (mn.value as HTMLElement).style.transform = `rotateZ(${mm}deg)` ; (sc.value as HTMLElement).style.transform = `rotateZ(${ss}deg)` } let timer: any = null onMounted(() => { timeChange() timer = setInterval(timeChange, 1000) }) onUnmounted(() => { timer && window.clearInterval(timer) }) return { hr, mn, sc, } } } </script> <style scoped lang="scss"> .clock { width: 300px; height: 300px; border-radius: 50%; display: flex; justify-content: center; align-items: center; position: relative; &:before { content: ''; width: 15px; height: 15px; border-radius: 50%; position: absolute; z-index: 10; } .hour, .min, .sec { position: absolute; } .hour, .hr { width: 160px; height: 160px; } .min, .mn { width: 200px; height: 200px; } .sec, .sc { width: 230px; height: 230px; } .hr, .mn, .sc { display: flex; justify-content: center; border-radius: 50%; } .hr::before { content: ''; width: 8px; height: 80px; //background-color: #b03232; border-radius: 6px; } .mn::before { content: ''; width: 4px; height: 95px; //background-color: #fff; border-radius: 6px; } .sc::before { content: ''; width: 2px; height: 150px; //background-color: #fff; border-radius: 4px; } } </style>Copy the code

    In the actual rotation, an entire element is rotated, not a pointer

  3. Draw the dial background

    This is where the most complex part of drawing a clock is, if we just use the Rotate () and transform-Origin properties, we’ll see the dial scale look like this

    Why is that? The reason is very simple, because in the traversal process, each scale has its own height, with the accumulation of height, the origin of rotation of each scale is different, simply speaking, the center of the circle moves. Here’s the solution. Just center them with position: absolute.

<template> <div class="light"> <div class="clock"> <ul class="scaleBg"> <li v-for="i in 60" :key="i" class="scale" :style="scale(i)"></li> <li v-for="i in 12" :key="i" class="scaleNum" :style="scaleNum(i)"> <span :style="fScaleNum(i)">{{ i }}</span> </li> </ul> <div class="hour"> <div ref="hr" class="hr"></div> </div> <div class="min"> <div ref="mn" class="mn"></div> </div> <div class="sec"> <div ref="sc" class="sc"></div> </div> </div> </div> </template> <script lang="ts"> import { ref, onMounted, onUnmounted } from 'vue' export default { setup() { const hr = ref<HTMLElement | null>(null) const mn = ref<HTMLElement | null>(null) const sc = ref<HTMLElement | null>(null) const timeChange = () => { let day = new Date() let hh = Day.gethours () * 30 // one hour to 30 degrees let mm = day.getminutes () * 6 // one scale let ss = day.getseconds () * 6 // one scale; (hr.value as HTMLElement).style.transform = `rotateZ(${hh + mm / 12}deg)` ; (mn.value as HTMLElement).style.transform = `rotateZ(${mm}deg)` ; (sc.value as HTMLElement).style.transform = `rotateZ(${ss}deg)` } let timer: any = null onMounted(() => { timeChange() timer = setInterval(timeChange, 1000) }) onUnmounted(() => { timer && window.clearInterval(timer) }) const scale = (i: number) => { if (i === 0 || i % 5 === 0) { return { transform: `rotate(${i * 6}deg)`, height: '16px' } } else { return { transform: `rotate(${i * 6}deg)` } } } const scaleNum = (i: number) => { if (i === 12) { return { left: '146px', transform: `rotate(${i * 30}deg)` } } else { return { transform: Rotate (${I * 30}deg) '}}} const fScaleNum = (I: number) => {return {display: 'block', transform: `rotate(${-i * 30}deg)` } } return { hr, mn, sc, scale, scaleNum, fScaleNum } } } </script> <style scoped lang="scss"> .clock { width: 300px; height: 300px; border-radius: 50%; display: flex; justify-content: center; align-items: center; position: relative; //box-shadow: 0-15px rgba(255, 255, 255, 0.05), inset 0-15px rgba(255, 255, 255, 0.05), // 0 15px rgba(255, 255, 0.05), 255, 0.05), inset 0 15px 15px rgba(255, 255, 255, 0.05); &:before { content: ''; width: 15px; height: 15px; border-radius: 50%; position: absolute; //background: #fff; z-index: 10; } .hour, .min, .sec { position: absolute; } .hour, .hr { width: 160px; height: 160px; } .min, .mn { width: 200px; height: 200px; } .sec, .sc { width: 230px; height: 230px; } .hr, .mn, .sc { display: flex; justify-content: center; border-radius: 50%; } .hr::before { content: ''; width: 8px; height: 80px; //background-color: #b03232; border-radius: 6px; } .mn::before { content: ''; width: 4px; height: 95px; //background-color: #fff; border-radius: 6px; } .sc::before { content: ''; width: 2px; height: 150px; //background-color: #fff; border-radius: 4px; } } .scaleBg { position: relative; width: 100%; height: 100%; .scale { width: 2px; height: 6px; background: #fff; position: absolute; left: 150px; top: 0; transform-origin: center 150px; } .scaleNum { position: absolute; display: flex; justify-content: center; left: 148px; top: 30px; font-size: 12px; transform-origin: center 120px; } } .light { .clock { box-shadow: 0-15px 15px rgba(255, 255, 255, 0.05), inset 0-15px 15px rgba(255, 255, 255, 0.05), 0 15px 15px rgba(255, 255, 255, 255, gba, 0 Inset 0 15px 15px rgba(255, 255, 255, 0.05); &:before { background: #181818; } .hr::before { background-color: #b03232; } .mn::before { background-color: #525252; } .sc::before { background-color: #383737; } .scale { background: #181818; } } } .dark { .clock { box-shadow: 0-15px 15px rgba(255, 255, 255, 0.05), inset 0-15px 15px rgba(255, 255, 255, 0.05), 0 15px 15px rgba(255, 255, 255, 255, gba, 0 Inset 0 15px 15px rgba(255, 255, 255, 0.05); &:before { background: #fff; } .hr::before { background-color: #b03232; } .mn::before { background-color: #fff; } .sc::before { background-color: #fff; } .scale { background: #fff; } } } </style>Copy the code

conclusion

Technology to flexible use ah, CSS really strong ah!!