Bun

CSS

Bun 的打包器内置支持 CSS,并提供以下功能

  • 将现代/未来的特性转译为可在所有浏览器中运行的代码(包括供应商前缀)
  • 代码压缩
  • CSS Modules
  • Tailwind (通过原生打包器插件)

转译

Bun 的 CSS 打包器让您可以使用现代/未来的 CSS 特性,而无需担心浏览器兼容性——这都归功于其默认启用的转译和供应商前缀功能。

Bun 的 CSS 解析器和打包器是直接将 LightningCSS 从 Rust 移植到 Zig 的,其打包方法则借鉴了 esbuild。转译器将现代 CSS 语法转换为向后兼容的等价形式,使其能在所有浏览器中运行。

非常感谢 LightningCSSesbuild 的作者们的杰出工作。

浏览器兼容性

默认情况下,Bun 的 CSS 打包器支持以下浏览器

  • ES2020
  • Edge 88+
  • Firefox 78+
  • Chrome 87+
  • Safari 14+

语法降级

嵌套

CSS 嵌套规范允许您通过将选择器嵌套在一起,来编写更简洁、更直观的样式表。您不必在 CSS 文件中重复父选择器,而是可以直接在父块内编写子样式。

/* With nesting */
.card {
  background: white;
  border-radius: 4px;

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

  .content {
    padding: 1rem;
  }
}

Bun 的 CSS 打包器会自动将这种嵌套语法转换为传统的扁平化 CSS,使其能在所有浏览器中运行。

/* Compiled output */
.card {
  background: white;
  border-radius: 4px;
}

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

.card .content {
  padding: 1rem;
}

您还可以将媒体查询和其他 at 规则嵌套在选择器中,从而无需重复选择器模式。

