Über diese Website

Dieser Kasten steht auf jeder Seite in der linken Spalte. Was darin steht, änderst du in der Konfiguration unter Plugins — oder du schaltest ihn dort ab.

Über dieses Handbuch

Dieses Handbuch gehört zur Vorlage Example für QuartzControl. Es erklärt die Vorlage und führt zugleich alles vor, was sie kann.

Der Text hier kommt aus einer Markdown-Datei, nicht aus der Konfiguration.

SVG mit CSS gestalten

SVG mit CSS gestalten

Ziel

Farben, Linien und Zustände eines SVG per CSS steuern statt im SVG-Code: Icons sollen die Textfarbe übernehmen, beim Hover reagieren, im Dark Mode passen und sich bei Bedarf animieren lassen.

Voraussetzungen

  • Das SVG steht inline im HTML oder wird über <use> eingesetzt. In <img> oder als background-image erreicht das CSS der Seite das SVG nicht (siehe SVG-Code verstehen).
  • Grundbegriffe wie viewBox und path: SVG-Code verstehen.

Getestet mit / Stand

Stand 2026-10-18. Alle Codebeispiele habe ich in Chrome 155 nachgestellt, Firefox und Safari nicht.

Vorgehen

1. Die wichtigsten Eigenschaften

SVG-Formen haben eigene CSS-Eigenschaften:1

