Skip to main content
Bun 的打包工具内置支持 CSS,具有以下功能:
  • 转译现代/未来特性以兼容所有浏览器(包括厂商前缀)
  • 压缩
  • CSS 模块
  • Tailwind(通过原生打包插件)

转译

Bun 的 CSS 打包工具让你可以使用现代/未来的 CSS 特性,而不必担心浏览器兼容性 —— 这都要归功于其默认启用的转译和厂商前缀功能。 Bun 的 CSS 解析器和打包工具是 LightningCSS 从 Rust 到 Zig 的直接移植,打包方法则受 esbuild 启发。转译器将现代 CSS 语法转换为适用于各种浏览器的向后兼容等价物。
特别感谢 LightningCSS 和 esbuild 的作者们的出色工作。

浏览器兼容性

默认情况下,Bun 的 CSS 打包目标浏览器包括:
  • ES2020
  • Edge 88+
  • Firefox 78+
  • Chrome 87+
  • Safari 14+

语法降级

嵌套

CSS 嵌套规范允许你通过将选择器嵌套在彼此内部来编写更简洁、更直观的样式表。你无需在整个 CSS 文件中重复父选择器,可以直接在父块内书写子样式。
styles.css
/* 使用嵌套 */
.card {
  background: white;
  border-radius: 4px;

  .title {
    font-size: 1.2rem;
    font-weight: bold;
  }

  .content {
    padding: 1rem;
  }
}
Bun 的 CSS 打包工具会自动将此嵌套语法转换成传统的扁平 CSS,以兼容所有浏览器:
styles.css
/* 编译输出 */
.card {
  background: white;
  border-radius: 4px;
}

.card .title {
  font-size: 1.2rem;
  font-weight: bold;
}

.card .content {
  padding: 1rem;
}
你也可以在选择器内嵌套媒体查询和其他 at 规则,避免重复选择器模式:
styles.css
.responsive-element {
  display: block;

  @media (min-width: 768px) {
    display: flex;
  }
}
编译后为:
styles.css
.responsive-element {
  display: block;
}

@media (min-width: 768px) {
  .responsive-element {
    display: flex;
  }
}

颜色混合

color-mix() 函数让你根据指定比例在选定的色彩空间内轻松混合两种颜色。这个强大的特性让你无需手动计算结果值就能创建颜色变化。
styles.css
.button {
  /* 在 RGB 色彩空间中以 30%:70% 混合蓝色和红色 */
  background-color: color-mix(in srgb, blue 30%, red);

  /* 为悬停状态创建较浅的变体 */
  &:hover {
    background-color: color-mix(in srgb, blue 30%, red, white 20%);
  }
}
Bun 的 CSS 打包工具会在构建时评估这些颜色混合(当所有颜色值已确定,非 CSS 变量),生成适用于所有浏览器的静态颜色值:
styles.css
.button {
  /* 精确计算得到的结果色 */
  background-color: #b31a1a;
}

.button:hover {
  background-color: #c54747;
}
此功能特别适合创建程序推导的颜色系统,如色调、色深和强调色,无需预处理器或自定义工具。

相对颜色

CSS 现在允许你使用相对颜色语法修改颜色的单个组成部分。此强大功能让你通过调整亮度、饱和度或单独通道来创建颜色变体,而无需重新计算整个颜色。
styles.css
.theme-color {
  /* 以基础色为起点,将亮度增加 15% */
  --accent: lch(from purple calc(l + 15%) c h);

  /* 以我们的品牌蓝色为基色,制作一个去饱和版本 */
  --subtle-blue: oklch(from var(--brand-blue) l calc(c * 0.8) h);
}
Bun 的 CSS 打包工具会在构建时计算这些相对颜色修改(不使用 CSS 变量时),生成适用于浏览器的静态颜色值:
.theme-color {
  --accent: lch(69.32% 58.34 328.37);
  --subtle-blue: oklch(60.92% 0.112 240.01);
}
这种方式非常适用于主题生成、创建无障碍颜色变体或基于数学关系构建颜色刻度,而非硬编码每个值。

LAB 颜色

