tool.xpcool.com/src/assets/styles/tdesign-theme.scss
夏犀麟 dd38aeaf38
All checks were successful
Build and Deploy (tool.xpcool.com) / build-and-deploy (push) Successful in 1m10s
feat(theme): 改版为清晰蓝卡片工作台并接管 UI 库尺度
主色青玉改宝石蓝,字号整体放大一档(正文 16px),
通过 --td-comp-* 与 --td-font-* 接管 TDesign 控件高度与文字,
修复 theme-mode 选择器权重不足导致深色变量被 UI 库覆盖的问题。
2026-09-14 23:54:53 +08:00

515 lines
20 KiB
SCSS
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.

/* ============================================================
* TDesign 主题控制层UI 库主题)
* ------------------------------------------------------------
* 本文件负责「控制 UI 库组件本身的色彩与风格」,分四件事:
* ① 色阶:品牌蓝 / 中性蓝灰 / 语义色的 10 级色板(我们的色,喂给 TDesign
* ② 语义角色:把 tokens.scss 的 --tk-* 映射到 TDesign 的 --td-*
* ③ 组件尺度:控件高度 / 内边距 / 字号 / 行高(本版为解决「控件太小」新增)
* ④ 组件级微调:卡片、输入框、按钮、弹层的外形修正
*
* 为什么这样做60+ 个工具页面里已有大量 t-card / t-button / t-input /
* t-select / t-tag全部改一遍既不现实也容易漏。TDesign 的组件样式
* 完全建立在 --td-* 变量之上(例如 .t-input.t-size-l 的高度取自
* var(--td-comp-size-xl)),所以改变量 = 全站组件改版,属最小风险改造。
*
* ⚠️ 三条必须遵守的约束(踩过坑):
* 1. 只覆盖 TDesign 真实存在的变量名。写错名字不会报错,只是静默不生效。
* 新增前请在 node_modules/tdesign-vue-next 的样式产物里确认。
* 2. --td-font-body-* 是复合变量size/line-height 简写),
* 所以放大字号时必须同步改 --td-font-size-* 与 --td-line-height-*
* 只改前者会出现「大字号被小行高挤住」的破版。
* 3. 尺度变量不要动 --td-size-N 阶梯本身(那是 TDesign 的原子刻度,
* 图标、徽标、间距都在用);只覆盖 --td-comp-size-* 一层。
*
* 命名桥接对应关系(速查):
* --tk-accent → --td-brand-color (按钮/主色底)
* --tk-accent-text → --td-text-color-brand (链接/图标色)
* --tk-bg → --td-bg-color-page
* --tk-surface → --td-bg-color-container
* --tk-border → --td-border-level-1-color
* ============================================================ */
/* ============================================================
* 浅色主题
* ============================================================ */
:root,
:root[theme-mode='light'] {
/* ---------- 品牌色阶宝石蓝1 最浅 → 10 最深) ---------- */
--td-brand-color-1: #eff4ff;
--td-brand-color-2: #dbe6fe;
--td-brand-color-3: #c0d4fe;
--td-brand-color-4: #96b6fd;
--td-brand-color-5: #6294fb;
--td-brand-color-6: #3b76f6;
--td-brand-color-7: #2563eb;
--td-brand-color-8: #1d4ed8;
--td-brand-color-9: #1e3fb0;
--td-brand-color-10: #1b3690;
/* ---------- 语义色阶 ---------- */
--td-success-color-1: #e6f7ee;
--td-success-color-2: #c9efdb;
--td-success-color-3: #98ddb9;
--td-success-color-4: #5ec592;
--td-success-color-5: #26a86d;
--td-success-color-6: #178a56;
--td-success-color-7: #0e6d43;
--td-success-color-8: #0a5233;
--td-success-color-9: #073a24;
--td-success-color-10: #042514;
--td-warning-color-1: #fdf3e3;
--td-warning-color-2: #f8e3c1;
--td-warning-color-3: #efcd96;
--td-warning-color-4: #e3b264;
--td-warning-color-5: #cf9433;
--td-warning-color-6: #b07a1f;
--td-warning-color-7: #8d5f14;
--td-warning-color-8: #6d480d;
--td-warning-color-9: #4f3308;
--td-warning-color-10: #342104;
--td-error-color-1: #fdeceb;
--td-error-color-2: #f9d3d1;
--td-error-color-3: #f0b0ac;
--td-error-color-4: #e2857f;
--td-error-color-5: #cc5a53;
--td-error-color-6: #ab403a;
--td-error-color-7: #8a2f2a;
--td-error-color-8: #6a211d;
--td-error-color-9: #4c1613;
--td-error-color-10: #320d0b;
/* ---------- 中性色阶蓝灰1 最浅 → 14 最深)
* 深浅两套主题共用同一条色阶:浅色主题取低号,深色主题取高号 ---------- */
--td-gray-color-1: #f4f6fb;
--td-gray-color-2: #eef2f9;
--td-gray-color-3: #e2e8f3;
--td-gray-color-4: #ccd7e8;
--td-gray-color-5: #b1bdd3;
--td-gray-color-6: #8f9cb4;
--td-gray-color-7: #6e7994;
--td-gray-color-8: #55617a;
--td-gray-color-9: #3d4759;
--td-gray-color-10: #2e3747;
--td-gray-color-11: #263147;
--td-gray-color-12: #1b2333;
--td-gray-color-13: #131926;
--td-gray-color-14: #0b0f18;
/* ---------- 语义角色 ---------- */
--td-brand-color: var(--tk-accent);
--td-brand-color-hover: var(--tk-accent-hover);
--td-brand-color-active: var(--tk-accent-active);
--td-brand-color-focus: var(--tk-accent-surface-strong);
--td-brand-color-disabled: #96b6fd;
--td-brand-color-light: var(--tk-accent-surface);
--td-brand-color-light-hover: var(--tk-accent-surface-strong);
--td-success-color: var(--td-success-color-5);
--td-success-color-hover: var(--td-success-color-4);
--td-success-color-active: var(--td-success-color-6);
--td-success-color-focus: var(--td-success-color-2);
--td-success-color-disabled: var(--td-success-color-3);
--td-success-color-light: var(--td-success-color-1);
--td-success-color-light-hover: var(--td-success-color-2);
--td-warning-color: var(--td-warning-color-5);
--td-warning-color-hover: var(--td-warning-color-4);
--td-warning-color-active: var(--td-warning-color-6);
--td-warning-color-focus: var(--td-warning-color-2);
--td-warning-color-disabled: var(--td-warning-color-3);
--td-warning-color-light: var(--td-warning-color-1);
--td-warning-color-light-hover: var(--td-warning-color-2);
--td-error-color: var(--td-error-color-5);
--td-error-color-hover: var(--td-error-color-4);
--td-error-color-active: var(--td-error-color-6);
--td-error-color-focus: var(--td-error-color-2);
--td-error-color-disabled: var(--td-error-color-3);
--td-error-color-light: var(--td-error-color-1);
--td-error-color-light-hover: var(--td-error-color-2);
/* ---------- 背景 ---------- */
--td-bg-color-page: var(--tk-bg);
--td-bg-color-container: var(--tk-surface);
--td-bg-color-container-hover: var(--tk-surface-hover);
--td-bg-color-container-active: var(--tk-surface-active);
--td-bg-color-container-select: var(--tk-surface-raised);
--td-bg-color-secondarycontainer: var(--tk-surface-sunken);
--td-bg-color-secondarycontainer-hover: var(--tk-surface-hover);
--td-bg-color-secondarycontainer-active: var(--tk-surface-active);
--td-bg-color-component: var(--tk-surface-sunken);
--td-bg-color-component-hover: var(--tk-surface-hover);
--td-bg-color-component-active: var(--tk-border-strong);
--td-bg-color-component-disabled: var(--tk-surface-sunken);
--td-bg-color-secondarycomponent: var(--tk-surface-hover);
--td-bg-color-secondarycomponent-hover: var(--tk-surface-active);
--td-bg-color-secondarycomponent-active: var(--tk-border-strong);
--td-bg-color-specialcomponent: var(--tk-surface-raised);
/* 遮罩:用带色相的深色,避免死黑 */
--td-mask-active: rgba(9, 15, 32, 0.55);
--td-mask-disabled: rgba(255, 255, 255, 0.6);
--td-mask-background: var(--tk-surface);
/* ---------- 文字 ---------- */
--td-text-color-primary: var(--tk-text);
--td-text-color-secondary: var(--tk-text-secondary);
--td-text-color-placeholder: var(--tk-text-placeholder);
--td-text-color-disabled: #b1bdd3;
--td-text-color-anti: var(--tk-text-on-accent);
--td-text-color-brand: var(--tk-accent-text);
--td-text-color-link: var(--tk-accent-text);
--td-text-color-watermark: rgba(15, 23, 41, 0.08);
/* ---------- 描边 ---------- */
--td-border-level-1-color: var(--tk-border);
--td-component-stroke: var(--tk-border);
--td-border-level-2-color: var(--tk-border-strong);
--td-component-border: var(--tk-border-strong);
/* ---------- 圆角:统一收口为 --tk-radius-* ---------- */
--td-radius-small: var(--tk-radius-sm);
--td-radius-default: var(--tk-radius-md);
--td-radius-medium: var(--tk-radius-lg);
--td-radius-large: var(--tk-radius-xl);
--td-radius-extraLarge: var(--tk-radius-2xl);
--td-radius-round: var(--tk-radius-pill);
--td-radius-circle: 50%;
/* ---------- 阴影:带背景色相的冷调投影 ---------- */
--td-shadow-1: var(--tk-shadow-1);
--td-shadow-2: var(--tk-shadow-2);
--td-shadow-3: var(--tk-shadow-3);
--td-shadow-inset-top: inset 0 0.5px 0 var(--tk-border);
--td-shadow-inset-right: inset 0.5px 0 0 var(--tk-border);
--td-shadow-inset-bottom: inset 0 -0.5px 0 var(--tk-border);
--td-shadow-inset-left: inset -0.5px 0 0 var(--tk-border);
--td-table-shadow-color: rgba(15, 23, 41, 0.08);
/* ---------- 滚动条 ---------- */
--td-scrollbar-color: rgba(15, 23, 41, 0.18);
--td-scrollbar-hover-color: rgba(15, 23, 41, 0.34);
--td-scroll-track-color: transparent;
/* ---------- 字体 ---------- */
--td-font-family: var(--tk-font-sans);
--td-font-family-medium: var(--tk-font-sans);
}
/* ============================================================
* 深色主题
* ============================================================ */
:root[theme-mode='dark'] {
/* ---------- 品牌色阶(深色下 1 最深 → 10 最浅) ---------- */
--td-brand-color-1: #16244d;
--td-brand-color-2: #1a2d63;
--td-brand-color-3: #1e377c;
--td-brand-color-4: #234298;
--td-brand-color-5: #2a4fb5;
--td-brand-color-6: #3059d6;
--td-brand-color-7: #2563eb;
--td-brand-color-8: #4a80f5;
--td-brand-color-9: #7aa8ff;
--td-brand-color-10: #b3ccff;
/* ---------- 语义色阶 ---------- */
--td-success-color-1: #06291a;
--td-success-color-2: #07341f;
--td-success-color-3: #0a4429;
--td-success-color-4: #0c5533;
--td-success-color-5: #0e6a3f;
--td-success-color-6: #11804c;
--td-success-color-7: #199a5d;
--td-success-color-8: #2cb673;
--td-success-color-9: #52cf94;
--td-success-color-10: #86e0b6;
--td-warning-color-1: #342104;
--td-warning-color-2: #452c07;
--td-warning-color-3: #59380b;
--td-warning-color-4: #6f4610;
--td-warning-color-5: #8a5717;
--td-warning-color-6: #a76b1f;
--td-warning-color-7: #c48529;
--td-warning-color-8: #dda044;
--td-warning-color-9: #eebb6f;
--td-warning-color-10: #f6d79c;
--td-error-color-1: #320d0b;
--td-error-color-2: #43120f;
--td-error-color-3: #571713;
--td-error-color-4: #6c1e18;
--td-error-color-5: #83261f;
--td-error-color-6: #9d342b;
--td-error-color-7: #ba473c;
--td-error-color-8: #d26155;
--td-error-color-9: #e58377;
--td-error-color-10: #f2aca4;
/* ---------- 语义角色 ----------
* 注意:深色下按钮底保持 #2563eb与白字 5.17:1
* 而链接/图标另用更亮的 --tk-accent-text 保证在深底上可读。 */
--td-brand-color: var(--tk-accent);
--td-brand-color-hover: var(--tk-accent-hover);
--td-brand-color-active: var(--tk-accent-active);
--td-brand-color-focus: var(--tk-accent-surface-strong);
--td-brand-color-disabled: #1e377c;
--td-brand-color-light: var(--tk-accent-surface);
--td-brand-color-light-hover: var(--tk-accent-surface-strong);
--td-success-color: var(--td-success-color-8);
--td-success-color-hover: var(--td-success-color-9);
--td-success-color-active: var(--td-success-color-7);
--td-success-color-focus: var(--td-success-color-2);
--td-success-color-disabled: var(--td-success-color-3);
--td-success-color-light: var(--td-success-color-1);
--td-success-color-light-hover: var(--td-success-color-2);
--td-warning-color: var(--td-warning-color-8);
--td-warning-color-hover: var(--td-warning-color-7);
--td-warning-color-active: var(--td-warning-color-6);
--td-warning-color-focus: var(--td-warning-color-2);
--td-warning-color-disabled: var(--td-warning-color-3);
--td-warning-color-light: var(--td-warning-color-1);
--td-warning-color-light-hover: var(--td-warning-color-2);
--td-error-color: var(--td-error-color-8);
--td-error-color-hover: var(--td-error-color-7);
--td-error-color-active: var(--td-error-color-6);
--td-error-color-focus: var(--td-error-color-2);
--td-error-color-disabled: var(--td-error-color-3);
--td-error-color-light: var(--td-error-color-1);
--td-error-color-light-hover: var(--td-error-color-2);
/* ---------- 背景 ---------- */
--td-bg-color-page: var(--tk-bg);
--td-bg-color-container: var(--tk-surface);
--td-bg-color-container-hover: var(--tk-surface-hover);
--td-bg-color-container-active: var(--tk-surface-active);
--td-bg-color-container-select: var(--tk-surface-raised);
--td-bg-color-secondarycontainer: var(--tk-surface-sunken);
--td-bg-color-secondarycontainer-hover: var(--tk-surface-hover);
--td-bg-color-secondarycontainer-active: var(--tk-surface-active);
--td-bg-color-component: var(--tk-surface-sunken);
--td-bg-color-component-hover: var(--tk-surface-hover);
--td-bg-color-component-active: var(--tk-surface-active);
--td-bg-color-component-disabled: var(--tk-surface-sunken);
--td-bg-color-secondarycomponent: var(--tk-surface-hover);
--td-bg-color-secondarycomponent-hover: var(--tk-surface-active);
--td-bg-color-secondarycomponent-active: var(--tk-border-strong);
--td-bg-color-specialcomponent: var(--tk-surface-raised);
--td-mask-active: rgba(0, 0, 0, 0.72);
--td-mask-disabled: rgba(19, 25, 38, 0.6);
--td-mask-background: var(--tk-surface);
/* ---------- 文字 ---------- */
--td-text-color-primary: var(--tk-text);
--td-text-color-secondary: var(--tk-text-secondary);
--td-text-color-placeholder: var(--tk-text-placeholder);
--td-text-color-disabled: #55617a;
--td-text-color-anti: var(--tk-text-on-accent);
--td-text-color-brand: var(--tk-accent-text);
--td-text-color-link: var(--tk-accent-text);
--td-text-color-watermark: rgba(233, 238, 248, 0.1);
/* ---------- 描边 ---------- */
--td-border-level-1-color: var(--tk-border);
--td-component-stroke: var(--tk-border);
--td-border-level-2-color: var(--tk-border-strong);
--td-component-border: var(--tk-border-strong);
/* ---------- 圆角 / 阴影 / 滚动条 / 字体 ---------- */
--td-radius-small: var(--tk-radius-sm);
--td-radius-default: var(--tk-radius-md);
--td-radius-medium: var(--tk-radius-lg);
--td-radius-large: var(--tk-radius-xl);
--td-radius-extraLarge: var(--tk-radius-2xl);
--td-radius-round: var(--tk-radius-pill);
--td-radius-circle: 50%;
--td-shadow-1: var(--tk-shadow-1);
--td-shadow-2: var(--tk-shadow-2);
--td-shadow-3: var(--tk-shadow-3);
--td-shadow-inset-top: inset 0 0.5px 0 var(--tk-border);
--td-shadow-inset-right: inset 0.5px 0 0 var(--tk-border);
--td-shadow-inset-bottom: inset 0 -0.5px 0 var(--tk-border);
--td-shadow-inset-left: inset -0.5px 0 0 var(--tk-border);
--td-table-shadow-color: rgba(0, 0, 0, 0.3);
--td-scrollbar-color: rgba(233, 238, 248, 0.18);
--td-scrollbar-hover-color: rgba(233, 238, 248, 0.34);
--td-scroll-track-color: transparent;
--td-font-family: var(--tk-font-sans);
--td-font-family-medium: var(--tk-font-sans);
}
/* ============================================================
* ③ UI 库组件尺度控制(本版新增,解决「控件太小」)
* ------------------------------------------------------------
* 与主题无关,因此三个选择器都要写(且必须用 :root[theme-mode=...] 这一
* 与 TDesign 同级权重的写法,否则会被 UI 库自身的深色变量盖掉):
* 直接改 --td-size-* 会连带影响图标/徽标,所以只覆盖 --td-comp-* 一层。
*
* 放大前后对照TDesign 默认 → 本版):
* 默认输入框/按钮/下拉 32px → 40px
* 大号控件 40px → 48px
* 小号控件 24px → 28px
* 控件文字 14px → 16px与正文同号读起来不再「小一号」
* ============================================================ */
/* ============================================================
* 深色主题的中性色阶(补在主题块之外,便于与尺度控制放在一起)
* ------------------------------------------------------------
* TDesign 在深色下使用「反向灰阶」1 最深 → 14 最浅),
* 不覆盖的话组件会退回 UI 库自带的冷灰,与本主题的蓝灰体系脱节。
* ============================================================ */
:root[theme-mode='dark'] {
--td-gray-color-1: #0b0f18;
--td-gray-color-2: #131926;
--td-gray-color-3: #1b2333;
--td-gray-color-4: #222c3f;
--td-gray-color-5: #263147;
--td-gray-color-6: #35415c;
--td-gray-color-7: #4a5670;
--td-gray-color-8: #6e7994;
--td-gray-color-9: #8f9cb4;
--td-gray-color-10: #b1bdd3;
--td-gray-color-11: #ccd7e8;
--td-gray-color-12: #e2e8f3;
--td-gray-color-13: #eef2f9;
--td-gray-color-14: #f4f6fb;
}
:root,
:root[theme-mode='light'],
:root[theme-mode='dark'] {
/* ---------- 控件高度阶梯 ---------- */
--td-comp-size-xxxs: 18px; /* 复选框、小圆点 */
--td-comp-size-xxs: 24px; /* 小号控件t-tag / 紧凑按钮) */
--td-comp-size-xs: 28px;
--td-comp-size-s: 32px;
--td-comp-size-m: 40px; /* ★ 默认控件:输入框 / 按钮 / 下拉 / 日期选择 */
--td-comp-size-l: 44px;
--td-comp-size-xl: 48px; /* large 尺寸输入框、下拉触发框 */
--td-comp-size-xxl: 52px;
--td-comp-size-xxxl: 60px;
/* ---------- 控件内边距:随高度同步放宽,否则大控件里的文字会贴边 ---------- */
--td-comp-paddingTB-xxs: 4px;
--td-comp-paddingTB-xs: 6px;
--td-comp-paddingTB-s: 8px;
--td-comp-paddingTB-m: 12px;
--td-comp-paddingTB-l: 14px;
--td-comp-paddingTB-xl: 20px;
--td-comp-paddingLR-xxs: 6px;
--td-comp-paddingLR-xs: 8px;
--td-comp-paddingLR-s: 12px;
--td-comp-paddingLR-m: 16px;
--td-comp-paddingLR-l: 20px;
--td-comp-paddingLR-xl: 28px;
/* ---------- 字号:控件文字提到 16px与正文同号 ---------- */
--td-font-size-body-small: 13px;
--td-font-size-body-medium: 16px;
--td-font-size-body-large: 17px;
--td-font-size-title-small: 16px;
--td-font-size-title-medium: 18px;
--td-font-size-title-large: 20px;
--td-font-size-link-small: 13px;
--td-font-size-link-medium: 15px;
--td-font-size-link-large: 17px;
--td-font-size-mark-small: 13px;
--td-font-size-mark-medium: 15px;
/* ---------- 行高:必须与上面成对修改,否则大字号会被小行高挤住 ---------- */
--td-line-height-body-small: 22px;
--td-line-height-body-medium: 24px;
--td-line-height-body-large: 26px;
--td-line-height-title-small: 24px;
--td-line-height-title-medium: 28px;
--td-line-height-title-large: 30px;
--td-line-height-link-small: 22px;
--td-line-height-link-medium: 24px;
--td-line-height-link-large: 26px;
--td-line-height-mark-small: 22px;
--td-line-height-mark-medium: 24px;
}
/* ============================================================
* ④ 组件级微调(清晰蓝 · 卡片工作台)
* ------------------------------------------------------------
* 一条贯穿全站的原则:
* 内容容器(卡片/面板)→ 白底 + 细描边 + 轻投影,与页面底拉开层次
* 功能控件(输入框/按钮/下拉)→ 更实的描边 + 明确的聚焦反馈
* 本版与上一版最大的区别就在这里:卡片重新「有形」,不再是无框纸面。
* ============================================================ */
/* 卡片:轻投影 + 细描边hover 时抬到第二档阴影 */
.t-card {
border-radius: var(--tk-radius-xl);
box-shadow: var(--tk-shadow-1);
}
.t-card--bordered {
border-color: var(--tk-border);
box-shadow: none;
}
.t-card--shadow {
box-shadow: var(--tk-shadow-2);
}
.t-card__header {
font-weight: 620;
font-size: var(--tk-text-lg);
letter-spacing: var(--tk-track-title);
}
.t-card__title {
letter-spacing: var(--tk-track-title);
}
/* 卡片内边距放大一档;窄屏收回默认值,否则手机上内容可用宽度会不够 */
.t-card .t-card__body {
padding: var(--tk-space-5) var(--tk-space-6);
}
/* 输入框 / 文本域:聚焦时用主色描边 + 柔和外发光 */
.t-input__wrap,
.t-textarea__inner {
transition:
border-color var(--tk-dur-fast) var(--tk-ease-out),
box-shadow var(--tk-dur-fast) var(--tk-ease-out);
}
.t-is-focused .t-input__wrap,
.t-is-focused .t-textarea__inner {
box-shadow: 0 0 0 3px var(--tk-accent-ring);
}
/* 按钮:按压时轻微下沉,补足 TDesign 缺失的触感反馈 */
.t-button:not(.t-is-disabled):active {
transform: translateY(1px);
}
/* 下拉/选择器的选项行:默认行高偏挤,放大后一屏可见项变少但扫读更快 */
.t-select-option,
.t-dropdown__item {
font-size: var(--td-font-size-body-medium);
}
/* 弹层:统一使用较大的圆角与柔和阴影 */
.t-popup__content,
.t-dialog,
.t-drawer {
border-radius: var(--tk-radius-xl);
}
.t-dialog__header {
font-weight: 620;
letter-spacing: var(--tk-track-title);
}
/* 窄屏:大内边距在手机上会挤掉内容宽度,这里整体收回到常规密度 */
@media (max-width: 767px) {
.t-card .t-card__body {
padding: var(--tk-space-4);
}
}