bootstrap-component
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseBootstrap 6 component CSS
Bootstrap 6 组件CSS
Author a component's styles and markup — the non-JavaScript pieces. Bootstrap 6 components are built from a Sass map of CSS custom properties (the token map), a base class that emits those tokens, and modifier classes that override them.
For interactive behavior, see the skill. For palettes, theme colors, and color modes, see the skill.
bootstrap-component-jsbootstrap-color-system编写组件的样式与标记——即非JavaScript部分。Bootstrap 6组件由包含CSS自定义属性的Sass映射(令牌映射)、输出这些令牌的基类,以及覆盖令牌的修饰符类构建而成。
如需交互行为,请参考技能。如需调色板、主题色与颜色模式,请参考技能。
bootstrap-component-jsbootstrap-color-systemWorkflow
工作流程
- Step 1: Plan the component
- Step 2: Create the partial and token map
- Step 3: Write the base class
- Step 4: Add modifiers, variants, and sizes
- Step 5: Wire up theme colors
- Step 6: Markup and accessibility
- Step 7: Register the partial
- Step 8: Document the component
- Step 9: Verify
- 步骤1:规划组件
- 步骤2:创建分部文件与令牌映射
- 步骤3:编写基类
- 步骤4:添加修饰符、变体与尺寸
- 步骤5:接入主题色
- 步骤6:标记与可访问性
- 步骤7:注册分部文件
- 步骤8:编写组件文档
- 步骤9:验证
Step 1: Plan the component
步骤1:规划组件
- Pick a singular, kebab-case name. It drives everything: the partial , the base class
scss/_<name>.scss, the token prefix.<name>, and the map--<name>-*.$<name>-tokens - Decide what the component needs before writing CSS:
- Tokens only — one look, customized through CSS variables. Model on .
scss/_alert.scss - Variants — contextual color treatments like . Model on
.badge-subtle.scss/_badge.scss - Variants and sizes — model on .
scss/buttons/_button.scss
- Tokens only — one look, customized through CSS variables. Model on
- Check whether an existing component already covers the need. Extending one with a modifier is preferable to adding a near-duplicate.
Never edit generated output in , , or . Source lives in and .
dist/js/dist/_site/scss/js/src/- 选择一个单数形式的kebab-case命名。它将决定所有相关内容:分部文件、基类
scss/_<name>.scss、令牌前缀.<name>,以及映射--<name>-*。$<name>-tokens - 在编写CSS前确定组件的需求:
- 仅令牌 — 单一外观,通过CSS变量自定义。参考的模式。
scss/_alert.scss - 变体 — 上下文相关的颜色处理,例如。参考
.badge-subtle的模式。scss/_badge.scss - 变体与尺寸 — 参考的模式。
scss/buttons/_button.scss
- 仅令牌 — 单一外观,通过CSS变量自定义。参考
- 检查现有组件是否已满足需求。使用修饰符扩展现有组件,优于添加几乎重复的新组件。
切勿编辑、或中的生成产物。源代码位于和目录中。
dist/js/dist/_site/scss/js/src/Step 2: Create the partial and token map
步骤2:创建分部文件与令牌映射
Create . Declare the empty map first, then fill it through :
scss/_<name>.scssdefaults()scss
@use "config" as *;
@use "functions" as *;
@use "mixins/border-radius" as *;
@use "mixins/tokens" as *;
$widget-tokens: () !default;
// scss-docs-start widget-tokens
// stylelint-disable-next-line scss/dollar-variable-default
$widget-tokens: defaults(
(
--widget-gap: var(--spacer-2),
--widget-padding-x: var(--spacer-4),
--widget-padding-y: var(--spacer-2),
--widget-color: var(--theme-fg, inherit),
--widget-bg: var(--theme-bg-subtle, var(--bg-1)),
--widget-border-color: var(--theme-border, var(--border-color)),
--widget-border-radius: var(--radius-5),
),
$widget-tokens
);
// scss-docs-end widget-tokensRules that matter here:
- The line is what makes the map overridable —
$widget-tokens: () !default;writes into it, and@use "bootstrap/scss/bootstrap" with ($widget-tokens: (…))merges those overrides over your defaults. Passingdefaults()for a key removes that token entirely.null - The second assignment needs the comment, since it intentionally reassigns without
stylelint-disable-next-line scss/dollar-variable-default.!default - Token names are namespaced to the component and written unprefixed. Bootstrap's dist and CDN CSS run PostCSS to add the prefix (
--bs-); compiling the source yourself keeps them unprefixed.--bs-widget-bg - Build values from existing global tokens — ,
var(--spacer-3),var(--radius-5),var(--border-width)— rather than hardcoded lengths, so the component scales with the rest of the framework.var(--font-weight-semibold) - The /
scss-docs-startmarkers are load-bearing: the docs page renders the map withscss-docs-end, which throws at build time if the markers are missing.<ScssDocs>
创建文件。首先声明空映射,再通过填充:
scss/_<name>.scssdefaults()scss
@use "config" as *;
@use "functions" as *;
@use "mixins/border-radius" as *;
@use "mixins/tokens" as *;
$widget-tokens: () !default;
// scss-docs-start widget-tokens
// stylelint-disable-next-line scss/dollar-variable-default
$widget-tokens: defaults(
(
--widget-gap: var(--spacer-2),
--widget-padding-x: var(--spacer-4),
--widget-padding-y: var(--spacer-2),
--widget-color: var(--theme-fg, inherit),
--widget-bg: var(--theme-bg-subtle, var(--bg-1)),
--widget-border-color: var(--theme-border, var(--border-color)),
--widget-border-radius: var(--radius-5),
),
$widget-tokens
);
// scss-docs-end widget-tokens此处的重要规则:
- 这一行是映射可被覆盖的关键——
$widget-tokens: () !default;可以向其中写入内容,@use "bootstrap/scss/bootstrap" with ($widget-tokens: (…))会将这些覆盖值合并到你的默认值之上。为某个键传入defaults()会完全移除该令牌。null - 第二次赋值需要添加注释,因为它是有意不带
stylelint-disable-next-line scss/dollar-variable-default的重新赋值。!default - 令牌名称带有组件命名空间,且不带前缀编写。Bootstrap的dist版本与CDN CSS会通过PostCSS添加前缀(即
--bs-);自行编译源码则会保留无前缀的形式。--bs-widget-bg - 使用现有全局令牌构建值——例如、
var(--spacer-3)、var(--radius-5)、var(--border-width)——而非硬编码的长度值,这样组件可以随框架整体缩放。var(--font-weight-semibold) - /
scss-docs-start标记是必需的:文档页面使用scss-docs-end渲染映射,如果缺少这些标记,构建时会报错。<ScssDocs>
Step 3: Write the base class
步骤3:编写基类
Declarations go inside a cascade layer, with the token map emitted on the root selector:
scss
@layer components {
.widget {
@include tokens($widget-tokens);
display: flex;
gap: var(--widget-gap);
align-items: center;
padding: var(--widget-padding-y) var(--widget-padding-x);
color: var(--widget-color);
background-color: var(--widget-bg);
border: var(--border-width) solid var(--widget-border-color);
@include border-radius(var(--widget-border-radius));
}
}- Pick the right layer. Components use , form controls
@layer components, helpers@layer forms. The order is declared once in@layer helpers:scss/_root.scss.colors, config, root, reboot, layout, content, forms, components, custom, helpers, utilities - comes first, then declarations, then nested rules. Declarations read
@include tokens($widget-tokens), never the Sass map directly.var(--widget-*) - Use and
@include border-radius()instead of the raw properties — stylelint blocks the raw ones because the mixins honor@include transition(),$enable-rounded, and$enable-transitions.prefers-reduced-motion - Use logical properties (,
padding-inline-start,margin-block-end) so the component works in RTL without an override.inset-inline-start - No /
lighten()— usedarken(), relativecolor-mix(), oroklch(). Nolight-dark()/border: none— useoutline: none.0
声明需放在级联层内,令牌映射输出在根选择器上:
scss
@layer components {
.widget {
@include tokens($widget-tokens);
display: flex;
gap: var(--widget-gap);
align-items: center;
padding: var(--widget-padding-y) var(--widget-padding-x);
color: var(--widget-color);
background-color: var(--widget-bg);
border: var(--border-width) solid var(--widget-border-color);
@include border-radius(var(--widget-border-radius));
}
}- 选择正确的层。组件使用,表单控件使用
@layer components,辅助类使用@layer forms。层的顺序在@layer helpers中统一声明:scss/_root.scss。colors, config, root, reboot, layout, content, forms, components, custom, helpers, utilities - 放在最前面,然后是声明,最后是嵌套规则。声明通过
@include tokens($widget-tokens)读取值,切勿直接使用Sass映射。var(--widget-*) - 使用和
@include border-radius()而非原生属性——stylelint会禁止使用原生属性,因为这些mixin会遵循@include transition()、$enable-rounded配置以及$enable-transitions设置。prefers-reduced-motion - 使用逻辑属性(、
padding-inline-start、margin-block-end),这样组件无需额外覆盖即可支持RTL布局。inset-inline-start - 不要使用/
lighten()—— 请使用darken()、相对color-mix()或oklch()。不要使用light-dark()/border: none—— 请使用outline: none。0
Step 4: Add modifiers, variants, and sizes
步骤4:添加修饰符、变体与尺寸
A modifier only overrides tokens; it should not repeat the base declarations:
scss
.widget-lg {
--widget-padding-x: var(--spacer-6);
--widget-padding-y: var(--spacer-3);
--widget-border-radius: var(--radius-7);
}When a component has a set of contextual treatments, drive them from an overridable map whose values are theme sub-keys, then loop. This is the pattern:
scss/_badge.scssscss
// scss-docs-start widget-variants
$widget-variants: () !default;
$widget-variants: defaults(
(
"subtle": (
"color": "fg",
"bg": "bg-subtle",
"border-color": "transparent"
),
"outline": (
"color": "fg",
"bg": "transparent",
"border-color": "border"
)
),
$widget-variants
);
// scss-docs-end widget-variants
@layer components {
// scss-docs-start widget-variant-loop
@each $variant, $properties in $widget-variants {
.widget-#{$variant} {
@each $property, $value in $properties {
@if $value == "transparent" {
--widget-#{$property}: transparent;
} @else {
--widget-#{$property}: var(--theme-#{$value});
}
}
}
}
// scss-docs-end widget-variant-loop
}Mapping to theme sub-keys rather than literal colors is what lets work without a variant-per-color explosion.
.widget-outline.theme-successSizes follow the button pattern: a list run through , looped into classes that re-point the component's tokens at the shared scale.
defaults()--btn-input-<size>-*scss
$widget-sizes: () !default;
$widget-sizes: defaults(
("sm", "lg"),
$widget-sizes
);defaults()$widget-sizes: ("sm": null)修饰符仅覆盖令牌,不应重复基类的声明:
scss
.widget-lg {
--widget-padding-x: var(--spacer-6);
--widget-padding-y: var(--spacer-3);
--widget-border-radius: var(--radius-7);
}当组件有一组上下文相关的样式时,通过一个可覆盖的映射来驱动,映射的值为主题子键,然后通过循环生成样式。这是的模式:
scss/_badge.scssscss
// scss-docs-start widget-variants
$widget-variants: () !default;
$widget-variants: defaults(
(
"subtle": (
"color": "fg",
"bg": "bg-subtle",
"border-color": "transparent"
),
"outline": (
"color": "fg",
"bg": "transparent",
"border-color": "border"
)
),
$widget-variants
);
// scss-docs-end widget-variants
@layer components {
// scss-docs-start widget-variant-loop
@each $variant, $properties in $widget-variants {
.widget-#{$variant} {
@each $property, $value in $properties {
@if $value == "transparent" {
--widget-#{$property}: transparent;
} @else {
--widget-#{$property}: var(--theme-#{$value});
}
}
}
}
// scss-docs-end widget-variant-loop
}映射到主题子键而非字面颜色,这样才能正常工作,避免了为每种颜色都创建一个变体的爆炸式增长。
.widget-outline.theme-success尺寸遵循按钮的模式:将一个列表通过处理,循环生成类,将组件的令牌重新指向共享的尺度。
defaults()--btn-input-<size>-*scss
$widget-sizes: () !default;
$widget-sizes: defaults(
("sm", "lg"),
$widget-sizes
);defaults()$widget-sizes: ("sm": null)Step 5: Wire up theme colors
步骤5:接入主题色
Theme classes (, , …) are generated from and set a fixed set of variables: , , , , , , , , and .
.theme-primary.theme-danger$theme-colors--theme-base--theme-fg--theme-fg-emphasis--theme-bg--theme-bg-subtle--theme-bg-muted--theme-border--theme-focus-ring--theme-contrastA component gets theme support for free by reading those variables with a neutral fallback, which is why the defaults in Step 2 look like this:
scss
--widget-color: var(--theme-fg, inherit),
--widget-bg: var(--theme-bg-subtle, var(--bg-1)),
--widget-border-color: var(--theme-border, var(--border-color)),Unthemed markup uses the fallbacks; adding a theme class recolors the component with no extra CSS:
html
<div class="widget theme-danger">…</div>Use on a nested subtree to drop inherited tokens and return to those fallbacks.
.theme-reset--theme-*Do not hardcode or a specific theme color in component tokens. Adding or overriding theme colors themselves is covered by the skill.
var(--red-500)bootstrap-color-system主题类(、等)由生成,会设置一组固定的变量:、、、、、、、以及。
.theme-primary.theme-danger$theme-colors--theme-base--theme-fg--theme-fg-emphasis--theme-bg--theme-bg-subtle--theme-bg-muted--theme-border--theme-focus-ring--theme-contrast组件通过读取这些变量并设置中性的回退值,即可免费获得主题支持,这也是步骤2中的默认值看起来像这样的原因:
scss
--widget-color: var(--theme-fg, inherit),
--widget-bg: var(--theme-bg-subtle, var(--bg-1)),
--widget-border-color: var(--theme-border, var(--border-color)),无主题的标记会使用回退值;添加主题类即可重新着色组件,无需额外CSS:
html
<div class="widget theme-danger">…</div>在嵌套的子树上使用,可以移除继承的令牌,回退到上述回退值。
.theme-reset--theme-*切勿在组件令牌中硬编码或特定的主题色。添加或覆盖主题色本身的内容请参考技能。
var(--red-500)bootstrap-color-systemStep 6: Markup and accessibility
步骤6:标记与可访问性
- Start from the semantic element. Add ARIA only where the markup can't convey meaning on its own — for example on a live message,
role="alert"on a disclosure trigger.aria-expanded - Interactive parts must be reachable by keyboard and show a visible focus ring. The helper applies
.focus-ringonoutline: var(--focus-ring-width) solid var(--theme-focus-ring, var(--focus-ring-color)); theme-aware components inherit the right color automatically.:focus-visible - Give icon-only controls an accessible name with text or
.visually-hidden.aria-label - Never signal state through color alone; pair it with text, an icon, or an ARIA attribute.
- Keep the markup RTL-safe: logical properties in CSS, no left/right assumptions in the DOM order.
- 从语义化元素开始。仅在标记本身无法传达含义时添加ARIA——例如在实时消息上添加,在展开/收起触发器上添加
role="alert"。aria-expanded - 可交互部分必须可通过键盘访问,并显示可见的焦点环。辅助类会在
.focus-ring状态下应用:focus-visible;支持主题的组件会自动继承正确的颜色。outline: var(--focus-ring-width) solid var(--theme-focus-ring, var(--focus-ring-color)) - 为仅含图标的控件提供可访问名称,可通过文本或
.visually-hidden实现。aria-label - 切勿仅通过颜色传达状态;需搭配文本、图标或ARIA属性。
- 保持标记的RTL安全性:CSS使用逻辑属性,DOM顺序中不要有左/右的固有假设。
Step 7: Register the partial
步骤7:注册分部文件
Forward the partial from in the components block, keeping the existing ordering:
scss/bootstrap.scssscss
@forward "widget";Components that live in a subdirectory (, , ) are forwarded from that directory's barrel, and the barrel is forwarded from . Add new files to the barrel, not to , in that case.
scss/buttons/scss/forms/scss/helpers/index.scssscss/bootstrap.scssbootstrap.scss在的components块中转发该分部文件,保持现有的顺序:
scss/bootstrap.scssscss
@forward "widget";位于子目录(、、)中的组件,从该目录的 barrel文件转发,barrel文件再由转发。这种情况下,将新文件添加到barrel中,而非直接添加到。
scss/buttons/scss/forms/scss/helpers/index.scssscss/bootstrap.scssbootstrap.scssStep 8: Document the component
步骤8:编写组件文档
-
Add:
site/src/content/docs/components/<name>.mdxmarkdown--- title: Widget description: Documentation and examples for Bootstrap’s widget component. toc: true css_layer: components ---Add(orjs: optional) when the component ships a JavaScript plugin.js: required -
Add an entry tounder the Components section. The sidebar drives the nav, the page ordering, and inclusion in
site/data/sidebar.yml, so a page without an entry is effectively invisible:llms.txtyaml- title: Widget meta: - added: 6.0.0 -
Show usage withfor live demos, and render the token map under a
<Example>section:### Variablesmarkdown<CSSVariables component="Widgets" className="widget" /> <ScssDocs name="widget-tokens" file="scss/_widget.scss" /> -
Link internally withrather than a hardcoded versioned path.
[[docsref:/components/widget/]]
-
添加文件:
site/src/content/docs/components/<name>.mdxmarkdown--- title: Widget description: Documentation and examples for Bootstrap’s widget component. toc: true css_layer: components ---如果组件附带JavaScript插件,添加(或js: optional)。js: required -
在的Components部分添加条目。侧边栏决定了导航、页面排序以及是否包含在
site/data/sidebar.yml中,因此没有条目的页面实际上是不可见的:llms.txtyaml- title: Widget meta: - added: 6.0.0 -
使用展示用法以提供实时演示,并在
<Example>部分渲染令牌映射:### 变量markdown<CSSVariables component="Widgets" className="widget" /> <ScssDocs name="widget-tokens" file="scss/_widget.scss" /> -
使用进行内部链接,而非硬编码的带版本路径。
[[docsref:/components/widget/]]
Step 9: Verify
步骤9:验证
- — catches disallowed properties, wrong declaration order, and missing logical properties.
npm run css-lint - — compiles, prefixes, and minifies. Confirm the tokens land in
npm run csswith thedist/css/bootstrap.cssprefix.--bs- - — fails on a broken
npm run docs-build, a missing sidebar entry, or missingdocsrefmarkers.scss-docs - Check the component in the browser: with and without a theme class, in both color modes, with on
dir="rtl"(v6 has no separate RTL stylesheet — logical properties do the work), and with reduced motion enabled if it animates.<html>
- —— 检查出不允许的属性、错误的声明顺序以及缺失的逻辑属性。
npm run css-lint - —— 编译、添加前缀并压缩。确认令牌以
npm run css前缀出现在--bs-中。dist/css/bootstrap.css - —— 当
npm run docs-build损坏、侧边栏条目缺失或docsref标记缺失时会构建失败。scss-docs - 在浏览器中检查组件:分别在有和无主题类的情况下、两种颜色模式下、设置
<html>的情况下(v6没有单独的RTL样式表——由逻辑属性实现),如果组件有动画,还要在启用减少动效的情况下检查。dir="rtl"
In your own project
在你自己的项目中
The same pattern works for your own components on top of Bootstrap. In , the pieces you need and follow Steps 2–6 unchanged:
custom.scss@usescss
@use "bootstrap/scss/config" as *;
@use "bootstrap/scss/mixins/tokens" as *;
@use "bootstrap/scss/bootstrap";
$widget-tokens: () !default;
$widget-tokens: defaults(
(
--widget-bg: var(--theme-bg-subtle, var(--bg-1)),
),
$widget-tokens
);
@layer custom {
.widget {
@include tokens($widget-tokens);
background-color: var(--widget-bg);
}
}Use the layer, which sits after and before and , so your styles win over component defaults while utilities still override yours. Retuning an existing Bootstrap component doesn't require any of this — override its CSS variables at runtime, or pass its map through at compile time.
customcomponentshelpersutilities$*-tokenswith ()同样的模式也适用于你基于Bootstrap开发的自定义组件。在中,你需要的部分,然后不变地遵循步骤2-6:
custom.scss@usescss
@use "bootstrap/scss/config" as *;
@use "bootstrap/scss/mixins/tokens" as *;
@use "bootstrap/scss/bootstrap";
$widget-tokens: () !default;
$widget-tokens: defaults(
(
--widget-bg: var(--theme-bg-subtle, var(--bg-1)),
),
$widget-tokens
);
@layer custom {
.widget {
@include tokens($widget-tokens);
background-color: var(--widget-bg);
}
}使用层,它位于之后、和之前,因此你的样式会覆盖组件默认值,而工具类仍能覆盖你的样式。调整现有Bootstrap组件不需要这些——在运行时覆盖其CSS变量,或在编译时通过传入其映射即可。
customcomponentshelpersutilitieswith ()$*-tokens