Files
novalon-website/docs/design/hero-redesign-proposal.md
T
zhangxiang e4bbe3822d feat(home): hero 信息层重构 — 声明先行,数据指标下沉为独立成果带
参考 Accenture Radical Relevance 设计语言(方向 A,用户已决策):
- hero 内数据条移出,主张(副标题)前置,一屏只负责一句话声明 + 一个行动
- 新增 HeroStatsBand 成果带,滚动触发(Glance 层),承接下沉的指标
- H1 字重 900→700,hero 内 KPI 数字同步收敛,对齐「字重 9→3」克制
- 右侧数据看板保持单电压(仅品牌红),hero 内已无辅助色

验证(evidence-first):
- type-check 0 errors / lint 0 errors(127 warnings 均为既有、与本改无关)
- jest 13 passed(含新断言:hero 内不含 hero-stats、数据下沉成果带仍渲染)
- 视觉回归 22 passed(首页浅/深快照已 update;19 个非首页页零 diff,证明改动仅影响首页)

含 docs/design/hero-redesign-proposal.md(设计提案,未改代码)

P0 批次;P1(点阵 token 化 + L2 光标聚光)待续
2026-08-31 21:24:05 +08:00

322 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Hero 重设计方案(参考 Accenture / 埃森哲)
> 状态:**提案,待决策**(本文件不改动任何代码)
> 日期:2026-08-31
> 触发:张翔「动态粒子先不着急实现,需要配合重新设计 hero,希望能够参考埃森哲」
> 关联:暗黑模式 Phase 2`refactor/optimize-ui`)、`src/lib/constants/hero-themes.ts`
---
## 0. 结论先行
**不建议照搬埃森哲的「纯黑全出血 hero」。** 埃森哲的 hero 是 `#000000` 纯黑底 + 单一紫电压 —— 这与你已定的「hero 浅色方案,好做暗黑模式」方向正面冲突。
但埃森哲真正值得迁移的不是「黑」,而是**三条纪律**:
| 纪律 | 埃森哲 | 迁移到 Novalon 的可行性 |
|---|---|---|
| **单一电压色** | `#A600FF` 紫,全站只有一个品牌色 | ✅ 直接可迁(我们是 `#C41E3A` 朱砂红) |
| **单一签名符号** | `>` 大于号,出现在 logo 旁 / CTA 尾 / 链接末端 | ✅ **已经对齐**`CTAButton` 已 pill + `ArrowRight` |
| **Glance / Skim / Absorb 三层交互** | 滚动 / 悬浮 / 点击展开 | ⚠️ 我们只有 Glance 的一半(进场动画),**Skim 层缺失** |
**关键判断**:hero 背景层(点阵 / 粒子)在这套纪律里是**第三优先级**——它是氛围,不是信息。
所以正确顺序是:**先重构 hero 的信息层与交互层,再上背景层**。粒子排在最后,且在「光标聚光」验证有效后再决定要不要上。
**另一个关键判断**:选浅色 hero 不是放弃埃森哲的深色观感,而是**让暗黑模式自动替我们实现它**。
hero 底色走 `--color-bg-primary` token → 浅色模式是浅底 editorial 观感,暗黑模式自动变深底 → **一份代码,两种观感**,这正是埃森哲「白色反转带」机制的镜像。
---
## 1. 现状诊断
### 1.1 代码事实
| 项 | 位置 | 现状 |
|---|---|---|
| 底色 | `home-content-v15.tsx:160` | `bg-bg-primary` ✅ 已 token 化 |
| 点阵 | `home-content-v15.tsx:164-169` | 静态 48px 网格,`rgba(196,30,58,0.4)` **硬编码** + `opacity-[0.03]` |
| 标题 | 同文件 `:193` | `font-black`900)、`text-4xl → 7xl` |
| 数据条 | 同文件 `:199-218` | 3 个指标,**排在主张(副标题)之前** |
| 副标题 | 同文件 `:221-230` | 排在**数据条之后** |
| CTA | 同文件 `:233-250` | `CTAButton`pill + 箭头)✅ |
| 右侧视觉 | 同文件 `:254-261` | `HeroProductVisual` 静态 SVG 看板 |
| 纹理配置 | `hero-themes.ts` | 11 主题 × 6 种 texture,**全项目零消费方(死配置)** |
| 光标交互 | `hero-section-v2.tsx:128` | 已有 radial-gradient 跟随实现,但**首页未启用** |
### 1.2 实测数据(脚本计算,非估算)
**文字 / 图形对比度**
| 组合 | 实测 | WCAG 判定 |
|---|---|---|
| `#C41E3A` 品牌红 / 浅底 `#FFFFFF` | **5.84:1** | 正文 AA ✅ |
| `#C41E3A` 品牌红 / 深底 `#0A0E14` | **3.31:1** | 大字 AA ✅(**正文不达标**) |
| `#E04A68` brand-light / 深底 | **4.93:1** | 正文 AA ✅ |
| `#CBD5E1` text-secondary / 深底 | 13.03:1 | 正文 AA ✅ |
> ⚠️ **修正一条此前的错误印象**:之前记录「品牌红在深底约 2.4:1」是错的,实测 **3.31:1**。
> 结论需相应修正:品牌红在深底**可作大字号**(≥24px),但**不可作正文/小字**——小字必须切 `--color-brand-light`。
**点阵可见度(alpha 合成后与底的对比度)**
| 底色 | 当前 alpha=0.03 | 0.06 | 0.10 | 0.14 | 0.20 |
|---|---|---|---|---|---|
| 浅底(brand 红) | **1.05:1** ← 当前值 | 1.10 | 1.18 | **1.26** | 1.40 |
| 深底(brand 红) | 1.01 | 1.02 | 1.05 | 1.07 | 1.12 |
| 深底(brand-light `#E04A68` | 1.02 | 1.05 | 1.08 | 1.13 | **1.22** |
| 深底(中性浅灰 `#F8FAFC` | 1.06 | **1.13** | **1.27** | 1.44 | 1.77 |
**结论(重要)**
1. **当前 hero 点阵基本不可见**——浅底 1.05:1,深底 1.01:1。现在这个纹理是「心理安慰」,用户感知不到。要么提 alpha,要么承认无效重做。
2. **深底用品牌红做点阵是死路**——alpha 到 0.4 才 1.38:1。因为品牌红本身在深底亮度就低。
3. **推荐取值**
- 浅色模式:brand 红 @ **alpha 0.10~0.14**1.18~1.26:1,可感知不抢戏)
- 暗黑模式:中性浅灰 `rgb(var(--color-text-muted-rgb))` @ **alpha 0.06~0.10**1.13~1.27:1
—— 比 brand-light 更高效(同 alpha 下对比度更高),且不引入第二电压色,符合埃森哲「灰度纪律」
---
## 2. 埃森哲设计语言拆解
来源:Accenture.com 2023-2024 改版(Sana / Sunwha Park 案例 + 公开 DESIGN.md 拆解)
### 2.1 视觉层
| 特征 | 埃森哲做法 |
|---|---|
| 画布 | 近黑 `#0a0a0a` 为默认;**纯黑 `#000000` 用于全出血 hero / 视频背景 / footer** |
| 单一电压 | **Accenture Purple `#a600ff`** —— 只承载 `>` 标记、主 CTA pill、链接 hover、focus ring、accent band。无第二品牌色 |
| 字体 | Graphik 单一字族;**字重 9 → 3**display 用 bold(700),正文 regular(400);大标题上限 80px |
| CTA | Pillradius 9999+ 尾部 `>`;主 CTA 紫色实心,次 CTA 白色描边 |
| 灰度纪律 | 紫色之外的**一切**走灰度:近黑底、白→灰墨色、`#2e2e2e` 细 hairline |
| 卡片 | hairline 边框 + hover 时**微抬起**,不用重阴影 |
| 反转带 | insight / research / case-study 区块**翻转成白底深字**——刻意的「我们开始讲实质内容了」语域切换。紫色在两种底上都通过,品牌连续性不断 |
### 2.2 交互层(这是最值得抄的部分)
**Glance / Skim / Absorb**
- **Glance(滚动)** —— 首屏即给完整答案,滚动时内容单流逐步展开
- **Skim(悬浮)** —— 不点击就能获得更多(hover 展开、预览、微交互)
- **Absorb(点击展开)** —— 需要深度时再展开详情
配套:主页与主要页面是**单一内容流**single stream of content),一点一点展开,而非一屏塞满所有模块。
### 2.3 方法论层
- **Radical Relevance**(北极星):刷新熟悉的、把复杂的变简单、只给受众真正要的
- **Create something new, without creating something new**:不新造资产,而是**提升已有资产**——从字体、色彩、被忽视的插画与渐变入手
- **Motion choreography**:动效表达「技术与人类巧思交汇处的魔法」,为组件与交互建立**统一编排**functional button / page transition / kinetic element 都遵循同一套)
- 成果:字体权重 9→3、品牌色 60→24、40+ 组件库、52 个市场、8 个月上线、旧站 70% 跳出率 → 改版后显著改善
---
## 3. 埃森哲语言 → Novalon 映射
| 埃森哲要素 | Novalon 现状 | 差距 | 建议动作 |
|---|---|---|---|
| 深色画布(hero 纯黑) | 浅色 token 底 | **方向性差异**(你已选浅色) | 保留浅色;深色观感由暗黑模式自动提供(见 §5) |
| 单一电压色 | 品牌红 + blue/teal/amber/purple/cyan 五色辅助 | 电压分散 | **hero 内只留品牌红一个色**,辅助色退出 hero 区域 |
| `>` 签名符号 | `CTAButton` 已 pill + `ArrowRight`hover translate-x | ✅ **已对齐** | 保持;可考虑把箭头语义从「装饰」升格为「签名」,全站 CTA 统一 |
| 字重 9→3 | 5 个字族(sans/display/mono/brand/serif+ `font-black`(900) | 字重超发 | **hero 内收到 2 档**:标题 700(去掉 900)+ 正文 400。全站字族精简列为**独立低优先项** |
| `#2e2e2e` hairline | 已有 `--color-border-primary: #EEF2F7`(浅)/ `#1E293B`(深) | ✅ 已有细线体系 | 保持 |
| 卡片 hairline + hover 微抬 | 部分卡片用重阴影 | 中等差距 | hero 内卡片统一 hairline + hover 微抬 |
| Glance(滚动展开) | 有 `ScrollReveal` / `StaggerReveal` + 进场动画 | 部分具备 | 见 §4.3 |
| **Skim(悬浮预览)** | **hero 内缺失**`hero-section-v2` 有 hover 光晕但首页未启用) | **主要缺口** | 见 §4.3 |
| Absorb(点击展开) | 无 | 主要缺口 | 见 §4.3 |
| 单一内容流渐进展开 | hero 一屏塞 6 类元素(badge/H1/3 数据/副标题/2 CTA/SVG | **信息密度过高** | 见 §4.2 |
---
## 4. Hero 重设计方案
### 4.1 两个方向
#### 方向 AEditorial Hero(**推荐**)—— 对标埃森哲「白色反转带」
**核心**:把 hero 做成埃森哲的**反转带**——浅底、深字、单一电压、极克制的背景纹理。暗黑模式下自动翻转为深色观感。
- 底色 `--color-bg-primary`(浅)/ 自动 `#0A0E14`(深)
- hero 内**只有品牌红一个彩色**,其余全灰度
- 标题 700 字重(去掉 900),单一字族
- 背景:静态点阵 + 光标聚光(无粒子,或极少)
- CTApill + 箭头(已具备)
**优点**:与暗黑模式战略**完全同向**(零额外维护成本);符合你已定的浅色方向;埃森哲的「编辑/研究区块翻白底」本来就是他们的实质内容语域。
**风险**:观感偏「咨询公司」而非「科技公司」,冲击力弱于纯黑 hero。
#### 方向 BFull-bleed Dark Hero —— 埃森哲原味(**不推荐**)
- 纯黑 `#000000` 全出血 + 白字 + 品牌红单电压 + 粒子/渐变背景
- **问题 1**:与「浅色 hero 好做暗黑模式」方向冲突,hero 需要**单独维护一套反色逻辑**,退化成两套代码
- **问题 2**:暗黑模式下再反色一次,会出现「深色模式里 hero 反而是唯一不变的黑块」的割裂
- **问题 3**:成本高(需为 hero 单独建 dark 兼容层 + 视觉回归基线全量更新)
> **折中**:方向 A 在暗黑模式下**天然获得**方向 B 的观感。这不是妥协,是白赚。
### 4.2 信息层重构(方向 A 落地)
**当前顺序**(有问题):
```
badge → H1 → 3 个数据指标 → 副标题(主张)→ CTA →(右侧)静态 SVG 看板
↑ 先看到数字,才看到主张 —— 阅读顺序反了
```
**建议顺序**(埃森哲式「声明先行」):
```
eyebrowslogan badge
H1 主张(单一声明,不超过 2 行)
一句支撑(≤ 2 行,回答「凭什么信你」)
CTA(主 pill + 次 pill
── hero 结束 ──
成果带 / 信任带(3 个数据指标 + 客户共创状态) ← 数据条下沉为滚动触发的 Glance 层
```
**要点**
1. **数据条移出 hero**,成为紧随其后的独立带。hero 只负责「一句话说清你是谁 + 一个行动」。这直接对应埃森哲「单一内容流,逐步展开」。
2. 右侧 `HeroProductVisual` **保留**(B2B 需要产品感),但从「静态装饰」升级为「渐进展开」(见 Absorb),且不与左栏争主视觉。
3. **字重收敛**H1 由 `font-black`(900) → `font-bold`(700)。埃森哲 80px 大标题就用 700,900 在中文大字号下会糊成一团。
4. **辅助色退出 hero**hero 内不出现 blue/teal/amber/purple/cyan,只留朱砂红。
### 4.3 交互层设计(Glance / Skim / Absorb 落地)
| 层 | 现状 | 建议 |
|---|---|---|
| **Glance**(滚动) | 有进场动画 + `ScrollReveal` | hero 内元素用**统一编排**stagger 60-80msduration 200-300ms`ease-ink`);数据条下沉后由滚动触发 reveal |
| **Skim**(悬浮) | **缺失** | **光标聚光**(见 §5.2):鼠标移动时,点阵在光标周围局部提亮 —— 不点击就获得反馈,且**构成 hero 的「动态感」主来源** |
| **Absorb**(点击/展开) | 缺失 | 右侧产品看板:进场时 SVG 逐级描边点亮(stroke-dashoffset 动画),滚动到视口中央时 KPI 数字 count-up;次 CTA「查看产品矩阵」作为深度入口 |
> **关键**:Skim 层的光标聚光**就是「动态粒子」的低成本替代**。
> 它同样提供「hero 是活的」的观感,但零 canvas、零逐帧 JS、零性能风险。
> 建议**先上聚光,观察 1-2 周效果,再决定要不要真上粒子**。
---
## 5. 背景层分层设计(点阵 / 聚光 / 粒子的定位)
背景层拆成 4 层,从底到顶:
### L0 — 底色(已具备)
`bg-bg-primary` → 浅色 `#FFFFFF` / 暗黑 `#0A0E14`。✅ 无需改动。
### L1 — 静态点阵(需改造)
- **现状**`rgba(196,30,58,0.4)` 硬编码 + `opacity-[0.03]`48px 网格 → 实测 1.05:1**基本不可见**
- **改造**
1. 颜色改走 token(这是硬编码,暗黑模式下不会反色)
2. alpha 提到可感知区间
3. 网格 48px → **24px**(埃森哲式细密感,且 24px 与项目 spacing 体系对齐)
| 模式 | 点阵取色 | alpha | 实测对比度 |
|---|---|---|---|
| 浅色 | `rgb(var(--color-brand-rgb))` | **0.12** | 1.22:1 |
| 暗黑 | `rgb(var(--color-text-muted-rgb))`(中性浅灰) | **0.08** | 1.20:1 |
实现位置:建议抽成 `globals.css` 的 utility(已有 `.bg-texture-grid` / `.bg-texture-dots` 先例),
颜色与 alpha 全部走 CSS 变量 → **暗黑模式零 JS 自动切换**
### L2 — 光标聚光(`Skim` 层,**建议优先实现**
技术方案(**无 canvas、无逐帧 JS**):
- 两层同 tiling 的点阵:底层 L1 静态(低 alpha),上层同网格但高 alpha
- 上层用 `mask-image: radial-gradient(circle 280px at var(--x) var(--y), black, transparent)`
- 鼠标移动时**只写 2 个 CSS 变量** `--x` / `--y``pointermove` + `requestAnimationFrame` 节流)
- 合成与遮罩全交给 GPU
成本:一次 paint + 每帧 2 个变量写入。比粒子方案低一个数量级。
> 项目内已有先例:`hero-section-v2.tsx:128` 的 radial-gradient 跟随,
> 以及 `design-system.ts:63` 的 `inkGlow``var(--mouse-x)` / `var(--mouse-y)`)。
> **这是复用既有资产,正合埃森哲「create something new without creating something new」**。
### L3 — 真粒子(**暂缓**,按你的指示)
若后续仍要上,必须满足的硬约束(前置调研结论):
| 约束 | 要求 |
|---|---|
| 数量 | ≤ 50 用 CSS keyframes(零运行时);50-300 用 canvas> 1000 用 shader |
| 连线 | **禁用**(500 粒子 = 125k 次距离检查/帧,二次方成本) |
| DPR | cap 到 **1.5**(DPR 3 比 1 多 9 倍像素) |
| 停循环 | `IntersectionObserver` 离屏即停 + `visibilitychange` 切后台即停 |
| 无障碍 | `prefers-reduced-motion: reduce` → 渲染**静态帧**,不做动画 |
| 暗黑模式 | 粒子颜色走 token,不可硬编码 |
### 5.3 hero-themes.ts 的 texture 死配置接线
`hero-themes.ts` 里 11 个主题各配了 `texture { type, opacity, color }`6 种类型:`grid` / `data-flow` / `layers` / `shield-hex` / `circuit` / `none`),
但**全项目无任何消费方**——Grep `theme.texture` / `texture.type` 零结果,各 hero 组件都是内联硬编码纹理。
建议:重设计时把 **L1 层接线到 `theme.texture`**
```
theme.texture.type → 6 个 CSS utility 类(.hero-texture-grid 等)
theme.texture.color → 改走 CSS 变量(--hero-texture-color),支持暗黑模式覆盖
theme.texture.opacity → CSS 变量 --hero-texture-opacity
```
收益:11 个主题一次性获得纹理差异化 + 暗黑模式自动兼容,且消灭死配置。
---
## 6. 暗黑模式兼容性
| 项 | 处理 | 依据 |
|---|---|---|
| hero 底色 | 已走 `bg-bg-primary` token ✅ | 自动反色 |
| 点阵颜色 | **必须 token 化**(当前硬编码 `rgba(196,30,58,0.4)`) | 硬编码在深底 1.01:1 完全不可见 |
| 点阵 alpha | 浅 0.12 / 深 0.08,用 CSS 变量按模式覆盖 | 实测浅 1.22:1 / 深 1.20:1 |
| hero 内品牌红大字 | `#C41E3A` **可用**3.31:1,满足 AA 大字 ≥3:1 | 实测 |
| hero 内品牌红小字 / badge 文字 | **必须切 `#E04A68`**4.93:1,正文 AA | 实测,3.31:1 不达正文 AA |
| 光标聚光颜色 | 深底用中性浅灰而非品牌红(同 alpha 下对比度更高,且不引入第二电压) | 实测 1.27 vs 1.05 |
| 动画 | `prefers-reduced-motion` → 静态帧 | 项目已有 `useReducedMotion` hook |
**待确认的前置问题**:当前 `globals.css``html[data-theme='dark']` 块**未覆盖 `--color-brand`**
即暗黑模式下品牌红仍是 `#C41E3A`。hero 内小字需显式用 `text-brand-light`
或在 dark 块加一条 `--color-brand: #E04A68` 全局覆盖(影响面大,需单独评估)。
---
## 7. 分阶段实施计划(待决策后执行)
| 阶段 | 内容 | 产出 | 依赖 |
|---|---|---|---|
| **P0** | 信息层重构:数据条下沉、主张先行、字重 900→700、辅助色退出 hero | 新 hero 结构 + 视觉回归基线更新 | 方向 A/B 决策 |
| **P1** | 背景 L1:点阵 token 化(24px / 色+alpha 走变量)+ 接线 `hero-themes.ts` texture | 11 主题纹理差异化 + 暗黑模式自动兼容 | P0 |
| **P2** | 背景 L2:光标聚光(mask + CSS 变量,无 canvas)→ Skim 层 | hero「活起来」,零性能风险 | P1 |
| **P3** | Absorb 层:右侧看板渐进描边 + KPI count-up | 交互闭环 | P2 |
| **P4** | (可选)真粒子:**仅在 P2 验证后仍觉得不够时** | 需满足 §5 L3 全部硬约束 | P2 效果评估 |
每阶段门禁:`type-check` / `lint` / `jest` / 视觉回归 / computed-style 暗黑模式验证(沿用 Phase 2 节奏)。
---
## 8. 待你决策(3 个问题)
1. **方向**A(Editorial 浅底,推荐)还是 B(纯黑全出血,不推荐)?
2. **信息密度**:数据指标条是否同意**移出 hero**,下沉为滚动触发的成果带?
3. **背景层节奏**:是否同意**先上 L1 点阵改造 + L2 光标聚光**,粒子放到最后评估(可能永远不上)?
---
## 附录:信源
| 内容 | 来源 |
|---|---|
| 埃森哲设计语言(画布/电压/字体/CTA/hairline/反转带) | Accenture DESIGN.md 拆解,webdesignhot.com |
| 埃森哲改版方法论(Radical Relevance / Glance-Skim-Absorb / 字重 9→3 / 色 60→24 / motion choreography | Sana 案例页 sana.works/accenture-comSunwha Park2023-2024 |
| 点阵 / 聚光 / 粒子成本模型 | 前置会话技术调研(CSS radial-gradient tiling、mask-image 光标跟随、DPR cap、IntersectionObserver、prefers-reduced-motion |
| 对比度数据 | **本文件 §1.2 实测**Python 按 WCAG 2.1 相对亮度公式计算,脚本一次性运行,非估算) |
| 项目现状代码位置 | `home-content-v15.tsx` / `hero-section-v2.tsx` / `hero-themes.ts` / `globals.css` / `tailwind.config.js` 直接读取 |