bootstrap-utility-api

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Bootstrap 6 utility API

Bootstrap 6 utility API

Every utility class Bootstrap ships is generated from one Sass map,
$utilities
. Each entry describes a family of classes — the property it sets, the values it accepts, and which variants to generate. Customizing utilities means editing that map, not writing CSS.
Bootstrap 自带的所有工具类都由一个 Sass 映射
$utilities
生成。每个条目描述了一类类族——其设置的属性、接受的值,以及要生成的变体。自定义工具类意味着编辑这个映射,而非编写 CSS。

Workflow

工作流程

  • Step 1: Understand how generation works
  • Step 2: Read a utility definition
  • Step 3: Add a utility
  • Step 4: Modify, rename, or remove a default utility
  • Step 5: Generate responsive, state, print, and dark variants
  • Step 6: Compose values with custom properties and advanced selectors
  • Step 7: Trim the generated CSS
  • Step 8: Add a utility to Bootstrap itself
  • Step 9: Verify

  • 步骤 1:理解生成原理
  • 步骤 2:解读工具类定义
  • 步骤 3:添加工具类
  • 步骤 4:修改、重命名或移除默认工具类
  • 步骤 5:生成响应式、状态、打印和深色模式变体
  • 步骤 6:使用自定义属性和高级选择器组合值
  • 步骤 7:精简生成的 CSS
  • 步骤 8:向 Bootstrap 本身添加工具类
  • 步骤 9:验证

Step 1: Understand how generation works

步骤 1:理解生成原理

scss/utilities/_api.scss
is the whole pipeline:
scss
@include generate-utility-at-properties($utilities);

@layer utilities {
  @include generate-utilities-loop($utilities, $breakpoints);
}
Three consequences worth knowing before you touch anything:
  • Utilities are the last cascade layer, so they win over component styles without needing
    !important
    . Only groups that opt in with
    important: true
    add it.
  • @property
    registration happens outside the layer.
    Every custom property a utility assigns (
    --bg
    ,
    --fg
    ,
    --bc
    ,
    --rounded-size
    , …) is registered with
    syntax: "*"; inherits: false
    , so applying
    .border-inverse
    doesn't leak its composed value into descendants. New utilities that assign custom properties get this automatically.
  • The map is configured on the
    config
    module, not
    bootstrap
    .
    $utilities
    is declared in
    scss/_config.scss
    and only populated in
    scss/_utilities.scss
    (which loads config with
    @use "config" as *
    ). Configuring the wrong module fails:
scss
// Does NOT work — "This variable was not declared with !default in the @used module."
@use "bootstrap/scss/bootstrap" with (
  $utilities: (…)
);

// Works — configure config first, then load Bootstrap
@use "bootstrap/scss/config" with (
  $utilities: (…)
);
@use "bootstrap/scss/bootstrap";
The same applies to any variable that lives in
_config.scss
(
$radius
,
$spacers
,
$breakpoints
,
$zindex-levels
). Variables declared in a partial that
bootstrap.scss
forwards —
$root-tokens
,
$colors
,
$blue
— can be configured on
bootstrap
directly.

scss/utilities/_api.scss
是整个生成流程的核心:
scss
@include generate-utility-at-properties($utilities);

@layer utilities {
  @include generate-utilities-loop($utilities, $breakpoints);
}
在进行任何修改之前,有三个要点值得了解:
  • 工具类位于最后一个级联层,因此无需
    !important
    就能覆盖组件样式。只有通过
    important: true
    显式开启的组才会添加
    !important
    。
  • @property
    注册在层之外进行。
    工具类分配的每个自定义属性(
    --bg
    、
    --fg
    、
    --bc
    、
    --rounded-size
    等)都会以
    syntax: "*"; inherits: false
    的规则注册,因此使用
    .border-inverse
    不会将其组合值泄漏到后代元素中。分配自定义属性的新工具类会自动获得此特性。
  • 映射是在
    config
    模块中配置的,而非
    bootstrap
    模块。
    $utilities
    在
    scss/_config.scss
    中声明,仅在
    scss/_utilities.scss
    中被填充(该文件通过
    @use "config" as *
    加载配置)。配置错误的模块会导致失败:
scss
// Does NOT work — "This variable was not declared with !default in the @used module."
@use "bootstrap/scss/bootstrap" with (
  $utilities: (…)
);