EigenschaftWirkung
fillFarbe der Fläche (none für keine)
strokeFarbe der Kontur
stroke-widthStrichstärke. Die Kontur liegt mittig auf dem Pfad, halb innen und halb außen
stroke-linecapLinienenden: butt, round, square
stroke-linejoinEcken: miter, round, bevel
stroke-dasharray, stroke-dashoffsetStrichmuster und wo es beginnt
fill-opacity, stroke-opacityDeckkraft getrennt für Fläche und Kontur
paint-orderob Kontur oder Fläche oben liegt
.diagramm path {
  fill: none;
  stroke: var(--akzent);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

2. Verstehen, warum CSS die Attribute schlägt

Ein exportiertes SVG hat oft Farben als Attribute: <path fill="#1A1A1A">. Solche Präsentationsattribute sehen stark aus, sind in der Kaskade aber das Schwächste überhaupt: Jede CSS-Regel gewinnt gegen sie, egal wie unspezifisch. Präsentationsattribute schlagen nur vererbte Werte.2

In Chrome 155 nachgeprüft:

SituationErgebnis
fill="red" und CSS .icon rect { fill: blue }blau
fill="red" und CSS :where(.icon) rect { fill: blue } (Spezifität 0)blau
style="fill: green" und CSS .icon rect { fill: blue }grün (Inline-Style schlägt das Stylesheet)

↗ Beispiel in neuem Tab öffnen

Soueidan rät, die Attribute im SVG nicht zu löschen: Sie sind ein guter Fallback, falls das CSS einmal nicht lädt.2

3. Farbe von außen übernehmen: currentColor

currentColor steht für den aktuellen Wert von color. Setzt man im SVG fill="currentColor", übernimmt das Icon automatisch die Textfarbe seiner Umgebung:

<button class="loeschen">
  <svg viewBox="0 0 20 20" aria-hidden="true">
    <path d="…" fill="currentColor"/>
  </svg>
  Löschen
</button>
.loeschen { color: crimson; }
.loeschen:hover { color: darkred; }   /* das Icon färbt sich mit */

↗ Beispiel in neuem Tab öffnen

Das ist der einfachste Weg, Icons zu Hover-Zuständen, Dark Mode und Forced-Colors-Modus passend zu halten. In Chrome 155 übernahm das Icon die Farbe des Buttons. (Die Begründung mit dem Forced-Colors-Modus ist eigene Ableitung, nicht getestet.)

4. Inhalte von use stylen

Bei <use> liegt der eingesetzte Inhalt in einem versteckten Shadow DOM. Das hat Folgen:23

<svg style="display: none">
  <symbol id="stern" viewBox="0 0 24 24">
    <path d="…"/>
  </symbol>
</svg>
 
<svg class="icon"><use href="#stern"/></svg>
AnsatzWirkt? (Chrome 155)
Selektor von außen: .icon path { fill: red }nein
Regel auf das Original: #stern path { fill: green }ja, für alle Kopien gleich
Vererbung: .icon { fill: blue }, Pfad ohne eigenes fillja
Custom Property: .icon { --farbe: orange }, im Original fill: var(--farbe, black)ja
fill="currentColor" im Original, .icon { color: … }ja

Custom Properties sind der flexibelste Weg, weil sie vererbt werden und damit in den Klon gelangen. MDN empfiehlt sie ausdrücklich für unterschiedlich gestaltete <use>-Kopien.4

#stern path { fill: var(--stern-farbe, currentColor); }
 
.bewertung .icon       { --stern-farbe: gold; }
.bewertung .icon.leer  { --stern-farbe: lightgray; }

Zwei Farben ohne Custom Properties (nach Soueidan): Ein Teil bekommt fill="currentColor", der andere gar kein fill. Dann steuert man am <use>-Container den einen Teil über fill und den anderen über color.2 In Chrome 155 nachgestellt.

.logo { fill: navy; color: orange; }

↗ Beispiel in neuem Tab öffnen

Funktioniert in Chrome 155 auch: var() direkt im Attribut, also <path fill="var(--farbe, black)">. In den ausgewerteten Quellen steht das nicht. Ich würde mich deshalb auf die Variante im style-Attribut oder im Stylesheet verlassen.

5. Zustände: hover und focus

Inline-SVG-Elemente reagieren auf :hover wie HTML-Elemente:1

.karte:hover .pfeil { stroke: var(--akzent); }

Bei <use> ist es heikler: MDN schreibt, dass „nur wenige Browser“ :hover an Elementen im Klon unterstützen.4 In Chrome 155 reagierte #symbol path:hover im Klon. Robuster ist es, den Zustand am umgebenden Element abzufragen und per Vererbung oder Custom Property weiterzugeben, also .button:hover .icon { --farbe: … }.

6. Geometrie per CSS ändern

Seit SVG 2 sind viele Geometrie-Attribute auch CSS-Eigenschaften (Geometry Properties): x, y, width, height, cx, cy, r, rx, ry und d.3 In Chrome 155 ließen sich width/height am rect, r/cx am circle und sogar d: path("M 0 0 L 40 40") per CSS setzen.

Das MDN-Tutorial „Fills and strokes“ behauptet noch das Gegenteil: width, height und Pfadbefehle gingen nicht per CSS.1 Die Referenzseite zu <use> nennt sie dagegen ausdrücklich als Geometry Properties.3 Das Tutorial ist hier veraltet, zumindest für Chrome. Wie Firefox und Safari das handhaben, habe ich nicht geprüft.

7. Drehen und skalieren: transform-box

Bei SVG-Elementen liegt der Bezugspunkt für transform standardmäßig nicht in der Mitte des Elements, sondern beim Ursprung des SVG. Ein rotate(90deg) schwenkt die Form deshalb um die obere linke Ecke des SVG herum aus dem Bild. Mit transform-box: fill-box bezieht sich die Transformation auf die Form selbst:

.zahnrad {
  transform-box: fill-box;
  transform-origin: center;
}
.zahnrad:hover { rotate: 90deg; }

↗ Beispiel in neuem Tab öffnen

In Chrome 155 nachgemessen: Ohne transform-box landete das gedrehte Rechteck links außerhalb des SVG (x = −4), mit fill-box drehte es sich an Ort und Stelle. Die Erklärung ist eigene Ableitung aus dem Verhalten, MDN-Seiten zu transform-box habe ich nicht ausgewertet.

8. Strichstärke beim Skalieren festhalten

Wird ein SVG verzerrt oder stark skaliert, wachsen die Linien mit. vector-effect: non-scaling-stroke hält die Strichstärke fest:5

.diagramm path { vector-effect: non-scaling-stroke; }

↗ Beispiel in neuem Tab öffnen

Nützlich für Diagramme mit preserveAspectRatio="none". In Chrome 155 nachgestellt: Eine Linie mit stroke-width="1" in einem stark gestreckten SVG wurde mehrere Pixel dick, mit non-scaling-stroke blieb sie 1 Pixel.

9. Linie zeichnen lassen

Mit stroke-dasharray und stroke-dashoffset lässt sich eine Linie so animieren, als würde sie gezeichnet. Mit pathLength="1" am Pfad muss man die echte Länge nicht kennen, weil der Browser dann so rechnet, als wäre der Pfad 1 lang:

<path class="zeichnen" pathLength="1" d="…" fill="none" stroke="currentColor"/>
@media (prefers-reduced-motion: no-preference) {
  .zeichnen {
    stroke-dasharray: 1;
    stroke-dashoffset: 1;            /* ganz versteckt */
    animation: zeichnen 1.5s ease-out forwards;
  }
}
@keyframes zeichnen {
  to { stroke-dashoffset: 0; }       /* ganz sichtbar */
}

↗ Beispiel in neuem Tab öffnen

In Chrome 155 nachgestellt: Mit stroke-dashoffset: 1 ist die Linie unsichtbar, mit 0.5 halb und mit 0 ganz zu sehen. pathLength kommt in den ausgewerteten Quellen nicht vor, das Muster ist verbreitete Praxis. Mehr zu Bewegung und Rücksichtnahme: Barrierearme Animationen.

10. Dark Mode

Für Inline-SVG reicht meist currentColor oder eine Custom Property, die im Dark Mode umgestellt wird (siehe CSS Custom Properties).

Für SVG-Dateien in <img> kann das SVG die Einstellung selbst abfragen:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
  <style>
    circle { fill: black; }
    @media (prefers-color-scheme: dark) { circle { fill: white; } }
  </style>
  <circle cx="10" cy="10" r="9"/>
</svg>

↗ Beispiel in neuem Tab öffnen

In Chrome 155 nachgestellt, mit dunklem Systemdesign: Welcher Fall greift, hängt von color-scheme am <img> ab, das es von der Seite erbt.

color-scheme am <img> bzw. auf der SeiteKreis
nicht gesetzt oder light darkweiß (folgt dem System)
lightschwarz
darkweiß

Ein SVG-Bild folgt also der Farbeinstellung der Seite. Setzt ein Theme-Schalter color-scheme am Wurzelelement, ziehen die SVG-Bilder mit. Eine Seite, die mit color-scheme: light fest hell bleibt, bekommt auch helle SVGs. In den ausgewerteten Quellen steht das nicht, und Firefox und Safari habe ich nicht geprüft.

Warum funktioniert das?

flowchart TD
  A["Welcher fill-Wert gilt?"] --> B{"style-Attribut am Element?"}
  B -- ja --> B1["style-Attribut gewinnt"]
  B -- nein --> C{"Passende Regel im Stylesheet?"}
  C -- ja --> C1["Stylesheet gewinnt,<br/>egal wie spezifisch"]
  C -- nein --> D{"Präsentationsattribut fill=…?"}
  D -- ja --> D1["Attribut gilt"]
  D -- nein --> E["vom Elternelement geerbt,<br/>bei use auch vom use-Element"]

Präsentationsattribute zählen wie Regeln in einem Stylesheet mit dem niedrigsten möglichen Rang.2 Deshalb setzt sich jede echte CSS-Regel durch. Vererbung greift nur, wenn gar nichts gesetzt ist. Darauf beruhen currentColor, Custom Properties und das Stylen von <use>-Inhalten. Das Diagramm fasst Soueidans Erklärung zusammen und lässt !important und Cascade Layers weg.

Fallstricke

  • SVG in <img> lässt sich nicht von außen stylen. Wer Farben per CSS steuern will, muss inline einbinden oder <use> verwenden.
  • Schwarze Flächen nach dem Aufräumen. Löscht man fill im SVG und setzt kein CSS, fällt der Browser auf den Standardwert zurück, und der ist Schwarz.2
  • fill: none vergessen. Linien-Icons (nur Kontur) brauchen ausdrücklich fill: none, sonst wird die Fläche schwarz gefüllt.
  • Konturen werden abgeschnitten. Die Kontur liegt halb außerhalb des Pfads. Reicht der Pfad bis an den Rand der viewBox, fehlt die äußere Hälfte. Abhilfe: etwas Luft in der viewBox lassen. (Eigene Ableitung aus der mittigen Lage der Kontur.)
  • stroke-width mit Einheit. Die Strichstärke wird in User Units der viewBox gerechnet. Bei viewBox="0 0 24 24" und 48px Darstellungsgröße wird stroke-width: 2 zu 4 Pixeln. (Eigene Ableitung, siehe SVG-Code verstehen.)
  • Selektoren erreichen den <use>-Klon nicht. Siehe Schritt 4.

Browsersupport

Laut web-features 3.43.0 (abgefragt 2026-10-18):

FeatureStand
SVG, currentColorBaseline widely available
paint-orderBaseline widely available seit 2026-09-22
transform-boxBaseline newly available seit 2024-04-16
vector-effectlaut MDN-Banner widely available („since July 2020“), in web-features nicht als eigener Eintrag gefunden
context-fill/context-strokelimited: Chrome 124, Firefox 111, Safari fehlt

Siehe auch

Quellen

Eigene Ergänzungen: die Tests in Chrome 155 (Kaskade, <use>-Tabelle, var() im Attribut, Geometry Properties, transform-box, non-scaling-stroke, Strichanimation, Dark Mode im <img>), das Diagramm, das Muster mit pathLength="1" und die Fallstricke zu fill: none, abgeschnittenen Konturen und stroke-width.

Footnotes

  1. SVG Füllung und Kontur (MDN), Abschnitte „Fill and Stroke Attributes“ und „Using CSS“, Stand 2026-08-07. ↩ ↩2 ↩3

  2. Styling SVG use Content with CSS (Sara Soueidan), Abschnitte „The Style Cascade“, „Overriding Presentation Attribute Values From CSS“, „Using the CSS currentColor Variable“ und „Styling Content with CSS Custom Properties“, 2015-07-16. ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  3. use-Element (MDN), Abschnitte „Attributes“ und „Usage notes“, Stand 2026-08-14. ↩ ↩2 ↩3

  4. SVG und CSS (MDN), Hinweis am Anfang und Abschnitt „Simplified structure“, Stand 2026-08-03. ↩ ↩2

  5. vector-effect Attribut (MDN), Abschnitt „Usage notes“, Stand 2025-04-03. ↩

Weiterlesen

Diese Seite gehört zu gui-test — der Beispielvorlage für QuartzControl. Ein Überblick über alle Bereiche steht auf der Startseite.

Auf einem schmalen Bildschirm ist die Navigation oben eingeklappt.