浅灰底色上摆着一小块键盘,上面是 command 和 Z 两枚键帽。鼠标按下去,键帽会向下沉 4px、底部的厚度阴影同时收窄,按下点还会扩散出一圈淡淡的水波;松开就弹回原位。更好玩的是,直接按物理键盘上的 Command(Windows 上是 Ctrl)或 Z 键,屏幕上的键帽也会跟着陷下去。技术上是 CSS 做外观、几十行原生 JavaScript 做交互,没有用任何库,也没有图片。
键帽的厚度是怎么做出来的
全靠多层 box-shadow。一枚键帽叠了七层阴影:四层 inset 描出上亮下暗的斜面,一层实色偏移当作键帽侧壁,剩下两层是落在底座上的投影。
按下时改的是阴影而不只是位移。元素下移的同时,侧壁那层阴影从 5px 缩到 1px,视觉上键帽就真的「矮」了一截,而不是整体平移。
水波是按点击位置临时生成的。脚本读取键帽的尺寸和鼠标坐标,算出圆心后插入一个 span,动画结束时监听 animationend 自己移除,不会越积越多。
用 pointer 事件而不是 mouse 事件
交互监听的是 pointerdown / pointerup / pointerleave,而不是常见的 mousedown 那一套:
key.addEventListener("pointerdown", function (e) { ... });pointer 事件会把鼠标、触摸、手写笔统一成一套回调,所以这个键帽在手机上直接就能按,不用额外写 touch 分支。加 pointerleave 是为了处理「按住后把指针拖出键帽」的情况,否则键帽会一直卡在凹陷状态。
能改的地方
键帽尺寸在 .key 的宽高,圆角、间距、底座颜色在 .keyboard 上;想做成深色机械键盘,把那几层阴影的亮暗色换成深色系即可。要加更多按键,复制一个 .key 并给它一个 id,再到脚本末尾的 keydown / keyup 判断里加一条对应的按键名就行。
常见问题
按物理键盘没反应?
要先点一下页面让它获得焦点,键盘事件才会派发到窗口上。另外脚本同时监听了 Meta 和 Control,所以 Mac 的 Command 和 Windows 的 Ctrl 都能触发。
手机上能用吗?
能。交互用的是 pointer 事件,触摸会正常触发下陷和水波;只是手机没有物理键盘,键盘联动那部分不会生效。
适合用在哪
快捷键教学与产品引导页、键盘类产品的介绍页、开发者工具的帮助面板,也可以拆出来当作一个有反馈感的通用按钮。阴影分层与水波生成的完整写法都在源码里,下载后可查看。