纯 CSS 实现手作印章盖戳打卡动效:朱砂印泥渗透与微震

在极简清单与习惯手账中,当用户完成一项待办任务时,一个简单机械的勾选框(Checkbox)往往无法给大脑带来足够的正向反馈。
而在真实手作手账里,每当完成一件重要的事情,我们习惯拿起红木印章,蘸满朱砂印泥,在纸面上用力盖下一枚“済”或“已完成”的红色印戳。
为了在屏幕上还原这种让人感到踏实与愉悦的手作仪式感,我们用纯 CSS 关键帧动画、内联 SVG 噪点渗透遮罩与 Web Vibration API,封装了一个极具物理打击感的印章盖戳组件。
+——————————————————————–+
| 手作印章盖戳物理打击三阶段拆解 |
+——————————————————————–+
| 阶段一: 抬起悬浮 (0% -> scale(2.2), rotate(-18deg), opacity: 0) |
| | |
| 阶段二: 重力砸落 (0.16s 极速到达 scale(0.92), rotate(2deg)) |
| ├── 模拟重力砸在宣纸上的微弹性过载压缩 |
| └── 触发手机硬件 18ms 触感微震 (navigator.vibrate(18)) |
| | |
| 阶段三: 弹性释放与印泥渗透 (0.28s -> scale(1.0), rotate(-1.5deg)) |
| └── SVG 斑驳噪点蒙版激活: 呈现朱砂印泥渗透棉浆纸纤维的自然微瑕|
+——————————————————————–+
1. 纯 CSS 核心打击动画与印泥纹理实现
/* 朱砂手作印戳基础样式 */
.stamp-seal {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
width: 48px;
height: 48px;
border: 2.5px solid #D36135; /* 经典朱砂暖红 */
border-radius: 50%;
color: #D36135;
font-family: 'LXGW WenKai', serif;
font-weight: 700;
font-size: 15px;
letter-spacing: 1px;
user-select: none;
/* 模拟天然印泥的微小缺墨与粗糙度 */
mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.6' numOctaves='3'/%3E%3C/filter%3E%3Ccircle cx='50' cy='50' r='48' filter='url(%23n)' opacity='0.9'/%3E%3C/svg%3E");
}
/* 物理砸落按压动画 */
.is-stamp-impact {
animation: seal-slam 0.28s cubic-bezier(0.18, 0.89, 0.32, 1.28) forwards;
}
@keyframes seal-slam {
0% {
opacity: 0;
transform: scale(2.2) rotate(-18deg) translateY(-10px);
}
65% {
opacity: 1;
transform: scale(0.92) rotate(3deg) translateY(0);
box-shadow: 0 0 0 rgba(211, 97, 53, 0);
}
85% {
transform: scale(1.05) rotate(-2deg);
}
100% {
opacity: 1;
transform: scale(1) rotate(-1.5deg);
box-shadow: 1px 1px 0px rgba(211, 97, 53, 0.35);
}
}
2. React 打卡组件与触觉反馈
import React, { useState } from "react";
export const StampCheckButton: React.FC<{
isDone: boolean;
onToggle: () => void;
text?: string;
}> = ({ isDone, onToggle, text = "済" }) => {
const handleClick = () => {
if (!isDone && typeof navigator !== "undefined" && "vibrate" in navigator) {
navigator.vibrate([0, 15, 8]); // 模拟印章撞击的清脆双震
}
onToggle();
};
return (
<button
onClick={handleClick}
className="focus:outline-none select-none transition-transform active:scale-95"
title={isDone ? "取消完成" : "盖戳完成 🪓"}
>
{isDone ? (
<div className="stamp-seal is-stamp-impact">
<span>{text}</span>
</div>
) : (
<div className="w-10 h-10 border-2 border-dashed border-stone-300 rounded-full hover:border-[#88AA99] transition-colors flex items-center justify-center">
<span className="text-xs text-stone-300">○</span>
</div>
)}
</button>
);
};
仪式感的心里锚定
当手指轻轻按下,耳边伴随着清脆的震动,一枚鲜红的朱砂小印章稳稳落在纸面上。
这种纯粹的掌控感与完成感,能瞬间驱散所有的拖延与疲惫,让前行的每一步都充满信心。