现代 CSS 支持 LAB、LCH、OKLAB 和 OKLCH 等感知均匀色彩空间,相较于传统 RGB 有显著优势。这些色彩空间能表示超出标准 RGB 色域的颜色,带来更鲜明和视觉一致的设计。
styles.css
.vibrant-element {
  /* 一种超出 sRGB 色域边界的鲜艳红色 */
  color: lab(55% 78 35);

  /* 使用感知色彩空间的平滑渐变 */
  background: linear-gradient(to right, oklch(65% 0.25 10deg), oklch(65% 0.25 250deg));
}
Bun 的 CSS 打包工具会自动将这些高级色彩格式转换为向后兼容的备选方案,以支持尚未实现的浏览器:
styles.css
.vibrant-element {
  /* 退回到最接近的 RGB 近似 */
  color: #ff0f52;
  /* 支持更宽色域的浏览器使用 P3 备选 */
  color: color(display-p3 1 0.12 0.37);
  /* 支持该格式的浏览器保持原值 */
  color: lab(55% 78 35);

  background: linear-gradient(to right, #cd4e15, #3887ab);
  background: linear-gradient(to right, oklch(65% 0.25 10deg), oklch(65% 0.25 250deg));
}
此分层方法确保所有浏览器间获得最佳色彩渲染,同时让你在设计中使用最新的色彩技术。

color 函数

color() 函数提供了一种标准化方式,使用各种预定义色彩空间来指定颜色,拓展了传统 RGB 空间以外的设计选项。这样可访问更宽广的色域,创造更鲜艳的设计。
styles.css
.vivid-element {
  /* 使用 Display P3 色彩空间实现更宽色域 */
  color: color(display-p3 1 0.1 0.3);

  /* 使用 A98 RGB 色彩空间 */
  background-color: color(a98-rgb 0.44 0.5 0.37);
}
对于尚不支持这些高级色彩函数的浏览器,Bun 的 CSS 打包工具会提供合适的 RGB 备选:
styles.css
.vivid-element {
  /* 优先使用 RGB 备选以获得最大兼容 */
  color: #fa1a4c;
  /* 保留原色以支持兼容浏览器 */
  color: color(display-p3 1 0.1 0.3);

  background-color: #6a805d;
  background-color: color(a98-rgb 0.44 0.5 0.37);
}
该功能让你立即使用现代色彩空间,同时保证设计在所有浏览器上均可正常使用,支持浏览器显示最佳色彩,其他浏览器显示合理近似值。

HWB 颜色

HWB(色相、白度、黑度)色彩模型提供了基于纯色相中掺加白色或黑色比例的直观表达方式。许多设计师发现这一方法比调整 RGB 或 HSL 值更自然,便于创建颜色变体。
styles.css
.easy-theming {
  /* 纯青色,无白无黑 */
  --primary: hwb(180 0% 0%);

  /* 同色相,加入 20% 白色(色调) */
  --primary-light: hwb(180 20% 0%);

  /* 同色相,加入 30% 黑色(阴影) */
  --primary-dark: hwb(180 0% 30%);

  /* 添加白色和黑色的柔和版本 */
  --primary-muted: hwb(180 30% 20%);
}
Bun 的 CSS 打包工具会自动将 HWB 颜色转换为兼容所有浏览器的 RGB:
styles.css
.easy-theming {
  --primary: #00ffff;
  --primary-light: #33ffff;
  --primary-dark: #00b3b3;
  --primary-muted: #339999;
}
HWB 模型特别适合为设计系统创建系统化颜色变化,比直接操作 RGB 或 HSL 更直观地制作一致的色调与阴影。

颜色表示法

现代 CSS 引入了更直观简洁的颜色写法。空格分隔的颜色语法省去 RGB 和 HSL 里的逗号,带 alpha 通道的十六进制形式能紧凑指定透明度。
styles.css
.modern-styling {
  /* 空格分隔的 RGB 表示法(无逗号) */
  color: rgb(50 100 200);

  /* 空格分隔带 alpha 的 RGB */
  border-color: rgba(100 50 200 / 75%);

  /* 带 alpha 通道的 8 位十六进制 */
  background-color: #00aaff80;

  /* 简化的 HSL 表示 */
  box-shadow: 0 5px 10px hsl(200 50% 30% / 40%);
}
Bun 的 CSS 打包工具自动将这些现代颜色格式转为兼容旧版浏览器的格式:
styles.css
.modern-styling {
  /* 转为旧版需要的逗号格式 */
  color: rgb(50, 100, 200);

  /* 透明度通道妥善处理 */
  border-color: rgba(100, 50, 200, 0.75);

  /* 十六进制带 alpha 转为 rgba */
  background-color: rgba(0, 170, 255, 0.5);

  box-shadow: 0 5px 10px rgba(38, 115, 153, 0.4);
}
这一转换过程让你编写更简洁现代的 CSS,同时确保样式在所有浏览器中正常工作。

light-dark() 颜色函数

light-dark() 函数为实现尊重用户系统偏好的明暗色方案提供了优雅方案,无需复杂的媒体查询。该函数接受两个颜色值,并自动基于当前色彩方案上下文选择合适的颜色。
styles.css
:root {
  /* 定义支持的颜色方案 */
  color-scheme: light dark;
}

.themed-component {
  /* 根据系统偏好自动选择颜色 */
  background-color: light-dark(#ffffff, #121212);
  color: light-dark(#333333, #eeeeee);
  border-color: light-dark(#dddddd, #555555);
}

/* 需要时覆盖系统偏好 */
.light-theme {
  color-scheme: light;
}

.dark-theme {
  color-scheme: dark;
}
对于尚不支持本特性的浏览器,Bun 的 CSS 打包工具将其转换为使用 CSS 变量及适当回退的写法:
styles.css
:root {
  --lightningcss-light: initial;
  --lightningcss-dark: ;
  color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
  :root {
    --lightningcss-light: ;
    --lightningcss-dark: initial;
  }
}

.light-theme {
  --lightningcss-light: initial;
  --lightningcss-dark: ;
  color-scheme: light;
}

.dark-theme {
  --lightningcss-light: ;
  --lightningcss-dark: initial;
  color-scheme: dark;
}

.themed-component {
  background-color: var(--lightningcss-light, #ffffff) var(--lightningcss-dark, #121212);
  color: var(--lightningcss-light, #333333) var(--lightningcss-dark, #eeeeee);
  border-color: var(--lightningcss-light, #dddddd) var(--lightningcss-dark, #555555);
}
此方法让你无需复制样式或编写复杂媒体查询,即可优雅地处理明暗主题,同时兼容尚不原生支持此功能的浏览器。

逻辑属性

CSS 逻辑属性允许你根据文档的书写模式和文本方向定义布局、间距及尺寸,而非物理屏幕方向。对于创建自动适配不同书写系统的国际化布局至关重要。
styles.css
.multilingual-component {
  /* 适应书写方向的外边距 */
  margin-inline-start: 1rem;

  /* 无论文本方向,都合理的内边距 */
  padding-block: 1rem 2rem;

  /* 顶部起始角的边框半径 */
  border-start-start-radius: 4px;

  /* 尊重书写模式的尺寸 */
  inline-size: 80%;
  block-size: auto;
}
对于不完全支持逻辑属性的浏览器,Bun 的 CSS 打包工具会将其编译为带适当方向调整的物理属性:
styles.css
/* 左到右语言 */
.multilingual-component:dir(ltr) {
  margin-left: 1rem;
  padding-top: 1rem;
  padding-bottom: 2rem;
  border-top-left-radius: 4px;
  width: 80%;
  height: auto;
}

/* 右到左语言 */
.multilingual-component:dir(rtl) {
  margin-right: 1rem;
  padding-top: 1rem;
  padding-bottom: 2rem;
  border-top-right-radius: 4px;
  width: 80%;
  height: auto;
}
若不支持 :dir() 选择器,还会自动生成额外回退,确保布局跨所有浏览器和书写系统正常。此举简化了国际化设计的创建过程,同时兼容旧版浏览器。

:dir() 选择器

:dir() 伪类选择器允许你基于文本方向(RTL 或 LTR)样式化元素,提供无需 JavaScript 即可创建方向感知设计的强大方案。该选择器基于文档方向或显式方向属性匹配元素。
styles.css
/* 根据文本方向应用不同样式 */
.nav-arrow:dir(ltr) {
  transform: rotate(0deg);
}

.nav-arrow:dir(rtl) {
  transform: rotate(180deg);
}

/* 基于文本流的位置定位元素 */
.sidebar:dir(ltr) {
  border-right: 1px solid #ddd;
}

.sidebar:dir(rtl) {
  border-left: 1px solid #ddd;
}
对于尚不支持 :dir() 选择器的浏览器,Bun 的 CSS 打包工具将其转换为支持更广的 :lang() 选择器并添加适当语言映射:
styles.css
/* 作为回退转换为基于语言的选择器 */
.nav-arrow:lang(en, fr, de, es, it, pt, nl) {
  transform: rotate(0deg);
}

.nav-arrow:lang(ar, he, fa, ur) {
  transform: rotate(180deg);
}

.sidebar:lang(en, fr, de, es, it, pt, nl) {
  border-right: 1px solid #ddd;
}

.sidebar:lang(ar, he, fa, ur) {
  border-left: 1px solid #ddd;
}
此转换允许你编写方向感知的 CSS,确保在不支持 :dir() 的浏览器中也能可靠工作。如多参数 :lang() 不被支持,工具会自动生成进一步回退。

:lang() 选择器

:lang() 伪类选择器允许你基于元素的语言设置应用样式,使得轻松实现语言特定样式成为可能。现代 CSS 支持 :lang() 接受多个语言代码,能更高效组合语言规则。
styles.css
/* 针对中日韩语言的排版调整 */
:lang(zh, ja, ko) {
  line-height: 1.8;
  font-size: 1.05em;
}

/* 不同语言组的引号样式 */
blockquote:lang(fr, it, es, pt) {
  font-style: italic;
}

blockquote:lang(de, nl, da, sv) {
  font-weight: 500;
}
对于不支持多参数 :lang() 的浏览器,Bun 的 CSS 打包工具将其转换为使用 :is() 选择器以保持相同行为:
styles.css
/* 使用 :is() 组合多个语言以提高兼容 */
:is(:lang(zh), :lang(ja), :lang(ko)) {
  line-height: 1.8;
  font-size: 1.05em;
}

blockquote:is(:lang(fr), :lang(it), :lang(es), :lang(pt)) {
  font-style: italic;
}

blockquote:is(:lang(de), :lang(nl), :lang(da), :lang(sv)) {
  font-weight: 500;
}
如有需要,Bun 可提供额外的 :is() 回退,确保语言特定样式跨所有浏览器正常工作。这种方案简化带有不同语言组排版和样式规则的国际化设计。

:is() 选择器

:is() 伪类函数(前称 :matches())允许你通过组合多个选择器书写更简洁且可读的选择器。其接受选择器列表作为参数,只要其中任意选择器匹配即生效,显著减少 CSS 书写重复。
styles.css
/* 不用分别写这些 */
/* 
.article h1,
.article h2,
.article h3 {
  margin-top: 1.5em;
}
*/

/* 可以写成 */
.article :is(h1, h2, h3) {
  margin-top: 1.5em;
}

/* 复杂示例,多个组合 */
:is(header, main, footer) :is(h1, h2, .title) {
  font-family: "Heading Font", sans-serif;
}
对于不支持 :is() 的浏览器,Bun 的 CSS 打包工具提供使用厂商前缀的替代写法:
/* 使用 -webkit-any 回退 */
.article :-webkit-any(h1, h2, h3) {
  margin-top: 1.5em;
}

/* 使用 -moz-any 回退 */
.article :-moz-any(h1, h2, h3) {
  margin-top: 1.5em;
}

/* 现代浏览器保留原写法 */
.article :is(h1, h2, h3) {
  margin-top: 1.5em;
}

/* 复杂示例的回退 */
:-webkit-any(header, main, footer) :-webkit-any(h1, h2, .title) {
  font-family: "Heading Font", sans-serif;
}

:-moz-any(header, main, footer) :-moz-any(h1, h2, .title) {
  font-family: "Heading Font", sans-serif;
}

:is(header, main, footer) :is(h1, h2, .title) {
  font-family: "Heading Font", sans-serif;
}
厂商前缀版本相比标准化的 :is() 选择器存在一定限制,尤其在复杂选择器中。Bun 会智能处理这些限制,仅在能正确工作的情况下使用前缀版本。

:not() 选择器

:not() 伪类允许你排除匹配指定选择器的元素。现代版本支持多个参数,允许你用更简洁的选择器排除多种模式。
styles.css
/* 选择所有按钮,排除主按钮和次按钮 */
button:not(.primary, .secondary) {
  background-color: #f5f5f5;
  border: 1px solid #ddd;
}

/* 应用样式于所有标题,排除侧边栏或页脚内的 */
h2:not(.sidebar *, footer *) {
  margin-top: 2em;
}
对于不支持多参数 :not() 的浏览器,Bun 的 CSS 打包工具将该语法转换成兼容版本,并保留相同行为:
styles.css
/* 转换为使用带 :is() 的 :not() */
button:not(:is(.primary, .secondary)) {
  background-color: #f5f5f5;
  border: 1px solid #ddd;
}

h2:not(:is(.sidebar *, footer *)) {
  margin-top: 2em;
}
如果 :is() 不被支持,Bun 会生成进一步回退:
styles.css
/* 额外回退以确保最大兼容 */
button:not(:-webkit-any(.primary, .secondary)) {
  background-color: #f5f5f5;
  border: 1px solid #ddd;
}

button:not(:-moz-any(.primary, .secondary)) {
  background-color: #f5f5f5;
  border: 1px solid #ddd;
}

button:not(:is(.primary, .secondary)) {
  background-color: #f5f5f5;
  border: 1px solid #ddd;
}
此转换确保否定选择器在各浏览器间正常工作,同时保持正确优先级和原选择器行为。

数学函数

CSS 现在包含丰富的数学函数,允许你直接在样式表中执行复杂计算。这包括标准数学函数 (round()mod()rem()abs()sign())、三角函数 (sin()cos()tan()asin()acos()atan()atan2()) 以及指数函数 (pow()sqrt()exp()log()hypot())。
styles.css
.dynamic-sizing {
  /* 限定值在最小和最大之间 */
  width: clamp(200px, 50%, 800px);

  /* 四舍五入到最接近的倍数 */
  padding: round(14.8px, 5px);

  /* 动画或布局的三角函数 */
  transform: rotate(calc(sin(45deg) * 50deg));

  /* 组合多个函数的复杂数学 */
  --scale-factor: pow(1.25, 3);
  font-size: calc(16px * var(--scale-factor));
}
Bun 的 CSS 打包工具会在构建时对所有已知常量(非变量)求值,生成优化的输出:
styles.css
.dynamic-sizing {
  width: clamp(200px, 50%, 800px);
  padding: 15px;
  transform: rotate(35.36deg);
  --scale-factor: 1.953125;
  font-size: calc(16px * var(--scale-factor));
}
此方式让你能以更具表现力和可维护性的数学关系编写 CSS,然后编译为优化的值,实现最高浏览器兼容性和性能。

媒体查询范围

现代 CSS 支持直观的范围语法,用比较运算符 <><=>= 来指定断点,替代冗长的 min-max- 前缀。这样语法更符合我们对值和范围的习惯理解。
styles.css
/* 比较运算符的现代写法 */
@media (width >= 768px) {
  .container {
    max-width: 720px;
  }
}

/* 使用 <= 和 >= 的包含范围 */
@media (768px <= width <= 1199px) {
  .sidebar {
    display: flex;
  }
}

/* 使用 < 和 > 的排他范围 */
@media (width > 320px) and (width < 768px) {
  .mobile-only {
    display: block;
  }
}
Bun 的 CSS 打包工具会将这些现代范围查询转换为传统媒体查询语法,确保兼容所有浏览器:
styles.css
/* 转换为传统 min/max 语法 */
@media (min-width: 768px) {
  .container {
    max-width: 720px;
  }
}

@media (min-width: 768px) and (max-width: 1199px) {
  .sidebar {
    display: flex;
  }
}

@media (min-width: 321px) and (max-width: 767px) {
  .mobile-only {
    display: block;
  }
}
这让你编写更直观、数学化的媒体查询,同时确保样式表在不支持现代范围语法的浏览器中正常工作。

简写属性

CSS 引入了多个现代简写属性,提升代码可读性和可维护性。Bun 的 CSS 打包工具确保这些便捷简写在所有浏览器上可用,必要时转成长写属性。
styles.css
/* 对齐简写 */
.flex-container {
  /* align-items 和 justify-items 的简写 */
  place-items: center start;

  /* align-content 和 justify-content 的简写 */
  place-content: space-between center;
}

.grid-item {
  /* align-self 和 justify-self 的简写 */
  place-self: end center;
}

/* 双值溢出属性 */
.content-box {
  /* 第一个值对应水平,第二个垂直 */
  overflow: hidden auto;
}

/* 增强的文本装饰 */
.fancy-link {
  /* 结合多条文本装饰属性 */
  text-decoration: underline dotted blue 2px;
}

/* 双值 display 语法 */
.component {
  /* 外层和内层显示类型 */
  display: inline flex;
}
对于不支持这些现代简写的浏览器,Bun 会转换为对应的长写组件属性:
styles.css
.flex-container {
  /* 展开对齐属性 */
  align-items: center;
  justify-items: start;

  align-content: space-between;
  justify-content: center;
}

.grid-item {
  align-self: end;
  justify-self: center;
}

.content-box {
  /* 分别控制溢出方向 */
  overflow-x: hidden;
  overflow-y: auto;
}

.fancy-link {
  /* 单独文本装饰属性 */
  text-decoration-line: underline;
  text-decoration-style: dotted;
  text-decoration-color: blue;
  text-decoration-thickness: 2px;
}

.component {
  /* 单值 display */
  display: inline-flex;
}
该转换确保样式表既保持简洁现代,又兼容最广浏览器。

双点位置渐变

双点位置渐变语法是现代 CSS 特性,通过在渐变中相邻的两个位置指定相同颜色,创建硬色阶过渡。适合制作条纹、色带及多色设计。
styles.css
.striped-background {
  /* 在 30%-40% 制造绿色到红色的硬切换 */
  background: linear-gradient(
    to right,
    yellow 0%,
    green 20%,
    green 30%,
    red 30%,
    /* 双点位置制造硬边界 */ red 70%,
    blue 70%,
    blue 100%
  );
}

.progress-bar {
  /* 制造明显色块 */
  background: linear-gradient(
    to right,
    #4caf50 0% 25%,
    /* 绿色从 0% 到 25% */ #ffc107 25% 50%,
    /* 黄色从 25% 到 50% */ #2196f3 50% 75%,
    /* 蓝色从 50% 到 75% */ #9c27b0 75% 100% /* 紫色从 75% 到 100% */
  );
}
对于不支持该语法的浏览器,Bun 的 CSS 打包工具自动转换为传统格式,复制颜色停点:
styles.css
.striped-background {
  background: linear-gradient(
    to right,
    yellow 0%,
    green 20%,
    green 30%,
    red 30%,
    /* 分成两段色点 */ red 70%,
    blue 70%,
    blue 100%
  );
}

.progress-bar {
  background: linear-gradient(
    to right,
    #4caf50 0%,
    #4caf50 25%,
    /* 两段色点绿段 */ #ffc107 25%,
    #ffc107 50%,
    /* 两段色点黄段 */ #2196f3 50%,
    #2196f3 75%,
    /* 两段色点蓝段 */ #9c27b0 75%,
    #9c27b0 100% /* 两段色点紫段 */
  );
}
此转换让你在源代码使用更简洁的双定位语法,同时确保渐变在所有浏览器正常显示。

system-ui 字体

system-ui 通用字体族让你使用设备的原生 UI 字体,创造与操作系统更为融合的界面外观。无需为每个平台指定不同字体堆栈即可达到更原生的感觉。
styles.css
.native-interface {
  /* 使用系统默认 UI 字体 */
  font-family: system-ui;
}

.fallback-aware {
  /* 带显式回退的系统 UI 字体 */
  font-family: system-ui, sans-serif;
}
对于不支持 system-ui 的浏览器,Bun 的 CSS 打包工具自动扩展为跨平台的综合字体堆栈:
styles.css
.native-interface {
  /* 为所有主流平台扩展 */
  font-family:
    system-ui,
    -apple-system,
    BlinkMacSystemFont,
    "Segoe UI",
    Roboto,
    "Noto Sans",
    Ubuntu,
    Cantarell,
    "Helvetica Neue";
}

.fallback-aware {
  /* 扩展字体堆栈后保留原轮廓回退 */
  font-family:
    system-ui,
    -apple-system,
    BlinkMacSystemFont,
    "Segoe UI",
    Roboto,
    "Noto Sans",
    Ubuntu,
    Cantarell,
    "Helvetica Neue",
    sans-serif;
}
此方案让你只用简单写 system-ui,但确保界面在所有操作系统和浏览器上都适当适配。扩展字体堆栈包含适合 macOS/iOS、Windows、Android、Linux 的系统字体及旧浏览器回退。

CSS 模块

除常规 CSS 外,Bun 的打包工具还支持打包 CSS 模块,具有如下特性:
  • 零配置自动检测 CSS 模块文件(.module.css
  • 组合(composes 属性)
  • 在 JSX/TSX 中导入 CSS 模块
  • 对 CSS 模块错误用法给予警告/错误提示
CSS 模块是采用 .module.css 扩展名的 CSS 文件,其中所有类名和动画都限定于文件内,避免因 CSS 声明默认全局导致的类名冲突。 底层,Bun 的打包工具将局部作用域的类名转为唯一标识符。

快速入门

创建一个以 .module.css 结尾的 CSS 文件:
styles.module.css
.button {
  color: red;
}
other-styles.module.css
.button {
  color: blue;
}
然后你可以导入此文件,比如在 TSX 文件中:
https://mintcdn.com/ikxin/RzFFGbzo0-4huILA/icons/typescript.svg?fit=max&auto=format&n=RzFFGbzo0-4huILA&q=85&s=a3dffd2241f05776d3bd25171d0c5a79app.tsx
import styles from "./styles.module.css";
import otherStyles from "./other-styles.module.css";

export default function App() {
  return (
    <>
      <button className={styles.button}>Red button!</button>
      <button className={otherStyles.button}>Blue button!</button>
    </>
  );
}
导入的 styles 对象将包含所有类名及其唯一标识符:
https://mintcdn.com/ikxin/RzFFGbzo0-4huILA/icons/typescript.svg?fit=max&auto=format&n=RzFFGbzo0-4huILA&q=85&s=a3dffd2241f05776d3bd25171d0c5a79app.tsx
import styles from "./styles.module.css";
import otherStyles from "./other-styles.module.css";

console.log(styles);
console.log(otherStyles);
输出将为:
https://mintcdn.com/ikxin/RzFFGbzo0-4huILA/icons/typescript.svg?fit=max&auto=format&n=RzFFGbzo0-4huILA&q=85&s=a3dffd2241f05776d3bd25171d0c5a79app.tsx
{
  button: "button_123";
}

{
  button: "button_456";
}
由此可见,每个文件的类名都是独一无二的,避免冲突!

组合

CSS 模块允许你组合类选择器,实现样式规则的复用。 例如:
styles.module.css
.button {
  composes: background;
  color: red;
}

.background {
  background-color: blue;
}
等同于写:
styles.module.css
.button {
  background-color: blue;
  color: red;
}

.background {
  background-color: blue;
}
使用 composes 有几点规则要注意:
组合规则:
  • composes 属性必须写在任何常规 CSS 属性之前
  • 只能在带有单个类名的简单选择器上使用 composes
styles.module.css
#button {
  /* 无效!`#button` 不是类选择器 */
  composes: background;
}

.button,
.button-secondary {
  /* 无效!`.button, .button-secondary` 不是简单选择器 */
  composes: background;
}

从独立 CSS 模块文件组合

你也可以从其他 CSS 模块文件中组合类:
background.module.css
.background {
  background-color: blue;
}
styles.module.css
.button {
  composes: background from "./background.module.css";
  color: red;
}
组合来自不同文件的类时,请确保它们不包含相同的属性。CSS 模块规范指出,来自不同文件且属性冲突的组合行为未定义,导致输出可能不同且不可靠。