// Works — configure config first, then load Bootstrap
@use "bootstrap/scss/config" with (
  $utilities: (…)
);
@use "bootstrap/scss/bootstrap";
这同样适用于
_config.scss
中的所有变量(
$radius
、
$spacers
、
$breakpoints
、
$zindex-levels
)。而在
bootstrap.scss
转发的分部文件中声明的变量(如
$root-tokens
、
$colors
、
$blue
)可以直接在
bootstrap
模块上配置。

Step 2: Read a utility definition

步骤 2:解读工具类定义

A group is a map. The simplest form needs two keys:
scss
"overflow": (
  property: overflow,
  values: auto hidden visible scroll,
),
The full option set, as validated by
generate-utility()
:
KeyRequiredWhat it does
property
YesProperty name, space-separated list of names, or a map of property-to-value pairs
values
YesList (class suffix equals the value) or map (keys become suffixes; a
null
key omits the suffix)
class
NoClass name to use instead of the property name
selector
No
class
(default),
attr-starts
, or
attr-includes
child-selector
NoDescendant selector, wrapped in
:where()
for zero specificity
variables
NoCustom properties to emit — a map of static values, or a list that each receive the utility value
state
NoPseudo-class variants to generate, e.g.
hover focus
responsive
NoGenerate a class per breakpoint (default
false
)
print
NoGenerate
print:
-prefixed classes (default
false
)
dark
NoGenerate
dark:
-prefixed classes inside
prefers-color-scheme: dark
(default
false
)
important
NoAppend
!important
(default
false
)
enabled
NoSet
false
to suppress output while keeping the definition (default
true
)
The generator validates as it goes, which makes mistakes cheap to find: a missing
property
or
values
is a hard
@error
, a non-boolean
responsive
is a hard
@error
, and a misspelled key is a
@warn
listing the valid ones.

一个工具类组就是一个映射。最简单的形式需要两个键:
scss
"overflow": (
  property: overflow,
  values: auto hidden visible scroll,
),
完整的选项集(由
generate-utility()
验证)如下:
键是否必填作用
property
是属性名称、以空格分隔的名称列表,或属性-值对的映射
values
是列表(类后缀等于值)或映射(键作为后缀;
null
键表示省略后缀)
class
否替代属性名称使用的类名
selector
否可选值为
class
(默认)、
attr-starts
或
attr-includes
child-selector
否后代选择器,包裹在
:where()
中以实现零特异性
variables
否要输出的自定义属性——可以是静态值的映射,或每个都接收工具类值的列表
state
否要生成的伪类变体,例如
hover focus
responsive
否为每个断点生成一个类(默认
false
)
print
否生成带
print:
前缀的类(默认
false
)
dark
否在
prefers-color-scheme: dark
中生成带
dark:
前缀的类(默认
false
)
important
否追加
!important
(默认
false
)
enabled
否设置为
false
可在保留定义的同时禁止输出(默认
true
)
生成器会在运行过程中进行验证,因此错误很容易发现:缺少
property
或
values
会触发强制
@error
,
responsive
不是布尔值也会触发强制
@error
,而拼写错误的键会触发
@warn
并列出所有有效键。

Step 3: Add a utility

步骤 3:添加工具类

Your map is merged over Bootstrap's defaults, so pass only what's new:
scss
@use "bootstrap/scss/config" with (
  $utilities: (
    "cursor": (
      property: cursor,
      class: cursor,
      responsive: true,
      values: auto pointer grab,
    ),
  )
);
@use "bootstrap/scss/bootstrap";
That yields
.cursor-auto
,
.cursor-pointer
,
.cursor-grab
, plus
.sm:cursor-*
through
.2xl:cursor-*
.
Value shapes control the class names:
scss
// List — suffix is the value itself: .cursor-pointer
values: auto pointer grab,

// Map — keys become suffixes: .tint-brand
values: (brand: var(--purple-500), muted: var(--gray-200)),

// null key — no suffix at all: .shout
values: (null: uppercase),

你的映射会与 Bootstrap 的默认映射合并,因此只需传入新增的内容:
scss
@use "bootstrap/scss/config" with (
  $utilities: (
    "cursor": (
      property: cursor,
      class: cursor,
      responsive: true,
      values: auto pointer grab,
    ),
  )
);
@use "bootstrap/scss/bootstrap";
这会生成
.cursor-auto
、
.cursor-pointer
、
.cursor-grab
,以及从
.sm:cursor-*
到
.2xl:cursor-*
的响应式类。
值的形式决定了类名:
scss
// List — suffix is the value itself: .cursor-pointer
values: auto pointer grab,

