mcpField
B
bootstrap-color-system

bootstrap-color-system

github.com/twbs设计与 UI175.0k362 次安装今天更新
代码仓库

关于 bootstrap-color-system

用于调整 Bootstrap 6 Sass 与 CSS 令牌系统的颜色 Skill,帮助开发者选择合适层级配置色板、语义主题、颜色模式和运行时样式。

主要功能

  1. 01配置 OKLCH 色相与色阶
  2. 02映射语义主题角色
  3. 03自定义明暗模式
  4. 04运行时覆盖 CSS 变量
  5. 05生成颜色工具类

适用场景

  1. 01调整 Bootstrap 品牌色板
  2. 02添加语义主题颜色
  3. 03设置页面或租户专属颜色
  4. 04验证颜色令牌与对比度

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/twbs/bootstrap --skill bootstrap-color-system

安装后在 Claude Code 中输入/bootstrap-color-system确认已加载。

详细介绍

Bootstrap 6 颜色系统

Bootstrap 6 的颜色遵循固定的处理流程:少数几个 oklch() 色相生成完整色阶,其中一部分色阶获得语义角色,组件读取这些角色,而不是色相。自定义颜色时,需要选择正确的层进行修改,因此请先确定你的任务属于哪一层。

工作流

  • 第 1 步:找到需要修改的层
  • 第 2 步:基础色相和色阶
  • 第 3 步:主题颜色
  • 第 4 步:用于背景、前景和边框的层颜色
  • 第 5 步:颜色模式
  • 第 6 步:编译时覆盖
  • 第 7 步:运行时覆盖
  • 第 8 步:函数和工具
  • 第 9 步:验证

第 1 步:找到需要修改的层

以下是处理流程及各阶段对应的文件:

  1. 基础色相 — scss/_colors.scss 将 16 个色相定义为 oklch() 标量,并将它们收集到 $colors 中。
  2. 颜色色阶 — 同一文件使用 color-mix() 从每个色相派生出 025–975 各级,并将 --blue-500、--red-200 等输出到 :root 中。
  3. 主题颜色 — scss/_theme.scss 将语义名称(primary、danger 等)逐一映射到这些色阶令牌。
  4. 根令牌 — scss/_root.scss 将每个主题角色输出为 --<name>-<role>(--danger-bg-subtle),并输出层颜色令牌。
  5. 主题类 — scss/helpers/_theme-colors.scss 在 @layer helpers 中输出 .theme-<name>,将 --<name>-<role> 重新映射到通用的 --theme-<role>。
  6. 组件和工具 — 读取 --theme-*(并使用中性色作为回退值)和层令牌。没有任何内容会读取原始色相。

根据任务选择对应的层:更换品牌蓝属于第 1 阶段,新增语义颜色属于第 3 阶段,调整单个组件的样式需要修改组件令牌(参见 bootstrap-component 技能),而应用中的临时调整则应使用运行时 CSS 变量覆盖。


第 2 步:基础色相和色阶

每个色相都是一个为 500 级提供基准的 oklch() 值:

$blue: oklch(60% 0.24 240) !default;

这 16 个色相分别是蓝色、靛蓝、紫罗兰色、紫色、粉色、红色、橙色、琥珀色、黄色、黄绿色、绿色、蓝绿色、青色、棕色、灰色和铅灰色,另有 $white 和 $black。$colors 通过 defaults() 收集这些颜色,因此映射会进行合并,而不是替换。

色阶是自动生成的,而非手工挑选。每个色相的 025 050 100 200 300 400 级会与 $tint-color(var(--white))混合,600 700 800 900 950 975 级则会与 $shade-color(var(--black))混合,使用 $color-mix-space 指定的颜色空间(lab)。修改一个色相,就会重新派生出它的整套色阶。

向 $colors 合并新色相,即可自动获得完整色阶,以及基于 $colors 构建的所有颜色工具:

@use "bootstrap/scss/bootstrap" with (
  $colors: (
    "slate": oklch(55% 0.04 250),
  )
);

色调和阴影百分比($color-tints、$color-shades)、混合空间以及混合目标,都可以用相同方式配置。也可以通过 $color-tokens 覆盖单个级别。

刻意使用 var(--white) / var(--black) 进行混合:这样可以让 color-mix() 保留在输出中,而不会被 CSS 压缩器简化为静态的 lab() 值。


第 3 步:主题颜色

scss/_theme.scss 中的 $theme-colors 定义了八种语义颜色——primary、accent、success、danger、warning、info、inverse、secondary——每种颜色都是一个包含九种角色的嵌套映射:

