bootstrap 5 utility api 扩展必须严格按顺序:先导入 functions 和 variables,再用 map-merge 扩展 $utilities,最后导入 utilities;新增项需四层嵌套结构(property→responsive→state→value),并注意 property 冲突覆盖、null 值声明及断点逻辑。

必须先重定义 $utilities,再导入 utilities
Bootstrap 5 的 Utility API 不是“写完就生效”,它依赖 Sass 编译时对 $utilities 这个 map 的读取和遍历。你不能在 _utilities.scss 里直接追加,也不能在 @import "bootstrap/scss/utilities" 之后再改 $utilities——那时已经编译完了,你的修改被忽略。
正确顺序只有这一种:
-
@import "bootstrap/scss/functions";(必需,map-merge在这里定义) -
@import "bootstrap/scss/variables";(提供默认$utilities基础值) - 用
map-merge($utilities, (...))扩展你的新项 -
@import "bootstrap/scss/utilities";(此时才真正调用generate-utility())
顺序错任意一步,比如把 map-merge 放在 variables 前,Sass 会报 $utilities is undefined;放在这行之后,新类根本不会出现在最终 CSS 中。
$utilities 新增项必须满足四层嵌套结构
每个新增 utility 条目不是扁平对象,而是严格按 property → responsive → state → value 四层嵌套。漏掉任何一层,对应能力就失效。
常见错误写法:
"text-brand": ( property: color, values: (brand: #2563eb) )
这会导致:.text-brand 生成,但 .text-sm-brand 不生成(缺 responsive),.text-brand:hover 也不生成(缺 state 层)。
正确结构示例:
"text-brand": (
property: color,
class: text-brand,
values: (
brand: map-get($theme-colors, primary)
),
responsive: true,
states: (hover: true)
)
-
class字段可显式指定前缀,避免和内置text-冲突(比如你想叫color-brand就写class: color-brand) -
responsive: true才触发断点循环(sm、md等),设为false或不写则只生成基础类 -
states: (hover: true)是启用伪类的开关,不是直接写hover: ...—— 后者会被忽略
避免 class 名与 property 冲突的隐蔽覆盖
Bootstrap 对相同 property 的 utility 采用后定义覆盖前定义策略,且无警告。比如你新增:
"bg-gradient-horiz": ( property: background-image, values: (horiz: linear-gradient(90deg, #0d6efd, #6f42c1)) )
而 Bootstrap 5.3.8 默认没配 background-image 类,所以安全。但如果你写:
"text-blur": ( property: color, values: (blur: rgba(0,0,0,.3)) )
这就和内置的 text-primary 共享 property: color,最终 .text-blur 会完全覆盖所有 .text-* 的 color 声明,包括 .text-white —— 浏览器只会应用最后一条 color 规则。
更危险的是:两个 utility 都设 property: margin,哪怕 class 名不同(mt-safe 和 mb-tight),也属于同一 property 分组,后者覆盖前者。
规避方式:
- 优先用 Bootstrap 未占用的 property,如
backdrop-filter、clip-path、scroll-margin - 若必须用已有 property(如
color),确保新增项的values键名不与内置冲突(不要叫primary、success) - 用
class字段显式隔离前缀,例如class: color-alt,而非依赖自动推导
响应式断点和 null 的实际含义
responsive: true 并不等于“自动适配所有断点”。它只是启用断点循环逻辑,真正生成哪些类,取决于当前项目加载的 $grid-breakpoints 和你是否显式补全 null 值。
比如你扩展一个 shadow-heavy,只写了:
values: ( sm: 0 4px 8px rgba(0,0,0,.1), md: 0 8px 16px rgba(0,0,0,.15) )
那么 .shadow-heavy(即无断点前缀)根本不会生成——因为没提供 null 键。Sass 认为“默认断点”需要明确声明。
正确写法必须包含 null:
values: ( null: 0 2px 4px rgba(0,0,0,.1), sm: 0 4px 8px rgba(0,0,0,.1), md: 0 8px 16px rgba(0,0,0,.15) )
否则你在小屏下连基础阴影都没有,只在 sm 及以上生效,容易误判为“响应式失效”。
这个 null 不是占位符,是真实 key,代表最小断点(min-width: 0)下的值。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











