这是一款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; }}