# 网站动画与 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。