角色用途
base派生其余颜色的原始品牌色
bg纯色背景,例如纯色按钮或徽章
bg-subtle用于警告、浅色按钮和提示框的淡色表面
bg-muted比浅色表面再深一级
fg浅色表面上的文本
fg-emphasis浅色表面上对比度更高的文本
contrast位于 base / bg 上的文本和图标
border浅色表面上的边框
focus-ring焦点轮廓颜色

大多数角色都是 light-dark(…) 配对值,并且每个值都是对色阶令牌的 var() 引用,而非字面颜色:

"danger": (
  "base": var(--red-500),
  "fg": light-dark(var(--red-600), var(--red-400)),
  "bg-subtle": light-dark(var(--red-100), var(--red-900)),
  "border": light-dark(var(--red-300), var(--red-600)),
  "contrast": var(--white)
),

该映射会生成两类内容::root, :host 上的 --danger-fg 类令牌,以及一个将这些令牌赋给通用 --theme-fg、--theme-bg-subtle 等变量的 .theme-danger 类。这种间接引用正是设计目的——组件只要基于 --theme-* 编写,就能通过一条规则支持所有当前和未来的颜色。

在嵌套子树上使用 .theme-reset,可将这些 --theme-* 令牌设为 initial,让子元素恢复为组件默认值。

primary、success 和 danger 键是必需的;其他代码(链接、焦点环、表单状态、已选中控件)会读取它们的令牌。重命名或删除这些键会导致构建失败。


第 4 步:用于背景、前景和边框的分层颜色

中性色表面不属于 $theme-colors。scss/_theme.scss 中的三个独立映射负责定义这些颜色:

  • $theme-bgs → --bg-body、--bg-1 至 --bg-4(对比度逐渐增强的表面),以及 --bg-white、--bg-black、--bg-transparent。
  • $theme-fgs → --fg-body、--fg-1 至 --fg-4(强调程度逐渐降低)。
  • $theme-borders → --border-body、--border-subtle、--border-muted、--border-emphasized。

将它们用作组件令牌中未应用主题时的回退值:var(--theme-bg-subtle, var(--bg-1))、var(--theme-border, var(--border-color))。请注意,--border-color 是 $root-tokens 中的独立全局令牌,是组件的默认边框颜色,与这组 --border-* 令牌不同。

与 $theme-colors 不同,这些映射都是扁平映射,因此可以轻松扩展,增加一个表面层级。所有四个映射都会通过 defaults() 合并,因此只需传入要更改的键。


第 5 步:颜色模式

Bootstrap 6 不会针对每种模式重新声明变量。每个自适应令牌都是一个 light-dark() 配对值,CSS 会根据继承的 color-scheme 进行解析:

  • :root, :host 设置 color-scheme: light dark,因此默认模式取决于操作系统的偏好。
  • [data-bs-theme="dark"] 和 [data-bs-theme="light"] 会在对应子树上设置 color-scheme,强制使用指定模式。它适用于任何元素,支持嵌套,且不需要 JavaScript。

因此,切换模式只需设置一个属性;编写自适应颜色时,只需使用 light-dark(),而无需编写深色模式覆盖代码块。

对于 light-dark() 无法处理的情况,有两个 mixin:

// Non-color values can't go through light-dark()
@include color-mode(dark, $root: true) {
  --shadow-strength: 2.4;
}

color-mode($mode, $root) 会遵循 $color-mode-type 配置,该配置默认为 "media-query"(生成 @media (prefers-color-scheme: …));将其设为 "data" 则改为生成 [data-bs-theme="…"] 选择器。color-scheme($name) 是普通的媒体查询封装,适用于始终需要使用媒体查询的情况。

自定义模式的工作方式相同:添加自己的 [data-bs-theme="blue"] 选择器,并在其中覆盖令牌。


步骤 6:编译时覆盖

通过 defaults() 构建的映射——$colors、$color-tokens、$root-tokens、$theme-colors、$theme-bgs、$theme-fgs、$theme-borders,以及每个组件的 $*-tokens——都会合并。只传入你要更改的键,传入 null 可移除某项。

嵌套的主题颜色映射会向下合并一层。要更改内置主题的某个角色,请传入该主题的整个子映射。部分子映射会替换该主题的其他角色。

调整现有主题颜色时,最简单的方法仍然是在下一层修改色相,这样所有派生值都会随之变化:

@use "bootstrap/scss/bootstrap" with (
  $blue: oklch(58% 0.21 250)
);

要添加或重新设置主题颜色的样式,请通过主入口传入部分 $theme-colors 映射。defaults() 会保留内置项。除非替换整个子映射,否则请保留 primary、success 和 danger:

