104 lines
5.4 KiB
Markdown
104 lines
5.4 KiB
Markdown
# 网站动画与 UX 提升 — 设计文件
|
||
|
||
**日期**: 2026-05-29
|
||
**目标**: 在**不改变 UI 布局和颜色**的前提下,为 Arkie Library 前端加入精致动画并提升使用者体验,效果与性能兼顾,并顺手清理冗余代码。
|
||
|
||
---
|
||
|
||
## 1. 背景与约束
|
||
|
||
- 技术栈:React 18 + TypeScript + Vite + Tailwind CSS。
|
||
- 主题:深色 (`#141319`),金色重点 (`#eeb726` / `#ffd35c`)。
|
||
- 现有动画:`ark-page-fade-in`(页面淡入 240ms)、`ark-header-menu-enter`(菜单 clip-path 180ms),皆已支援 `prefers-reduced-motion`。
|
||
- **硬约束**:
|
||
- 不改变任何布局、颜色、字体、间距。仅加入「动作 / 时间 / 反馈」。
|
||
- 全部动画必须尊重 `prefers-reduced-motion: reduce`。
|
||
- 效果与性能兼顾:库需按需加载、bundle 影响最小化。
|
||
|
||
## 2. 决策(已与用户确认)
|
||
|
||
| 项目 | 决定 |
|
||
|------|------|
|
||
| 动画强度 | 适中活泼(moderate & lively),克制但明显 |
|
||
| 范围 | 全站(首页、浏览、分类、分类详情、搜索、关于、收藏) |
|
||
| 实现方式 | **混合方案**:`framer-motion`(LazyMotion 精简模式)+ 纯 CSS/Tailwind |
|
||
| 冗余清理 | 实作中一并清理(如 `RecommendedCard` 内两边相同的三元运算) |
|
||
|
||
### 库分工
|
||
- **framer-motion (v11, `LazyMotion` + `m`)**:页面切换退场动画(`AnimatePresence`)、弹簧悬停质感、筛选/排序卡片重排(`layout`)、复杂 stagger 编排。
|
||
- **CSS / Tailwind**:骨架屏 shimmer、图片加载淡入、简单滚动出现(无需 framer 的场景)。
|
||
|
||
## 3. 架构与组件
|
||
|
||
### 3.1 动画基础设施(一次建好,全站复用)
|
||
|
||
- `tailwind.config.js`:新增 `keyframes`(`shimmer`、`fade-in-up`、`scale-in`)、对应 `animation`,统一缓动 `cubic-bezier(0.22, 1, 0.36, 1)`。
|
||
- `src/index.css`:新增可复用工具类与 reduced-motion 保护。
|
||
- `src/motion/` 新目录:
|
||
- `MotionProvider.tsx`:包 `LazyMotion`(`domAnimation` features),全站只引入一次,确保精简 bundle。
|
||
- `variants.ts`:共享 variants(`fadeInUp`、`staggerContainer`、`cardHover`、`pageTransition`)与统一 transition 设定。
|
||
- `useRevealOnScroll.ts`:轻量 `IntersectionObserver` hook,元素进入视窗触发一次(CSS 路径用)。
|
||
- `Reveal.tsx`:薄包装组件,子元素滚动进入视窗时 fade-in-up(内部用 framer 的 `whileInView` 或 CSS hook,择一统一)。
|
||
|
||
### 3.2 页面切换退场(framer-motion)
|
||
|
||
- 在 `PublicLayout` 的 `<Outlet/>` 外层用 `AnimatePresence mode="wait"`,以 `pathname+search` 为 key。
|
||
- 退场/进场使用 `pageTransition` variant(淡入 + 轻微位移,~220ms)。
|
||
- 取代现有 `ark-page-fade-in`(避免重复;保留 CSS 作为 reduced-motion fallback)。
|
||
|
||
### 3.3 滚动出现(Scroll Reveal)
|
||
|
||
- 列表/区块(首页 carousel/区段、浏览 grid、分类卡片)以 `Reveal` 包装,依序 stagger(~60ms)淡入上浮,只触发一次。
|
||
- grid 大量项目时限制 stagger 上限,避免长列表整体延迟。
|
||
|
||
### 3.4 悬停与微互动(不改样式,仅加动作)
|
||
|
||
- 卡片:现有 `hover:scale-[1.02]` 升级为 framer 弹簧整卡轻浮 + 阴影过渡(沿用金色边框)。
|
||
- 下载按钮:`active:scale` 点击反馈 + 完成时的状态过渡。
|
||
- 导航连结:金色下划线滑入(`gold-underline` 过渡化)。
|
||
|
||
### 3.5 载入与反馈(UX 重点)
|
||
|
||
- **骨架屏**:新增 `src/components/Skeleton.tsx`(带 shimmer),用于列表/卡片/详情加载态,取代空白或突兀闪现。
|
||
- **图片淡入**:图片 `onLoad` 后淡入(卡片封面、详情图),避免硬切。
|
||
- **Toast**:轻量 `src/components/Toast.tsx` + provider,下载成功/失败提示(沿用现有配色),无障碍 `aria-live`。
|
||
|
||
## 4. 冗余代码清理
|
||
|
||
- `RecommendedCard.tsx`:
|
||
- `useFigmaDesign ? "group-hover:scale-[1.02]" : "group-hover:scale-[1.02]"` → 两边相同,简化。
|
||
- spinner `useFigmaDesign ? "h-5 w-5 animate-spin" : "h-5 w-5 animate-spin"` → 简化。
|
||
- 实作各档案时移除遇到的同类重复(不做无关重构)。
|
||
|
||
## 5. 资料流 / 隔离
|
||
|
||
- 动画相关逻辑集中于 `src/motion/`,组件只引用 variants/hook,不内嵌魔术数字。
|
||
- `MotionProvider` 在 app root 包一次;各页面无需重复设定。
|
||
- 骨架屏 / Toast 为独立、可单测的展示组件。
|
||
|
||
## 6. 无障碍与性能
|
||
|
||
- 所有 framer 动画与 CSS 动画在 `prefers-reduced-motion: reduce` 下降级为无动作或纯淡入。
|
||
- 使用 `LazyMotion` 精简 features,避免引入完整 framer bundle。
|
||
- 动画用 `transform`/`opacity`(GPU 友好),避免 layout thrash。
|
||
- build 后检查 bundle 体积变化在可接受范围。
|
||
|
||
## 7. 实作顺序
|
||
|
||
1. 安装 framer-motion + 建 `src/motion/` 基础设施 + tailwind/CSS keyframes。
|
||
2. `MotionProvider` 接入 app root。
|
||
3. 页面切换退场(PublicLayout)。
|
||
4. Scroll reveal(全站列表/区块)。
|
||
5. 骨架屏 + 图片淡入。
|
||
6. 悬停/微互动升级。
|
||
7. Toast 反馈。
|
||
8. 清理冗余代码。
|
||
9. `npm run build` 验证 + reduced-motion 验证。
|
||
|
||
## 8. 验收标准
|
||
|
||
- 视觉布局/颜色与改动前一致(仅多了动作)。
|
||
- `npm run build` 通过,bundle 增量可控(framer 精简模式)。
|
||
- 开启「减少动态效果」时网站仍可正常使用、无动画。
|
||
- 全站列表有 scroll reveal、卡片有弹簧悬停、加载有骨架屏、下载有 toast。
|