这是一款CSS3和JS制作超酷霓虹电子钟效果。该电子时钟通过HTML和CSS代码构建霓虹灯效果的电子时钟,并通过简单的JS代码来驱动电子时钟的运动。
使用方法
HTML代码
<main>
<div class="clock" role="img">
<div class="clock__ticks">
<div class="clock__tick"></div>
<div class="clock__tick"></div>
<div class="clock__tick"></div>
<div class="clock__tick"></div>
<div class="clock__tick"></div>
<div class="clock__tick"></div>
<div class="clock__tick"></div>
<div class="clock__tick"></div>
<div class="clock__tick"></div>
<div class="clock__tick"></div>
<div class="clock__tick"></div>
<div class="clock__tick"></div>
</div>
<div class="clock__hands">
<div class="clock__hand clock__hand--h"></div>
<div class="clock__hand clock__hand--m"></div>
<div class="clock__hand clock__hand--s" data-hand="s"></div>
</div>
</div>
</main>
CSS代码
* {
border: 0;
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--hue: 223;
--hue1: 243;
--hue2: 303;
--bg: hsl(var(--hue),10%,5%);
--fg: hsl(var(--hue),10%,95%);
--primary: hsl(var(--hue),90%,50%);
--trans-dur: 0.3s;
font-size: calc(16px + (24 - 16) * (100vw - 320px) / (2560 - 320));
}
.container {
background:
radial-gradient(circle at center,hsla(0,0%,0%,0.5) 8em,hsla(0,0%,0%,0.8) 12em),
url(../img/bricks.jpg) center / 16.9em 20em;
color: var(--fg);
display: flex;
font: 1em/1.5 sans-serif;
height: 70vh;
min-height: 375px;
transition:
background-color var(--trans-dur),
color var(--trans-dur);
}
main {
margin: auto;
padding: 1.5em 0;
}
.clock {
--hrAngle: 0;
--minAngle: 0;
--secAngle: 0;
position: relative;
width: 16em;
height: 16em;
}
.clock:before,
.clock:after,
.clock__ticks,
.clock__tick,
.clock__hands,
.clock__hand {
position: absolute;
}
.clock:before,
.clock:after {
border-radius: 50%;
box-shadow:
0 0 0 0.25em hsl(var(--hue1),90%,95%) inset,
0 0 1.5em 0.5em hsla(var(--hue1),90%,50%,0.7) inset,
0 0 1.5em 0.25em hsla(var(--hue1),90%,50%,0.7),
0 0 7.5em hsla(var(--hue1),90%,50%,0.5) inset,
0 0 7.5em hsla(var(--hue1),90%,50%,0.5);
content: "";
display: block;
}
.clock:before {
width: 100%;
height: 100%;
}
.clock:after {
inset: 8%;
}
.clock__ticks,
.clock__hands {
z-index: 1;
}
.clock__ticks {
width: 100%;
height: 100%;
}
.clock__tick {
background-color: hsl(0,0%,95%);
border-radius: 0.2em;
box-shadow: 0 0 0.75em 0.25em hsla(0,0%,50%,0.7);
top: calc(50% - 0.6em);
left: calc(50% - 0.2em);
width: 0.4em;
height: 1.2em;
transform-origin: 50% 50%;
}
.clock__tick:nth-child(3n + 1) {
border-radius: 0.375em;
box-shadow:
0 0 0 0.25em hsl(0,0%,95%) inset,
0 0 0.75em 0.5em hsla(0,0%,50%,0.7) inset,
0 0 0.75em 0.25em hsla(0,0%,50%,0.7),
0 0 4.5em hsla(0,0%,50%,0.5);
top: calc(50% - 0.75em);
left: calc(50% - 0.375em);
width: 0.75em;
height: 1.5em;
}
.clock__tick:nth-child(1) { transform: translateY(-5.25em); }
.clock__tick:nth-child(2) { transform: rotate(30deg) translateY(-5.25em); }
.clock__tick:nth-child(3) { transform: rotate(60deg) translateY(-5.25em); }
.clock__tick:nth-child(4) { transform: rotate(90deg) translateY(-5.25em); }
.clock__tick:nth-child(5) { transform: rotate(120deg) translateY(-5.25em); }
.clock__tick:nth-child(6) { transform: rotate(150deg) translateY(-5.25em); }
.clock__tick:nth-child(7) { transform: rotate(180deg) translateY(-5.25em); }
.clock__tick:nth-child(8) { transform: rotate(210deg) translateY(-5.25em); }
.clock__tick:nth-child(9) { transform: rotate(240deg) translateY(-5.25em); }
.clock__tick:nth-child(10) { transform: rotate(270deg) translateY(-5.25em); }
.clock__tick:nth-child(11) { transform: rotate(300deg) translateY(-5.25em); }
.clock__tick:nth-child(12) { transform: rotate(330deg) translateY(-5.25em); }
.clock__hands {
border-radius: 50%;
box-shadow: 0 0 0 0.25em hsl(var(--hue2),90%,95%) inset;
filter:
drop-shadow(0 0 0.125em hsl(var(--hue2),90%,50%))
drop-shadow(0 0 0.75em hsl(var(--hue2),90%,50%));
top: calc(50% - 0.75em);
left: calc(50% - 0.75em);
width: 1.5em;
height: 1.5em;
}
.clock__hand {
bottom: 50%;
transform-origin: 50% 100%;
}
.clock__hand--h {
border-radius: 0.5em 0.5em 0 0;
box-shadow: 0 0 0 0.25em hsl(var(--hue2),90%,95%) inset;
left: calc(50% - 0.4em);
width: 0.8em;
height: 2.5em;
transform: rotate(var(--hrAngle)) translateY(-0.5em);
}
.clock__hand--m {
border-radius: 0.5em 0.5em 0 0;
box-shadow: 0 0 0 0.25em hsl(var(--hue2),90%,95%) inset;
left: calc(50% - 0.4em);
width: 0.8em;
height: 3.75em;
transform: rotate(var(--minAngle)) translateY(-0.5em);
}
.clock__hand--s {
background-color: hsl(var(--hue2),90%,95%);
border-radius: 0.2em 0.2em 0 0;
left: calc(50% - 0.2em);
width: 0.4em;
height: 3.75em;
transform: rotate(var(--secAngle)) translateY(-0.5em);
}
JS代码
window.addEventListener("DOMContentLoaded", () => {
const c = new Clock11(".clock");
});
class Clock11 {
constructor(el) {
this.el = document.querySelector(el);
this.init();
}
init() {
this.timeUpdate();
}
get timeAsObject() {
const date = new Date();
const h = date.getHours();
const m = date.getMinutes();
const s = date.getSeconds();
return { h, m, s };
}
get timeAsString() {
const [h, m, s, ap] = this.timeDigitsGrouped;
return `${h}:${m}:${s} ${ap}`;
}
get timeDigitsGrouped() {
// this accessible string uses the 12-hour clock
let { h, m, s } = this.timeAsObject;
const ap = h > 11 ? "PM" : "AM";
// deal with midnight
if (h === 0) h += 12;else
if (h > 12) h -= 12;
// prepend 0 to the minute and second if single digits
if (m < 10) m = `0${m}`;
if (s < 10) s = `0${s}`;
return [h, m, s, ap];
}
animateHand(hand) {
const time = this.timeAsObject;
const minFraction = time.s / 60;
const angleB = Utils.decPlaces(360 * minFraction, 3);
const angleA = angleB - 6;
this.el?.querySelector(`[data-hand="${hand}"]`)?.animate(
[
{ transform: `rotate(${angleA}deg) translateY(-0.5em)` },
{ transform: `rotate(${angleB}deg) translateY(-0.5em)` }],
{ duration: 300, easing: "cubic-bezier(0.77,0,0.18,1)" });
}
timeUpdate() {
// update the accessible timestamp in the `aria-label`
this.el?.setAttribute("aria-label", this.timeAsString);
// move the hands
const time = this.timeAsObject;
const minFraction = time.s / 60;
const hrFraction = (time.m + minFraction) / 60;
const twelveHrFraction = (time.h + hrFraction) / 12;
this.el?.style.setProperty("--secAngle", `${Utils.decPlaces(360 * minFraction, 3)}deg`);
this.el?.style.setProperty("--minAngle", `${Utils.decPlaces(360 * hrFraction, 3)}deg`);
this.el?.style.setProperty("--hrAngle", `${Utils.decPlaces(360 * twelveHrFraction, 3)}deg`);
this.animateHand("s");
// loop
clearTimeout(this.timeUpdateLoop);
this.timeUpdateLoop = setTimeout(this.timeUpdate.bind(this), 1e3);
}}
class Utils {
static decPlaces(n, d) {
return Math.round(n * 10 ** d) / 10 ** d;
}}