@use "bootstrap/scss/bootstrap" with (
  $theme-colors: (
    "brand": (
      "base": var(--indigo-500),
      "fg": light-dark(var(--indigo-600), var(--indigo-400)),
      "fg-emphasis": light-dark(var(--indigo-800), var(--indigo-300)),
      "bg": var(--indigo-500),
      "bg-subtle": light-dark(var(--indigo-100), var(--indigo-900)),
      "bg-muted": light-dark(var(--indigo-200), var(--indigo-800)),
      "border": light-dark(var(--indigo-300), var(--indigo-600)),
      "focus-ring": light-dark(color-mix(in oklch, var(--indigo-500) 50%, var(--bg-body)), color-mix(in oklch, var(--indigo-500) 75%, var(--bg-body))),
      "contrast": var(--white)
    )
  )
);

如果你只想再添加一种主题颜色,而不需要工具类,可以跳过 Sass 配置,手动编写类。组件只依赖 --theme-* 令牌:

@layer helpers {
  .theme-brand {
    --theme-base: var(--purple-500);
    --theme-bg: var(--purple-500);
    --theme-bg-subtle: light-dark(var(--purple-100), var(--purple-900));
    --theme-fg: light-dark(var(--purple-600), var(--purple-400));
    --theme-border: light-dark(var(--purple-300), var(--purple-600));
    --theme-contrast: var(--white);
  }
}

这样,.theme-brand 就能用于所有支持主题的组件。代价是:工具类和 --brand-* 根令牌由 $theme-colors 生成,因此 .bg-brand 和 var(--brand-bg) 将不存在。


步骤 7:运行时覆盖

每个令牌都是 CSS 自定义属性,因此大多数颜色更改完全不需要重新编译:

/* Global — repeat on :host if you adopt the stylesheet in a shadow root */
:root,
:host {
  --bs-primary-bg-subtle: #eef2ff;
}

/* One subtree */
.marketing-hero {
  --bs-theme-bg-subtle: #eef2ff;
}

在 Sass 中,令牌名称不带前缀(例如 --primary-bg-subtle)。Bootstrap 的 dist 和 CDN CSS 会运行 PostCSS 来添加 --bs- 前缀,因此覆盖已发布的 CSS 时请使用 --bs-*,自行编译源码时则使用不带前缀的名称。

运行时覆盖适用于按页面或租户设置主题;编译时配置则用于更改系统的默认值。


步骤 8:函数和工具类

scss/_theme.scss 中的辅助函数用于跨颜色映射读取数据,主要用于生成工具类:

  • theme-color-values($role) — 返回颜色名称到该角色原始值的扁平映射。
  • theme-color-refs($role) — 与上面相同,但值为 var(--<name>-<role>) 引用。
  • theme-token-refs($map, $prefix) — 用于层级颜色映射的对应函数。
  • theme-opacity-values($var, $fallback) — 使用 color-mix() 与 transparent 混合生成的不透明度阶梯。

scss/_functions.scss 中的 color-contrast($background) 使用 WCAG 对比度算法,返回浅色、深色或黑色前景色。它适用于 Sass 颜色值,不适用于 var() 引用,因此用于构建时色板和生成的类;$theme-colors 中的 contrast 角色则用于运行时。

生成的工具类遵循角色名称:每种主题颜色都有 .fg-primary、.fg-emphasis-primary、.fg-contrast-primary、.bg-primary、.bg-subtle-primary、.bg-muted-primary、.border-primary 和 .border-subtle-primary。层级颜色也会生成同样的工具类(.bg-1 至 .bg-4、.fg-1 至 .fg-4、.border-subtle);不透明度则按 10 为步长,以数字阶梯应用于相同的类名,例如 .fg-50、.bg-70、.border-30。

如果你想为整个元素设置主题,而不是只重新着色某个属性,请改用 .theme-*。


步骤 9:验证

  1. 运行 npm run css-lint,然后运行 npm run css。
  2. 在编译后的 dist/css/bootstrap.css 中搜索预期的令牌(--bs-primary-bg-subtle、--bs-slate-500),确认它们已生成。
  3. 检查两种颜色模式:操作系统偏好设置、data-bs-theme="dark",以及其中嵌套的 data-bs-theme="light"。
  4. 验证所有新增主题颜色的对比度——至少检查两种模式下 bg 上的 contrast,以及 bg-subtle 上的 fg。
  5. 如果你在 $colors 或 $theme-colors 中添加或移除了条目,请确认生成的工具类和 .theme-* 类已相应更改,并确认 npm run docs-build 仍能通过(文档会根据这些映射渲染色板)。

评论

支持 Markdown