// Map — keys become suffixes: .tint-brand
values: (brand: var(--purple-500), muted: var(--gray-200)),

// null key — no suffix at all: .shout
values: (null: uppercase),

Step 4: Modify, rename, or remove a default utility

步骤 4:修改、重命名或移除默认工具类

The merge is shallow: supplying an existing group key replaces that entire group. Overriding one option and omitting the rest fails loudly —
scss
// Errors: "Utility is missing required `property` key"
"overflow": (
  responsive: true,
  values: visible hidden scroll auto,
),
so copy the full definition from
scss/_utilities.scss
and add your change:
scss
@use "bootstrap/scss/config" with (
  $utilities: (
    // Make overflow responsive
    "overflow": (
      property: overflow,
      values: auto hidden visible scroll,
      responsive: true,
    ),
    // Remove a family entirely
    "width": null,
    // Rename .ms-* to v4-style .ml-*: drop the original, add a replacement
    "margin-start": null,
    "margin-start-alias": (
      property: margin-inline-start,
      class: ml,
      responsive: true,
      values: (0: 0, 1: var(--spacer-1), 2: var(--spacer-2), auto: auto),
    ),
  )
);
@use "bootstrap/scss/bootstrap";
Note the CSS tokens in that last group. The file configuring
config
can't read Bootstrap's Sass members —
$spacers
,
$negative-spacers
, and helpers like
map-merge-multiple()
aren't in scope yet — so restate values as CSS tokens (
var(--spacer-2)
, which tracks the spacer scale) or as literals.
To extend an existing family without copying its definition, register a new group that reuses the same
class
:
scss
"width-extra": (
  property: width,
  class: w,
  responsive: true,
  values: (10: 10%, 15: 15%),
),
This adds
.w-10
and
.w-15
next to Bootstrap's
.w-25
…
.w-100
, and is usually the better choice — it survives Bootstrap updates that change the original group.
Prefer
enabled: false
over
null
when you want the definition to stay visible in the map (useful in a shared config where the group is documented but intentionally off).

合并是浅合并:提供一个已有的组键会替换整个组。仅覆盖一个选项而省略其余选项会直接报错——
scss
// Errors: "Utility is missing required `property` key"
"overflow": (
  responsive: true,
  values: visible hidden scroll auto,
),
因此请从
scss/_utilities.scss
中复制完整定义,然后添加你的修改:
scss
@use "bootstrap/scss/config" with (
  $utilities: (
    // Make overflow responsive
    "overflow": (
      property: overflow,
      values: auto hidden visible scroll,
      responsive: true,
    ),
    // Remove a family entirely
    "width": null,
    // Rename .ms-* to v4-style .ml-*: drop the original, add a replacement
    "margin-start": null,
    "margin-start-alias": (
      property: margin-inline-start,
      class: ml,
      responsive: true,
      values: (0: 0, 1: var(--spacer-1), 2: var(--spacer-2), auto: auto),
    ),
  )
);
@use "bootstrap/scss/bootstrap";
注意最后一组中的 CSS 令牌。配置
config
的文件无法读取 Bootstrap 的 Sass 成员——
$spacers
、
$negative-spacers
以及
map-merge-multiple()
等辅助函数此时还不在作用域内——因此请将值重新表述为 CSS 令牌(如
var(--spacer-2)
,它会跟随间距尺度变化)或字面量。
要扩展现有类族而无需复制其定义,可以注册一个复用相同
class
的新组:
scss
"width-extra": (
  property: width,
  class: w,
  responsive: true,
  values: (10: 10%, 15: 15%),
),
这会在 Bootstrap 原有的
.w-25
到
.w-100
之外新增
.w-10
和
.w-15
,通常这是更好的选择——即使 Bootstrap 更新修改了原始组,这些扩展也能正常工作。
如果你希望定义在映射中保持可见(在共享配置中很有用,即该组有文档说明但被有意关闭),请优先使用
enabled: false
而非
null
。

Step 5: Generate responsive, state, print, and dark variants

步骤 5:生成响应式、状态、打印和深色模式变体

v6 uses prefixes, not infixes or suffixes. All four variant types compose with the base class name:
OptionGenerated classNotes
responsive: true
.md:cursor-pointer
One pass per key in
$breakpoints
; written
.md\:
in the CSS
state: hover focus
.hover:cursor-pointer
Selector is
.hover\:cursor-pointer:hover
print: true
.print:d-none
Wrapped in
@media print
dark: true
.dark:bg-black
Wrapped in
@media (prefers-color-scheme: dark)
responsive
and
state
stack, producing
.md:hover:cursor-pointer
. Each variant multiplies the generated CSS, so enable them per group rather than globally.

