文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

一篇带给你运用CSS 绘制一个时钟

2024-12-02 04:10

关注

练习 CSS 一个很好的方法就是绘制各式各样的 UI,比如这样一个时钟?

你也可以访问「文章底部原文链接」查看实际效果。

CSS 绘制这样一个布局有几个难点:

  1. 环形排列的刻度。
  2. 环形分布的数字。
  3. 自动运行的指针。

下面就来一一实现它,相信能学到很多 CSS 绘制和动画的小技巧。

一、环形排列的刻度

提到“环形”,可以想到锥形渐变 conic-gradient[2]。假设有这样一个容器。

<clock>clock>

加上一点锥形渐变。

clock{
width: 300px;
height: 300px;
background: conic-gradient(#333 0 15deg, #cddc39 0deg 30deg);
}

可以得到这样的效果。

如何做出交错相间的效果呢?可以试试 repeating-conic-gradient[3]。

clock{

background: repeating-conic-gradient(#333 0 15deg, #cddc39 0deg 30deg);
}

效果如下:

还是看不出和刻度有啥关系?没关系,我们把黑色部分的角度改小一点。

clock{

background: repeating-conic-gradient(#333 0 1deg, #cddc39 0deg 30deg);
}

效果如下:

这样绘制出来的几条线是不是刚好可以对应时钟的刻度?

然后将整个形状变成圆环,可以用 MASK 来实现,实现如下:

clock{

border-radius: 50%;
-webkit-mask: radial-gradient(transparent 145px, red 0);
}

效果如下:

其实,这里还有一个小细节,黑色部分并不是居中的,需要修正一下(可以更改起始角度,指定 from)。然后,将这个草绿色换成透明就可以了,完整代码如下:

clock{

background: repeating-conic-gradient(from -.5deg, #333 0 1deg, transparent 0deg 30deg);
border-radius: 50%;
-webkit-mask: radial-gradient(transparent 145px, red 0);
}

最终效果:

分钟的刻度也是同样的道理,因为共有 60 个刻度,所以最小角度是 6 度(360 / 60),实现如下:

clock{

background: repeating-conic-gradient(#333 0 1deg, #cddc39 0deg 6deg);
}

利用 CSS 背景可以无限叠加的特性,可以将这两个背景绘制在同一个元素下,所以完整代码如下:

clock{

background: repeating-conic-gradient(from -.5deg, #333 0 1deg, transparent 0deg 30deg),
repeating-conic-gradient(from -.5deg, #ccc 0 1deg, transparent 0deg 6deg);
border-radius: 50%;
-webkit-mask: radial-gradient(transparent 145px, red 0);
}

最终表盘刻度效果如下:

二、环形分布的数字

看到这种布局,我的第一反应其实是 textPath[4],这个 SVG 元素可以让文本沿着指定路径进行排列,比如下面这个 MDN 上的例子:

<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<path id="MyPath" fill="none" stroke="red"
d="M10,90 Q90,90 90,45 Q90,10 50,10 Q10,10 10,40 Q10,70 45,70 Q70,70 75,50" />
<text>
<textPath href="#MyPath">
Quick brown fox jumps over the lazy dog.
textPath>
text>
svg>

效果如下:

但是,这种方式有一个缺陷,无法改变文字的角度,只能沿着路径垂直方向,而时钟的数字方向都是正常的。

经过一番琢磨,发现还有一种方式也有类似沿着路径的布局方式,那就是 offset-path[5]! 下面是 MDN 上的一个演示效果:

那么和环形排列数字有什么关系呢?假设有这样一个布局:

<clock-pane>
<num>1num>
clock-pane>

然后将这个数字指定到一个圆形的路径上(目前仅支持 path )。

num{
offset-path: path('M250 125c0 69.036-55.964 125-125 125S0 194.036 0 125 55.964 0 125 0s125 55.964 125 125z');
}

效果如下(起始点是跟随 path 路径的):

然后,可以通过 offset-distance[6]来改变元素在路径上的位置,并且支持百分比。

num{
offset-path: path('M250 125c0 69.036-55.964 125-125 125S0 194.036 0 125 55.964 0 125 0s125 55.964 125 125z');
offset-distance: 100%
}

下面是从 0 到 100% 的变化。

默认情况下元素的角度也是自适应垂直于路径的,和 textPath 比较类似。但是我们可以手动指定固定角度,需要 offset-rotate[7],指定为 0deg 就行了。

num{
offset-path: path('M250 125c0 69.036-55.964 125-125 125S0 194.036 0 125 55.964 0 125 0s125 55.964 125 125z');
offset-distance: 100%
}

效果如下,角度已经完全归正了。

如果有类似的布局需求,是不是可以参考这个案例呢?

接下来,我们通过 CSS 变量,把 12 个数字自动归位到指定位置。

<clock-pane>
<num style="--i:1">1num>
<num style="--i:2">2num>
<num style="--i:3">3num>
<num style="--i:4">4num>
<num style="--i:5">5num>
<num style="--i:6">6num>
<num style="--i:7">7num>
<num style="--i:8">8num>
<num style="--i:9">9num>
<num style="--i:10">10num>
<num style="--i:11">11num>
<num style="--i:12">12num>
clock-pane>

配合 calc 计算,完整代码如下:

num{
position: absolute;
offset-path: path('M250 125c0 69.036-55.964 125-125 125S0 194.036 0 125 55.964 0 125 0s125 55.964 125 125z');
offset-distance: calc( var(--i) * 10% / 1.2 - 25%);
offset-rotate: 0deg;
}

效果如下:

三、自动运行的指针

三个指针的绘制应该没有太大的难度,假设结构如下:

<hour>hour>
<min>min>
<sec>sec>

需要注意一下旋转的中心。

hour{
position: absolute;
width: 4px;
height: 60px;
background: #333;
transform-origin: center bottom;
transform: translateY(-50%) rotate(30deg);
}
min{
position: absolute;
width: 4px;
height: 90px;
background: #333;
transform-origin: center bottom;
transform: translateY(-50%) rotate(60deg);
}
sec{
position: absolute;
width: 2px;
height: 120px;
background: red;
transform-origin: center bottom;
transform: translateY(-50%) rotate(90deg);
}
sec::after{
content: '';
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
left: 50%;
bottom: 0;
background: #fff;
border: 4px solid #333;
transform: translate(-50%, 50%);
}

效果如下:

到这一步静态布局就算完成了,那么如何运行呢?

之前在这篇文章 还在使用定时器吗?CSS 也能实现电子时钟 有详细讲解到,不借助定时器,也完全可以用 CSS 动画来实现!

回到这里,运行的原理很简单,就是一个无限循环的 CSS 动画,如下:

@keyframes clock {
to {
transform: translateY(-50%) rotate(360deg);
}
}

不同的是,时针、分针、秒针的周期不一样,时针转一圈是 12 小时、分针是 60 分钟、秒针是 60 秒,各自需要换算成 秒数(CSS 单位只支持 秒 和 毫秒),为了方便测试,这里将速度调快了 60s → 6s。

代码实现就是(--step 是一分钟)。

hour{

transform: translateY(-50%) rotate(0);
animation: clock calc(var(--step) * 60 * 12) infinite;
}
min{

transform: translateY(-50%) rotate(0);
animation: clock calc(var(--step) * 60) infinite;
}
sec{

transform: translateY(-50%) rotate(0);
animation: clock var(--step) infinite;
}

效果如下:

是不是有些奇怪?秒针在旋转时先慢慢变快,然后又慢慢变慢,这是由于默认的动画函数是ease,所以需要改成linear。

sec{

animation: clock var(--step) infinite linear;
}

这样就好多了。不过平时所见的时钟,秒针通常都那种走一下,停下的,还有一种“滴答滴答”的节奏感,并不是这种无缝的。在 CSS 动画中,是不是有点像阶梯状,没错,可以用到 CSS 的 steps 函数,不了解这个的可以参考张老师的这篇文章:CSS3 animation属性中的steps功能符深入介绍[8],实现如下:

sec{

animation: clock var(--step) infinite steps(60);
}

效果如下:

接下来需要通过 JS 初始化时间,仅此而已。需要注意的是,在获取的时候加上偏移量,比如 12:30,分针其实是 12.5,以此类推。代码实现如下:

const d = new Date()
const h = d.getHours();
const m = d.getMinutes();
const s = d.getSeconds();
clock.style.setProperty('--ds', s)
clock.style.setProperty('--dm', m + s/60)
clock.style.setProperty('--dh', h + m/60 + s/3600)

然后 CSS 中可以通过 animation-delay来指定动画的起始位置。

hour{

animation: clock calc(var(--step) * 60 * 12) infinite linear;
animation-delay: calc( -1 * var(--step) * var(--dh) * 60);
}
min{

animation: clock calc(var(--step) * 60) infinite linear;
animation-delay: calc( -1 * var(--step) * var(--dm));
}
sec{

animation: clock var(--step) infinite steps(60);
animation-delay: calc( -1 * var(--step) * var(--ds) / 60 );
}

然后加点轮廓装饰,就实现了文章开头的效果:

完整代码可以查看 「文章底部原文链接」。

四、简单总结一下

以上就是CSS 绘制时钟的全部过程了,本文更侧重于绘制过程,特别是是环形布局技巧,这里简单总结一下:

  1. 碰到环形图案可以想到 conic-gradient。
  2. 环形刻度绘制的原理是 conic-gradient 和 MASK 裁剪。
  3. 文字沿路径排列可以使用 textPath。
  4. textPath 不支持改变文字角度。
  5. offset-path 可以让元素沿指定路径进行布局。
  6. offset-path 可以设置元素在路径的偏移和角度。
  7. 时钟自动运行的原理的是 CSS 动画。
  8. 时钟、分钟、秒钟的区别是动画时长不同。
  9. “滴答滴答”的效果可以用 steps 实现。
  10. 时间初始化可以通过 animation delay 实现。

当然本文重点并不是在于实现了一个时钟,而是在于 CSS 绘制技巧的积累和掌握。有了相关的积累,以后在碰到类似的布局,在脑子里过滤一下,马上就能找到解决方案。

参考资料

[1]CSS clock: https://codepen.io/xboxyan/pen/JjMWQBP。

[2]conic-gradient: https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/conic-gradient。

[3]repeating-conic-gradient: https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/repeating-conic-gradient。

[4]textPath: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/textPath。

[5]offset-path: https://developer.mozilla.org/en-US/docs/Web/CSS/offset-path。

[6]offset-distance: https://developer.mozilla.org/en-US/docs/Web/CSS/offset-distance。

[7]offset-rotate: https://developer.mozilla.org/en-US/docs/Web/CSS/offset-rotate。

[8]CSS3 animation属性中的steps功能符深入介绍: https://www.zhangxinxu.com/wordpress/2018/06/css3-animation-steps-step-start-end/。

来源:前端侦探内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