Tænk på custom properties som et API
Tænk på custom properties som små indstillinger i din CSS. Hvis navnene fortæller, hvad de styrer, bliver det lettere at læse og ændre en komponent senere.
.card { --card-bg: var(--surface-2, #fff); --card-space: var(--space-m, 1rem);
background: var(--card-bg); padding: var(--card-space);}Målet er ikke bare at få flere variabler, men at undgå hårdkodede særregler.
Pattern 1: Lokal override uden at bryde globalt
Brug lokale custom properties til variation i stedet for at kopiere hele komponenten.
.card[data-tone="muted"] { --card-bg: var(--surface-muted);}Det er et godt mønster, når en komponent skal have få, tydelige variationer, som går igen flere steder. Du ændrer værdien, men ikke selve strukturen.
En nyttig tommelfingerregel er, at nogle variabler godt må ændres udefra, mens andre kun bør bruges internt i komponenten.
Pattern 2: Tematiseret sektion
I følgende demo bruges custom properties i lag: sektionen sætter temaet, og cardet læser det ind gennem sine egne variabler. Det er vigtigt, hvis et card senere skal bruges et andet sted, for så skal det stadig kunne stå på egne ben.
- Først får hver sektion sin egen baggrundsvariabel, så forskellen mellem
default,darkogmutedsamles ét sted. - Derefter får sektionen også styr på overskriftsfarven, så kontrasten følger temaet uden ekstra specialregler.
- Så får
.cardsine egne variabler til baggrund, overskrift og tekst, så komponenten også virker uden for en tematiseret sektion. - Til sidst får sektionen lov til at påvirke cardet gennem nogle mellemled, så cardet kan tilpasse sig konteksten uden at miste sine egne fallbacks.
Det ligger tæt på Brad Frosts idé om themeable design systems: temaet sætter rammerne, mens komponenten stadig har sine egne indstillinger. Se fx Creating themeable design systems.
Samme demo sat op i Astro:
Pattern 3: Nesting + custom properties til kontekst
I denne demo bruges variabler til at lade en komponent reagere på sin kontekst uden at CSS’en bliver tung.
Pointen er, at du flytter beslutningen op i container query’en, men lader selve reglerne længere nede være enkle. padding, font-size og layout læser bare en variabel, i stedet for at hver regel selv skal kende breakpointet eller containerens bredde.
Det minder om det Adam Argyle kalder adaptive props: en variabel skifter værdi med konteksten, så resten af komponenten kan nøjes med at bruge den.
Pattern 4: Boolsk styring uden ekstra klasse-API
“Boolean prop”-øvelsen viser et praktisk mønster, hvor én variabel kan tænde eller slukke for en adfærd flere steder på én gang.
Det smarte her er, at 0 og 1 kan bruges som et lille skiftehåndtag (toggle) i calc(). Når variablen skifter, kan du påvirke rotation, afstand, opacity eller andre værdier uden at skrive nye selectors for hver lille variation.
Det ligger tæt på Adam Argyles swap props og Ana Tudors idé om dry switching: én lille variabel kan styre flere visuelle ændringer på én gang.
Pattern 5: SVG-ikon i en custom property
Nogle gange er det praktisk at gemme et lille SVG-ikon i en variabel, hvis det samme ikon skal bruges flere steder uden ekstra markup.
:root { --checkmark-icon: url("data:image/svg+xml,...");}
li::before { background: var(--checkmark-icon) 50% 50% / 100% auto no-repeat;}Det er især fint til små, dekorative ikoner, som bare skal opføre sig som et billede i en pseudo eller baggrund.
Ulempen er, at SVG’en nu bare er en streng. Du kan ikke nemt gå ind og style enkelte dele af den, animere dens indhold eller ændre den på samme måde som rigtig inline SVG i HTML.
Hvis du vil farve ikonet dynamisk, findes der dog et godt workaround: brug SVG’en som mask-image og lad background-color styre farven. Det virker bedst til simple, ensfarvede ikoner. Har du brug for mere kontrol end det, er rigtig inline SVG i markup som regel det bedre valg.
Praktisk checkliste
- Fortæller variabelnavnene, hvad de styrer (
--btn-bg) frem for bare hvilken farve de har (--blue-1)? - Er det tydeligt, hvilke variabler der må overrides udefra, og hvilke der kun bruges internt i komponenten?
- Kan en variant løses ved at ændre en værdi, i stedet for at duplikere hele selector-blokken?
- Har komponenten sine egne variabler (
--card-*), før parenten eller sektionen begynder at ændre dem? - Hvis en variabel skifter med konteksten, ligger beslutningen så ét sted, mens resten af reglerne bare læser værdien?
- Hvis du bruger
0og1som toggle, gør det så koden enklere flere steder på én gang og ikke bare mere kryptisk? - Hvis du gemmer et SVG-ikon i en variabel, er det så kun fordi det skal bruges som et simpelt billede og ikke fordi du skal style eller animere indholdet?