CSS 中的时钟和手表

2025-06-09

CSS 中的时钟和手表

几年前,当 CSS 三角函数成为基线时,我写了一篇关于它们的文章。我做的一个例子是一个纯 CSS 的模拟时钟:

从那时起,CSS 引入了一系列功能 - 其中之一就是offset-path,它非常适合在时钟上创建索引(我听起来像是一个钟表专家,但我在 Google 上搜索到了这个)。

废话不多说,让我们用更多酷炫的功能来扩展我的旧示例吧!我们会将其封装到 Web 组件中,以便于自定义,但如果您愿意,也可以继续使用纯 CSS。


首先,我们建立一个简单的网格,分为 3 行:

主电网

:host {
  aspect-ratio: 1;
  background: #f2f2f2;
  border-radius: 50%;
  display: grid;
  grid-template-rows: repeat(3, 1fr);
}
Enter fullscreen mode Exit fullscreen mode

索引是<li>内的一组元素<ul>,用于offset-distance / path将它们放置在圆圈周围:

li {
  display: inline-block;
  list-style: none;
  offset-distance: var(--_d);
  offset-path: content-box;
  width: fit-content;
}
Enter fullscreen mode Exit fullscreen mode

每个<li>都有一个度(实际上是百分比),在--_d自定义属性中定义:

<li style="--_d:0%">|</li>
Enter fullscreen mode Exit fullscreen mode

这让我们:

指数

默认情况下,offset-rotate元素会自动旋转以跟随路径方向。此行为正是我们索引所需要的,因此我们无需设置任何其他旋转。

现在,对于数字,我们也将使用<li>,但这次是在有序列表中<ol>

<ol>
  <li style="--_d:300deg">1</li>
</ol>
Enter fullscreen mode Exit fullscreen mode

我们将使用cos()sin()来放置数字,就像我原来的例子一样。

li {
  --_r: calc((100% - 15cqi) / 2);
  --_x: calc(var(--_r) + (var(--_r) * cos(var(--_d))));
  --_y: calc(var(--_r) + (var(--_r) * sin(var(--_d))));
  aspect-ratio: 1;
  display: grid;
  left: var(--_x);
  place-content: center;
  position: absolute;
  top: var(--_y);
  width: 15cqi;
}
Enter fullscreen mode Exit fullscreen mode

我们得到:

数字

现在,让我们创建指针和日期的标记。盖子将作为伪元素添加。我之前一直琢磨着这里应该用什么好的、语义化的标记?我放弃了,只用了一堆<div>s 😄

<nav part="hands">
  <div part="seconds"></div>
  <div part="minutes"></div>
  <div part="hours"></div>
  <time part="date"></time>
</nav>
Enter fullscreen mode Exit fullscreen mode

我们将它定位<nav>在主网格的中间行,并创建一个 3 列网格:

:host::part(hands) {
  display: grid;
  grid-area: 2 / 1 / 3 / 1;
  grid-template-columns: repeat(3, 1fr);
}
Enter fullscreen mode Exit fullscreen mode

这给了我们:
手

最后,我们将标签放在主网格最后一行的顶部中央:

标签


手部动画

为了制作手部动画,我们只需要一个动画:

@keyframes turn {
  to { transform: rotate(1turn); }
}
Enter fullscreen mode Exit fullscreen mode

但是,需要以 3 种截然不同的方式调用它:

:host::part(hours) {
  animation: turn 43200s linear infinite;
  animation-delay: var(--_dh, 0ms);
}
:host::part(minutes) {
  animation: turn 3600s steps(60, end) infinite;
  animation-delay: var(--_dm, 0ms);
}
:host::part(seconds) {
  animation: turn 60s linear infinite;
  animation-delay: var(--_ds, 0ms);
}
Enter fullscreen mode Exit fullscreen mode

就是这样!...如果你不介意时钟总是从中午开始!

要用实际时间初始化时钟,我们需要更新延迟属性:--_dh--_dm--_ds——为此,我们需要一小段 JavaScript:

const time = new Date();
const hour = -3600 * (time.getHours() % 12);
const mins = -60 * time.getMinutes();
app.style.setProperty('--_dm', `${mins}s`);
app.style.setProperty('--_dh', `${(hour+mins)}s`);
Enter fullscreen mode Exit fullscreen mode

变体

样式变体非常简单(请参阅文章末尾的最终演示)。

SAIKO 怎么样:

西光

或者 ROBEX(抱歉我的名字缺乏想象力!):

罗比克斯

