- 重构版主提示词(14 parts,面向 ClassHelper 灵动岛重构) - ClassIsland 全量规格提示词(20 parts,含分卷与逐章版本) - 投喂指南、分卷、逐节文件 - 调研记录、一致性基线、生成与质检脚本
357 lines
36 KiB
Markdown
357 lines
36 KiB
Markdown
## 3. 设计系统 Token 总表(颜色 / 字体 / 圆角 / 间距 / 阴影 / 层级 / DPI / 深浅色)
|
||
|
||
本节是整份提示词的「地基」。实现者必须先落地本节的 token(CSS 自定义属性 + TypeScript 常量),再开始写任何界面。任何界面代码**不得**出现裸色值、裸字号、裸圆角,一律引用本节 token。
|
||
|
||
实现技术栈为 ClassHelper 的 Electron + Vue 3 栈,宿主已有 `packages/ui/src/tokens.css` 的 `--ch-ui-*` 与桌面端 `renderer/styles/index.css` 的 `--ch-*`。**保留并复用**这些既有 token 作为「应用外壳层」,新增 `--ci-*` 命名空间承载 ClassIsland 主界面(岛)层 token。两层必须分开:`--ch-*` 管设置中心/管理页,`--ci-*` 管岛与课程信息。
|
||
|
||
### 3.1 颜色 Token
|
||
|
||
#### 3.1.1 强调色与派生色
|
||
|
||
| Token 名 | 默认值 | 用途 | 建议 CSS 变量 | 源码证据 |
|
||
|---|---|---|---|---|
|
||
| `PrimaryColor`(用户强调色) | `#00BFFF`(Colors.DeepSkyBlue) | 设置项「强调色」的默认值;`ColorSource=0` 时作为全站 accent | `--ci-accent` | `ClassIsland/Models/Settings.cs:35`、`Settings.cs:992` |
|
||
| `SecondaryColor` | `#7FFFD4`(Colors.Aquamarine) | 备用强调色(组件/图表次级色) | `--ci-accent-2` | `Settings.cs:36`、`Settings.cs:1003` |
|
||
| FluentAvalonia 初始 accent | `DodgerBlue`=`#1E90FF` | 主题服务尚未介入时的启动色 | `--ci-accent-fallback` | `ClassIsland/App.axaml:17` |
|
||
| `SelectedPlatte` 兜底 | `DodgerBlue`=`#1E90FF` | 壁纸调色板取不到颜色时的兜底 | `--ci-accent-palette-fallback` | `Settings.cs:1036-1039`、`Settings.cs:80` |
|
||
| `AccentFillColorDefaultBrush` | 由 accent 派生(Fluent 资源) | 提醒遮罩填充、教程高亮框、进度条强调 | `--ci-accent-fill` | `ClassIsland.Core/StylesBase.axaml:90-93`、`XamlThemes/FluentTheme/Styles.axaml:180` |
|
||
| `AccentFillColorTertiaryBrush` | accent 低透明度变体 | 课程列表展开态底色 | `--ci-accent-fill-tertiary` | `ClassIsland.Core/Controls/LessonsControls/LessonControlExpanded.axaml:182` |
|
||
| `AccentTextFillColorPrimaryBrush` | accent 文字色 | 拖拽高亮描边、TeachingTip 指示箭头 | `--ci-accent-text` | `EditableComponentsListBox.axaml:310`、`MyTeachingTipStyles.axaml:213` |
|
||
| `TextOnAccentFillColorPrimaryBrush` | 白/黑(随 accent 对比度) | 遮罩上的文字 | `--ci-text-on-accent` | `FluentTheme/Styles.axaml:162,182`;`ClassicTheme/Styles.axaml:142` |
|
||
| `CustomizedAccentBarBackground1Brush` | 亮 `#FFDDE6F0` / 暗 `#26374C`;运行时被覆盖为 accent 的 10% 透明 | 「强调按钮」淡底、`Button.foreground-accent` | `--ci-accent-soft` | `Themes/LightTheme.axaml:18`、`Themes/DarkTheme.axaml:18`、`Services/ThemeService.cs:66-74` |
|
||
|
||
运行时强调色决策必须严格按以下分支实现(源码见 `ClassIsland/MainWindow.axaml.cs:743-764`):
|
||
|
||
1. `ColorSource == 0`(自定义)→ 使用 `PrimaryColor`;
|
||
2. `ColorSource == 1`(壁纸主题色)或 `3`(屏幕主题色)→ 使用 `SelectedPlatte`(壁纸调色板第 `SelectedPlatteIndex` 项);
|
||
3. `ColorSource == 2`(跟随系统)→ 传 `null`,交给系统强调色;
|
||
4. 其余 → 兜底 `DodgerBlue`。
|
||
|
||
`--ci-accent-soft` 必须以 `color-mix(in srgb, var(--ci-accent) 10%, transparent)` 实时推导,不得写死。ClassHelper 已有等价写法可复用:`packages/ui/src/theme.css:4-9` 用 `color-mix()` 派生 Element Plus 的 `--el-color-primary-light-*`。
|
||
|
||
#### 3.1.2 前景文字阶梯(前景色 5 级)
|
||
|
||
主界面自定义前景色时,前景色不是 1 个值,而是**由同一个基色派生出 5 个 alpha 版本**,必须按下表实现(源码:`ClassIsland.Core/Helpers/UI/ControlColorHelper.cs:20-52`):
|
||
|
||
| 层级 | 资源键 | alpha | 用途 | 建议 CSS 变量 |
|
||
|---|---|---|---|---|
|
||
| 1 | `TextFillColorPrimaryBrush` | 255(100%) | 主要文字、标题 | `--ci-text-1` |
|
||
| 2 | `TextFillColorInformativeSecondaryBrush` | 218(85.5%) | 次要说明(本项目覆盖值) | `--ci-text-2` |
|
||
| 3 | `TextFillColorSecondaryBrush` | 197(77.3%) | 辅助文字 | `--ci-text-3` |
|
||
| 4 | `TextFillColorTertiaryBrush` | 135(52.9%) | 装饰/弱提示 | `--ci-text-4` |
|
||
| 5 | `TextFillColorDisabledBrush` | 93(36.5%) | 禁用态 | `--ci-text-5` |
|
||
|
||
实现规则:
|
||
- 未启用自定义前景色时,上述 5 个 token 使用 Fluent 默认值:亮色 `#E4000000` / `#9E000000` / `#72000000` / `#5C000000`,深色 `#FFFFFFFF` 及对应 alpha 版本【推断:FluentAvalonia 资源值不在本仓库,按 Fluent 2 规范给出】。
|
||
- 启用自定义前景色时,5 个 token 全部按上表 alpha 从 `CustomForegroundColor` 派生,且**必须同时**重设 `TemplatedControl.Foreground` 与 `TextElement.Foreground`,否则模板内文字会漏改(`ControlColorHelper.cs:34-40`)。
|
||
- 关闭自定义前景色时,必须 `Remove` 这 5 个局部资源并 `SetValue(..., AvaloniaProperty.UnsetValue)` 回落(`ControlColorHelper.cs:44-50`)——映射到 CSS 即删除元素上的内联 `--ci-text-*`,回落 `:root`。
|
||
- 两个默认覆盖值:亮色 `TextFillColorInformativeSecondaryBrush = #c0000000`(75% 黑),深色 `#daffffff`(85.5% 白)(`Themes/LightTheme.axaml:20`、`Themes/DarkTheme.axaml:20`)。
|
||
- 语义层级类必须映射为 CSS 工具类:`.l-primary|.l1 → --ci-text-1`、`.l-secondary|.l2 → --ci-text-2`、`.l-instructive|.l3 → --ci-text-3`、`.l-decoration|.l4 → --ci-text-4`、`.l-inactive|.l5 → --ci-text-5`(`ClassIsland.Core/Themes/Layers.axaml:10-43`)。
|
||
|
||
#### 3.1.3 背景与表面色
|
||
|
||
| Token 名 | 亮色 | 深色 | 用途 | 建议 CSS 变量 | 源码证据 |
|
||
|---|---|---|---|---|---|
|
||
| `SolidBackgroundFillColorBaseBrush` | `#F3F3F3`【推断】 | `#202020`【推断】 | 经典主题岛背景、编辑模式窗口底、抽屉内容底、主题卡渐变底 | `--ci-bg-base` | `ClassicTheme/Styles.axaml:214`;`DrawerHost.axaml:29`;`MainWindow.axaml:188` |
|
||
| `SolidBackgroundFillColorSecondaryBrush` | `#EEEEEE`【推断】 | `#1C1C1C`【推断】 | Fluent 主题岛背景 | `--ci-bg-secondary` | `FluentTheme/Styles.axaml:45` |
|
||
| `SolidBackgroundFillColorTertiaryBrush` | `#F9F9F9`【推断】 | `#282828`【推断】 | 弹出层底(`.popup-bg`) | `--ci-bg-tertiary` | `StylesBase.axaml:291` |
|
||
| `ControlFillColorSecondaryBrush` | 半透明白/黑 | 同左 | 主题卡底色 | `--ci-fill-secondary` | `ThemesSettingsPage.axaml:149` |
|
||
| `SmokeFillColorDefaultBrush` | 半透明遮罩 | 同左 | 编辑模式窗口背景、抽屉忽略层 | `--ci-smoke` | `MainWindow.axaml:178`;`DrawerHost.axaml:20` |
|
||
| `Layer` 应用底色 | `#F3F3F3` | `#161719` | 设置中心/管理页页面底(沿用 ClassHelper) | `--ch-bg` | `ClassHelper/renderer/styles/index.css:27,114` |
|
||
| `Layer` 卡片底 | `rgba(255,255,255,.7)` | `rgba(32,33,36,.72)` | 应用外壳卡片 | `--ch-layer` | 同上 `:28,115` |
|
||
| `CustomBackgroundColor` | `#000000`(默认) | 同左 | 岛自定义背景色默认值 | `--ci-island-bg-custom` | `Settings.cs:34`、`Settings.cs:1129` |
|
||
|
||
主界面行的背景最终呈现必须叠加两个不透明度:
|
||
- 自定义背景色本身的不透明度:`--ci-island-bg-opacity`,默认 `0.5`(`Settings.cs:64`、`:1141`;Fluent 用 `MainWindowStylesAssist.BackgroundOpacity` 绑定到 `Border.Opacity`,见 `FluentTheme/Styles.axaml:44`);
|
||
- 整行不透明度:`MainWindowLineSettings.Opacity`,默认 `1.0`(`ClassIsland.Core/Models/Components/MainWindowLineSettings.cs:42`;`Controls/MainWindowLine.axaml:51`)。
|
||
- 鼠标移出淡化态:整行 `opacity = 0.05`(`Controls/MainWindowLine.axaml:73-75`)。
|
||
|
||
#### 3.1.4 描边与分隔线
|
||
|
||
| Token 名 | 值 | 用途 | 建议 CSS 变量 | 源码证据 |
|
||
|---|---|---|---|---|
|
||
| 岛描边 | 1px `ControlElevationBorderBrush` | 经典/Fluent 行背景描边 | `--ci-stroke-island` / 宽度 `--ci-stroke-island-w:1px` | `FluentTheme/Styles.axaml:46-47`;`ClassicTheme/Styles.axaml:61-65` |
|
||
| `ControlStrokeColorDefaultBrush` | 亮色半透明黑 | 编辑模式选中框描边 | `--ci-stroke-control` | `MainWindow.axaml:357` |
|
||
| `DividerStrokeColorDefaultBrush` | 亮色半透明黑 | 操作条分隔线(1px,长 25px) | `--ci-stroke-divider` | `MainWindow.axaml:610-612` |
|
||
| `SurfaceStrokeColorFlyoutBrush` | 半透明 | 弹窗描边 | `--ci-stroke-flyout` | `StylesBase.axaml:292` |
|
||
| `ControlStrongFillColorDefaultBrush` | 中灰 | OOBE 方块、Workflow 进度条底、Shimmer 底 | `--ci-fill-strong` | `OobeIntroAnimationControl.axaml:34`;`WorkflowProgressIndicatorItemControl.axaml:26`;`Shimmer.axaml:11` |
|
||
| 主题卡描边 | 1px `ControlElevationBorderBrush` | 主题网格卡片 | `--ci-stroke-card` | `ThemesSettingsPage.axaml:150-151` |
|
||
| 拖拽高亮描边 | 1px accent | 组件拖拽占位 | `--ci-stroke-drag` | `EditableComponentsListBox.axaml:310-311` |
|
||
| 教程高亮描边 | 2.5px(外框)/ 3px(四角) | 教程 spotlight | `--ci-stroke-tutorial` | `TutorialHighlightControl.axaml:96-118` |
|
||
|
||
#### 3.1.5 状态色
|
||
|
||
天气与空气质量状态色(浅色/深色两套,必须都实现):
|
||
|
||
| 语义 | 亮色 | 深色 | 建议 CSS 变量 | 源码证据 |
|
||
|---|---|---|---|---|
|
||
| AQI 1 优 | `ForestGreen`=`#228B22` | `MediumSeaGreen`=`#3CB371` | `--ci-aqi-1` | `LightTheme.axaml:10`;`DarkTheme.axaml:10` |
|
||
| AQI 2 良 | `#CCCC00` | `Yellow`=`#FFFF00` | `--ci-aqi-2` | `:11` |
|
||
| AQI 3 轻度 | `DarkOrange`=`#FF8C00` | `Orange`=`#FFA500` | `--ci-aqi-3` | `:12` |
|
||
| AQI 4 中度 | `IndianRed`=`#CD5C5C` | 同亮色 | `--ci-aqi-4` | `:13` |
|
||
| AQI 5 重度 | `DarkRed`=`#8B0000` | 同亮色 | `--ci-aqi-5` | `:14` |
|
||
| AQI 6 严重 | `Purple`=`#800080` | `MediumPurple`=`#9370DB` | `--ci-aqi-6` | `:15` |
|
||
| 雨天图标色 | `Blue`=`#0000FF` | `DeepSkyBlue`=`#00BFFF` | `--ci-weather-rain` | `LightTheme.axaml:3`;`DarkTheme.axaml:3` |
|
||
| 上课发光 | `DropShadowEffect` blur 6(亮)/2(暗),颜色 `#FFFF00` | 同左 | `--ci-glow-class` | `LightTheme.axaml:4-7`;`DarkTheme.axaml:4-7` |
|
||
| 危险/删除按钮 | `IndianRed`=`#CD5C5C` | 同左 | `--ci-danger` | `Themes/Generic.xaml:225-226,275-276`;`MainWindow.axaml:435` |
|
||
| 警告/错误图标 | `SystemFillColorCriticalBrush` / `SystemFillColorCautionBackgroundBrush` | 同左 | `--ci-warning-*` | `StylesBase.axaml:209,217`;`ThemesSettingsPage.axaml:343` |
|
||
|
||
#### 3.1.6 阴影与遮罩色(必须逐值实现)
|
||
|
||
| 用途 | 值 | 建议 CSS 变量 | 源码证据 |
|
||
|---|---|---|---|
|
||
| Fluent 岛投影 | `0 4 8 2 #48000000` | `--ci-shadow-island: 0 4px 8px 2px #48000000` | `FluentTheme/Styles.axaml:49` |
|
||
| 提醒遮罩时岛投影 | `0 8 32 0 #66000000` | `--ci-shadow-mask` | `FluentTheme/Styles.axaml:324,327` |
|
||
| 竖抽屉/遮罩卡投影 | `0 8 32 0 #66000000` | `--ci-shadow-drawer` | `VerticalDrawer.axaml:45` |
|
||
| 横抽屉内浮层投影 | `0 0 8 #33000000` | `--ci-shadow-drawer-x` | `DrawerHost.axaml:33` |
|
||
| 经典主题提醒时行投影 | `DropShadowEffect` BlurRadius=8, Opacity=1, Offset=0 | `--ci-shadow-classic-mask` | `ClassicTheme/Styles.axaml:283-287` |
|
||
| 时间线装饰器阴影 | `DropShadowEffect` opacity 0.4, blur 8 | `--ci-shadow-adorn` | `Themes/Generic.xaml:215-219` |
|
||
| 弹窗底渐变遮罩 | `#00ffffff`→(0.65)`#00ffffff`→(1)`#ffffffff` | `--ci-mask-fade` | `ThemesSettingsPage.axaml:162-169` |
|
||
| 教程聚光遮罩 | `#99000000`(60% 黑) | `--ci-scrim-tutorial` | `TutorialSpotlightControl.axaml:45-61` |
|
||
| 编辑模式调试叠加 | `#77222222` | `--ci-debug-bg` | `MainWindow.axaml:645` |
|
||
| 启动闪屏底 | `#88111111` + 1px `ControlStrokeColorOnAccentDefaultBrush` | `--ci-splash-bg` | `SplashWindow.axaml:24-28` |
|
||
| 主题卡渐变底 | 径向 `#ff0c0e1f`→`#ff0d1111`(关于页) | `--ci-brand-gradient-a/b` | `AboutSettingsPage.axaml:153-154` |
|
||
| 关于页正文底 | `#0d1111` | `--ci-brand-dark` | `AboutSettingsPage.axaml:131` |
|
||
| 通知涟漪默认填充 | `AccentFillColorDefaultBrush`(可被 `NotificationContent.Color` 覆盖) | `--ci-ripple` | `RippleEffect.axaml.cs:61`;`MainWindowLine.cs:750` |
|
||
| 通知涟漪描边宽 | 200(Ellipse StrokeThickness) | `--ci-ripple-stroke:200` | `RippleEffect.axaml:15` |
|
||
|
||
### 3.2 字体 Token
|
||
|
||
#### 3.2.1 字体族
|
||
|
||
| Token | 值 | 用途 | 建议 CSS 变量/写法 |
|
||
|---|---|---|---|
|
||
| `AppFont`(全局默认) | `HarmonyOS Sans SC, Microsoft YaHei UI, Noto Sans CJK SC, Noto Sans SC, PingFang SC, Source Han Sans SC, SimHei, WenQuanYi Micro Hei, sans-serif, FluentSystemIcons-Resizable` | 全应用默认字体 | `--ci-font: 'HarmonyOS Sans SC', 'Microsoft YaHei UI', 'Noto Sans CJK SC', 'Noto Sans SC', 'PingFang SC', 'Source Han Sans SC', SimHei, sans-serif` |
|
||
| `MainWindowFont`(岛字体,用户可改) | 默认等于 `DefaultFontFamilyKey`:`avares://ClassIsland/Assets/Fonts/#HarmonyOS Sans SC, ...FluentSystemIcons-Resizable` | 只作用于岛的 `ZoomBorder` 文本 | `--ci-font-island`(元素级覆盖) |
|
||
| `HarmonyOsSans`(旧键) | `HarmonyOS Sans SC, Microsoft YaHei UI, SimHei` | 旧样式/右键菜单 | 兼容别名 |
|
||
| `BackendFontFamily` | `Microsoft YaHei UI` | 后端渲染/图表兜底 | `--ci-font-backend` |
|
||
| 图标字体 1 | `FluentSystemIcons-Resizable`(`avares://ClassIsland.Core/Assets/Fonts/#FluentSystemIcons-Resizable`) | 全局 Fluent 图标 | `--ci-font-icon-fluent` |
|
||
| 图标字体 2 | `lucide`(`#lucide`) | Lucide 天气图标等 | `--ci-font-icon-lucide` |
|
||
| 图标字体 3 | `SF-Symbols`(`#SF-Symbols`) | SFSymbols 天气图标 | `--ci-font-icon-sf` |
|
||
|
||
证据:`ClassIsland/Assets/Fonts/Fonts.axaml:3`、`Assets/Fonts/Fonts.xaml:3`、`MainWindow.axaml.cs:185-189`、`App.axaml:48`、`ClassIsland.Core/AppBase.cs:142-152`、`ClassIsland.Core/ThemeBase.axaml:46-47`。
|
||
|
||
实现要求:
|
||
- 字体栈**必须按上表顺序**声明,任何一环缺失即回落下一位;不得只写 `HarmonyOS Sans SC`。
|
||
- 字体文件必须以本地资源打包,**禁止**运行时从网络加载字体(离线教室环境)。
|
||
- 图标字体与正文字体必须拆成两个 token,图标组件禁止继承正文字体族。
|
||
|
||
#### 3.2.2 字重
|
||
|
||
字重设置以整数保存,映射表必须逐值实现(`ClassIsland.Core/Converters/IntToFontWeightConverter.cs:16-28`):
|
||
|
||
| 数值 | 字重名 | CSS |
|
||
|---|---|---|
|
||
| 100 | Thin | 100 |
|
||
| 200 | ExtraLight | 200 |
|
||
| 300 | Light | 300 |
|
||
| 400 | Normal | 400 |
|
||
| 500 | Medium(**默认**) | 500 |
|
||
| 600 | SemiBold | 600 |
|
||
| 700 | Bold | 700 |
|
||
| 800 | ExtraBold | 800 |
|
||
| 900 | Black | 900 |
|
||
| 其他 | Normal | 400 |
|
||
|
||
默认字重来自 `Settings.cs:101`(`(int)FontWeight.Medium` = 500)。岛内绝大多数文字必须用 500(Medium),标题可用 700(Bold),说明文字用 400(Regular)。
|
||
|
||
4 档核心字号在设置页的输入范围均为 **1–40 px**(`AppearanceSettingsPage.axaml:482-533`,`NumberBox` 的 `Minimum=1`、`Maximum=40`)。实现时必须允许 1–40 的整数/小数输入,并在预览区用四行示例文字实时展示 4 档效果(源码「字号预览」tab:`AppearanceSettingsPage.axaml:570-591`)。
|
||
|
||
#### 3.2.3 字号阶梯(核心 4 档 + 扩展档)
|
||
|
||
核心 4 档是**用户可调**的「主界面字号」,默认值与用途如下(`Settings.cs:197-200`;`ClassIsland.Core/ThemeBase.axaml:32-35`;`Settings.cs:1209-1251`):
|
||
|
||
| Token | 默认 px | 用途 | 建议 CSS 变量 | 证据 |
|
||
|---|---|---|---|---|
|
||
| `MainWindowSecondaryFontSize` | 14 | 次要信息:天气副标题、日期星期、倒计时标签 | `--ci-fs-secondary` | `ThemeBase.axaml:32`;`WeatherComponent.axaml:261,294,296,305` |
|
||
| `MainWindowBodyFontSize` | 16 | 正文:课程名、时间、温度 | `--ci-fs-body` | `ThemeBase.axaml:33`;`MainWindow.axaml:313`;`CountDownComponent.axaml:65` |
|
||
| `MainWindowEmphasizedFontSize` | 18 | 强调:时钟、提醒主文案 | `--ci-fs-emphasized` | `ThemeBase.axaml:34`;`ClockComponent.axaml:14`;`TwoIconsMaskTemplate.axaml:14` |
|
||
| `MainWindowLargeFontSize` | 20 | 大号标题 | `--ci-fs-large` | `ThemeBase.axaml:35` |
|
||
|
||
扩展固定档(非用户设置,必须写死为 token 并说明来源):
|
||
|
||
| 字号 | 用途 | 建议 CSS 变量 | 证据 |
|
||
|---|---|---|---|
|
||
| 9 | 启动闪屏版本号(0.5 不透明度) | `--ci-fs-version` | `SplashWindow.axaml:86-87` |
|
||
| 12 | 主题卡作者名 | `--ci-fs-caption` | `ThemesSettingsPage.axaml:191` |
|
||
| 13 | 组件设置小字、ClassHelper 控件基准 | `--ci-fs-control-base` | `CountDownComponentSettingsControl.axaml:185-201`;`ClassHelper/renderer/styles/index.css:97` |
|
||
| 14 | 通用控件/次级标签 | `--ci-fs-label` | `MainWindow.axaml:406,452,497` |
|
||
| 16 | 主题卡名称、闪屏状态文字 | `--ci-fs-title` | `ThemesSettingsPage.axaml:188`;`SplashWindow.axaml:80` |
|
||
| 17 | 滚动提醒文字 | `--ci-fs-rolling` | `RollingTextTemplate.axaml:26` |
|
||
| 18 | OOBE 说明文字 | `--ci-fs-oobe-body` | `WelcomeWindowIntroControl.xaml:166` |
|
||
| 20 | 启动 logo 文字、导航标签 | `--ci-fs-brand` | `SplashWindow.axaml:56-58`;`StylesBase.axaml:118-123` |
|
||
| 22 | 天气温度/图标文字 | `--ci-fs-weather` | `WeatherComponent.axaml:86-175` |
|
||
| 32 | OOBE 大标题 | `--ci-fs-oobe-title` | `OobeIntroAnimationControl.axaml:69,87`;`WelcomePage.axaml:38` |
|
||
|
||
实现硬约束:
|
||
- 4 档核心字号必须由**用户设置驱动**,且必须能作用到「组件自身」与「单个主界面行」两个作用域:行级覆盖时把 4 个变量写到行根元素的 `style` 上;关闭行级覆盖时移除内联变量,回落 `:root`(`MainWindowCustomizableNodeHelper.cs:20-37`)。
|
||
- 缩放:所有字号乘以界面缩放 `--ci-scale`(默认 1.0),但**不得**用浏览器 zoom,必须用布局缩放以保持像素对齐(见 3.8)。
|
||
- 行高:源码未给出显式 `LineHeight`,建议正文 `line-height: 1.25`、说明文字 `1.6`【推断:依据 ClassHelper `theme.css:60-63` 的 `line-height:1.6` 与 ClassIsland 主界面 40px 行高/16px 字号的比值】。
|
||
|
||
### 3.3 圆角 Token
|
||
|
||
| Token | 默认值 | 用途 | 建议 CSS 变量 | 证据 |
|
||
|---|---|---|---|---|
|
||
| `RadiusX` / `RadiusY`(岛圆角) | `8`(UI 范围 `0–20`,步进 `0.5`,提示文案:调至最大时左右边缘为半圆) | 主界面行背景圆角;`SizeDoubleToCornerRadiusConverter` 以 `ConverterParameter=1.0` 直接取值(除以 1 即原值) | `--ci-radius-island: 8px` | `Settings.cs:183-184`、`:1187-1207`;`AppearanceSettingsPage.axaml:75-87`;`FluentTheme/Styles.axaml:48,91,124,160-168,252`;`SizeDoubleToCornerRadiusConverter.cs:12-18` |
|
||
| 行级自定义圆角 | `0`(关闭) | 单行覆盖圆角 | `--ci-radius-island-local` | `MainWindowLineSettings.cs:40-41` |
|
||
| 岛内容高度 | `40` | 所有行的容器高度(Fluent/Classic 同值) | `--ci-island-height: 40px` | `FluentTheme/Styles.axaml:65`;`ClassicTheme/Styles.axaml:16`;`MainWindowLine.axaml:16` |
|
||
| 弹窗圆角 | `6` | `.popup-bg`、编辑模式操作条 | `--ci-radius-popup: 6px` | `StylesBase.axaml:295`;`MainWindow.axaml:488,599` |
|
||
| 卡片圆角 | `4` | 设置项卡片、主题卡、Shimmer、时间线装饰器、OOBE 提示 | `--ci-radius-card: 4px` | `StylesBase.axaml:257-260`;`ThemesSettingsPage.axaml:152,161`;`Themes/Generic.xaml:214` |
|
||
| 控件圆角 | `4` | 按钮/输入框等 | `--ci-radius-control: 4px` | ClassHelper `index.css:52`;`theme.css:10` |
|
||
| 抽屉圆角 | `8 8 0 0` | 底部竖抽屉 | `--ci-radius-drawer: 8px 8px 0 0` | `VerticalDrawer.axaml:9` |
|
||
| 胶囊圆角 | `999` | 徽标、胶囊按钮 | `--ci-radius-pill: 999px` | `classic-island.css:308,454,541,694` |
|
||
| 圆形按钮 | `14`(28×28) | 主题卡安装按钮 | `--ci-radius-icon-btn: 14px` | `ThemesSettingsPage.axaml:246-249` |
|
||
| OOBE 大圆钮 | `24`(48×48) | 欢迎页「下一步」 | `--ci-radius-oobe-btn: 24px` | `WelcomePage.axaml:61-65` |
|
||
| 岛内小元素 | `0.5 × --ci-island-font` / `0.36 × --ci-island-font` | 岛内图标块 | 用 calc 派生 | `classic-island.css:388,403,476,502` |
|
||
|
||
实现硬约束:
|
||
- 岛圆角必须**四角同值**(源码把 `RadiusX` 同时传给宽高两个方向:`FluentTheme/Styles.axaml:31-34` 传两次 `RadiusX`),不得实现「椭圆圆角」。
|
||
- 圆角必须作用于「背景层」与「内容裁剪层」两层,且两层同值,否则内容会溢出圆角外(`FluentTheme/Styles.axaml:48,91,124,160-168`)。
|
||
- 若引入 ClassHelper 的连续圆角(squircle),必须保持 `SUPERELLIPSE_EXPONENT = 4.2`、每角 `CORNER_SEGMENTS = 14`、展开卡半径 `min(48*scale, w/2, h/2)` 不变(`ClassHelper/packages/desktop-client/src/island/squircle.ts:21,24,79-81`)。**默认实现必须用 CSS `border-radius`**(与 Avalonia `CornerRadius` 的直角圆弧一致,保证与 ClassIsland 逐像素相同);连续圆角只能由主题包显式启用(P2),不得作为默认岛外形。
|
||
|
||
### 3.4 间距 Token
|
||
|
||
| Token | 值 | 用途 | 建议 CSS 变量 | 证据 |
|
||
|---|---|---|---|---|
|
||
| 行内容左右内边距 | `12 0` | 岛内容区 `GridContentRoot.Margin` | `--ci-island-pad-x: 12px` | `FluentTheme/Styles.axaml:110`;`ClassicTheme/Styles.axaml:100` |
|
||
| 行内容最小宽度 | `20` | `MinWidth` | `--ci-island-min-w: 20px` | `FluentTheme/Styles.axaml:109` |
|
||
| 组件间距 | `6 0` | 每个 `ComponentPresenter.Margin`;**token 值取相邻间距 12px**(每个组件左右各 6px),供 `calc(var(--ci-component-gap) / 2)` 反推单侧 margin | `--ci-component-gap: 12px` | `MainWindow.axaml:396,546`;与 part 04 §4.4 对齐 |
|
||
| 行间距 | `5` | 多行堆叠 `StackPanel.Spacing`(用户设置) | `--ci-line-gap: 5px` | `Settings.cs:219`;`MainWindow.axaml:344` |
|
||
| 设置页容器 | `margin 12 12 18 12`;`max-width 960`;`spacing 4` | 设置页正文 | `--ci-settings-pad` / `--ci-settings-max-w: 960px` | `StylesBase.axaml:67-71`;`ThemeBase.axaml:37` |
|
||
| 组件设置容器 | `margin 4 0 4 12`;`max-width 960`;`spacing 4` | 子组件设置 | `--ci-component-settings-pad` | `StylesBase.axaml:73-77` |
|
||
| 弹窗内边距 | `12` | `.popup-bg` | `--ci-popup-pad: 12px` | `StylesBase.axaml:294` |
|
||
| 主题卡网格 | 单元高 `150`;目标宽 `328`;单元 `margin 2`;卡内 `padding 8` | 主题市场网格 | `--ci-theme-card-h: 150px`、`--ci-theme-card-w: 328px` | `ThemesSettingsPage.axaml:139-142,172` |
|
||
| 编辑模式操作条 | 底距 `64`;`padding 4`;按钮间距 `6` | 编辑态底部工具条 | `--ci-editbar-bottom: 64px` | `MainWindow.axaml:595-604` |
|
||
| 闪屏 | 尺寸 `400×100`;`padding 17`;logo 高 `24`;行距 `8`;底部进度条高 `4` | 启动闪屏 | `--ci-splash-w: 400px`、`--ci-splash-h: 100px` | `SplashWindow.axaml:16-17,24,29,42,92-96` |
|
||
| 岛内水平内边距(ClassHelper 风格) | `0.78 × 字号` | 岛胶囊左右内边距 | calc 派生 | `classic-island.css:215` |
|
||
| 进度条高度 | `3px` | 岛内倒计时/提醒进度条统一高度 | `--ci-progress-height: 3px` | 与 part 04 §4.4 对齐;源码进度条未显式设高(`FluentTheme/Styles.axaml:126-146`),取 FluentAvalonia ProgressBar 默认值【推断】 |
|
||
| 岛内元素间距(ClassHelper) | `0.62 × 字号` | 岛内行间距 | calc 派生 | `classic-island.css:212` |
|
||
|
||
### 3.5 透明与模糊 Token
|
||
|
||
| Token | 值 | 用途 | 建议实现 | 证据 |
|
||
|---|---|---|---|---|
|
||
| 主窗口透明级别 | `Transparent` | 非编辑态的岛窗口必须逐像素透明 | Electron `transparent: true` + `backgroundColor: '#00000000'` | `MainWindow.axaml:168-176` |
|
||
| 编辑模式透明级别 | `AcrylicBlur, Transparent`(回退 Transparent) | 编辑态窗口使用亚克力 | 只能用 CSS `backdrop-filter` 在自绘层模拟,**不得**用 `setBackgroundMaterial`(会破坏逐像素透明) | `MainWindow.axaml:177-181`;ClassHelper `island.ts:1726-1734` 明确禁止 |
|
||
| 普通窗口模式 | 若禁用透明则 `TransparencyLevelHint=None` | 窗口模式 | `transparent:false` | `MainWindow.axaml:187-190` |
|
||
| 闪屏透明 | `AcrylicBlur, Transparent` | 启动闪屏 | `backdrop-filter: blur(...)` + 半透明底 | `SplashWindow.axaml:21` |
|
||
| 岛背景不透明度 | `0.5`(默认范围 0–1,步进 0.05,滑块带数值气泡) | 背景层 opacity | `--ci-island-opacity`(主名;兼容别名 `--ci-island-bg-opacity`) | `Settings.cs:64,1141`;`AppearanceSettingsPage.axaml:61-72`;`FluentTheme/Styles.axaml:44` |
|
||
| 行整体不透明度 | `1.0`(行级设置,可被单行覆盖) | 行级 opacity | `--ci-line-opacity` | `MainWindowLineSettings.cs:42` |
|
||
| 鼠标移出淡化 | `0.05` | 悬停淡出模式 | `opacity:.05` | `MainWindowLine.axaml:73-75` |
|
||
| 提醒特效渲染缩放 | `1.0`;屏高 ≥1400 → `0.75`;≥2000 → `0.5`(自动时) | 强提醒涟漪窗口缩放 | `--ci-effect-scale` | `Settings.cs:150`;`MainWindow.axaml.cs:377-392` |
|
||
| 遮罩动画层级不透明度 | 0 → 1(0.1s) | 遮罩出现时附加投影 | `box-shadow` transition | `FluentTheme/Styles.axaml:355-367` |
|
||
|
||
硬规则:
|
||
- **不得**给岛卡片加 `backdrop-filter`(会把整块矩形模糊掉);模糊只允许出现在「编辑模式窗口背景」与「闪屏底」这两个整窗层。
|
||
- 岛必须是「透明窗口 + 自绘圆角卡片」,卡片外区域完全透明、可点击穿透(与 ClassHelper 一致,见 `island.ts:250-257`)。
|
||
|
||
### 3.6 层级(z-index)Token
|
||
|
||
| 层 | 数值 | 用途 | 建议 CSS 变量 | 证据 |
|
||
|---|---|---|---|---|
|
||
| 窗口层级-底层 | `WindowLayer=0` | 岛沉到桌面层(`Bottommost`),仅提醒/编辑时置顶 | `--ci-z-window:0` | `Settings.cs:52`;`MainWindow.axaml.cs:843-874` |
|
||
| 窗口层级-置顶 | `WindowLayer=1`(默认) | 岛始终置顶 | `--ci-z-window-top:1` | 同上;默认值 `Settings.cs:52` |
|
||
| 岛内容层 | 0 | 正常内容 | — | — |
|
||
| 遮罩/覆盖层 | 1 | 内容之上、背景之下 | `--ci-z-mask:1` | `FluentTheme/Styles.axaml:155-197` |
|
||
| 拖拽占位 | `1`(且 opacity .5) | 编辑态拖动项 | `--ci-z-drag:1` | `MainWindow.axaml:478-481` |
|
||
| 时间线装饰器 | `9999` | 分割线/行动装饰器必须压住时间块 | `--ci-z-timeline-adorn:9999` | `Themes/Generic.xaml:193,243` |
|
||
| 「无穷大」哨兵 | `33550336` | 必须永远最前的元素(OOBE 方块、时间线提示、拖拽阈值) | `--ci-z-sentinel:33550336` | `OobeIntroAnimationControl.axaml:45`;`TimeLineListControl.axaml:309`;`MainWindow.axaml:334` |
|
||
| 提醒特效窗口 | 独立 Topmost 窗口 | 全屏涟漪,高于一切 | 独立 BrowserWindow `alwaysOnTop` | `Views/TopmostEffectWindow.axaml.cs:120-128` |
|
||
| 教程聚光灯 | 独立置顶窗口 | 遮罩挖洞 | 独立窗口 | `Controls/Tutorial/TutorialSpotlightControl.axaml:41` |
|
||
| 抽屉遮罩 | 覆盖内容 | 横/竖抽屉 | `--ci-z-drawer:10`【推断】 | `DrawerHost.axaml`、`VerticalDrawer.axaml` |
|
||
| 应用外壳引导层 | `10000` | 全屏引导 | `--ch-z-guide:10000` | `ClassHelper/packages/ui/src/theme.css:155` |
|
||
| 主题切换快照层 | 旧 `1` / 新 `2` | View Transition 两帧 | `--ch-z-view-old/new` | `ClassHelper/renderer/styles/index.css:948-954` |
|
||
|
||
实现必须满足:
|
||
- 岛内容、遮罩、覆盖层在同一「行」内按上表叠放;多行之间不重叠(`MainWindowLine` 的 `ClipToBounds=False`,行本身不裁剪)。
|
||
- `33550336` 是源码里反复使用的「无穷大」哨兵(同时被用作拖拽阈值 `HorizontalDragThreshold="33550336"` 表达「禁止横向拖动」,见 `MainWindow.axaml:334`)。实现时可直接用 `z-index: 2147483647` 代替,但**必须**在常量注释里保留原值语义。
|
||
- 编辑器/设置中心内任何弹窗、Tooltip 都必须高于主内容;不得用负 z-index 实现遮罩。
|
||
|
||
### 3.7 DPI 与缩放规则
|
||
|
||
| 规则 | 数值/算法 | 证据 |
|
||
|---|---|---|
|
||
| 界面缩放用户设置 | `Scale`,默认 `1.0`,UI 范围 `0.75–2.5`,步进 `0.05`(滑块带数值气泡,格式 `F2`) | `Settings.cs:86,1153`;`Views/SettingPages/AppearanceSettingsPage.axaml:27-39` |
|
||
| 缩放实现 | 用 `LayoutTransform`(布局缩放)+ `ScaleTransform`,同时作用于所有行;**不得**用 `transform: scale()` 直接缩放窗口内容(会模糊) | `MainWindow.axaml:250-265` |
|
||
| 编码缩放补偿 | `GridRootLeft = Width/10*(Scale-1)`、`GridRootTop = Height/10*(Scale-1)` | `MainWindow.axaml.cs:881-882,938-939` |
|
||
| 编辑模式缩放边界 | `MinZoom 0.5` / `MaxZoom 3` / `ZoomSpeed 1.2`,`EnableConstrains=True`,显示缩放指示 | `MainWindow.axaml:199-209` |
|
||
| 窗口尺寸换算 | 逻辑宽 = 物理宽 / `dpiX`;逻辑高 = (物理高 − 1) / `dpiY`(−1 防被误判全屏) | `MainWindow.axaml.cs:969-971` |
|
||
| 窗口定位 | 使用**物理像素** `PixelPoint`,不做 dpi 换算 | `MainWindow.axaml.cs:905-909` |
|
||
| 安全区(主题声明) | 竖直安全区 = 当前启用主题 `VerticalSafeAreaPx` 的最大值;Fluent 主题为 `20` | `Services/XamlThemeService.cs:111-135`;`App.Services.xaml.cs:314` |
|
||
| 教程运行时的安全区 | 主题安全区与 `150` 取大者 | `MainWindow.axaml.cs:898-902` |
|
||
| 通知特效窗口缩放 | `1 / dpiX` | `MainWindow.axaml.cs:929` |
|
||
| 鼠标命中判定 | 屏幕坐标与 `Bounds * dpi * Scale` 比较 | `Controls/MainWindowLine.cs:625-636` |
|
||
| 字体缩放(关怀模式,应用外壳) | `--ch-font-scale: 1`;关怀模式 `1.15`,只放大字号不动几何 | `ClassHelper/renderer/styles/index.css:103,973-979` |
|
||
| 岛内字号缩放(ClassHelper 模型) | 所有岛内尺寸由 `--island-font` 用 `calc()` 派生 | `classic-island.css:2-7,57` |
|
||
|
||
实现要求:
|
||
- 所有视觉常量必须定义在 96 DPI 的 CSS px 基准上,再由 `--ci-scale` 统一放大;不得为不同 DPI 写两套值。
|
||
- 多显示器:每行/每窗口使用「所在显示器」的 DPI 与工作区;切换显示器必须重新计算窗口尺寸与位置(`GetSelectedScreenSafe`,`MainWindow.axaml.cs:806-812`)。
|
||
- `Scale` 改变时必须重算窗口宽高与安全区,不能只改 CSS transform。
|
||
|
||
### 3.8 深浅色规则
|
||
|
||
| 规则 | 要求 | 证据 |
|
||
|---|---|---|
|
||
| 主题模式枚举 | `0=跟随系统`、`1=明亮`、`2=黑暗`;默认 `2`(黑暗) | `Settings.cs:32,979-989`;`Services/ThemeService.cs:53-59` |
|
||
| 跟随系统实现 | `themeVariant=Default` + `preferSystemTheme=true`;系统切换要实时响应 | `ThemeService.cs:53-63` |
|
||
| 资源覆盖机制 | Light/Dark 两套 ThemeDictionary,同名 key 覆盖:`RainyColorBrush`、`LuminousClass`、6 个 AQI、`CustomizedAccentBarBackground1Brush`、`TextFillColorInformativeSecondaryBrush` | `App.axaml:35-38`;`Themes/LightTheme.axaml`、`Themes/DarkTheme.axaml` |
|
||
| 自定义前景色优先级 | 用户自定义前景色 > 主题前景色;关闭时回落主题 | `ControlColorHelper.cs:20-52` |
|
||
| 自定义背景色优先级 | 用户自定义背景色 > 主题背景;关闭时回落 `SolidBackgroundFillColor*` | `FluentTheme/Styles.axaml:51-56`;`ClassicTheme/Styles.axaml:216-218` |
|
||
| 深色下的阴影 | 阴影颜色不变(黑),只调不透明度;**不得**在深色下把投影改成白色 | Fluent `#48000000`/`#66000000`/`#33000000` 与 `VerticalDrawer.axaml:47` 注释「Even in WinUI, shadow is always black regardless of light/dark mode」 |
|
||
| ClassHelper 深色底色 | 应用壳亮 `#F3F3F3`/暗 `#161719`;卡片 `rgba(255,255,255,.7)` / `rgba(32,33,36,.72)` | `renderer/styles/index.css:27-48,114-137` |
|
||
| 主题切换过渡 | 窗口 `Background` 用 200ms 过渡;整页换肤用圆形扩散 View Transition(320×1.5=480ms) | `MainWindow.axaml:40-44`;`ClassHelper/renderer/composables/motion.ts:226-235` |
|
||
|
||
实现禁止项:
|
||
- 禁止在组件里写死 `#fff`/`#000`;必须走 `--ci-text-*`。
|
||
- 禁止只做深色、不做亮色(两套必须同步验收)。
|
||
- 禁止在深色模式使用纯黑 `#000000` 作为岛背景(默认自定义背景色是黑,但必须靠 `--ci-island-bg-opacity` 降为 50% 并叠加主题描边,否则与桌面融为一体)。
|
||
|
||
### 3.9 ClassHelper 侧落点(实现映射表)
|
||
|
||
| 内容 | 落点文件 | 要求 |
|
||
|---|---|---|
|
||
| 应用外壳 token | `packages/ui/src/tokens.css` | 保留 `--ch-ui-*`,新增 `--ci-*` 只读引用 |
|
||
| 应用外壳主题 | `packages/ui/src/theme.css` | 把 `--ci-accent` 注入 `--el-color-primary` 系列,`color-mix` 派生 |
|
||
| 桌面端全局样式 | `packages/desktop-client/src/renderer/styles/index.css` | 在 `:root` 与 `html.dark` 中定义 `--ci-*` 的亮/暗值 |
|
||
| 岛渲染进程样式 | `src/island/classic-island.css`、`custom-island.css` | 定义 `--island-*` 与 `--wn-*`(`classic-island.css:60-82`) |
|
||
| 动效常量 | `packages/shared/src/motion.ts` + 桌面端/管理端 `composables/motion.ts` | 新增 token 只加在 shared;不得两端各抄一份(`motion.ts:14-16` 明确约束) |
|
||
| 设计常量的 TS 形态 | `packages/shared/src/constants.ts` | 输出 `CLASSISLAND_TOKENS` 常量对象,供窗口几何计算复用 |
|
||
|
||
### 3.10 落地顺序与常见错误
|
||
|
||
实现顺序必须严格如下,不得跳步:
|
||
|
||
1. 先在 `packages/shared/src/constants.ts` 建立常量对象(颜色、字号、圆角、间距、层级、DPI 基准),字段名与本节 token 名一一对应,导出为只读(`as const`)。
|
||
2. 在 `packages/ui/src/tokens.css` 的 `:root` 写入亮色值,在 `html.dark` 写入深色值;两处必须保持键集合完全一致,缺一个键都算不合格。
|
||
3. 在 `packages/desktop-client/src/renderer/styles/index.css` 引入 `--ci-*` 的桌面端覆盖(通知特效窗口、闪屏窗口等独立渲染入口要单独引入同一份 token)。
|
||
4. 在 `src/island/classic-island.css` 与 `custom-island.css` 里把 `--island-*` 映射到 `--ci-*`,禁止在岛样式里重新定义颜色字面量。
|
||
5. 最后才写组件;组件只允许消费 token。
|
||
|
||
常见错误(必须在实现时主动规避):
|
||
|
||
- 把「行级字号覆盖」写成给整个岛设置字号:这样改一行会连带改所有行,与源码作用域不符(源码把资源写在行控件自身,见 `MainWindowCustomizableNodeHelper.cs:20-26`)。
|
||
- 把 5 级前景色实现成「同一颜色的不同 `opacity` 属性」:`opacity` 会连带影响子元素与阴影,源码用的是颜色 alpha 通道(`ControlColorHelper.cs:24-33`),必须写进颜色值本身。
|
||
- 用 `filter: drop-shadow()` 代替 `box-shadow` 实现岛投影:`filter` 会新建渲染表面,开合时出现闪帧(ClassHelper `classic-island.css:114-120` 已记录该问题)。
|
||
- 在深色主题下把阴影改成 `rgba(0,0,0,.6)` 以外的颜色,或直接删除阴影:源码在两种主题下都用黑色阴影,只改透明度。
|
||
- 忘记「安全区」:Fluent 主题声明了 `20px` 竖直安全区,岛贴边时会空出这段距离(`App.Services.xaml.cs:314`、`XamlThemeService.cs:111-135`),漏实现会导致岛压住任务栏或屏幕边缘。
|
||
- 忘记 `Scale` 变化时重算窗口:只改 CSS 会导致点击热区与可见区域错位(源码在 `MainWindow.axaml.cs:876-931` 每次都重算 `Bounds` 与 `ActualClientBound`)。
|
||
- 把「编辑模式操作条」的层级设在岛内容之下:它必须浮在行内容之上,且底距 64px(`MainWindow.axaml:595`)。
|
||
|
||
### 3.11 验收标准
|
||
|
||
实现者必须逐条自查,全部通过才算完成本节:
|
||
|
||
1. **颜色**:全仓库(渲染进程 + 主进程 + shared)搜索,除 token 定义文件外不得出现 `#` 开头的颜色字面量;`grep -r "#[0-9a-fA-F]\{6\}"` 的命中只允许出现在 token 文件与主题包预览样式中。
|
||
2. **强调色**:修改 `--ci-accent` 一处,岛背景描边、提醒遮罩、进度条、按钮强调态、天气图标强调色**全部**同步变化,无残留默认蓝。
|
||
3. **5 级前景**:开启自定义前景色后,5 个 alpha 分别为 100%/85.5%/77.3%/52.9%/36.5%;关闭后 5 个变量被移除并回落。
|
||
4. **字号**:把 4 档字号分别改成 10/20/30/40,岛内所有文字按对应档位变化且不溢出 40px 行高外的容器;行级覆盖可只影响单行。
|
||
5. **圆角**:把 `--ci-radius-island` 从 8 改到 20,背景层与裁剪层同时变化,内容不溢出四角;其他卡片圆角不受影响。
|
||
6. **间距**:改 `--ci-island-pad-x` 与 `--ci-component-gap`,内容宽度变化后背景宽度动画仍正常(见 part 14)。
|
||
7. **透明**:非编辑态岛卡片外区域 100% 透明(用取色器/截图验证 alpha=0);编辑态出现亚克力底;全程不允许整窗材质导致卡片外出现色块。
|
||
8. **层级**:编辑态拖动项浮在其他项之上;提醒遮罩覆盖内容但低于右上角操作按钮(若有);`33550336` 哨兵元素永远最前。
|
||
9. **DPI**:在 100%/125%/150%/200% 四档缩放下,岛高度逻辑值恒为 40、圆角逻辑值恒为 8、文字不模糊;跨显示器拖动后重新计算,无半个像素的缝。
|
||
10. **深浅色**:Light/Dark 各截图对照,两类主题的 AQI 色、雨天色、说明文字 alpha 与上表一致;深色下阴影仍为黑色。
|
||
11. **CSS 变量唯一来源**:`--ci-*` 只在两处定义(`:root` 与 `html.dark`),组件内只引用不重定义(行级作用域覆盖除外)。
|
||
12. **字符集**:所有 token 名使用 kebab-case,前缀统一为 `ci-`;禁止出现 `--ci-primaryColor` 这类混合命名。
|