Bun

CSS

Bun 的 bundler 內建支援 CSS,並具備以下功能

  • 將現代/未來功能轉譯為可在所有瀏覽器上運作 (包含供應商前綴)
  • 最小化
  • CSS 模組
  • Tailwind (透過原生 bundler 外掛程式)

轉譯

Bun 的 CSS bundler 讓您可以使用現代/未來的 CSS 功能,而無需擔心瀏覽器相容性 — 這一切都歸功於其預設啟用的轉譯和供應商前綴功能。

Bun 的 CSS 解析器和 bundler 是 LightningCSS 的直接 Rust → Zig 移植版本,其打包方法靈感來自 esbuild。轉譯器將現代 CSS 語法轉換為向後相容的等效語法,使其能在各種瀏覽器上運作。

非常感謝 LightningCSSesbuild 的作者們所做的出色工作。

瀏覽器相容性

預設情況下,Bun 的 CSS bundler 目標鎖定以下瀏覽器

  • 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 bundler 會自動將這種巢狀語法轉換為傳統的扁平 CSS,使其能在所有瀏覽器中運作

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

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

.card .content {
  padding: 1rem;
}

您也可以將媒體查詢和其他 at-rules 巢狀內嵌在選取器內,從而無需重複選取器模式

.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 bundler 會在建置時評估這些色彩混合,產生能在所有瀏覽器中運作的靜態顏色值

.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);
}

Bun 的 CSS bundler 會在建置時計算這些相對色彩修改(當不使用 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 bundler 會自動將這些進階色彩格式轉換為向後相容的替代方案,以適用於尚不支援它們的瀏覽器

.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() 函數提供了一種標準化的方式來指定各種預定義色彩空間中的顏色,擴展了您在傳統 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 bundler 提供了適當的 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 bundler 會自動將 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 bundler 會自動轉換這些現代色彩格式,以確保與舊版瀏覽器相容

.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 bundler 會將其轉換為使用帶有適當回退的 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 bundler 會將它們編譯為具有適當方向調整的實體屬性

/* 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 bundler 會將其轉換為更廣泛支援的 :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,即使是那些尚不原生支援 :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 bundler 會轉換此語法以使用 :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 bundler 使用供應商前綴替代方案提供回退

/* 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 bundler 會將此語法轉換為更相容的形式,同時保留相同的行為

/* 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 bundler 會在建置時評估這些數學表達式,從而產生最佳化的輸出

.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 bundler 會將這些現代範圍查詢轉換為傳統的媒體查詢語法,以與所有瀏覽器相容

/* 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 bundler 透過在需要時將這些方便的簡寫轉換為其完整寫法等效項,來確保這些簡寫在所有瀏覽器上都能運作。

/* 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 bundler 會自動將其轉換為傳統格式,方法是複製顏色停止點

.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 bundler 會自動將其擴展為全面的跨平台字體堆疊

.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 的 bundler 也支援打包 CSS modules,並支援以下功能

  • 自動偵測 CSS module 檔案 (.module.css),無需任何配置
  • 組合 (composes 屬性)
  • 將 CSS modules 匯入 JSX/TSX
  • 針對 CSS modules 的無效用法發出警告/錯誤

CSS module 是一個 CSS 檔案(具有 .module.css 擴展名),其中所有類別名稱和動畫都限定於檔案範圍。這有助於您避免類別名稱衝突,因為 CSS 宣告預設為全域範圍。

在底層,Bun 的 bundler 會將本地限定範圍的類別名稱轉換為唯一識別碼。

開始使用

建立一個具有 .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 規範指出,從具有衝突屬性的單獨檔案組合類別是 未定義的行為,這表示輸出可能不同且不可靠。