😵‍💫 产品:你能不能让按钮 hover 有个动效?我直接做了个 UI 框架

起因:一句话的"需求"

一天,产品在设计稿下方评论说:

"按钮 hover 能不能有点交互感?像你之前那个小 demo 那种~"

我本来以为就是加个 transition,小事一桩。

css 复制代码
button {
  transition: all 0.2s ease;
}
button:hover {
  transform: scale(1.05);
}

上线后产品说:"嗯,这个感觉不错耶,那我们把所有按钮 hover 都做成统一的吧。"

我知道,我完了。


没有人只加一个动效:于是我干脆封装了

在统一动效过程中,我意识到各类按钮(Primary、Danger、Ghost)对 hover 的预期不同。

于是我封装了一个 motion map:

ts 复制代码
const hoverMotionMap = {
  primary: 'scale',
  danger: 'shake',
  ghost: 'glow',
}

再写一个小 hook:

ts 复制代码
export function useHoverMotion(type: 'primary' | 'danger' | 'ghost') {
  const motion = hoverMotionMap[type] || 'scale'
  return `hover-motion-${motion}`
}

组件里使用起来:

html 复制代码
<template>
  <button :class="motionClass">确认</button>
</template>

<script setup lang="ts">
import { useHoverMotion } from '@/hooks/useHoverMotion'
const motionClass = useHoverMotion('primary')
</script>

你知道的,一旦封装就止不住了

hook 写了,动效也开始丰富了起来。

1️⃣ scale(标准场景)

css 复制代码
.hover-motion-scale:hover {
  transform: scale(1.05);
}

2️⃣ shake(误操作提示)

css 复制代码
.hover-motion-shake:hover {
  animation: shake 0.25s ease-in-out;
}
@keyframes shake {
  0% { transform: translateX(0); }
  25% { transform: translateX(-3px); }
  50% { transform: translateX(3px); }
  75% { transform: translateX(-2px); }
  100% { transform: translateX(0); }
}

3️⃣ glow(高亮视觉)

css 复制代码
.hover-motion-glow:hover {
  box-shadow: 0 0 12px rgba(0, 123, 255, 0.6);
}

然后我干脆加了 Design Token 方案

考虑到未来可能有改版,我定义了 hover-effects.token.ts

ts 复制代码
export const hoverEffects = {
  scale: {
    transform: 'scale(1.05)',
    transition: 'all 0.2s ease',
  },
  glow: {
    boxShadow: '0 0 12px rgba(0, 123, 255, 0.6)',
    transition: 'all 0.2s ease',
  },
  shake: {
    animation: 'shake 0.25s ease-in-out',
  },
}

然后配合 Tailwind plugin 动态生成类名。


想着都封成组件了,不如抽出一套 UI 库

就这样,我加了:

  • <UIButton type="primary" motion="scale" />
  • <UIInput hover="glow" />
  • <UIForm label-align="right" hover="none" />

还写了 storybook 做展示:

ts 复制代码
export default {
  title: 'UI/Button',
  component: UIButton,
}

export const HoverScale = () => <UIButton motion="scale">确认</UIButton>

中途遇到的"意想不到"问题

① 部分动效在移动端体验极差

iOS 的 :hover 会粘在上面,导致 glow 效果没法清除,我写了:

css 复制代码
@media (hover: none) {
  .hover-motion-glow:hover {
    box-shadow: none;
  }
}

② 某些动效导致 layout shift

比如 scale 会撑开父容器,后来我改用 transform-origin: center; 再加内边距预留。

③ 动效冲突问题

Hover 动效和 active/click 效果容易冲突。我写了 motion 状态做协调:

ts 复制代码
enum MotionState {
  Idle = 'idle',
  Hovered = 'hovered',
  Pressed = 'pressed',
}

温馨提示😭:

千万别让产品看到你写得有点好看的 demo。

📌 你可以继续看我的系列文章

相关推荐
郭邯1 分钟前
从零手写一个 UA 解析工具:我用 AI 辅助开发,踩了这些坑
前端
oh,huoyuyan3 分钟前
JS 动态网页抓不到?试试火车采集器网页抓取工具
开发语言·javascript·ecmascript
Heo4 分钟前
怎么保证缓存和数据库一致性?
前端·后端·面试
摇曳的精灵1 小时前
前端渲染优化
前端·前端渲染优化
WILLF1 小时前
前端视角:Python requests vs JS axios
前端·python
半个落月1 小时前
在浏览器里运行 DeepSeek-R1:React 对话界面与安全渲染(三)
前端·人工智能·react.js
Synmbrf1 小时前
micro-app 404 问题排查与修复
前端
西安栈上月明软件科技有限公司1 小时前
GEO 友好度检测器技术实现(已开源)
前端
汉堡大王95271 小时前
用 Trae Work 自动化任务,6 分钟生成一份前端生态周报
前端·javascript·人工智能
深圳佛手1 小时前
安装DeepSeek Harness npx @deepseek-ai/dsh web 长时间没反应,安装失败,如何解决?
前端