Commit d588d234 by Hermes Desktop

feat(skills): update ui-design-system

parent 23fb05eb
---
name: ui-design-system
description: 专业UI生成与现有界面优化技能。当用户请求生成UI界面、设计页面、优化现有界面、创建组件库、设计系统、App界面、Web界面、Dashboard、Landing Page、或任何涉及视觉交互设计时必须触发此技能。参考Google Material Design、Apple HIG、以及Pinterest级别审美标准,输出大气简约、高级美学的UI代码。即使用户只是说"帮我做个界面"、"优化一下UI"、"设计一个页面"也必须触发。
---
# UI Design System Skill
## 📋 背景与设计哲学
### 核心定位
本 Skill 专注于生成**大厂级别、Pinterest 审美、高级简约**的 UI 界面。参考标准:
- **Google Material Design 3** — 色彩系统、动效原则、组件规范
- **Apple Human Interface Guidelines** — 空间设计、排版节奏、细腻质感
- **Fluent Design (Microsoft)** — Acrylic 材质、深度层次
- **Pinterest / Dribbble 高赞设计** — 视觉张力、留白美学、色彩大胆
### 设计价值观
> "少即是多,但每一处都要有意图"
- **克制的奢华**:不是堆砌,而是精准取舍
- **系统性思维**:每个组件都来自同一设计语言
- **情绪传达**:界面有温度,有性格,不是功能机器
- **细节决定品质**:阴影、圆角、间距都是设计语言
---
## 🎯 触发后的工作流程
### Step 1: 需求分析(必须先做)
分析以下维度,在回复前先梳理清楚:
```
用途分类:
├── 生成新UI → 执行「UI Generation Protocol」
├── 优化现有UI → 执行「UI Audit & Optimization Protocol」
└── 组件设计 → 执行「Component Design Protocol」
产品类型:
├── Mobile App (iOS/Android 风格)
├── Web App / Dashboard
├── Landing Page / Marketing
├── Admin / B端系统
└── 创意/作品集页面
```
**必须明确的信息(缺失时主动询问或合理假设并说明):**
- 产品定位(面向谁?解决什么问题?)
- 品牌调性(科技感/温暖/奢华/年轻/专业?)
- 主色倾向(有偏好色系,或给我自由发挥)
- 交付格式(HTML/CSS、React/JSX、SVG 原型图)
---
## 🎨 色彩系统参考体系
### 参考「谷歌 Material You」调色板生成规则
**Tonal Palette 结构:**
```
Primary → 品牌主色,用于关键操作和焦点元素
Secondary → 辅助色,用于标签、图标、次要按钮
Tertiary → 对比色,用于强调差异化内容
Neutral → 灰阶体系,背景/表面/文字层级
Error → 错误/警告状态色
```
**推荐高级色板(可直接使用):**
| 风格 | Primary | Secondary | Accent | Surface |
|------|---------|-----------|--------|---------|
| 极简白 | #1A1A2E | #16213E | #E94560 | #F8F9FA |
| 深空科技 | #6C63FF | #3ECFCF | #FF6584 | #0D0D1A |
| 自然有机 | #2D6A4F | #95D5B2 | #F4A261 | #FEFDF8 |
| 奢华金融 | #1C1C28 | #8B7355 | #C9A84C | #F5F3EF |
| 现代橙红 | #FF4B2B | #FF416C | #FFA07A | #1A1A1A |
| 苹果式灰 | #007AFF | #34C759 | #FF9500 | #F2F2F7 |
| 薰衣草紫 | #7B61FF | #B693FD | #4DC9D9 | #FAFAFF |
| 珊瑚暖调 | #FF6B6B | #FFE66D | #4ECDC4 | #FFFAF0 |
### Apple HIG 间距系统
```css
/* 参考 Apple 8pt 网格系统 */
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px; /* 标准间距 */
--space-5: 20px;
--space-6: 24px; /* 组件内间距 */
--space-8: 32px; /* 区块间距 */
--space-10: 40px;
--space-12: 48px; /* 大区块间距 */
--space-16: 64px; /* 页面级间距 */
--space-24: 96px;
```
---
## 📐 排版系统
### 字体层级(参考 Apple SF / Google 字体)
```css
/* 优先使用有个性的字体组合 */
/* 选项 A: 科技感 */
--font-display: 'Space Grotesk', 'DM Sans';
--font-body: 'Inter', system-ui;
/* 选项 B: 人文优雅 */
--font-display: 'Playfair Display', 'Cormorant';
--font-body: 'Source Serif 4', Georgia;
/* 选项 C: 现代极简 */
--font-display: 'Syne', 'Outfit';
--font-body: 'Manrope', sans-serif;
/* 选项 D: 中文友好 */
--font-display: 'Noto Serif SC', serif;
--font-body: 'Noto Sans SC', sans-serif;
/* Type Scale (参考 Material 3) */
--type-display-large: clamp(40px, 5vw, 57px) / 1.12;
--type-display-medium: clamp(32px, 4vw, 45px) / 1.16;
--type-headline-large: clamp(24px, 3vw, 32px) / 1.25;
--type-headline-medium: clamp(20px, 2.5vw, 28px) / 1.29;
--type-title-large: 22px / 1.27;
--type-title-medium: 16px / 1.5;
--type-body-large: 16px / 1.5;
--type-body-medium: 14px / 1.43;
--type-label-large: 14px / 1.43;
--type-label-small: 11px / 1.45;
```
---
## 🧩 组件设计规范
### 卡片组件(Card)
```css
/* 参考 Material 3 Card Variants */
.card-elevated {
background: var(--surface);
border-radius: 12px;
box-shadow: 0px 1px 2px rgba(0,0,0,.06),
0px 4px 16px rgba(0,0,0,.08);
transition: box-shadow 200ms ease, transform 200ms ease;
}
.card-elevated:hover {
box-shadow: 0px 4px 8px rgba(0,0,0,.08),
0px 12px 32px rgba(0,0,0,.12);
transform: translateY(-2px);
}
.card-filled {
background: var(--surface-variant);
border-radius: 12px;
border: none;
}
.card-outlined {
background: var(--surface);
border-radius: 12px;
border: 1px solid var(--outline-variant);
}
```
### 按钮系统(Button)
```css
/* Apple + Material 融合规范 */
.btn-primary {
height: 44px; /* Apple HIG 最小触控尺寸 */
padding: 0 24px;
border-radius: 10px; /* Apple 风格圆角 */
font-weight: 600;
font-size: 15px;
letter-spacing: -0.01em;
transition: all 150ms ease;
}
/* 按钮层级: Filled > Filled Tonal > Outlined > Text > Icon */
.btn-primary:hover { filter: brightness(1.08); transform: translateY(-1px); }
.btn-primary:active { transform: translateY(0); filter: brightness(0.95); }
```
### 输入框(Input)
```css
/* Material 3 风格输入框 */
.input-outlined {
height: 56px;
border: 1.5px solid var(--outline);
border-radius: 4px;
padding: 16px;
transition: border-color 200ms;
}
.input-outlined:focus {
border-color: var(--primary);
border-width: 2px;
}
/* Apple 风格输入框 */
.input-apple {
height: 44px;
background: rgba(120,120,128,0.12);
border: none;
border-radius: 10px;
padding: 0 16px;
}
```
---
## ✨ 动效与交互规范
### 动效曲线(参考 Apple Spring 和 Material Motion)
```css
/* Apple 弹性曲线 */
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
/* Material 标准曲线 */
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
/* 强调曲线 */
--ease-emphasized: cubic-bezier(0.2, 0, 0, 1);
/* 快入慢出 */
--ease-decelerate: cubic-bezier(0, 0, 0.2, 1);
/* 慢入快出 */
--ease-accelerate: cubic-bezier(0.3, 0, 1, 1);
/* 时长规范 */
--duration-short1: 50ms;
--duration-short2: 100ms;
--duration-short3: 150ms;
--duration-short4: 200ms; /* 微交互 */
--duration-medium1: 250ms;
--duration-medium2: 300ms; /* 标准转场 */
--duration-long1: 350ms;
--duration-long2: 400ms; /* 复杂动画 */
--duration-extra-long: 600ms+; /* 页面级切换 */
```
### 必须实现的微交互
- **Hover 状态**:背景色变化 + 轻微位移
- **Active 状态**:轻压效果 (scale 0.97)
- **Focus 状态**:清晰的焦点环(无障碍必须)
- **Loading 状态**:骨架屏或脉冲动画
- **页面加载**:元素交错淡入 (stagger delay)
---
## 🏗️ UI Generation Protocol(生成新 UI)
### 执行顺序
1. **定义设计 DNA** — 确定调性、主色、字体组合
2. **建立 CSS 变量体系** — 完整的 token 系统
3. **搭建布局骨架** — Grid/Flex 响应式结构
4. **实现核心组件** — 从最重要的交互元素开始
5. **添加视觉质感** — 渐变、阴影、纹理、背景
6. **注入微交互** — 动效、过渡、Hover 状态
7. **精调细节** — 间距、对齐、字重、行高
8. **响应式适配** — Mobile First
### 代码规范
```html
<!-- 必须包含的 meta -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="preconnect" href="https://fonts.googleapis.com">
<!-- 结构原则 -->
<!-- 1. CSS Variables 在 :root 统一定义 -->
<!-- 2. 组件用 BEM 或语义化命名 -->
<!-- 3. 响应式用 clamp() 而非 media query 断点堆叠 -->
<!-- 4. 动画性能优先用 transform/opacity -->
```
---
## 🔍 UI Audit & Optimization Protocol(优化现有 UI)
### 分析维度(拿到现有 UI 后,必须从这 6 个维度审查)
**1. 视觉层级**
- [ ] 是否有清晰的信息优先级?
- [ ] 用户视线路径是否顺畅?
- [ ] 重要信息是否足够突出?
**2. 色彩系统**
- [ ] 色彩对比度是否达标(WCAG AA: 4.5:1 文字)?
- [ ] 颜色使用是否一致、有系统性?
- [ ] 是否存在色彩混乱或过多颜色?
**3. 排版质量**
- [ ] 字体层级是否清晰(最多 3 个层级)?
- [ ] 行高/字间距是否舒适?
- [ ] 字体选择是否与品牌调性匹配?
**4. 间距与对齐**
- [ ] 是否遵循基准网格(4pt 或 8pt)?
- [ ] 组件内外间距是否统一?
- [ ] 元素对齐是否精准?
**5. 组件一致性**
- [ ] 相同功能的组件样式是否统一?
- [ ] 交互状态是否完整(默认/Hover/Active/Disabled)?
- [ ] 圆角、阴影是否系统化?
**6. 现代感与审美**
- [ ] 是否有过时的 UI 模式(阴影过重、渐变廉价)?
- [ ] 是否有 Pinterest 级别的视觉吸引力?
- [ ] 留白是否足够、有设计感?
### 优化输出格式
```
## UI 审查报告
### 🎯 核心问题(3-5个最重要的)
1. [问题描述] → [具体改进建议]
### 🎨 设计升级方案
[输出改进后的完整代码]
### 📊 改进对比
Before: [原方案问题]
After: [改进后效果]
```
---
## 🎪 Component Design Protocol(单组件设计)
适用于:按钮、卡片、导航栏、表单、Modal、Toast、Tab、Chip 等单一组件。
**输出标准:**
- 包含所有状态(Default / Hover / Active / Focus / Disabled / Loading)
- 提供 Dark Mode 变体
- 包含使用示例
- 代码直接可用,不需要额外依赖(除非用户指定框架)
---
## 🌟 高质量 UI 的标志性特征
参考 Pinterest 高赞、Dribbble 精选的共同特征:
### 必须具备
1. **清晰的焦点** — 每个页面只有一个最重要的视觉中心
2. **呼吸感** — 足够的留白,不拥挤
3. **色彩自信** — 不是"安全"的配色,而是有个性的
4. **字体有品位** — 不用默认字体,字重搭配有对比
5. **圆角有度** — 统一的圆角半径,不乱用
6. **阴影克制** — 一两层精准的阴影,不堆叠
7. **动效有意义** — 每个动画都在传达信息
### 绝对避免
- 彩虹色渐变按钮
- 廉价 box-shadow(`0 4px 8px rgba(0,0,0,0.5)` 这种)
- 全大写 + 粗体 + 红色 的"重要提示"
- 16 种以上颜色同时出现
- 响应式断点堆叠(用 clamp 代替)
- 图标和文字对不齐
- 移动端点击区域小于 44px
---
## 📦 参考文件
需要深度参考时,读取以下文件:
- `references/color-systems.md` — 完整色彩系统参考(Material 3, Apple, 自定义)
- `references/component-patterns.md` — 高质量组件代码片段库
- `references/layout-templates.md` — 常见页面布局模板(Dashboard, Landing, App)
- `references/animation-library.md` — 精选动效代码库
---
## ⚡ 快速决策树
```
用户给了设计稿/截图要优化?
→ 执行 UI Audit Protocol,先分析问题,再输出改进版本
用户要从零生成界面?
→ 问清楚用途和调性,选择色板,执行 Generation Protocol
用户只需要某个组件?
→ 执行 Component Protocol,输出所有状态变体
用户没说清楚要什么?
→ 询问:① 是什么产品 ② 大概什么风格 ③ 要 HTML 还是 React
```
# Color Systems Reference
## Google Material Design 3 — Dynamic Color
### Tonal Palette 完整结构
Material 3 的色彩系统基于 HCT 色彩空间(Hue, Chroma, Tone)。
**Primary Tonal Palette(主色调)**
```
Tone 100: #FFFFFF (最亮)
Tone 99: 极浅主色背景
Tone 95: 浅色主色容器
Tone 90: Primary Container (Light Mode)
Tone 80: Primary (Dark Mode)
Tone 70:
Tone 60:
Tone 50:
Tone 40: Primary (Light Mode)
Tone 30: On Primary Container (Light)
Tone 20: Primary Container (Dark)
Tone 10: On Primary (Light / On Primary Container Dark)
Tone 0: #000000 (最暗)
```
### 完整 Material 3 语义色 Token
```css
:root {
/* === Light Mode === */
/* Primary */
--md-sys-color-primary: #6750A4;
--md-sys-color-on-primary: #FFFFFF;
--md-sys-color-primary-container: #EADDFF;
--md-sys-color-on-primary-container: #21005D;
/* Secondary */
--md-sys-color-secondary: #625B71;
--md-sys-color-on-secondary: #FFFFFF;
--md-sys-color-secondary-container: #E8DEF8;
--md-sys-color-on-secondary-container: #1D192B;
/* Tertiary */
--md-sys-color-tertiary: #7D5260;
--md-sys-color-on-tertiary: #FFFFFF;
--md-sys-color-tertiary-container: #FFD8E4;
--md-sys-color-on-tertiary-container: #31111D;
/* Error */
--md-sys-color-error: #B3261E;
--md-sys-color-on-error: #FFFFFF;
--md-sys-color-error-container: #F9DEDC;
--md-sys-color-on-error-container: #410E0B;
/* Surface */
--md-sys-color-surface: #FFFBFE;
--md-sys-color-on-surface: #1C1B1F;
--md-sys-color-surface-variant: #E7E0EC;
--md-sys-color-on-surface-variant: #49454F;
--md-sys-color-surface-container-lowest: #FFFFFF;
--md-sys-color-surface-container-low: #F7F2FA;
--md-sys-color-surface-container: #F3EDF7;
--md-sys-color-surface-container-high: #ECE6F0;
--md-sys-color-surface-container-highest: #E6E0E9;
/* Outline */
--md-sys-color-outline: #79747E;
--md-sys-color-outline-variant: #CAC4D0;
/* Inverse */
--md-sys-color-inverse-surface: #313033;
--md-sys-color-inverse-on-surface: #F4EFF4;
--md-sys-color-inverse-primary: #D0BCFF;
/* Background */
--md-sys-color-background: #FFFBFE;
--md-sys-color-on-background: #1C1B1F;
/* Shadow & Scrim */
--md-sys-color-shadow: #000000;
--md-sys-color-scrim: #000000;
}
/* Dark Mode */
[data-theme="dark"] {
--md-sys-color-primary: #D0BCFF;
--md-sys-color-on-primary: #381E72;
--md-sys-color-primary-container: #4F378B;
--md-sys-color-on-primary-container: #EADDFF;
--md-sys-color-secondary: #CCC2DC;
--md-sys-color-on-secondary: #332D41;
--md-sys-color-secondary-container: #4A4458;
--md-sys-color-on-secondary-container: #E8DEF8;
--md-sys-color-surface: #1C1B1F;
--md-sys-color-on-surface: #E6E1E5;
--md-sys-color-surface-container: #211F26;
--md-sys-color-surface-container-high: #2B2930;
--md-sys-color-surface-container-highest: #36343B;
--md-sys-color-outline: #938F99;
--md-sys-color-background: #1C1B1F;
--md-sys-color-on-background: #E6E1E5;
}
```
---
## Apple HIG — System Colors
### iOS/macOS 系统色(完整集)
```css
:root {
/* iOS System Colors (Light) */
--apple-blue: #007AFF;
--apple-green: #34C759;
--apple-indigo: #5856D6;
--apple-orange: #FF9500;
--apple-pink: #FF2D55;
--apple-purple: #AF52DE;
--apple-red: #FF3B30;
--apple-teal: #30B0C7;
--apple-yellow: #FFCC00;
--apple-cyan: #32ADE6;
--apple-mint: #00C7BE;
--apple-brown: #A2845E;
/* iOS System Grays */
--apple-gray1: #8E8E93;
--apple-gray2: #AEAEB2;
--apple-gray3: #C7C7CC;
--apple-gray4: #D1D1D6;
--apple-gray5: #E5E5EA;
--apple-gray6: #F2F2F7;
/* iOS System Backgrounds */
--apple-bg-primary: #FFFFFF;
--apple-bg-secondary: #F2F2F7;
--apple-bg-tertiary: #FFFFFF;
--apple-grouped-bg: #F2F2F7;
--apple-grouped-bg-secondary: #FFFFFF;
/* iOS Separators */
--apple-separator: rgba(60, 60, 67, 0.29);
--apple-separator-opaque: #C6C6C8;
/* iOS Label Colors */
--apple-label: #000000;
--apple-label-secondary: rgba(60, 60, 67, 0.6);
--apple-label-tertiary: rgba(60, 60, 67, 0.3);
--apple-label-quaternary: rgba(60, 60, 67, 0.18);
/* iOS Fill Colors */
--apple-fill: rgba(120, 120, 128, 0.2);
--apple-fill-secondary: rgba(120, 120, 128, 0.16);
--apple-fill-tertiary: rgba(118, 118, 128, 0.12);
--apple-fill-quaternary: rgba(116, 116, 128, 0.08);
}
/* Dark Mode */
@media (prefers-color-scheme: dark) {
:root {
--apple-blue: #0A84FF;
--apple-green: #30D158;
--apple-indigo: #5E5CE6;
--apple-orange: #FF9F0A;
--apple-pink: #FF375F;
--apple-purple: #BF5AF2;
--apple-red: #FF453A;
--apple-teal: #40CBE0;
--apple-yellow: #FFD60A;
--apple-cyan: #64D2FF;
--apple-mint: #63E6E2;
--apple-gray1: #8E8E93;
--apple-gray2: #636366;
--apple-gray3: #48484A;
--apple-gray4: #3A3A3C;
--apple-gray5: #2C2C2E;
--apple-gray6: #1C1C1E;
--apple-bg-primary: #000000;
--apple-bg-secondary: #1C1C1E;
--apple-bg-tertiary: #2C2C2E;
--apple-label: #FFFFFF;
--apple-label-secondary: rgba(235, 235, 245, 0.6);
--apple-label-tertiary: rgba(235, 235, 245, 0.3);
}
}
```
---
## 精选高级自定义色板
### 1. Midnight Studio(深色科技)
```css
:root {
--primary: #7C3AED; /* 紫罗兰主色 */
--primary-light: #A78BFA;
--primary-dark: #5B21B6;
--accent: #10B981; /* 翡翠绿强调 */
--accent-warm: #F59E0B; /* 琥珀暖色 */
--bg: #09090B; /* 近黑背景 */
--bg-2: #18181B; /* 卡片表面 */
--bg-3: #27272A; /* 悬浮层 */
--border: rgba(255,255,255,0.08);
--border-strong: rgba(255,255,255,0.15);
--text-1: #FAFAFA;
--text-2: #A1A1AA;
--text-3: #71717A;
--shadow-glow: 0 0 40px rgba(124, 58, 237, 0.3);
}
```
### 2. Linen & Oak(人文暖调)
```css
:root {
--primary: #92400E; /* 深琥珀 */
--primary-light: #D97706;
--accent: #047857; /* 墨绿 */
--accent-warm: #9D174D; /* 酒红 */
--bg: #FEFCE8; /* 米黄背景 */
--bg-2: #FFFBEB;
--bg-3: #FEF3C7;
--surface: #FFFFFF;
--border: rgba(120, 80, 20, 0.12);
--text-1: #1C1917;
--text-2: #57534E;
--text-3: #A8A29E;
}
```
### 3. Arctic Glass(冷感极简)
```css
:root {
--primary: #0EA5E9; /* 冰蓝 */
--primary-light: #38BDF8;
--primary-dark: #0284C7;
--accent: #8B5CF6; /* 淡紫强调 */
--bg: #F8FAFC; /* 极浅灰蓝背景 */
--bg-2: #F1F5F9;
--bg-3: #E2E8F0;
--surface: #FFFFFF;
--glass: rgba(255, 255, 255, 0.7);
--glass-border: rgba(148, 163, 184, 0.3);
--text-1: #0F172A;
--text-2: #475569;
--text-3: #94A3B8;
}
```
### 4. Tokyo Night(暗色电影感)
```css
:root {
--primary: #7AA2F7; /* 东京蓝 */
--secondary: #BB9AF7; /* 东京紫 */
--accent: #7DCFFF; /* 青蓝 */
--warn: #FF9E64; /* 橙色警告 */
--error: #F7768E; /* 红色错误 */
--success: #9ECE6A; /* 绿色成功 */
--bg: #1A1B26; /* 东京暗背景 */
--bg-2: #16161E;
--bg-3: #24283B;
--bg-highlight: #292E42;
--border: #292E42;
--text-1: #C0CAF5;
--text-2: #9AA5CE;
--text-3: #565F89;
}
```
### 5. Coral Sunrise(活力橙红)
```css
:root {
--primary: #F97316; /* 活力橙 */
--primary-dark: #EA580C;
--secondary: #EC4899; /* 玫瑰粉 */
--accent: #14B8A6; /* 蒂芙尼绿 */
--bg: #FFFAF0; /* 象牙白背景 */
--bg-2: #FFF7ED;
--surface: #FFFFFF;
--border: rgba(249, 115, 22, 0.15);
--text-1: #1C1917;
--text-2: #78716C;
--text-3: #A8A29E;
--gradient: linear-gradient(135deg, #F97316, #EC4899);
}
```
---
## WCAG 对比度检查速查
| 文字/背景组合 | 对比度 | 是否达标 AA |
|-------------|--------|------------|
| #000 / #FFF | 21:1 | ✅ AAA |
| #1C1B1F / #FFFBFE | 18.1:1 | ✅ AAA |
| #6750A4 / #FFF | 4.6:1 | ✅ AA |
| #8E8E93 / #FFF | 3.9:1 | ⚠️ 仅大文字 |
| #007AFF / #FFF | 4.5:1 | ✅ AA |
**规则提醒:**
- 正文 (≤18pt 非粗体): 最低 4.5:1
- 大文字 (≥18pt 或 ≥14pt 粗体): 最低 3:1
- UI 组件和图形: 最低 3:1
# Component Patterns Library
## Navigation
### Top App Bar (Material 3 + Apple 混合风格)
```html
<header class="top-bar">
<div class="top-bar__inner">
<button class="icon-btn" aria-label="Menu">
<svg><!-- hamburger --></svg>
</button>
<h1 class="top-bar__title">Page Title</h1>
<div class="top-bar__actions">
<button class="icon-btn" aria-label="Search">
<svg><!-- search --></svg>
</button>
<button class="icon-btn" aria-label="More">
<svg><!-- more --></svg>
</button>
</div>
</div>
</header>
<style>
.top-bar {
position: sticky;
top: 0;
z-index: 100;
background: var(--surface);
border-bottom: 1px solid var(--outline-variant);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
background: rgba(255, 251, 254, 0.8);
}
.top-bar__inner {
display: flex;
align-items: center;
gap: 4px;
height: 64px;
padding: 0 8px;
max-width: 1280px;
margin: 0 auto;
}
.top-bar__title {
flex: 1;
font-size: 22px;
font-weight: 400;
letter-spacing: -0.02em;
color: var(--on-surface);
}
.icon-btn {
width: 48px;
height: 48px;
border-radius: 50%;
border: none;
background: transparent;
display: grid;
place-items: center;
cursor: pointer;
transition: background 150ms;
}
.icon-btn:hover { background: var(--on-surface-variant-8, rgba(73,69,79,0.08)); }
.icon-btn:active { background: var(--on-surface-variant-12, rgba(73,69,79,0.12)); }
</style>
```
### Side Navigation Rail (Material 3)
```html
<nav class="nav-rail">
<div class="nav-rail__fab">
<button class="fab-btn">+</button>
</div>
<ul class="nav-rail__list">
<li class="nav-item active">
<div class="nav-item__indicator">
<svg class="nav-item__icon"><!-- icon --></svg>
</div>
<span class="nav-item__label">Home</span>
</li>
<!-- more items -->
</ul>
</nav>
<style>
.nav-rail {
width: 80px;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: 12px 0;
background: var(--surface);
}
.nav-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
padding: 4px 0;
cursor: pointer;
min-width: 72px;
}
.nav-item__indicator {
width: 56px;
height: 32px;
border-radius: 16px;
display: grid;
place-items: center;
transition: background 200ms;
}
.nav-item.active .nav-item__indicator {
background: var(--secondary-container);
}
.nav-item:hover:not(.active) .nav-item__indicator {
background: var(--on-surface-8);
}
.nav-item__label {
font-size: 12px;
font-weight: 500;
letter-spacing: 0.02em;
color: var(--on-surface-variant);
}
.nav-item.active .nav-item__label {
color: var(--on-surface);
font-weight: 700;
}
</style>
```
---
## Cards
### Product Card (Pinterest 风格)
```html
<article class="product-card">
<div class="product-card__img-wrap">
<img class="product-card__img" src="..." alt="...">
<button class="product-card__save"></button>
</div>
<div class="product-card__body">
<p class="product-card__category">Category</p>
<h3 class="product-card__title">Product Name</h3>
<div class="product-card__footer">
<span class="product-card__price">$99</span>
<button class="product-card__cta">Add to Cart</button>
</div>
</div>
</article>
<style>
.product-card {
border-radius: 16px;
overflow: hidden;
background: var(--surface);
transition: transform 300ms var(--ease-spring), box-shadow 300ms;
cursor: pointer;
}
.product-card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0,0,0,0.12);
}
.product-card__img-wrap {
position: relative;
aspect-ratio: 4/3;
overflow: hidden;
}
.product-card__img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 600ms var(--ease-decelerate);
}
.product-card:hover .product-card__img {
transform: scale(1.04);
}
.product-card__save {
position: absolute;
top: 12px; right: 12px;
width: 36px; height: 36px;
border-radius: 50%;
background: rgba(255,255,255,0.9);
backdrop-filter: blur(8px);
border: none;
font-size: 16px;
cursor: pointer;
opacity: 0;
transform: scale(0.8);
transition: opacity 200ms, transform 200ms var(--ease-spring);
}
.product-card:hover .product-card__save {
opacity: 1;
transform: scale(1);
}
.product-card__body {
padding: 16px;
}
.product-card__category {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--primary);
margin-bottom: 4px;
}
.product-card__title {
font-size: 16px;
font-weight: 600;
color: var(--on-surface);
margin-bottom: 12px;
line-height: 1.3;
}
.product-card__footer {
display: flex;
align-items: center;
justify-content: space-between;
}
.product-card__price {
font-size: 20px;
font-weight: 700;
color: var(--on-surface);
letter-spacing: -0.02em;
}
.product-card__cta {
padding: 8px 16px;
border-radius: 20px;
background: var(--primary);
color: var(--on-primary);
border: none;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: filter 150ms, transform 150ms;
}
.product-card__cta:hover { filter: brightness(1.1); }
.product-card__cta:active { transform: scale(0.96); }
</style>
```
### Stats Card (Dashboard)
```html
<div class="stat-card">
<div class="stat-card__header">
<span class="stat-card__label">Total Revenue</span>
<div class="stat-card__icon-wrap">
<svg><!-- icon --></svg>
</div>
</div>
<p class="stat-card__value">$48,295</p>
<div class="stat-card__change positive">
<svg><!-- arrow up --></svg>
<span>+12.5% from last month</span>
</div>
</div>
<style>
.stat-card {
background: var(--surface);
border-radius: 20px;
padding: 24px;
border: 1px solid var(--outline-variant);
transition: box-shadow 200ms;
}
.stat-card:hover {
box-shadow: 0 4px 24px rgba(0,0,0,0.06);
}
.stat-card__header {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 12px;
}
.stat-card__label {
font-size: 14px;
color: var(--on-surface-variant);
font-weight: 500;
}
.stat-card__icon-wrap {
width: 40px; height: 40px;
border-radius: 12px;
background: var(--primary-container);
display: grid;
place-items: center;
color: var(--primary);
}
.stat-card__value {
font-size: 32px;
font-weight: 700;
letter-spacing: -0.03em;
color: var(--on-surface);
margin-bottom: 8px;
font-feature-settings: 'tnum';
}
.stat-card__change {
display: flex;
align-items: center;
gap: 4px;
font-size: 13px;
font-weight: 500;
}
.stat-card__change.positive { color: #16A34A; }
.stat-card__change.negative { color: #DC2626; }
</style>
```
---
## Forms
### Floating Label Input (Material 3)
```html
<div class="text-field">
<div class="text-field__container">
<input type="text" id="email" class="text-field__input" placeholder=" ">
<label for="email" class="text-field__label">Email address</label>
<fieldset class="text-field__border"><legend><span>Email address</span></legend></fieldset>
</div>
<span class="text-field__helper">We'll never share your email</span>
</div>
<style>
.text-field { display: flex; flex-direction: column; gap: 4px; }
.text-field__container {
position: relative;
height: 56px;
}
.text-field__input {
width: 100%;
height: 100%;
padding: 16px 16px 0;
font-size: 16px;
background: transparent;
border: none;
outline: none;
color: var(--on-surface);
z-index: 1;
position: relative;
}
.text-field__label {
position: absolute;
left: 16px;
top: 50%;
transform: translateY(-50%);
font-size: 16px;
color: var(--on-surface-variant);
pointer-events: none;
transition: all 150ms var(--ease-standard);
z-index: 2;
background: var(--surface);
padding: 0 4px;
}
.text-field__input:focus + .text-field__label,
.text-field__input:not(:placeholder-shown) + .text-field__label {
top: 0;
font-size: 12px;
font-weight: 500;
}
.text-field__input:focus + .text-field__label { color: var(--primary); }
.text-field__border {
position: absolute;
inset: 0;
margin: 0;
border: 1.5px solid var(--outline);
border-radius: 4px;
pointer-events: none;
padding: 0 12px;
transition: border-color 150ms, border-width 150ms;
}
.text-field__input:focus ~ .text-field__border {
border-color: var(--primary);
border-width: 2px;
}
.text-field__border legend { height: 0; font-size: 12px; font-weight: 500; padding: 0; }
.text-field__input:focus ~ .text-field__border legend,
.text-field__input:not(:placeholder-shown) ~ .text-field__border legend {
padding: 0 4px;
}
.text-field__helper {
font-size: 12px;
color: var(--on-surface-variant);
padding: 0 16px;
}
</style>
```
---
## Buttons — Complete System
```html
<!-- Primary (Filled) -->
<button class="btn btn--filled">Get Started</button>
<!-- Secondary (Filled Tonal) -->
<button class="btn btn--tonal">Learn More</button>
<!-- Outlined -->
<button class="btn btn--outlined">Cancel</button>
<!-- Text -->
<button class="btn btn--text">Skip</button>
<!-- Elevated -->
<button class="btn btn--elevated">Save Draft</button>
<!-- Icon + Label -->
<button class="btn btn--filled btn--icon">
<svg><!-- icon --></svg>
Add Item
</button>
<!-- Loading State -->
<button class="btn btn--filled btn--loading" disabled>
<span class="btn__spinner"></span>
Loading...
</button>
<style>
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
height: 40px;
padding: 0 24px;
border-radius: 20px; /* Material 3 全圆角 */
font-size: 14px;
font-weight: 500;
letter-spacing: 0.01em;
border: none;
cursor: pointer;
white-space: nowrap;
transition: all 150ms var(--ease-standard);
position: relative;
overflow: hidden;
}
.btn:disabled { opacity: 0.38; cursor: not-allowed; }
.btn:active:not(:disabled) { transform: scale(0.97); }
/* State layer */
.btn::after {
content: '';
position: absolute;
inset: 0;
background: currentColor;
opacity: 0;
transition: opacity 150ms;
}
.btn:hover::after { opacity: 0.08; }
.btn:active::after { opacity: 0.12; }
/* Variants */
.btn--filled { background: var(--primary); color: var(--on-primary); }
.btn--filled:hover { box-shadow: 0 1px 2px rgba(0,0,0,.1), 0 2px 6px rgba(0,0,0,.08); }
.btn--tonal { background: var(--secondary-container); color: var(--on-secondary-container); }
.btn--tonal:hover { box-shadow: 0 1px 2px rgba(0,0,0,.06), 0 2px 6px rgba(0,0,0,.06); }
.btn--outlined {
background: transparent;
color: var(--primary);
border: 1px solid var(--outline);
}
.btn--outlined:hover { background: rgba(103, 80, 164, 0.08); }
.btn--text { background: transparent; color: var(--primary); padding: 0 12px; }
.btn--elevated {
background: var(--surface-container-low);
color: var(--primary);
box-shadow: 0 1px 2px rgba(0,0,0,.06), 0 2px 8px rgba(0,0,0,.08);
}
.btn--elevated:hover { box-shadow: 0 2px 4px rgba(0,0,0,.08), 0 4px 12px rgba(0,0,0,.1); }
/* Spinner */
.btn__spinner {
width: 16px; height: 16px;
border: 2px solid rgba(255,255,255,0.3);
border-top-color: white;
border-radius: 50%;
animation: spin 0.6s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
</style>
```
---
## Feedback Components
### Toast / Snackbar (Material 3)
```html
<div class="snackbar" role="status">
<span class="snackbar__message">Changes saved successfully</span>
<button class="snackbar__action">Undo</button>
<button class="snackbar__close" aria-label="Close"></button>
</div>
<style>
.snackbar {
display: inline-flex;
align-items: center;
gap: 12px;
min-width: 288px;
max-width: 568px;
background: var(--inverse-surface);
color: var(--inverse-on-surface);
border-radius: 4px;
padding: 14px 16px;
box-shadow: 0 3px 5px rgba(0,0,0,.1), 0 8px 24px rgba(0,0,0,.14);
font-size: 14px;
animation: snackbar-in 300ms var(--ease-decelerate) forwards;
}
@keyframes snackbar-in {
from { transform: translateY(100%); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.snackbar__message { flex: 1; }
.snackbar__action {
background: none; border: none;
color: var(--inverse-primary);
font-size: 14px; font-weight: 500;
letter-spacing: 0.01em;
cursor: pointer;
padding: 4px 8px;
border-radius: 4px;
transition: background 150ms;
}
.snackbar__action:hover { background: rgba(255,255,255,0.1); }
.snackbar__close {
background: none; border: none;
color: var(--inverse-on-surface);
cursor: pointer; font-size: 18px; line-height: 1;
opacity: 0.7; transition: opacity 150ms;
}
</style>
```
### Badge
```css
.badge {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 16px;
height: 16px;
padding: 0 4px;
border-radius: 8px;
background: var(--error);
color: var(--on-error);
font-size: 11px;
font-weight: 600;
line-height: 1;
}
.badge--dot {
width: 8px; height: 8px;
padding: 0; min-width: unset;
border-radius: 50%;
}
.badge--large {
min-width: 24px; height: 24px;
border-radius: 12px;
font-size: 12px;
padding: 0 8px;
}
```
---
## Page Skeleton / Loading
```html
<div class="skeleton-card">
<div class="skeleton skeleton--image"></div>
<div class="skeleton-card__body">
<div class="skeleton skeleton--line" style="width: 60%"></div>
<div class="skeleton skeleton--line" style="width: 90%"></div>
<div class="skeleton skeleton--line" style="width: 75%"></div>
</div>
</div>
<style>
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
.skeleton {
background: linear-gradient(
90deg,
var(--surface-variant) 25%,
var(--surface-container) 50%,
var(--surface-variant) 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
border-radius: 4px;
}
.skeleton--image { width: 100%; aspect-ratio: 16/9; border-radius: 12px 12px 0 0; }
.skeleton--line { height: 14px; margin-bottom: 8px; border-radius: 7px; }
</style>
```
# Layout Templates Reference
## Dashboard Layout (Material 3 Canonical)
```html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Dashboard</title>
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
</head>
<body>
<div class="app-shell">
<!-- Side Navigation -->
<aside class="nav-drawer">
<div class="nav-drawer__header">
<div class="brand">
<div class="brand__icon"></div>
<span class="brand__name">AppName</span>
</div>
</div>
<nav class="nav-list">
<a href="#" class="nav-link active">
<svg class="nav-link__icon" viewBox="0 0 24 24">
<path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/>
</svg>
<span>Dashboard</span>
</a>
<!-- more links -->
</nav>
</aside>
<!-- Main Content -->
<div class="main-content">
<!-- Top Bar -->
<header class="top-bar">
<h1 class="page-title">Overview</h1>
<div class="top-bar__actions">
<button class="icon-btn">🔔</button>
<div class="avatar">JD</div>
</div>
</header>
<!-- Content Area -->
<main class="content-area">
<!-- Stats Row -->
<div class="stats-grid">
<!-- stat cards here -->
</div>
<!-- Charts -->
<div class="charts-grid">
<!-- chart cards here -->
</div>
</main>
</div>
</div>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--primary: #6750A4;
--primary-container: #EADDFF;
--on-primary-container: #21005D;
--secondary-container: #E8DEF8;
--surface: #FFFBFE;
--surface-container: #F3EDF7;
--surface-container-low: #F7F2FA;
--on-surface: #1C1B1F;
--on-surface-variant: #49454F;
--outline: #79747E;
--outline-variant: #CAC4D0;
--nav-width: 256px;
}
body {
font-family: 'Manrope', system-ui, sans-serif;
background: var(--surface-container-low);
color: var(--on-surface);
min-height: 100vh;
}
.app-shell {
display: flex;
min-height: 100vh;
}
/* Nav Drawer */
.nav-drawer {
width: var(--nav-width);
height: 100vh;
position: sticky;
top: 0;
background: var(--surface-container-low);
display: flex;
flex-direction: column;
border-right: 1px solid var(--outline-variant);
padding: 16px 12px;
flex-shrink: 0;
}
.nav-drawer__header { padding: 8px 12px 24px; }
.brand { display: flex; align-items: center; gap: 12px; }
.brand__icon {
width: 40px; height: 40px;
background: var(--primary);
color: white;
border-radius: 12px;
display: grid;
place-items: center;
font-size: 20px;
}
.brand__name { font-size: 18px; font-weight: 700; color: var(--on-surface); }
.nav-link {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
border-radius: 28px;
text-decoration: none;
color: var(--on-surface-variant);
font-size: 14px;
font-weight: 500;
transition: background 150ms, color 150ms;
margin-bottom: 4px;
}
.nav-link:hover { background: rgba(103,80,164,0.08); color: var(--on-surface); }
.nav-link.active {
background: var(--secondary-container);
color: var(--on-surface);
font-weight: 700;
}
.nav-link__icon { width: 20px; height: 20px; flex-shrink: 0; }
/* Main Content */
.main-content {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.top-bar {
height: 72px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 32px;
background: var(--surface-container-low);
border-bottom: 1px solid var(--outline-variant);
position: sticky;
top: 0;
z-index: 10;
}
.page-title { font-size: 28px; font-weight: 700; letter-spacing: -0.02em; }
.top-bar__actions { display: flex; align-items: center; gap: 8px; }
.avatar {
width: 36px; height: 36px;
background: var(--primary);
color: white;
border-radius: 50%;
display: grid;
place-items: center;
font-size: 13px;
font-weight: 700;
cursor: pointer;
}
.content-area { padding: 32px; overflow-y: auto; flex: 1; }
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
margin-bottom: 24px;
}
.charts-grid {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 16px;
}
@media (max-width: 768px) {
.nav-drawer { display: none; }
.charts-grid { grid-template-columns: 1fr; }
}
</style>
```
---
## Landing Page Layout
```html
<!-- Hero Section -->
<section class="hero">
<div class="hero__container">
<div class="hero__eyebrow">
<span class="badge-pill">New →</span>
<span>Introducing v2.0</span>
</div>
<h1 class="hero__headline">
Build beautiful apps<br>
<span class="hero__gradient-text">10x faster</span>
</h1>
<p class="hero__description">
The design system that scales with your team.
Beautiful by default, customizable by design.
</p>
<div class="hero__ctas">
<a href="#" class="btn btn--primary btn--lg">Get Started Free</a>
<a href="#" class="btn btn--ghost btn--lg">View Demo ↗</a>
</div>
<div class="hero__social-proof">
<div class="avatar-stack">
<img src="..." alt="">
<img src="..." alt="">
<img src="..." alt="">
<img src="..." alt="">
</div>
<p><strong>2,000+</strong> teams already building</p>
</div>
</div>
<div class="hero__visual">
<!-- Product Screenshot / Illustration -->
</div>
</section>
<style>
.hero {
min-height: 100vh;
display: grid;
grid-template-columns: 1fr 1fr;
align-items: center;
gap: 64px;
padding: 80px clamp(24px, 5vw, 80px);
max-width: 1280px;
margin: 0 auto;
}
.hero__eyebrow {
display: inline-flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: var(--on-surface-variant);
margin-bottom: 24px;
}
.badge-pill {
background: var(--primary-container);
color: var(--on-primary-container);
padding: 4px 10px;
border-radius: 20px;
font-size: 12px;
font-weight: 600;
}
.hero__headline {
font-size: clamp(36px, 5vw, 64px);
font-weight: 800;
letter-spacing: -0.04em;
line-height: 1.05;
color: var(--on-surface);
margin-bottom: 24px;
}
.hero__gradient-text {
background: linear-gradient(135deg, var(--primary), var(--tertiary));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero__description {
font-size: clamp(16px, 2vw, 20px);
line-height: 1.6;
color: var(--on-surface-variant);
max-width: 48ch;
margin-bottom: 40px;
}
.hero__ctas {
display: flex;
gap: 16px;
flex-wrap: wrap;
margin-bottom: 40px;
}
.btn--lg { height: 52px; padding: 0 32px; font-size: 16px; }
.btn--ghost {
background: transparent;
color: var(--on-surface);
border: 1.5px solid var(--outline-variant);
border-radius: 26px;
}
.btn--ghost:hover { background: var(--surface-variant); }
.hero__social-proof {
display: flex;
align-items: center;
gap: 12px;
font-size: 14px;
color: var(--on-surface-variant);
}
.avatar-stack {
display: flex;
}
.avatar-stack img {
width: 28px; height: 28px;
border-radius: 50%;
border: 2px solid var(--surface);
margin-right: -8px;
object-fit: cover;
}
@media (max-width: 900px) {
.hero {
grid-template-columns: 1fr;
text-align: center;
min-height: auto;
padding-top: 100px;
}
.hero__visual { display: none; }
.hero__ctas { justify-content: center; }
.hero__social-proof { justify-content: center; }
}
</style>
```
---
## Mobile App Layout (iOS-like)
```html
<div class="app">
<!-- Status Bar placeholder -->
<div class="status-bar"></div>
<!-- Content -->
<main class="app-content">
<!-- Large Title (iOS style) -->
<div class="large-title-area">
<h1 class="large-title">My Library</h1>
<button class="circle-btn">+</button>
</div>
<!-- Search Bar (iOS style) -->
<div class="search-bar">
<span class="search-icon">🔍</span>
<input type="search" placeholder="Search" class="search-input">
</div>
<!-- Horizontal Scroll Section -->
<section class="section">
<div class="section-header">
<h2 class="section-title">Featured</h2>
<a href="#" class="see-all">See All</a>
</div>
<div class="h-scroll">
<!-- cards -->
</div>
</section>
</main>
<!-- Tab Bar (iOS style) -->
<nav class="tab-bar">
<button class="tab-item active">
<svg class="tab-icon"><!-- icon --></svg>
<span class="tab-label">Home</span>
</button>
<button class="tab-item">
<svg class="tab-icon"><!-- icon --></svg>
<span class="tab-label">Explore</span>
</button>
<button class="tab-item">
<svg class="tab-icon"><!-- icon --></svg>
<span class="tab-label">Library</span>
</button>
<button class="tab-item">
<svg class="tab-icon"><!-- icon --></svg>
<span class="tab-label">Profile</span>
</button>
</nav>
</div>
<style>
.app {
width: 390px; /* iPhone 14 width */
height: 844px;
background: var(--bg-primary, #F2F2F7);
border-radius: 44px;
overflow: hidden;
display: flex;
flex-direction: column;
position: relative;
box-shadow: 0 32px 80px rgba(0,0,0,0.3);
font-family: -apple-system, 'SF Pro Display', system-ui;
}
.status-bar {
height: 47px;
background: transparent;
flex-shrink: 0;
}
.app-content {
flex: 1;
overflow-y: auto;
padding: 0 20px;
-webkit-overflow-scrolling: touch;
}
.app-content::-webkit-scrollbar { display: none; }
.large-title-area {
display: flex;
align-items: flex-end;
justify-content: space-between;
padding: 8px 0 20px;
}
.large-title {
font-size: 34px;
font-weight: 700;
letter-spacing: -0.02em;
color: var(--apple-label, #000);
}
.circle-btn {
width: 32px; height: 32px;
border-radius: 50%;
background: var(--apple-fill, rgba(120,120,128,0.2));
border: none;
font-size: 22px;
line-height: 1;
display: grid;
place-items: center;
cursor: pointer;
color: var(--apple-blue, #007AFF);
}
.search-bar {
display: flex;
align-items: center;
gap: 8px;
background: rgba(118, 118, 128, 0.12);
border-radius: 10px;
padding: 0 12px;
height: 36px;
margin-bottom: 24px;
}
.search-input {
flex: 1;
background: transparent;
border: none;
outline: none;
font-size: 17px;
color: var(--apple-label, #000);
}
.section { margin-bottom: 32px; }
.section-header {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 12px;
}
.section-title { font-size: 22px; font-weight: 700; letter-spacing: -0.01em; }
.see-all { font-size: 15px; color: var(--apple-blue, #007AFF); text-decoration: none; }
.h-scroll {
display: flex;
gap: 12px;
overflow-x: auto;
margin: 0 -20px;
padding: 0 20px 4px;
scrollbar-width: none;
}
.h-scroll::-webkit-scrollbar { display: none; }
/* Tab Bar */
.tab-bar {
height: 83px;
background: rgba(249, 249, 249, 0.94);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-top: 0.5px solid rgba(0,0,0,0.12);
display: flex;
align-items: flex-start;
padding: 8px 0 0;
flex-shrink: 0;
}
.tab-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
background: none;
border: none;
cursor: pointer;
padding: 4px 0;
color: var(--apple-gray1, #8E8E93);
transition: color 150ms;
}
.tab-item.active { color: var(--apple-blue, #007AFF); }
.tab-icon { width: 26px; height: 26px; }
.tab-label { font-size: 10px; font-weight: 500; letter-spacing: -0.01em; }
</style>
```
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment