Files
ele-HeiXiu/src/theme/globals.css
YoungestSongMo eb12248a62 feat: 主题切换性能优化 — View Transitions API + 0.15s 统一过渡 + 设置页增强
【问题】
  桌面端(Electron)切换主题时颜色变化速度不一致、明显卡顿。
  根因分析(4 轮迭代):
    1. 过渡时长不统一(body 0.3s / 组件 0.15s)→ 统一到 0.2s
    2. antd CSS-in-JS 标签替换导致瞬间变色 → 尝试 cssVar(无效,仍走标签替换)
    3. applyHtmlTheme 在 updater 回调中执行,与 antd CSS 变更不同帧 → 移入 useLayoutEffect
    4. html * 全局过渡在 Electron 中为数千 DOM 节点同步插值 → 合成器掉帧
  终极方案:View Transitions API(GPU 合成器 1 次 cross-fade 替代 N 个 CSS 过渡)
   + 精准 CSS 过渡覆盖 ~80 个 antd 容器类(回退方案)

  【修改】

  ThemeProvider.tsx — 核心重构
    - applyHtmlTheme 从 setIsDark updater → useLayoutEffect([isDark])
      确保自定义 CSS 变量与 antd CSS-in-JS 在同一次 React 提交中生效
    - View Transitions API:document.startViewTransition + flushSync
      GPU 合成器截取旧/新两帧做单次 cross-fade,消除多元素插值卡顿
    - 浏览器不支持时自动回退到 CSS transition 方案

  globals.css — 过渡策略
    - body: 0.3s ease → 0.15s linear
    - View Transitions 动画:::view-transition-old/new(root) 0.15s linear
    - ~80 个 antd 容器类精准过渡(Layout/Card/Modal/Table/Input/
      Select/Picker/Menu/Tabs/Tag/Alert/Empty/Result/Skeleton 等)
      按功能分组:布局 → 表格 → 表单 → 导航 → 反馈
      不覆盖交互组件自有 transition(Button/Switch/Slider 等)
      linear 替代 ease — 匀速插值,桌面应用更利落

  Layout.tsx / HomeContent.tsx / LeftPanel.tsx / ModelSelector.tsx
    - 过渡参数对齐:全部 0.2s → 0.15s linear

  SettingsPage.tsx — 用户体验
    - Modal 取消 keyboard={false},Esc 键可关闭
    - macOS:关闭按钮移至标题左侧(遵循 macOS HIG)
    - afterClose 中 blur 当前焦点元素,防止聚焦跳到导航栏

  【文档】
  CHANGELOG.md — 新增 0.0.15 版本记录
  CLAUDE.md — 新增主题系统架构章节(双轨颜色体系 / 时序 / 过渡策略)
2026-06-09 11:02:40 +08:00

