博客相关 CSSJavaScript前端

首页 profile 底线中间加了一个小时钟,结构很简单:

astro
<span class="home-profile-clock" aria-hidden="true">
<span class="home-profile-clock-second"></span>
</span>

时针和分针用 .home-profile-clock::before.home-profile-clock::after,秒针单独用 .home-profile-clock-second,这样不用额外塞太多 DOM。

表盘

表盘主要靠 CSS 背景叠出来:

css
.home-profile-clock {
--clock-size: 2.35rem;
--clock-major-tick-width: 0.08rem;
--clock-major-tick-length: 0.36rem;
--clock-minor-tick-angle: 2.4deg;
width: var(--clock-size);
height: var(--clock-size);
border: 1px solid color-mix(in srgb, var(--link) 48%, var(--border-soft) 52%);
border-radius: 50%;
background:
linear-gradient(var(--clock-major-tick-color), var(--clock-major-tick-color)) 50% 0 / var(--clock-major-tick-width) var(--clock-major-tick-length) no-repeat,
radial-gradient(circle, var(--bg) 0 60%, transparent 61%),
repeating-conic-gradient(
from -1.2deg,
var(--clock-minor-tick-color) 0 var(--clock-minor-tick-angle),
transparent var(--clock-minor-tick-angle) 30deg
);
}
  • linear-gradient 画 12、3、6、9 四个主刻度。
  • repeating-conic-gradient 画一圈短刻度。
  • radial-gradient 把中间盖住,让短刻度只留在外圈。

一开始试过 60 个短刻度,但表盘太小,最后看起来像噪点。改成 12 个小时刻度后更清楚。

指针

三根指针用三种颜色区分:时针深灰,分针偏蓝,秒针红色。

css
.home-profile-clock::before,
.home-profile-clock::after,
.home-profile-clock-second {
position: absolute;
left: 50%;
bottom: 50%;
transform-origin: 50% 100%;
}
.home-profile-clock::before {
width: 0.16rem;
height: 0.64rem;
background: var(--clock-hour-color);
transform: translateX(-50%) rotate(var(--clock-hour, 305deg));
}
.home-profile-clock::after {
width: 0.105rem;
height: 0.9rem;
background: var(--clock-minute-color);
transform: translateX(-50%) rotate(var(--clock-minute, 58deg));
}
.home-profile-clock-second {
width: 0.06rem;
height: 1rem;
background: var(--clock-second-color);
transform: translateX(-50%) rotate(var(--clock-second, 168deg));
}

关键是 transform-origin: 50% 100%,让指针围绕底部中心旋转。

动起来

JavaScript 只负责算角度,然后写进 CSS 变量:

ts
function setClockTime(clock: HTMLElement, now: Date) {
const seconds = now.getSeconds() + now.getMilliseconds() / 1000;
const minutes = now.getMinutes() + seconds / 60;
const hours = (now.getHours() % 12) + minutes / 60;
clock.style.setProperty('--clock-second', `${seconds * 6}deg`);
clock.style.setProperty('--clock-minute', `${minutes * 6}deg`);
clock.style.setProperty('--clock-hour', `${hours * 30}deg`);
}

requestAnimationFrame 持续更新,所以秒针是顺滑扫动的,不是一秒跳一下。

页面切换和隐藏标签页时做了停止处理:

ts
document.addEventListener('astro:before-swap', stopClock);
document.addEventListener('astro:page-load', initHomeClock);
document.addEventListener('visibilitychange', () => {
document.hidden ? stopClock() : initHomeClock();
});

移动端直接隐藏:

css
@media (max-width: 760px) {
.home-profile-clock {
display: none;
}
}

这个效果主要服务桌面端首页的底线装饰,小屏没有必要硬塞。