.responsive-element {
  display: block;

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

这将编译为

.responsive-element {
  display: block;
}

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

颜色混合

color-mix() 函数提供了一种简便的方法,可以根据指定的比例在选定的颜色空间中混合两种颜色。此强大功能使您无需手动计算结果值即可创建颜色变体。

.button {
  /* Mix blue and red in the RGB color space with a 30/70 proportion */
  background-color: color-mix(in srgb, blue 30%, red);

  /* Create a lighter variant for hover state */
  &:hover {
    background-color: color-mix(in srgb, blue 30%, red, white 20%);
  }
}

当所有颜色值都已知时(非 CSS 变量),Bun 的 CSS 打包器会在构建时计算这些颜色混合,生成适用于所有浏览器的静态颜色值。

.button {
  /* Computed to the exact resulting color */
  background-color: #b31a1a;
}

.button:hover {
  background-color: #c54747;
}

此功能对于使用程序化派生的色调、浅色和强调色创建颜色系统非常有用,而无需预处理器或自定义工具。

相对颜色

CSS 现在允许您使用相对颜色语法修改颜色的各个组件。此强大功能使您可以通过调整亮度、饱和度或单个通道等特定属性来创建颜色变体,而无需重新计算整个颜色。

.theme-color {
  /* Start with a base color and increase lightness by 15% */
  --accent: lch(from purple calc(l + 15%) c h);

  /* Take our brand blue and make a desaturated version */
  --subtle-blue: oklch(from var(--brand-blue) l calc(c * 0.8) h);
}

当不使用 CSS 变量时,Bun 的 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 色域的颜色,从而实现更鲜艳、视觉上更一致的设计。

.vibrant-element {
  /* A vibrant red that exceeds sRGB gamut boundaries */
  color: lab(55% 78 35);

  /* A smooth gradient using perceptual color space */
  background: linear-gradient(
    to right,
    oklch(65% 0.25 10deg),
    oklch(65% 0.25 250deg)
  );
}

对于尚不支持这些高级颜色格式的浏览器,Bun 的 CSS 打包器会自动将它们转换为向后兼容的替代格式。

.vibrant-element {
  /* Fallback to closest RGB approximation */
  color: #ff0f52;
  /* P3 fallback for browsers with wider gamut support */
  color: color(display-p3 1 0.12 0.37);
  /* Original value preserved for browsers that support it */
  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 空间之外。这使您能够访问更广泛的色域并创建更生动的效果。

.vivid-element {
  /* Using the Display P3 color space for wider gamut colors */
  color: color(display-p3 1 0.1 0.3);

  /* Using A98 RGB color space */
  background-color: color(a98-rgb 0.44 0.5 0.37);
}

对于尚未支持这些高级颜色函数的浏览器,Bun 的 CSS 打包器会提供适当的 RGB 回退。

.vivid-element {
  /* RGB fallback first for maximum compatibility */
  color: #fa1a4c;
  /* Keep original for browsers that support it */
  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 值相比,许多设计师发现这种方法在创建颜色变体方面更自然。

.easy-theming {
  /* Pure cyan with no white or black added */
  --primary: hwb(180 0% 0%);

  /* Same hue, but with 20% white added (tint) */
  --primary-light: hwb(180 20% 0%);

  /* Same hue, but with 30% black added (shade) */
  --primary-dark: hwb(180 0% 30%);

  /* Muted version with both white and black added */
  --primary-muted: hwb(180 30% 20%);
}

Bun 的 CSS 打包器会自动将 HWB 颜色转换为 RGB,以确保与所有浏览器的兼容性。

.easy-theming {
  --primary: #00ffff;
  --primary-light: #33ffff;
  --primary-dark: #00b3b3;
  --primary-muted: #339999;
}

HWB 模型使得为设计系统创建系统性颜色变体变得特别容易,提供了一种比直接处理 RGB 或 HSL 值更直观的方法来创建一致的色调和阴影。

颜色表示法

现代 CSS 引入了更直观、更简洁的颜色表示方法。空格分隔的颜色语法消除了 RGB 和 HSL 值中逗号的需要,而带有 alpha 通道的十六进制颜色则提供了一种简洁的方式来指定透明度。

.modern-styling {
  /* Space-separated RGB notation (no commas) */
  color: rgb(50 100 200);

  /* Space-separated RGB with alpha */
  border-color: rgba(100 50 200 / 75%);

  /* Hex with alpha channel (8 digits) */
  background-color: #00aaff80;

  /* HSL with simplified notation */
  box-shadow: 0 5px 10px hsl(200 50% 30% / 40%);
}

Bun 的 CSS 打包器会自动转换这些现代颜色格式,以确保与旧浏览器的兼容性。

.modern-styling {
  /* Converted to comma format for older browsers */
  color: rgb(50, 100, 200);

  /* Alpha channels handled appropriately */
  border-color: rgba(100, 50, 200, 0.75);

  /* Hex+alpha converted to rgba when needed */
  background-color: rgba(0, 170, 255, 0.5);

  box-shadow: 0 5px 10px rgba(38, 115, 153, 0.4);
}

此转换过程使您能够编写更清晰、更现代的 CSS,同时确保您的样式在所有浏览器中都能正常运行。

light-dark() 颜色函数

light-dark() 函数提供了一种优雅的解决方案,用于实现尊重用户系统偏好的颜色方案,而无需复杂的媒体查询。此函数接受两个颜色值,并根据当前的颜色方案上下文自动选择合适的颜色。

:root {
  /* Define color scheme support */
  color-scheme: light dark;
}

.themed-component {
  /* Automatically picks the right color based on system preference */
  background-color: light-dark(#ffffff, #121212);
  color: light-dark(#333333, #eeeeee);
  border-color: light-dark(#dddddd, #555555);
}

/* Override system preference when needed */
.light-theme {
  color-scheme: light;
}

.dark-theme {
  color-scheme: dark;
}

对于尚未支持此功能的浏览器,Bun 的 CSS 打包器会将其转换为使用带有适当回退的 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 逻辑属性允许您根据文档的书写模式和文本方向(而不是物理屏幕方向)来定义布局、间距和大小。这对于创建真正国际化的布局至关重要,这些布局可以自动适应不同的书写系统。

.multilingual-component {
  /* Margin that adapts to writing direction */
  margin-inline-start: 1rem;

  /* Padding that makes sense regardless of text direction */
  padding-block: 1rem 2rem;

  /* Border radius for the starting corner at the top */
  border-start-start-radius: 4px;

  /* Size that respects the writing mode */
  inline-size: 80%;
  block-size: auto;
}

对于尚不支持逻辑属性的浏览器,Bun 的 CSS 打包器会将它们编译为具有适当方向调整的物理属性。

/* For left-to-right languages */
.multilingual-component:dir(ltr) {
  margin-left: 1rem;
  padding-top: 1rem;
  padding-bottom: 2rem;
  border-top-left-radius: 4px;
  width: 80%;
  height: auto;
}

/* For right-to-left languages */
.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 即可创建方向感知设计的强大方法。此选择器根据文档或显式方向属性确定的方向性匹配元素。

/* Apply different styles based on text direction */
.nav-arrow:dir(ltr) {
  transform: rotate(0deg);
}

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

/* Position elements based on text flow */
.sidebar:dir(ltr) {
  border-right: 1px solid #ddd;
}

.sidebar:dir(rtl) {
  border-left: 1px solid #ddd;
}

对于尚不支持 :dir() 选择器的浏览器,Bun 的 CSS 打包器会将其转换为更广泛支持的 :lang() 选择器,并进行适当的语言映射。

/* Converted to use language-based selectors as fallback */
.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,该 CSS 在所有浏览器中都能可靠运行,即使是那些尚未原生支持 :dir() 选择器的浏览器。如果不支持 :lang() 的多个参数,则会提供进一步的回退。

:lang() 选择器

:lang() 伪类选择器允许您根据元素所属的语言来定位元素,从而轻松应用特定于语言的样式。现代 CSS 允许 :lang() 选择器接受多个语言代码,让您可以更有效地对特定于语言的规则进行分组。

/* Typography adjustments for CJK languages */
:lang(zh, ja, ko) {
  line-height: 1.8;
  font-size: 1.05em;
}

/* Different quote styles by language group */
blockquote:lang(fr, it, es, pt) {
  font-style: italic;
}

blockquote:lang(de, nl, da, sv) {
  font-weight: 500;
}

对于不支持 :lang() 选择器中多个参数的浏览器,Bun 的 CSS 打包器会将此语法转换为使用 :is() 选择器,以保持相同的行为。

/* Multiple languages grouped with :is() for better browser support */
: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 中的重复。

/* Instead of writing these separately */
/* 
.article h1,
.article h2,
.article h3 {
  margin-top: 1.5em;
}
*/

/* You can write this */
.article :is(h1, h2, h3) {
  margin-top: 1.5em;
}

/* Complex example with multiple groups */
:is(header, main, footer) :is(h1, h2, .title) {
  font-family: "Heading Font", sans-serif;
}

对于不支持 :is() 的浏览器,Bun 的 CSS 打包器会提供使用供应商前缀的替代方案作为回退。

/* Fallback using -webkit-any */
.article :-webkit-any(h1, h2, h3) {
  margin-top: 1.5em;
}

/* Fallback using -moz-any */
.article :-moz-any(h1, h2, h3) {
  margin-top: 1.5em;
}

/* Original preserved for modern browsers */
.article :is(h1, h2, h3) {
  margin-top: 1.5em;
}

/* Complex example with fallbacks */
:-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() 伪类允许您排除与特定选择器匹配的元素。此选择器的现代版本接受多个参数,让您可以使用一个简洁的选择器排除多个模式。

/* Select all buttons except primary and secondary variants */
button:not(.primary, .secondary) {
  background-color: #f5f5f5;
  border: 1px solid #ddd;
}

/* Apply styles to all headings except those inside sidebars or footers */
h2:not(.sidebar *, footer *) {
  margin-top: 2em;
}

对于不支持 :not() 中多个参数的浏览器,Bun 的 CSS 打包器会将此语法转换为更兼容的形式,同时保留与原始选择器相同的行为。

/* Converted to use :not with :is() for compatibility */
button:not(:is(.primary, .secondary)) {
  background-color: #f5f5f5;
  border: 1px solid #ddd;
}

h2:not(:is(.sidebar *, footer *)) {
  margin-top: 2em;
}

如果 :is() 不受支持,Bun 还可以生成进一步的回退。

/* Even more fallbacks for maximum compatibility */
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())。

.dynamic-sizing {
  /* Clamp a value between minimum and maximum */
  width: clamp(200px, 50%, 800px);

  /* Round to the nearest multiple */
  padding: round(14.8px, 5px);

  /* Trigonometry for animations or layouts */
  transform: rotate(calc(sin(45deg) * 50deg));

  /* Complex math with multiple functions */
  --scale-factor: pow(1.25, 3);
  font-size: calc(16px * var(--scale-factor));
}

当所有值都是已知的常量(不是变量)时,Bun 的 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- 前缀。此语法更易读,并且与我们通常思考值和范围的方式相匹配。

/* Modern syntax with comparison operators */
@media (width >= 768px) {
  .container {
    max-width: 720px;
  }
}

/* Inclusive range using <= and >= */
@media (768px <= width <= 1199px) {
  .sidebar {
    display: flex;
  }
}

/* Exclusive range using < and > */
@media (width > 320px) and (width < 768px) {
  .mobile-only {
    display: block;
  }
}

Bun 的 CSS 打包器会将这些现代范围查询转换为传统的媒体查询语法,以确保与所有浏览器的兼容性。

/* Converted to traditional min/max syntax */
@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 打包器通过在需要时将其转换为对应的长属性,确保这些方便的简写属性在所有浏览器上都能正常工作。

/* Alignment shorthands */
.flex-container {
  /* Shorthand for align-items and justify-items */
  place-items: center start;

  /* Shorthand for align-content and justify-content */
  place-content: space-between center;
}

.grid-item {
  /* Shorthand for align-self and justify-self */
  place-self: end center;
}

/* Two-value overflow */
.content-box {
  /* First value for horizontal, second for vertical */
  overflow: hidden auto;
}

/* Enhanced text-decoration */
.fancy-link {
  /* Combines multiple text decoration properties */
  text-decoration: underline dotted blue 2px;
}

/* Two-value display syntax */
.component {
  /* Outer display type + inner display type */
  display: inline flex;
}

对于尚不支持这些现代简写属性的浏览器,Bun 会将其转换为其组件长属性。

.flex-container {
  /* Expanded alignment properties */
  align-items: center;
  justify-items: start;

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

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

.content-box {
  /* Separate overflow properties */
  overflow-x: hidden;
  overflow-y: auto;
}

.fancy-link {
  /* Individual text decoration properties */
  text-decoration-line: underline;
  text-decoration-style: dotted;
  text-decoration-color: blue;
  text-decoration-thickness: 2px;
}

.component {
  /* Single value display */
  display: inline-flex;
}

此转换确保您的样式表保持清晰和易于维护,同时提供最广泛的浏览器兼容性。

双位置渐变

双位置渐变语法是一项现代 CSS 功能,它允许您通过在两个相邻位置指定相同的颜色来创建硬颜色停止点。这会产生清晰的过渡,而不是平滑的渐变,这对于创建条纹、色带和其他多色设计非常有用。

.striped-background {
  /* Creates a sharp transition from green to red at 30%-40% */
  background: linear-gradient(
    to right,
    yellow 0%,
    green 20%,
    green 30%,
    red 30%,
    /* Double position creates hard stop */ red 70%,
    blue 70%,
    blue 100%
  );
}

.progress-bar {
  /* Creates distinct color sections */
  background: linear-gradient(
    to right,
    #4caf50 0% 25%,
    /* Green from 0% to 25% */ #ffc107 25% 50%,
    /* Yellow from 25% to 50% */ #2196f3 50% 75%,
    /* Blue from 50% to 75% */ #9c27b0 75% 100% /* Purple from 75% to 100% */
  );
}

对于尚不支持此语法的浏览器,Bun 的 CSS 打包器会自动通过复制颜色停止点将其转换为传统格式。

.striped-background {
  background: linear-gradient(
    to right,
    yellow 0%,
    green 20%,
    green 30%,
    red 30%,
    /* Split into two color stops */ red 70%,
    blue 70%,
    blue 100%
  );
}

.progress-bar {
  background: linear-gradient(
    to right,
    #4caf50 0%,
    #4caf50 25%,
    /* Two stops for green section */ #ffc107 25%,
    #ffc107 50%,
    /* Two stops for yellow section */ #2196f3 50%,
    #2196f3 75%,
    /* Two stops for blue section */ #9c27b0 75%,
    #9c27b0 100% /* Two stops for purple section */
  );
}

此转换允许您在源代码中使用更清晰的双位置语法,同时确保渐变在所有浏览器中都能正确显示。

system-ui 字体

system-ui 通用字体系列允许您使用设备的本机 UI 字体,创建感觉与操作系统更集成的界面。这提供了更原生的外观和感觉,而无需为每个平台指定不同的字体堆栈。

.native-interface {
  /* Use the system's default UI font */
  font-family: system-ui;
}

.fallback-aware {
  /* System UI font with explicit fallbacks */
  font-family: system-ui, sans-serif;
}

对于尚不支持 system-ui 的浏览器,Bun 的 CSS 打包器会自动将其扩展为全面的跨平台字体堆栈。

.native-interface {
  /* Expanded to support all major platforms */
  font-family:
    system-ui,
    -apple-system,
    BlinkMacSystemFont,
    "Segoe UI",
    Roboto,
    "Noto Sans",
    Ubuntu,
    Cantarell,
    "Helvetica Neue";
}

.fallback-aware {
  /* Preserves the original fallback after the expanded stack */
  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 Modules

除了常规 CSS 之外,Bun 的打包器还支持打包 CSS Modules,并支持以下功能:

  • 自动检测 CSS Module 文件(.module.css),无需任何配置
  • 组合(composes 属性)
  • 将 CSS Module 导入 JSX/TSX
  • 对 CSS Module 的无效使用发出警告/错误

CSS Module 是一个 CSS 文件(扩展名为 .module.css),其中所有类名和动画都限定在文件范围内。这有助于您避免类名冲突,因为 CSS 声明默认是全局范围的。

在底层,Bun 的打包器将局部范围的类名转换为唯一的标识符。

入门

创建一个扩展名为 .module.css 的 CSS 文件

/* styles.module.css */
.button {
  color: red;
}

/* other-styles.module.css */
.button {
  color: blue;
}

然后您可以导入此文件,例如到 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>
    </>
  );
}

从导入 CSS Module 文件获得的 styles 对象将是一个对象,其中类名为键, 其唯一标识符为值。

import styles from "./styles.module.css";
import otherStyles from "./other-styles.module.css";

console.log(styles);
console.log(otherStyles);

这将输出

{
  button: "button_123";
}

{
  button: "button_456";
}

如您所见,类名是每个文件独有的,避免了任何冲突!

组合

CSS Modules 允许您将类选择器“组合”在一起。这允许您在多个类之间重用样式规则。

例如

/* styles.module.css */
.button {
  composes: background;
  color: red;
}

.background {
  background-color: blue;
}

将相当于编写

.button {
  background-color: blue;
  color: red;
}

.background {
  background-color: blue;
}

在使用 composes 时需要注意几条规则:

  • composes 属性必须出现在任何常规 CSS 属性或声明之前。
  • 您只能在**具有单个类名的简单选择器**上使用 composes
#button {
  /* Invalid! `#button` is not a class selector */
  composes: background;
}

.button,
.button-secondary {
  /* Invalid! `.button, .button-secondary` is not a simple selector */
  composes: background;
}

从单独的 CSS Module 文件组合

您还可以从单独的 CSS Module 文件组合。

/* background.module.css */
.background {
  background-color: blue;
}

/* styles.module.css */
.button {
  composes: background from "./background.module.css";
  color: red;
}

组合来自不同文件的类时,请确保它们不包含相同的属性。

CSS Module 规范规定,组合具有冲突属性的来自不同文件的类是 未定义行为,这意味着输出可能不同且不可靠。