375 lines
10 KiB
CSS
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.
/* ============================================================
* 全局样式 —— Tailwind CSS v4 指令 + 蓝紫渐变主题扩展 + 重置样式
* Tailwind v4 使用 CSS @theme 指令替代 tailwind.config.ts
* 设计令牌需与 tokens.ts / antd-theme.ts 保持同步。
* ============================================================ */
@import 'tailwindcss';
/* ============================================================
* Tailwind CSS v4 主题扩展(用 @theme 指令)
* 此处定义的自定义令牌会自动生成对应的 Tailwind 工具类。
* 例如colors.primary → bg-primary, text-primary, border-primary 等。
* ============================================================ */
/* 品牌色 — 蓝紫渐变 */
@theme {
/* 主色系 */
--color-primary: #6366f1; /* Indigo-500 */
--color-primary-light: #818cf8; /* Indigo-400 */
--color-primary-dark: #4f46e5; /* Indigo-600 */
--color-primary-50: #eef2ff; /* Indigo-50 */
--color-primary-100: #e0e7ff; /* Indigo-100 */
--color-primary-200: #c7d2fe; /* Indigo-200 */
--color-primary-300: #a5b4fc; /* Indigo-300 */
--color-primary-400: #818cf8; /* Indigo-400 */
--color-primary-500: #6366f1; /* Indigo-500 */
--color-primary-600: #4f46e5; /* Indigo-600 */
--color-primary-700: #4338ca; /* Indigo-700 */
--color-primary-800: #3730a3; /* Indigo-800 */
--color-primary-900: #312e81; /* Indigo-900 */
/* 辅助色系 — Violet */
--color-secondary: #8b5cf6; /* Violet-500 */
--color-secondary-light: #a78bfa; /* Violet-400 */
--color-secondary-dark: #7c3aed; /* Violet-600 */
/* 功能色 */
--color-success: #10b981;
--color-success-light: #d1fae5;
--color-warning: #f59e0b;
--color-warning-light: #fef3c7;
--color-error: #ef4444;
--color-error-light: #fee2e2;
--color-info: #3b82f6;
--color-info-light: #dbeafe;
/* 圆角 */
--radius-xs: 4px;
--radius-sm: 6px;
--radius-base: 8px;
--radius-lg: 12px;
--radius-xl: 16px;
--radius-2xl: 24px;
/* 字体 */
--font-family-base:
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans',
'PingFang SC', 'Microsoft YaHei', sans-serif;
--font-family-mono:
'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, 'Courier New', monospace;
/* 动画 */
--transition-duration: 0.2s;
--transition-timing: cubic-bezier(0.4, 0, 0.2, 1);
}
/* ============================================================
* 🌞 亮色模式 CSS 变量(默认)
* 这些变量与 tokens.ts 中的亮色令牌同步
* ============================================================ */
:root,
[data-theme='light'] {
/* 中性色 — 亮色 */
--color-text-base: #1e1b4b;
--color-text-secondary: #6b7280;
--color-text-tertiary: #9ca3af;
--color-bg-base: #ffffff;
--color-bg-container: #f9fafb;
--color-bg-layout: #f5f3ff;
--color-bg-elevated: #ffffff;
--color-border-base: #e5e7eb;
--color-border-secondary: #f3f4f6;
/* 阴影 */
--shadow-base: 0 1px 3px 0 rgba(99, 102, 241, 0.08), 0 1px 2px -1px rgba(99, 102, 241, 0.08);
--shadow-lg: 0 10px 15px -3px rgba(99, 102, 241, 0.1), 0 4px 6px -4px rgba(99, 102, 241, 0.1);
}
/* ============================================================
* 🌙 暗色模式 CSS 变量
* 当 <html data-theme="dark"> 时自动切换
* 这些变量与 tokens.ts 中的暗色令牌同步
* ============================================================ */
[data-theme='dark'] {
/* 中性色 — 暗色(科技蓝紫) */
--color-text-base: #e8e8fa;
--color-text-secondary: #a0a8d8;
--color-text-tertiary: #6e78b0;
--color-bg-base: #080c24;
--color-bg-container: #0f1340;
--color-bg-layout: #050818;
--color-bg-elevated: #171b52;
--color-border-base: #2a3278;
--color-border-secondary: #1c2250;
/* 暗色模式下品牌色提亮以保持对比度 */
--color-primary: #818cf8;
--color-primary-light: #a5b4fc;
--color-primary-dark: #6366f1;
/* 阴影 — 暗色下用深投影 */
--shadow-base: 0 1px 3px 0 rgba(0, 0, 0, 0.3), 0 1px 2px -1px rgba(0, 0, 0, 0.3);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -4px rgba(0, 0, 0, 0.4);
}
/* ============================================================
* 蓝紫渐变工具类
* Tailwind v4 使用 @utility 定义自定义工具类
* ============================================================ */
@utility gradient-primary {
background: linear-gradient(135deg, #4f46e5, #7c3aed);
}
@utility gradient-primary-hover {
background: linear-gradient(135deg, #6366f1, #8b5cf6);
}
@utility gradient-primary-text {
background: linear-gradient(135deg, #4f46e5, #7c3aed);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
@utility gradient-border {
border-image: linear-gradient(135deg, #4f46e5, #7c3aed) 1;
}
/* ============================================================
* 全局重置样式
* 仅放必要的重置,不堆积组件样式
* ============================================================ */
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-family: var(--font-family-base);
font-size: 14px;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
/* 亮/暗切换过渡 */
color-scheme: light dark;
}
body {
margin: 0;
padding: 0;
color: var(--color-text-base);
background-color: var(--color-bg-base);
min-height: 100vh;
transition:
background-color 0.15s linear,
color 0.15s linear;
}
/* ============================================================
* View Transitions API — GPU 合成器驱动的主题切换动画
* 替代 80+ 个独立 CSS 过渡,单次 cross-fade 消除 Electron 卡顿。
* 仅在 Chromium 111+Electron 28+)生效,其他浏览器回退 CSS 过渡。
* ============================================================ */
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 0.15s;
animation-timing-function: linear;
}
/* ============================================================
* 主题切换过渡 — 精准覆盖大面积视觉容器,避免 * 全局选择器
* 在 Electron 中为数千个 DOM 节点同时启动过渡造成卡顿。
*
* 策略:
* 1. 容器/布局组件Card / Modal / Layout / Drawer 等)
* 2. 表格 & 列表Table / List / Timeline
* 3. 表单控件Input / Select / Picker
* 4. 导航 & 标签Menu / Tabs / Tag / Breadcrumb
* 5. 反馈 & 展示Alert / Empty / Result / Statistic / Skeleton
*
* 不覆盖交互组件自有 transitionButton / Switch / Slider 等
* 均使用 transition: all特异性更高不受影响
* ============================================================ */
/* —— 布局 & 容器 —— */
body,
.ant-layout,
.ant-layout-header,
.ant-layout-sider,
.ant-layout-content,
.ant-card,
.ant-card-head,
.ant-card-body,
.ant-card-actions,
.ant-modal-content,
.ant-modal-header,
.ant-modal-body,
.ant-modal-footer,
.ant-drawer-content,
.ant-drawer-header,
.ant-drawer-body,
.ant-drawer-footer,
/* —— 表格 & 列表 —— */
.ant-table,
.ant-table-thead > tr > th,
.ant-table-tbody > tr > td,
.ant-table-tbody > tr:hover > td,
.ant-list,
.ant-list-item,
.ant-timeline-item,
.ant-transfer-list,
.ant-tree-node-content-wrapper,
/* —— 表单控件 —— */
.ant-input,
.ant-input-affix-wrapper,
.ant-select-selector,
.ant-select-dropdown,
.ant-picker,
.ant-picker-input,
.ant-picker-dropdown,
.ant-picker-panel-container,
.ant-input-number,
.ant-input-number-input,
.ant-radio-button-wrapper,
.ant-radio-group,
.ant-checkbox-wrapper,
.ant-segmented,
.ant-segmented-item,
.ant-upload-drag,
.ant-upload-list-item,
/* —— 导航 & 标签 —— */
.ant-menu,
.ant-menu-item,
.ant-menu-submenu-title,
.ant-tabs-nav,
.ant-tabs-nav-list,
.ant-tabs-tab,
.ant-tabs-content,
.ant-tag,
.ant-breadcrumb,
.ant-pagination-item,
.ant-dropdown-menu,
/* —— 反馈 & 展示 —— */
.ant-alert,
.ant-empty,
.ant-result,
.ant-statistic,
.ant-statistic-content,
.ant-badge,
.ant-avatar,
.ant-divider,
.ant-skeleton,
.ant-skeleton-input,
.ant-skeleton-button,
.ant-notification-notice,
.ant-message-notice-content,
.ant-popover-inner,
.ant-tooltip-inner,
.ant-collapse,
.ant-collapse-item,
.ant-collapse-header,
.ant-collapse-content-box,
.ant-descriptions-item-container {
transition:
color 0.15s linear,
background-color 0.15s linear,
border-color 0.15s linear,
box-shadow 0.15s linear;
}
#root {
min-height: 100vh;
}
/* 滚动条美化 */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: #c7d2fe;
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: #a5b4fc;
}
/* 暗色模式滚动条 */
[data-theme='dark'] ::-webkit-scrollbar-thumb {
background: #4338ca;
}
[data-theme='dark'] ::-webkit-scrollbar-thumb:hover {
background: #4f46e5;
}
/* 聚焦环 — 使用品牌色 */
:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
/* 选中文本 — 使用品牌色 */
::selection {
background: rgba(99, 102, 241, 0.2);
color: var(--color-text-base);
}
[data-theme='dark'] ::selection {
background: rgba(129, 140, 248, 0.3);
color: var(--color-text-base);
}
/* 链接全局样式 */
a {
color: var(--color-primary);
text-decoration: none;
transition: color var(--transition-duration) var(--transition-timing);
}
a:hover {
color: var(--color-primary-light);
}
/* ============================================================
* 窗口拖拽区域(自定义导航栏)
*
* macOS hiddenInset 模式下,整个导航栏区域可拖拽移动窗口。
* .navbar-drag-region → 可拖拽(背景区域)
* .navbar-no-drag → 不可拖拽(按钮、链接等交互元素)
* ============================================================ */
.navbar-drag-region {
-webkit-app-region: drag;
user-select: none;
}
.navbar-no-drag {
-webkit-app-region: no-drag;
}
/* macOS 红绿灯按钮区域不遮挡内容 */
@supports (-webkit-app-region: drag) {
.navbar-drag-region {
-webkit-app-region: drag;
}
}