应使用@mixin interact-state统一封装交互反馈,仅暴露$duration和$scale参数,固化触发条件、过渡属性与原点,避免伪类散落导致不一致及触摸设备状态残留问题。

直接用 @mixin interact-state 封装,参数只暴露 $duration 和 $scale,其余触发条件、过渡属性、原点全部固化——否则不同组件的点击反馈永远对不齐。
为什么不能单独写 :active 或 :hover
伪类样式散落在各处,改一个按钮的按压缩放,卡片折叠、图标旋转也得跟着调;更麻烦的是,:hover 在触摸设备上会残留(iOS Safari 不清状态),而 :active 在快速点击时可能根本没触发。Sass 不解决运行时行为,但能帮你把「该动多少、动多快、从哪动」提前锁死。
实操建议:
- 所有可交互元素(
.btn、.card、[role="button"])统一@include interact-state,不手写:active - 禁用
:hover作为主交互态,改用aria-pressed或is-active类配合微反馈 - 过渡属性固定为
transform $duration ease-out,不混用color或opacity,避免重绘
@mixin interact-state 该接收哪些参数
真正需要调节的只有两个值:持续时间和视觉强度。其他如 transform-origin、transition-property、是否启用 will-change 都应固化在 mixin 内部,避免下游误配。
实操建议:
- 参数只设
$duration: 150ms和$scale: 0.95,前者对应真实手指 tap 响应节奏,后者是用户感知到的反馈程度,不是像素缩放 - 变量命名用
$interaction-duration-tap、$interaction-tap-intensity,加interaction-前缀,和layout-、type-严格区隔 - 不传颜色、背景、边框等语义样式——这些由组件自身决定,mixin 只管「动」和「停」的节奏
:disabled 状态为什么不能只靠伪类
button:disabled:hover 根本不会触发,浏览器直接跳过整个规则链。而且屏幕阅读器对伪类状态不可读,aria-disabled="true" 才是正确入口。
实操建议:
- 统一用
[aria-disabled="true"]替代:disabled,确保语义与样式同步 - 在
@mixin interact-state内部显式处理[aria-disabled="true"],设pointer-events: none+ 微弱透明度(opacity: 0.4),不依赖伪类组合 - 禁用态下不执行任何 transform 动画,避免视觉抖动——这点容易被忽略,但用户一眼就能感知不一致
最易被忽略的一点:交互反馈不是越“动”越好,而是要在 150ms 内完成缩放+恢复,且所有组件的 $interaction-tap-intensity 必须来自同一份 map,否则设计师给的「轻点反馈」在按钮上是 0.95,在卡片上变成 0.88,用户感知就断层了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