...或者看看一些真正丰富多彩的例子:

缅甸语、泰国语和印度语

当然,后者可以通过手动添加标签来完成,但如果我们将其包装在 Web 组件中,维护起来就会更容易一些:

<analog-clock
  label="မြန်မာ"
  system="mymr"
  timezone="+6.5"
  class="burmese"
  indices
  marker="•">
</analog-clock>

<analog-clock
  label="ประเทศไทย"
  system="thai"
  timezone="+7"
  class="thai"
  indices
  marker="·"
  marker-hour="•">
</analog-clock>

<analog-clock
  label="अरुणाचल"
  system="wcho"
  timezone="+5.5"
  class="indian">
</analog-clock>
Enter fullscreen mode Exit fullscreen mode

让我们来研究一下。


Web 组件

将代码封装到<analog-clock>Web 组件中,可以方便地将模拟时钟添加到您的 Web 项目中。您可以通过各种属性和 CSS 自定义属性进行自定义。

安装与使用

通过 npm 安装:

npm i @browser.style/analog-clock
Enter fullscreen mode Exit fullscreen mode

或者直接通过 CDN 使用:

<script src="https://browser.style/ui/analog-clock/index.js" type="module"></script>
Enter fullscreen mode Exit fullscreen mode

然后,只需将组件添加到您的 HTML 中:

<analog-clock></analog-clock>
Enter fullscreen mode Exit fullscreen mode

基本示例

以下是一些常见的用例:

<!-- Simple clock for New York time -->
<analog-clock 
  label="New York" 
  timezone="-4">
</analog-clock>

<!-- Clock with date display and minute markers -->
<analog-clock 
  indices 
  date="day month" 
  label="Current Time">
</analog-clock>

<!-- Clock with custom markers and Roman numerals -->
<analog-clock 
  indices="hours"
  system="roman"
  marker="•"
  marker-hour="●"
  label="Roma">
</analog-clock>
Enter fullscreen mode Exit fullscreen mode

造型示例

可以使用 CSS 自定义属性来设置组件的样式:

/* Gold luxury theme */
.luxury {
  --analog-clock-bg: radial-gradient(
    circle at 50% 50%,
    #f4e5c3 50%,
    #e2ca7d 51%,
    #5c4d28 95%
  );
  --analog-clock-c: #2a2317;
  --analog-clock-ff: "Didot", serif;
  --analog-clock-second: #8b0000;
  --analog-clock-cap: #403428;
}

/* Minimalist theme */
.minimal {
  --analog-clock-bg: #fff;
  --analog-clock-c: #333;
  --analog-clock-indices-c: #ddd;
  --analog-clock-second: #ff4444;
  --analog-clock-cap-sz: 4cqi;
}
Enter fullscreen mode Exit fullscreen mode

数字系统

system属性支持各种数字系统,正如我们在之前的丰富多彩的示例中看到的那样:

<analog-clock system="mymr"></analog-clock>
<analog-clock system="thai"></analog-clock>
Enter fullscreen mode Exit fullscreen mode

时区支持

您可以使用以下timezone属性显示不同的时区:

<analog-clock label="New York" timezone="-4"></analog-clock>
<analog-clock label="London" timezone="0"></analog-clock>
<analog-clock label="Tokyo" timezone="+9"></analog-clock>
<analog-clock label="Mumbai" timezone="+5.5"></analog-clock>
Enter fullscreen mode Exit fullscreen mode

属性

  • date:显示日期。取值:“日”、“月”、“年”或任意组合
  • indices:显示刻度线。值:空(60 分)或“小时”(12 分)
  • label:时钟下方的文字标签
  • marker:用于索引的字符(默认值:“|”)
  • marker-hour:用于小时索引的字符(默认为标记值)
  • numerals:显示的数字数量(1-12,默认值:12)
  • steps:使用步进动画来显示秒针
  • system:数字系统。值:“roman”、“romanlow”或任何有效的国际数字系统
  • timezone:UTC 偏移量(以小时为单位)(例如,“-4”、“+1”、“+5.5”)

演示

这是 Codepen,里面有我们编写的所有时钟和手表:

现在去教孩子们如何读模拟时钟!

鏂囩珷鏉ユ簮锛�https://dev.to/madsstoumann/clocks-and-watches-in-css-36mm
PREV
前端安全:内容安全策略
NEXT
帮助我在周末推出 MVP 的 5 种方法 定义成功是什么样子 保持简单 不要重新发明轮子 可重复使用的代码 重新利用您知道的工具 最后的想法