v6 版本使用前缀而非中缀或后缀。所有四种变体类型都与基类名组合:
选项生成的类说明
responsive: true
.md:cursor-pointer
为
$breakpoints
中的每个键生成一次;在 CSS 中写为
.md\:
state: hover focus
.hover:cursor-pointer
选择器为
.hover\:cursor-pointer:hover
print: true
.print:d-none
包裹在
@media print
中
dark: true
.dark:bg-black
包裹在
@media (prefers-color-scheme: dark)
中
responsive
和
state
可以叠加,生成
.md:hover:cursor-pointer
。每种变体都会使生成的 CSS 成倍增加,因此请按组启用它们,而非全局启用。

Step 6: Compose values with custom properties and advanced selectors

步骤 6:使用自定义属性和高级选择器组合值

Most color-ish utilities don't set the property directly. They assign a local custom property and then consume it, which is what makes opacity and composition work:
scss
"tint": (
  property: (
    "--tint": null,
    "background-color": var(--tint),
  ),
  class: tint,
  values: (brand: var(--purple-500)),
),
A
null
value in the property map means "receive the utility's value"; every other entry is emitted as written. The above generates:
css
.tint-brand {
  --tint: var(--purple-500);
  background-color: var(--tint);
}
Related mechanics:
  • variables
    emits extra custom properties. As a map, each gets a static value on every class in the group; as a list, each receives the utility's value.
  • Property maps plus map values. When
    property
    is a map and a
    values
    entry is itself a map keyed by property name, each property picks its own value — useful for a group that sets several related properties at different values.
  • selector: attr-starts
    /
    attr-includes
    targets
    [class^="…"]
    /
    [class*="…"]
    instead of a class, and requires a
    class
    key. Bootstrap uses it so
    .ratio-16x9
    can feed
    aspect-ratio
    through
    --ratio
    .
  • child-selector
    wraps the rule in
    :where()
    , e.g.
    :where(.stack-gap-1 > *)
    . Zero specificity means a child's own styles still win.
Custom property names are written unprefixed in Sass. Bootstrap's dist and CDN CSS run PostCSS to add
--bs-
, so compiling the source yourself keeps them unprefixed.

大多数颜色类工具类不会直接设置属性。它们会分配一个本地自定义属性然后再使用它,这就是透明度和组合效果得以实现的原因:
scss
"tint": (
  property: (
    "--tint": null,
    "background-color": var(--tint),
  ),
  class: tint,
  values: (brand: var(--purple-500)),
),
属性映射中的
null
值表示「接收工具类的值」;其他所有条目都会按原样输出。上述代码会生成:
css
.tint-brand {
  --tint: var(--purple-500);
  background-color: var(--tint);
}
相关机制:
  • variables
    会输出额外的自定义属性。作为映射时,每个属性都会在组内的每个类上获得一个静态值;作为列表时,每个属性都会接收工具类的值。
  • 属性映射加映射值。 当
    property
    是一个映射,且某个
    values
    条目本身是一个以属性名为键的映射时,每个属性会选择自己的值——适用于需要为多个相关属性设置不同值的工具类组。
  • selector: attr-starts
    /
    attr-includes
    会以
    [class^="…"]
    /
    [class*="…"]
    而非类作为目标,且需要提供
    class
    键。Bootstrap 使用此特性让
    .ratio-16x9
    能够通过
    --ratio
    为
    aspect-ratio
    提供值。
  • child-selector
    会将规则包裹在
    :where()
    中,例如
    :where(.stack-gap-1 > *)
    。零特异性意味着子元素自身的样式仍然优先。
自定义属性名称在 Sass 中编写时不带前缀。Bootstrap 的发行版和 CDN CSS 会通过 PostCSS 添加
--bs-
前缀,因此如果你自行编译源码,这些属性将保持无前缀状态。

Step 7: Trim the generated CSS

步骤 7:精简生成的 CSS

Utilities are the biggest slice of Bootstrap's CSS, and the map is the cheapest place to cut:
  1. Start from the utilities-only entry point if you don't need components:
    scss
    @use "bootstrap/scss/config" with ($utilities: (…));
    @use "bootstrap/scss/bootstrap-utilities";
  2. Set unused groups to
    null
    (or
    enabled: false
    ) rather than relying on the minifier or a purge step.
  3. Turn
    responsive
    off on groups you only use at one breakpoint — a responsive group costs six copies of itself.
  4. Narrow
    values
    maps instead of deleting whole groups when you only need a few steps.
