写在前面之前我们分别做了极光、像素、3D 城市、夜色卡全是“纯视觉”。今天换一个思路做一个带“信息”的东西——一只真会走的时钟。毛玻璃卡片 三根指针秒针每秒跳一格分针、时针按真实速度行走开屏一瞬正好停在10:08:42——那是所有钟表广告都爱用的“经典姿势”。但全页没有一行JavaScript。怎么做到的只靠CSS的两个特性backdrop-filter做毛玻璃负的animation-delay把动画“倒带”到任意时刻。看完你会明白CSS的动画不止能“循环”还能“对时”。一、先看效果浅灰蓝背景上三团彩色光斑缓慢漂移中间浮着一张磨砂玻璃卡——透过玻璃能看见背景色块被糊成柔和的色晕。表盘里三根指针各就各位时针粗短、深蓝指向10和11之间分针细长、稍浅指向8分位置秒针最细、玫红带一个圆形尾部配重每秒跳一格三根针都按真实周期行走开屏即10:08:42。怎么跑起来新建一个demo.html把下面第二节的完整代码粘进去双击用浏览器打开截图党提示秒针每秒跳一格是这张图的“灵魂”。静图看不出跳格建议录GIF抓3–4秒让秒针跳3、4格动感立刻出来。二、完整代码复制即用!DOCTYPEhtmlhtmllangzh-CNheadmetacharsetUTF-8metanameviewportcontentwidthdevice-width, initial-scale1.0titleDay 05 · 玻璃拟态毛玻璃时钟/titlestyle*{margin:0;padding:0;box-sizing:border-box;}html, body{height:100%;}body{display:flex;align-items:center;justify-content:center;overflow:hidden;background:#e8edf4;font-family:PingFang SC,sans-serif;}/* —— 背景三团彩色光斑给玻璃「可糊之物」—— */.bg{position:fixed;inset:0;overflow:hidden;}.bg i{position:absolute;border-radius:50%;filter:blur(80px);opacity:.8;}.bg .c1{width:380px;height:380px;left:6%;top:10%;background:#b9a7ff;animation:drift1 14s ease-in-out infinite alternate;}.bg .c2{width:320px;height:320px;right:4%;top:38%;background:#7fe3d2;animation:drift2 18s ease-in-out infinite alternate;}.bg .c3{width:300px;height:300px;left:36%;bottom:-8%;background:#ffc2cf;animation:drift3 16s ease-in-out infinite alternate;}keyframesdrift1{to{transform:translate(70px,50px)scale(1.12);}}keyframesdrift2{to{transform:translate(-60px,-40px)scale(.92);}}keyframesdrift3{to{transform:translate(40px,-60px)scale(1.1);}}/* —— 玻璃卡片半透明底 高光边 backdrop-filter —— */.glass{position:relative;width:300px;padding:36px 30px 28px;border-radius:26px;background:rgba(255,255,255,.42);border:1px solidrgba(255,255,255,.65);backdrop-filter:blur(18px)saturate(1.3);-webkit-backdrop-filter:blur(18px)saturate(1.3);box-shadow:0 18px 50pxrgba(80,100,140,.18);}.glass::before{content:;position:absolute;inset:0;border-radius:inherit;background:linear-gradient(120deg,rgba(255,255,255,.55),rgba(255,255,255,0)42%);pointer-events:none;}/* —— 表盘双层 conic 刻度 环形遮罩 —— */.dial{position:relative;width:210px;height:210px;margin:0 auto;border-radius:50%;background:rgba(255,255,255,.5);border:1px solidrgba(255,255,255,.8);box-shadow:inset 0 2px 14pxrgba(90,110,150,.14);}.dial::before{content:;position:absolute;inset:10px;border-radius:50%;background:repeating-conic-gradient(from -1.2deg,rgba(44,58,85,.45)0deg 2.4deg,transparent 2.4deg 90deg),repeating-conic-gradient(from -0.5deg,rgba(44,58,85,.22)0deg 1deg,transparent 1deg 30deg);-webkit-mask:radial-gradient(closest-side,transparent 84%,#000 85%,#000 96%,transparent 96%);mask:radial-gradient(closest-side,transparent 84%,#000 85%,#000 96%,transparent 96%);}/* —— 指针动画周期 真实周期负 delay 对时到 10:08:42 —— */.hand{position:absolute;left:50%;bottom:50%;transform-origin:50% 100%;border-radius:6px;animation:rot linear infinite;}.hour{width:7px;height:54px;margin-left:-3.5px;background:#2b3a58;animation-duration:43200s;animation-delay:-36480s;}.min{width:5px;height:80px;margin-left:-2.5px;background:#42557c;animation-duration:3600s;animation-delay:-480s;}.sec{width:2px;height:92px;margin-left:-1px;background:#ef5f82;animation-duration:60s;animation-delay:-42s;animation-timing-function:steps(60);}.sec::after{content:;position:absolute;bottom:-12px;left:50%;width:8px;height:12px;margin-left:-4px;background:#ef5f82;border-radius:4px;}.cap{position:absolute;left:50%;bottom:50%;width:13px;height:13px;margin:-6.5px;border-radius:50%;background:#2b3a58;box-shadow:0 0 0 3pxrgba(255,255,255,.65);}keyframesrot{to{transform:rotate(360deg);}}.brand{margin-top:22px;text-align:center;font:400 11px/1SF Mono,Consolas,monospace;letter-spacing:.34em;color:#5a6a8a;}.sub{margin-top:8px;text-align:center;font:400 9px/1SF Mono,Consolas,monospace;letter-spacing:.22em;color:#93a0b8;}.tag{position:fixed;right:18px;bottom:14px;font:400 10px/1SF Mono,Consolas,monospace;letter-spacing:.28em;color:rgba(90,106,138,.5);}/style/headbodydivclassbgiclassc1/iiclassc2/iiclassc3/i/divdivclassglassdivclassdialdivclasshand hour/divdivclasshand min/divdivclasshand sec/divdivclasscap/div/divdivclassbrandGLASS · CLOCK/divdivclasssubZERO JS · 10:08 AM/div/divdivclasstag每天一个惊艳 CSS · DAY 05/div/body/html三、四个核心技法拆解技法1玻璃拟态三件套玻璃感 半透明白底 backdrop-filter: blur() 一条亮色1px高光边三者缺一不可。.glass{background:rgba(255,255,255,.42);/* ① 半透明白底 */border:1px solidrgba(255,255,255,.65);/* ② 高光边 */backdrop-filter:blur(18px)saturate(1.3);/* ③ 背后模糊 提饱和 */-webkit-backdrop-filter:blur(18px)saturate(1.3);/* Safari 前缀 */}为什么saturate(1.3)是必须的blur()把背后的颜色糊成一片颜色会变灰、变淡。加一点saturate把饱和度提回来玻璃才会“透出颜色”而不是“透出灰”。为什么高光边这么关键玻璃是有厚度的。1px的rgba(255,255,255,.65)描边模拟的就是玻璃切面的边缘反光。少了这条线卡片立刻变成“半透明塑料片”。再加一层玻璃反光.glass::before{content:;position:absolute;inset:0;border-radius:inherit;background:linear-gradient(120deg,rgba(255,255,255,.55),rgba(255,255,255,0)42%);pointer-events:none;/* 关键别挡住下层点击 */}一道从左上扫过、在42%处消失的白色渐变——这就是玻璃表面那道斜着的高光。质感立刻上一档。pointer-events: none千万别忘高光层铺满整张卡会挡住卡片内部所有交互如果以后加按钮、滑动之类。技法2玻璃后面必须「有东西可糊」这是玻璃拟态最容易被忽略、也最容易翻车的一条backdrop-filter只把“卡片背后的像素”糊掉。背景如果是纯色糊完还是纯色——毛玻璃感为零。所以第一步不是写玻璃是先给背后铺东西.bg i{position:absolute;border-radius:50%;filter:blur(80px);opacity:.8;}.bg .c1{background:#b9a7ff;}/* 紫 */.bg .c2{background:#7fe3d2;}/* 青 */.bg .c3{background:#ffc2cf;}/* 粉 */三团高饱和、大尺寸、低透明度的色斑各自 80px 模糊。它们就是“给玻璃可糊之物”。为什么还要让色斑动起来三团色斑各自配一个14s / 18s / 16s的缓慢位移动画。玻璃背后的色晕就会缓慢流动——静止的毛玻璃是照片流动的毛玻璃才是视频。注意时长要错开三个时长互质最小公倍数很大永远不会出现“三团色斑同时回到原位”的尴尬瞬间。技法3双层repeating-conic-gradient画表盘刻度表盘上那圈刻度不是图片、不是SVG而是两层锥形渐变叠出来的.dial::before{background:/* 第一层每 90° 一个粗刻度12 / 3 / 6 / 9 点 */repeating-conic-gradient(from -1.2deg,rgba(44,58,85,.45)0deg 2.4deg,transparent 2.4deg 90deg),/* 第二层每 30° 一个细刻度12 个小时位 */repeating-conic-gradient(from -0.5deg,rgba(44,58,85,.22)0deg 1deg,transparent 1deg 30deg);mask:radial-gradient(closest-side,transparent 84%,#000 85%,#000 96%,transparent 96%);}repeating-conic-gradient是什么和普通conic-gradient一样从中心放射但会重复。写0deg 2.4deg有色2.4deg 90deg透明就是“每90°里画一条2.4°宽的刻度”自动铺满整圈。为什么刻度要“内缩”每层渐变的0deg前面都加了一个小偏移from -1.2deg/from -0.5deg让刻度以“整点”为中心对称展开不会偏向一边。mask才是关键的一步mask:radial-gradient(closest-side,transparent 84%,/* 圆心到 84% 半径全透露出表盘底色 */#000 85%,#000 96%,/* 84% ~ 96% 半径保留刻度在这一圈 */transparent 96%);/* 96% 以外全透 */一层环形遮罩把整个渐变面“抠”成一个圆环——只有半径84%到96%之间的像素留下其余全被抹掉。这样刻度才会贴着表盘边缘不会铺满整个圆盘。改一格宽度、改一个角度就是一块新表盘。不用切图、不用SVG。技法4负animation-delay 把动画“倒带”到任意时刻这是整篇的灵魂。秒针动画周期60秒、分针3600秒、时针43200秒12小时都写成linear infinite.hand{animation:rot linear infinite;}keyframesrot{to{transform:rotate(360deg);}}如果什么都不做页面打开时三根针都停在12:00然后各自从零开始转。负animation-delay就是在说“这个动画早就在跑了现在应该跑到第X秒。”.hour{animation-duration:43200s;animation-delay:-36480s;}/* 36480s 10h08m */.min{animation-duration:3600s;animation-delay:-480s;}/* 480s 8m */.sec{animation-duration:60s;animation-delay:-42s;}/* 42s 42s */验算一下时针36480 / 43200 0.8444…→0.8444 × 12小时 10.13小时 10小时8分✓分针480 / 3600 0.1333…→0.1333 × 60分 8分✓秒针42 / 60 0.7→0.7 × 60秒 42秒✓所以开屏一瞬指针正好指向10:08:42。为什么必须是负值正delay是“等N秒后再开始”——页面打开时指针静止在12点等够时长才动。对时永远用负值它表示“动画起点在N秒之前”浏览器会直接跳到对应进度。秒针为什么用steps(60).sec{animation-timing-function:steps(60);}因为真石英钟就是跳格的。linear是连续扫描看起来像雷达steps(60)是把一圈分成60格一秒跳一格——这才是拟真的关键。这条技巧的通用价值所有“无限循环 需要指定初始相位”的场景都适用——旋转木马、进度环、天气图标、加载动画。记住它以后所有循环动画都能对得上时刻。四、踩坑位我全踩过你直接避① 背景是纯色还怪玻璃不“毛”/* ❌ 背景纯色backdrop-filter 没东西可糊 */body{background:#e8edf4;}.glass{backdrop-filter:blur(18px);}/* ✅ 先在背后铺彩色光斑再谈玻璃 */.bg .c1{background:#b9a7ff;}.bg .c2{background:#7fe3d2;}.bg .c3{background:#ffc2cf;}backdrop-filter只会把“背后已有的颜色”糊掉。背后是灰的糊完还是灰的。先铺色再谈玻璃。② 指针忘了transform-origin: 50% 100%/* ❌ 默认绕中心旋转指针像风扇叶片一样自转 */.hand{/* ... */}/* ✅ 原点必须在针尾底部中心 */.hand{transform-origin:50% 100%;}transform-origin默认是center center。指针会绕自己的几何中心转看起来像一根悬空的棍子在空中打转完全不指向任何方向。原点改成50% 100%底部中心它才会绕“针尾”旋转——也就是绕表盘中心转。③animation-delay写成正数/* ❌ 页面开屏10秒表还是12:00 */.sec{animation-delay:42s;}/* ✅ 对时永远用负值 */.sec{animation-delay:-42s;}正 delay是“等42秒再开始”页面会先静止42秒。任何“对时”场景都用负delay。④ 老版Firefox不支持backdrop-filter玻璃退化为半透明平面背后色斑毫无遮拦地透出来可读性暴跌。降级方案supportsnot(backdrop-filter:blur(1px)){.glass{background:rgba(255,255,255,.85);}/* 提高不透明度补偿 */}supports检测到不支持时把底色从.42提到.85卡片立刻变成“磨砂不透明”风格视觉损失可控。⑤ 秒针用linear却觉得“不像真钟”/* ❌ 连续扫动像雷达 */.sec{animation-timing-function:linear;}/* ✅ 跳格像石英钟 */.sec{animation-timing-function:steps(60);}linear是匀速连续扫过机械感为零。真石英钟是每秒“啪”地跳一格——steps(60)才是拟真。如果你想要机械表那种“扫秒”质感就反过来用cubic-bezier(.4, 2.08, .55, .44)做个带弹性的线性——不过那是另一种风格了。五、变式挑战10–30分钟动手才有收获任务给时钟接上真实时间只需3行JS。这是本专栏唯一一次“半开戒”——就当彩蛋。代码只有3行scriptconstdnewDate(),sd.getSeconds()60*(d.getMinutes()60*d.getHours());document.querySelector(.sec).style.animationDelay-${s}s;document.querySelector(.min).style.animationDelay-${s/60}s;document.querySelector(.hour).style.animationDelay-${s/3600}s;/script原理和负delay完全一样s算出“今天已过秒数”把三根指针的animationDelay动态设成负值浏览器立刻把动画“倒带”到当前时刻做完这一版你会发现CSS已经把99%干完了——时针、分针、秒针各自的周期、转速、跳格节奏全在CSS里。JS只是拨了一下表让起点对上现实时间。这就是CSS动画的正确姿势把“如何旋转”交给CSS把“从哪开始”交给JS。两者各司其职代码最短。进阶挑战有余力再玩加一条日期栏表盘下方用time或::after显示今日日期加一盏夜光给指针加box-shadow: 0 0 6px rgba(239,95,130,.7)夜里会有微微荧光把玻璃卡做成“可切换表盘”仿照radio方案给玻璃加一个“简约 / 罗马数字 / 无刻度”三档切换六、小结今天这一篇里藏着5个通用技能点技能适用场景玻璃拟态三件套半透底 描边 backdrop-filter所有毛玻璃卡片、弹窗、导航栏::before加玻璃反光 pointer-events:none所有需要“玻璃感”的容器背后铺色斑做“可糊之物”所有想凸显毛玻璃的场景repeating-conic-gradient 环形mask表盘、雷达、指南针、刻度盘负animation-delay所有“无限循环 指定初始相位”的动画最值得记住的一条负animation-delay是无限循环动画的“初始状态设定器”。想让它“看起来已经跑了X秒”就写-Xs。学会这一招你能把任何循环动画“瞬间对齐”到任意时刻——旋转木马停在某个位置、进度环从30%开始、天气图标从雨天播起……都不用 JS。另外一句话也值得记住纯CSS能做视觉做不了“现实感知”。表盘、指针、走时节奏CSS全包但对上真实时间只差3行JS。CSS和JS不是对立的——知道哪一部分交给CSS最优雅、哪一部分必须交给JS才是真的懂。
阅读完成 · 觉得有帮助?