card · hover 无布局跳动

卡片的核心判据:hover 时只改 transform 和 box-shadow, 绝不改 border-width / margin / padding / height。

把 1px 的跳动放大给你看

真实项目里这个 bug 通常是 border: 1px → 2px,只跳 1px —— 轻到说不清哪里不对,但整页会显得廉价。
下面故意放大到 4px,好让你一次看清楚。请分别把鼠标移到两张卡上。

反例:hover 改 border-width

移上来 —— 里面那把尺子和文字整体往下挪了,卡片也变高了。 一排卡片时,邻居会跟着抖。

2026-09-24
动物森友会 UI 库实拍
2026-09-27
MICRO 微交互组件实拍

本库:transform + box-shadow

移上来 —— 卡片整体抬起 2px,里面的内容一个像素都不动, 邻居也不会被推挤。

动物森友会 UI 库实拍 2026-09-24
MICRO 微交互组件实拍 2026-09-27

抬起 2px,不是 8px

卡片是"被拿起",不是"被弹起"。8px 以上会有游戏感 —— 长文和数据类界面不能要那种感觉。这也是森友会那套设计里我最认同的一条: 卡片 20px 圆角、无投影、hover 只抬 2px。

变体

flat

无边框,靠背景色和纸底的明度差分层。一排卡片时用它最干净。

elevated

默认带阴影。只用在浮层、弹窗。列表里全用它,阴影会互相打架。

selected

用 inset box-shadow 做内描边,不是改 border-width —— 同样为了不跳动。

compact

内边距 24→16、标题降到正文大小。用在"一屏要放十几张"的清单里。

整卡可点:Tab 一下试试

点标题,整卡可点

用键盘 Tab 到这里 —— 整张卡会出现焦点环,而不是只有标题那一小块。

对照:普通 div onclick

(这张是正确实现的对照说明)给 div 加 onclick:键盘 Tab 不到、 屏幕阅读器不认、不能中键新开、不能复制链接。

实现:卡内放一个真实的 <a>,用它的 ::after 铺满整卡。 焦点样式用 :focus-within,内部链接获焦时整卡显示 ring。

横向卡片(窄屏自动回退)

横向布局

560px 以下自动变回纵向。别手动覆盖这个回退。

门禁抓到的真问题

给 states.py 加了 card 形态后,跑 某项目 立刻多报 4 项 HIGH: .card / .card-grid / .side-card 全都缺 focus —— 那几张卡鼠标能 hover,但键盘 Tab 不到。

这就是"按形态分开检查"的价值:统一清单时这些根本不会被发现。