See Optimize for the wider picture, including Lightning CSS and purging.

工具类是 Bootstrap CSS 中占比最大的部分,而修改映射是最简便的精简方式:
  1. 如果你不需要组件,请从仅含工具类的入口点开始:
    scss
    @use "bootstrap/scss/config" with ($utilities: (…));
    @use "bootstrap/scss/bootstrap-utilities";
  2. 将未使用的组设置为
    null
    (或
    enabled: false
    ),而非依赖压缩工具或清除步骤。
  3. 对于仅在一个断点使用的组,请关闭
    responsive
    ——一个响应式组会生成六份自身的副本。
  4. 如果你只需要少数几个档位,请缩小
    values
    映射的范围,而非删除整个组。
更全面的信息请参阅优化,包括 Lightning CSS 和样式清除。

Step 8: Add a utility to Bootstrap itself

步骤 8:向 Bootstrap 本身添加工具类

When contributing a utility to the framework rather than a project:
  1. Add the group to the
    $utilities
    map in
    scss/_utilities.scss
    , near related groups, wrapped in
    // scss-docs-start utils-<name>
    /
    // scss-docs-end utils-<name>
    markers.
  2. Prefer composing through a custom property when the utility should interact with opacity or theme colors, and reuse existing token values (
    $spacers
    ,
    $util-opacity
    ,
    theme-color-refs()
    ) instead of literals.
  3. Document it on the matching page in
    site/src/content/docs/utilities/
    , rendering the definition with
    <ScssDocs name="utils-<name>" file="scss/_utilities.scss" />
    , and add a
    site/data/sidebar.yml
    entry if the page is new.
  4. Add coverage in
    scss/tests/utilities/_api.test.scss
    , which calls the generator mixins directly with a fixture map.
  5. Run
    npm run css
    . Its
    css-docs
    step regenerates
    dist/css/bootstrap-utilities.metadata.json
    , which the docs read — commit it alongside your change.

如果你是要为框架贡献工具类,而非在项目中使用:
  1. 将该组添加到
    scss/_utilities.scss
    的
    $utilities
    映射中,放在相关组附近,并用
    // scss-docs-start utils-<name>
    /
    // scss-docs-end utils-<name>
    标记包裹。
  2. 如果工具类需要与透明度或主题色交互,请优先通过自定义属性进行组合,并复用现有的令牌值(
    $spacers
    、
    $util-opacity
    、
    theme-color-refs()
    )而非字面量。
  3. 在
    site/src/content/docs/utilities/
    下的对应页面中编写文档,使用
    <ScssDocs name="utils-<name>" file="scss/_utilities.scss" />
    渲染定义,如果是新页面,请在
    site/data/sidebar.yml
    中添加条目。
  4. 在
    scss/tests/utilities/_api.test.scss
    中添加测试覆盖,该文件会使用测试映射直接调用生成器 mixin。
  5. 运行
    npm run css
    。其中的
    css-docs
    步骤会重新生成
    dist/css/bootstrap-utilities.metadata.json
    (供文档读取)——请将其与你的修改一并提交。

Step 9: Verify

步骤 9:验证

  1. npm run css-lint
    , then
    npm run css
    .
  2. Grep the compiled CSS for the classes you expected, including the escaped variants (
    \.md\\:cursor-pointer
    ), and confirm nothing you removed is still present.
  3. Confirm new custom properties appear in the
    @property
    block at the top of the file — if one is missing, the utility isn't assigning it through
    property
    or
    variables
    .
  4. Watch the Sass output for
    @warn
    lines about unknown keys; they're the fastest signal that an option was misspelled and silently ignored.
  5. Check specificity in the browser: utilities should override component styles through the layer order alone, without
    !important
    .
  1. 运行
    npm run css-lint
    ,然后运行
    npm run css
    。
  2. 在编译后的 CSS 中搜索你预期的类,包括转义后的变体(
    \.md\\:cursor-pointer
    ),并确认已移除的内容不再存在。
  3. 确认新的自定义属性出现在文件顶部的
    @property
    块中——如果缺少某个属性,说明该工具类没有通过
    property
    或
    variables
    分配它。
  4. 留意 Sass 输出中关于未知键的
    @warn
    行;这是发现选项拼写错误并被静默忽略的最快方式。
  5. 在浏览器中检查特异性:工具类应该仅通过层顺序就能覆盖组件样式,无需
    !important
    。