当前位置: 首页 > 科技观察

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

时间:2023-03-15 20:56:40 科技观察

练习CSS的一个好方法就是画各种UI,比如这样的时钟?也可以访问“文末原文链接”查看实际效果。CSS绘制这样的布局有几个难点:鳞片排列成一个圆圈。循环分布中的数字。自动运行指针。下面一一实现,相信你能学到很多CSS绘图和动画的技巧。1.排列成环的鳞片指的是“环”,可以想到conic-gradient[2]。假设有这样一个容器。加上一点锥形渐变。时钟{宽度:300px;高度:300px;background:conic-gradient(#333015deg,#cddc390deg30deg);}可以得到这个效果。如何做出交错效果?你可以试试repeating-conic-gradient[3]。clock{/**/background:repeating-conic-gradient(#333015deg,#cddc390deg30deg);}效果如下:还是看不出和刻度的关系?没关系,让我们将黑色部分的角度变小。clock{/**/background:repeating-conic-gradient(#33301deg,#cddc390deg30deg);}效果如下:这样画出来的线能不能正好对应时钟的刻度?然后把整个shape改成Formacircle,可以用MASK实现,如下:clock{/**/border-radius:50%;-webkit-mask:radial-gradient(transparent145px,red0);}效果如下:其实这里有个小细节,黑色部分没有居中,需要修正(可以改starting角度并指定从)。然后,只需将草绿色更改为透明即可。完整代码如下:clock{/**/background:repeating-conic-gradient(from-.5deg,#33301deg,transparent0deg30deg);边界半径:50%;-webkit-mask:radial-gradient(transparent145px,red0);}最终效果:分钟刻度相同,因为一共有60个刻度,所以最小角度为6度(360/60),实现如下:clock{/**/background:repeating-conic-gradient(#33301deg,#cddc390deg6deg);}利用css背景可以无限叠加的特性,绘制两个背景在同一个元素下,所以完整的代码如下:clock{/**/background:repeating-conic-gradient(from-.5deg,#33301deg,transparent0deg30deg),repeating-conic-gradient(from-.5deg,#ccc01deg,透明0deg6deg);边界半径:50%;-webkit-mask:radial-gradient(transparent145px,red0);}最终刻度盘刻度效果如下:2.数字呈环状分布看到这个布局,我第一反应居然是textPath[4]。此SVG元素允许文本沿指定路径排列,例如MDN上的以下示例:<路径id="MyPath"fill="none"stroke="red"d="M10,90Q90,9090,45Q90,1050,10Q10,1010,40Q10,7045,70Q70,7075,50"/><文字>敏捷的棕色狐狸跳过懒狗。效果如下:但是这个方法有一个缺陷,文字的角度不能改变,只能沿着路径的垂直方向,数字方向时钟正常。一番琢磨后,发现还有一种类似于沿路径布局的方法,那就是offset-path[5]!下面是一个在MDN上的演示效果:那么和数字循环排列有什么关系呢?假设有这样一个布局:1然后将这个编号赋值给一个圆形路径(目前只支持路径)。num{offset-path:path('M250125c069.036-55.964125-125125S0194.036012555.96401250s12555.964125125z');}效果如下(起点跟随路径):distance[6]改变元素在路径上的位置,支持百分比。num{偏移路径:路径('M250125c069.036-55.964125-125125S0194.036012555.96401250s12555.964125125z');offset-distance:100%}这是从0%到100%的变化。默认情况下,元素的角度也是自适应的,垂直于路径,类似于textPath。但是我们可以手动指定一个固定的角??度,这需要offset-rotate[7],指定0deg即可。num{偏移路径:路径('M250125c069.036-55.964125-125125S0194.036012555.96401250s12555.964125125z');offset-distance:100%}效果如下,角度已经完全归一化。如果你有类似的布局需求,可以参考这个案例吗?接下来,我们使用CSS变量将这12个数字自动返回到指定位置。<时钟窗格>123456789101112带calc计算,完整代码如下:num{position:absolute;偏移路径:路径('M250125c069.036-55.964125-125125S0194.036012555.96401250s12555.964125125z');偏移距离:calc(var(--i)*10%/1.2-25%);offset-rotate:0deg;}效果如下:3.自动运行三个指针的指针绘制应该不会太难,假设结构如下:需要注意旋转的中心。小时{位置:绝对;宽度:4px;高度:60px;背景:#333;变换原点:中心底部;变换:translateY(-50%)rotate(30deg);}min{position:absolute;宽度:4px;高度:90px;背景:#333;变换原点:中心底部;变换:translateY(-50%)rotate(60deg);}sec{position:absolute;宽度:2px;高度:120px;原点:中心底部;转换:translateY(-50%)rotate(90deg);}sec::after{content:'';位置:绝对;宽度:10px;高度:10px;50%;底部:0;背景:#fff;边框:4px实心#333;transform:translate(-50%,50%);}效果如下:静态布局到这一步就完成了,那么如何运行呢?之前这篇文章你还在用定时器吗?CSS也可以实现电子时钟。已经详细说明了,不用定时器也可以用CSS动画来实现!回到这里,操作原理很简单,就是无限循环CSS动画如下:@keyframesclock{to{transform:translateY(-50%)rotate(360deg);}}不同的是时针、分针、秒针的周期不同,时针转12圈,时针和分针是60分钟,秒针是60秒。每个都需要转换成秒(CSS单位只支持秒和毫秒)。为了测试方便,速度调整为60s→6s。代码实现是(--step是一分钟)。小时{/**/转换:translateY(-50%)rotate(0);animation:clockcalc(var(--step)*60*12)infinite;}min{/**/transform:translateY(-50%)rotate(0);animation:clockcalc(var(--step)*60)infinite;}sec{/**/transform:translateY(-50%)rotate(0);animation:clockvar(--step)infinite;}效果如下:是不是有点奇怪?秒针转动时慢慢变快,然后慢慢变慢。这是因为默认的动画函数是ease,所以需要改成linear。sec{/**/animation:clockvar(--step)infinitelinear;}这样好多了。然而,在我们平时看到的钟表中,秒针通常走走停停,有一种“滴答滴答滴答滴答”的节奏感,并不是天衣无缝。在CSS动画中,是不是有点像梯子?是的,你可以使用CSS的steps功能。不知道的可以参考张老师的这篇文章:深入介绍CSS3动画属性中的steps功能[8],实现如下:sec{/**/animation:clockvar(--step)infinitesteps(60);}效果如下:接下来需要通过JS初始化时间,仅此而已。需要注意的是获取的时候加上了偏移量,比如12:30,分针实际是12.5等等。代码实现如下:constd=newDate()consth=d.getHours();constm=d.getMinutes();consts=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:clockcalc(var(--step)*60*12)无限线性;animation-delay:calc(-1*var(--step)*var(--dh)*60);}min{/**/animation:clockcalc(var(--step)*60)无限线性;animation-delay:calc(-1*var(--step)*var(--dm));}sec{/**/animation:clockvar(--step)infinitesteps(60);animation-delay:calc(-1*var(--step)*var(--ds)/60);}然后加上一些Outline装饰就达到了文章开头的效果:完整代码可以查看“原文链接在文章底部”。4.小结以上就是用CSS绘制一个时钟的整个过程。本文更侧重于绘图过程,尤其是圆形布局技术。这里简单总结一下:遇到圆形图案,可以想到conic-gradient。圆形刻度绘制的原理是conic-gradient和MASKclipping。沿路径的文本可以使用textPath。textPath不支持更改文本角度。offset-path允许元素沿指定路径布局。offset-path可以设置元素在路径中的偏移量和角度。时钟自动走动的原理是CSS动画。钟、分、秒的区别在于动画时长不同。“滴答滴答”效果可以通过步骤来实现。可以通过动画延迟来实现时间初始化。当然,本文的重点不是实现时钟,而是CSS绘图技巧的积累和掌握。有了相关的积累,以后遇到类似布局的时候,在脑海里过滤一下,马上找到解决办法。参考文献[1]CSS时钟:https://codepen.io/xboxyan/pen/JjMWQBP。[2]圆锥梯度:https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/conic-gradient。[3]重复圆锥梯度:https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/repeating-conic-gradient。[4]文本路径:https://developer.mozilla.org/en-US/docs/Web/SVG/Element/textPath。[5]偏移路径:https://developer.mozilla.org/en-US/docs/Web/CSS/offset-path。[6]偏移距离:https://developer.mozilla.org/en-US/docs/Web/CSS/offset-distance。[7]偏移旋转:https://developer.mozilla.org/en-US/docs/Web/CSS/offset-rotate。[8]深入介绍CSS3动画属性中steps功能符号:https://www.zhangxinxu.com/wordpress/2018/06/css3-animation-steps-step-start-end/。