Sveltes Style-Scoping ist großartig — solange du innerhalb einer Komponente bleibst. Aber eine App lebt nicht in einer einzelnen Datei. Themes, Akzentfarben, Spacing-Skalen wollen geteilt werden. Die saubere Brücke dafür sind CSS Custom Properties (CSS-Variablen). Sie werden vom Browser vererbt und durchschneiden Sveltes Scoping ohne Tricks. Dieser Artikel zeigt, wie du sie in Svelte sinnvoll einsetzt — vom globalen Theme-Token bis zur per Komponente konfigurierten Einzelkachel.

Warum CSS-Variablen so gut zu Svelte passen

Sveltes Scoping setzt Klassennamen mit Hash-Suffix — das ist auf der Selektor-Ebene. CSS-Variablen leben aber auf der Kaskaden-Ebene: Sie werden vererbt. Wer im <html>-Element eine Variable definiert, kann sie an jedem Nachfahren auslesen, auch quer durch Komponenten-Grenzen.

css src/app.css (global)
:root {
    --color-accent: teal;
    --color-text: #1a1a1a;
    --space-2: 0.5rem;
    --space-4: 1rem;
    --radius-md: 8px;
}
svelte Card.svelte
<article>...</article>

<style>
    article {
        padding: var(--space-4);
        color: var(--color-text);
        border-radius: var(--radius-md);
    }
</style>

Die Komponente kennt die Variable nicht von Geburt an — sie holt sie sich beim Rendern aus dem Document-Stylesheet. Wenn :root die Definition liefert, funktioniert sie.

Das macht CSS-Variablen zur idealen Theme-Schnittstelle: zentral definiert, lokal verwendet.

Variablen pro Komponente überschreiben

Die Vererbungs-Mechanik wird interessant, wenn du lokal einen anderen Wert setzen willst — ohne den globalen Default zu verlieren.

svelte DangerCard.svelte
<article class="card">
    <slot />
</article>

<style>
    .card {
        /* Überschreibt --color-accent für sich selbst und alle Nachfahren */
        --color-accent: crimson;
        color: var(--color-accent);
    }
</style>

Jede CSS-Regel kann CSS-Variablen setzen, nicht nur lesen. Innerhalb dieser .card (und ihrer Kinder) liefert var(--color-accent) jetzt crimson. Außerhalb gilt weiter der globale Wert.

Damit kannst du eine Komponente sehr elegant variantengetrieben gestalten, ohne neue Klassen oder Selektor-Verschachtelungen.

CSS-Variablen von außen per style:

Bisher haben wir die Variable im CSS gesetzt. Manchmal soll sie aber dynamisch sein — etwa abhängig vom State der Anwendung. Dafür gibt es die style:-Direktive im Markup:

svelte ProgressBar.svelte
<script>
    let { progress = 0 } = $props();
</script>

<div class="bar" style:--progress="{progress}%">
    <div class="fill"></div>
</div>

<style>
    .bar {
        position: relative;
        height: 8px;
        background: var(--color-bg-elev);
        border-radius: 4px;
        overflow: hidden;
    }

    .fill {
        position: absolute;
        inset: 0;
        width: var(--progress);
        background: var(--color-accent);
        transition: width 200ms ease;
    }
</style>

Was passiert hier:

  1. style:--progress="{progress}%" setzt im Markup eine inline Custom Property auf dem <div>-Element.
  2. Im CSS liest .fill diese Variable mit var(--progress).
  3. Sobald sich progress im Script ändert, aktualisiert Svelte die Inline-Style-Eigenschaft. Die Breite des Balkens animiert sanft mit (transition).

Ohne diese Variable müsstest du style="width: {progress}%" direkt am .fill setzen — was funktioniert, aber das Markup mit Layout-Logik mischt. Mit der Variable bleibt CSS sauber im Style-Block.

Der Trick mit --style-props und der Komponente

Eine besonders elegante Anwendung: Komponenten lassen sich mit CSS-Variablen konfigurieren, ohne dass jede Anpassung eine neue Prop braucht.

svelte Pill.svelte
<script>
    let { children } = $props();
</script>

<span class="pill">
    {@render children()}
</span>

<style>
    .pill {
        display: inline-block;
        padding: 0.25em 0.75em;
        border-radius: 999px;
        background: var(--pill-bg, #eef);
        color: var(--pill-color, #224);
        font-size: var(--pill-size, 0.875rem);
    }
</style>

Die Komponente bietet drei „Konfigurations-Variablen” mit Defaults an. Jeder Konsument kann sie überschreiben — entweder per CSS-Klasse außen oder per style:-Direktive direkt am Element:

svelte Verwendung mit Override
<Pill>Standard</Pill>

<Pill style:--pill-bg="crimson" style:--pill-color="white">
    Achtung
</Pill>

<Pill style:--pill-size="1.1rem">
    Größer
</Pill>

Der Vorteil: Die Komponenten-API bleibt klein (kein eigener color, bg, size-Prop), die Anpassbarkeit ist trotzdem da. Wer mehr will, fügt einfach eine neue Variable hinzu.

Theme-Wechsel: Light- und Dark-Mode

Das gleiche Prinzip funktioniert für Themes. Du definierst zwei Sätze von Variablen, jeder unter einem Selektor:

css src/app.css
:root {
    --color-bg: #ffffff;
    --color-text: #1a1a1a;
    --color-line: #e2e2e2;
}

:root[data-theme='dark'] {
    --color-bg: #1a1a1a;
    --color-text: #f5f5f5;
    --color-line: #333;
}

Beim Theme-Wechsel setzt die App das Attribut auf dem <html>-Element:

svelte ThemeToggle.svelte
<script>
    let theme = $state('light');

    $effect(() => {
        document.documentElement.dataset.theme = theme;
    });
</script>

<button onclick={() => theme = theme === 'light' ? 'dark' : 'light'}>
    {theme}
</button>

Sobald data-theme="dark" gesetzt ist, gewinnt der zweite Variablen-Block. Alle Komponenten, die var(--color-bg) etc. nutzen, schalten automatisch um — ohne CSS-Klassen-Wechsel, ohne Komponenten neu zu rendern.

Häufige Stolperfallen

Variable in der Komponente definieren und außen erwarten. Eine Variable im <style> einer Komponente vererbt sich nur an die Nachfahren des stylenden Elements. Wer sie außerhalb der Komponente lesen will, muss sie auf einem Eltern-Element (oder im globalen Stylesheet) definieren.

Default-Wert vergessen. Wer var(--pill-bg) ohne Default schreibt und niemand setzt die Variable, bekommt leeren Hintergrund. Mit var(--pill-bg, #eef) hast du einen Fallback.

Tippfehler im Variablen-Namen. Anders als bei Klassen warnt der Compiler hier nicht — eine falsch geschriebene Variable führt einfach zu nicht funktionierendem CSS. Wer es absichern will, definiert globale Defaults und nutzt im IDE die Auto-Vervollständigung über .css-Dateien.

style: mit komplexen Werten. style:--ratio={0.5} setzt den Wert als String "0.5". Bei Längen-Werten musst du die Einheit manuell anhängen — style:--width="{px}px" oder per Template-String.

Berechnete Werte mit calc(...). Funktioniert tadellos: width: calc(var(--progress) * 1%) falls die Variable als reine Zahl ankommt. Praktisch, wenn du die Einheit nicht im Markup mitsenden willst.

Weiterführende Ressourcen

Externe Quellen

Verwandte Artikel

/ Weiter

Zurück zu Styling

Zur Übersicht