😵‍💫 产品:你能不能让按钮 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。

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

相关推荐
qq_529599381 分钟前
reactnative获取经纬度 获取此地信息 @react-native-community/geolocation
javascript·react native·react.js
前端大波3 分钟前
使用webpack-bundle-analyzer 对 react 老项目进行打包优化
前端·react.js·webpack·性能优化
前端 贾公子10 分钟前
(catalog协议) == pnpm (5)
前端·javascript·react.js
JarvanMo14 分钟前
深度解析:如何彻底终结 Flutter 异步操作中的 BuildContext 崩溃?
前端
wxr061619 分钟前
部署Spring Boot项目+mysql并允许前端本地访问
前端·spring boot·mysql·持续部署
假装我不帅25 分钟前
jquery-validation使用
前端·javascript·jquery
怕浪猫30 分钟前
React从入门到出门第六章 事件代理机制与原生事件协同
前端·javascript·react.js
天府之绝34 分钟前
uniapp 中使用uview表单验证时,自定义扩展的表单,在改变时无法触发表单验证处理;
开发语言·前端·javascript·vue.js·uni-app
be or not to be35 分钟前
Html-CSS动画
前端·css·html
初恋叫萱萱40 分钟前
技术基石与职场进阶:构建从Web后端到高性能架构的完整知识图谱
前端·架构·知识图谱