Skip to content

Theming And Variables

如果你發現自己在多個 components 裡一直重複寫顏色分支,問題多半是 design tokens,並不是少了什麼 runtime logic。

在 config 中定義 variables

ts
import { defineEngineConfig } from '@pikacss/core'

export default defineEngineConfig({
	variables: {
		variables: {
			// 簡單變數(預設會輸出在 :root 之下)
			'--color-bg': '#ffffff',
			'--color-text': '#1a1a1a',

			// 值為 null 的變數(只提供 autocomplete,不會真的輸出 CSS)
			'--external-var': null,

			// 掛在 selector 範圍下的 variables
			'[data-theme="dark"]': {
				'--color-bg': '#1a1a1a',
				'--color-text': '#ffffff',
			},

			// 帶有進階設定的 variable
			'--spacing-unit': {
				value: '4px',
				autocomplete: {
					asValueOf: ['margin', 'padding', 'gap'],
					asProperty: true,
				},
				pruneUnused: false, // 永遠包含在輸出中
			},
		},

		// 是否要從最終 CSS 移除未使用的 variables
		pruneUnused: true,

		// 不管有沒有被使用,都會一律保留的 variables
		safeList: ['--color-bg', '--color-text'],
	},
})

你也可以把 variable definitions 放在 selectors 之下,替不同主題建立各自的值。

ts
import { defineEngineConfig } from '@pikacss/core'

export default defineEngineConfig({
	variables: {
		variables: {
			// 基礎 token,不會直接在任何 atomic style 中被引用
			'--spacing-base': '4px',
			// 衍生 token,會在值中引用 --spacing-base
			'--spacing-lg': 'calc(var(--spacing-base) * 4)',
		},
		pruneUnused: true,
		// --spacing-base is not in safeList and is never used in pika() calls directly.
		// 但因為 --spacing-lg(它本身有被使用)會透過 var() 引用它,
		// BFS 展開會確保 --spacing-base 也會被保留在 CSS 輸出中。
	},
})

在 components 中使用 variables

ts
const className = pika({
	color: 'var(--color-text)',
	backgroundColor: 'var(--color-bg)',
})
css
/* Preflight:變數宣告 */
:root {
  --color-primary: #0ea5e9;
  --color-bg: #ffffff;
  --color-text: #1e293b;
}
[data-theme="dark"] {
  --color-bg: #0f172a;
  --color-text: #e2e8f0;
}

/* 由 pika() 產生的 atomic styles */
.pk-a { color: var(--color-text); }
.pk-b { background-color: var(--color-bg); }

如果 variable 的值需要在 runtime 依每個實例變動,請看 Dynamic Values 與 CSS Variables

一個實用的主題化策略

  1. 用 selectors 描述 light 或 dark 這類主題情境。
  2. 用 variables 承載實際的 token values。
  3. 讓 component style definitions 專注在語意化 token 的使用。

比起直接複製一整份深色和淺色的 component objects,這種拆法通常更容易維護。

該做與不該做

該做不該做
把主題值放進 CSS variables。沒有必要地為每個主題複製整個 component。
用 selectors 來界定 variable definitions 的範圍。把主題邏輯塞進 runtime object construction。
讓 component objects 保持語意化。在每個 component 裡把所有 token 都直接寫死。

Next