Skip to content

Dynamic Values 與 CSS Variables

PikaCSS 沒有 styling runtime。這正是它能維持效能與可預測性的原因之一,但也代表你處理 dynamic styling 的方式會跟傳統 runtime CSS-in-JS 不一樣。

如果某個值必須在 runtime 改變,請把 pika() 裡的 style definition 維持成靜態,再由你自己把變動的值綁到 CSS variable。

先分清楚你要處理的是哪一種需求

需求建議模式原因
有限個視覺狀態預先宣告 variants,然後在 runtime 切換 class names。PikaCSS 仍然可以預先掃描所有 style shape。
連續變化或每個實例都不同的值pika() 裡使用 var(--...),再於 runtime 綁定 variable。Style shape 保持靜態,value 仍然可以是 dynamic。
共用的主題 tokens在 config 裡定義 variables,並用 selectors 做範圍控制。Design system 可以維持集中且可重用。

不要這樣做

這是最常見、也最容易從 runtime CSS-in-JS 帶進來的習慣。

tsx
type ProgressBarProps = {
	value: number
	color: string
}

function ProgressBar({ value, color }: ProgressBarProps) {
	return (
		<div
			className={pika({
				width: `${value}%`,
				backgroundColor: color,
			})}
		/>
	)
}

pika() 沒辦法安全地分析這種 object,因為真正的 style values 要等到你的 app 執行後才會出現。

透過 CSS variables 綁定 runtime values

正確做法不是把更多 runtime 邏輯塞進 pika()。正確做法是讓 PikaCSS 產生參照 CSS variables 的靜態 declarations,再由你的 framework 或 DOM 程式碼去更新這些 variables。

tsx
import type { CSSProperties } from 'react'

type ProgressBarProps = {
	value: number
	color: string
}

const progressBar = pika({
	width: 'var(--progress-width)',
	backgroundColor: 'var(--progress-color)',
})

function ProgressBar({ value, color }: ProgressBarProps) {
	return (
		<div
			className={progressBar}
			style={{
				'--progress-width': `${value}%`,
				'--progress-color': color,
			} as CSSProperties}
		/>
	)
}

這樣能成立,是因為 PikaCSS 只需要輸出 width: var(--progress-width)background-color: var(--progress-color)。真正的 runtime 綁定仍然由你的 app 負責。

讓 style shape 保持靜態,variants 另外切換

很多 components 同時會有兩種動態需求:

  1. solidoutline 這種離散狀態
  2. 像資料帶進來的品牌色這種每個實例都不同的值

請把它們分開處理。

tsx
import type { CSSProperties } from 'react'

type BadgeVariant = 'solid' | 'outline'

const badgeClassNames = {
	solid: pika({
		backgroundColor: 'var(--badge-color)',
		color: 'white',
	}),
	outline: pika({
		border: '1px solid var(--badge-color)',
		color: 'var(--badge-color)',
	}),
} satisfies Record<BadgeVariant, string>

type BadgeProps = {
	variant: BadgeVariant
	color: string
}

function Badge({ variant, color }: BadgeProps) {
	return (
		<span
			className={badgeClassNames[variant]}
			style={{ '--badge-color': color } as CSSProperties}
		/>
	)
}

在 runtime 選擇靜態 class name,把真正會變的 token value 綁進 CSS variable。

一個好用的遷移心智模型

如果你原本習慣的是傳統 runtime CSS-in-JS,這個轉換很重要:

  1. 不要用 runtime 資料去組 style objects。
  2. 要在 runtime 從預先宣告好的 style objects 裡做選擇。
  3. 要把真正會變的值移進 CSS variables。
  4. 要讓 app layer 自己負責把 variable 指派到哪裡。

記住這條邊界

PikaCSS 可以幫你產生 var(--accent) 這種 references,但不會替你管理 --accent 的狀態。

如果你要處理的是共用 tokens 或主題切換,請接著看 Theming And Variables

Next