SVG/Tutorials/Einstieg/SVG mit CSS stylen

Aus SELFHTML-Wiki
< SVG‎ | Tutorials‎ | Einstieg
Wechseln zu: Navigation, Suche

Einer der großen Vorteile von SVG gegenüber zum Beispiel canvas ist die Möglichkeit SVG-Objekte mit CSS zu formatieren.[1]

Anders als bei HTML, wo die Trennung zwischen Inhalt und Design (mittels CSS) schon lange akzeptiert ist, wurde das Aussehen von SVG-Elementen ursprünglich allein durch XML-Attribute festgelegt.[2] Viele davon sind aber Präsentations- oder Geometrie-Attribute, die Sie auch über CSS notieren können. So wird das SVG-Markup schlanker, verständlicher und kann zentral im Stylesheet geändert werden.

XML vs. CSS

XML-Attribute und CSS-inline Style
<circle id="beispiel1"
  cx="50"
  cy="50"
  r="50" 
  fill="gold"
  stroke="steelBlue"
  stroke-width="2" 
/>

<circle id="beispiel2"
  style="cx:50; cy:50; r:50; fill:gold; stroke:steelBlue; stroke-width:2;"
/>

Im ersten Beispiel sind alle Angaben als XML-Attribute deklariert, während im zweiten Beispiel alle Stileigenschaften als Inline-CSS in einem style-Attribut zusammengefasst wurden.[3]

Beachten Sie: CSS-Angaben in einem style-Attribut haben - wie auch in HTML - Vorrang vor CSS-Angaben, die über CSS Regeln in <style>-Elementen oder in externen Stylesheets gemacht wurden.

Noch übersichtlicher ist es, die CSS-Anweisungen in einem style-Element zu notieren:

CSS-Regelsätze innerhalb eines style-Elements
<svg>
  <style type="text/css">
    <![CDATA[
      circle {
        cx: 50;
        cy: 50;
        r:  50;
        fill: gold;
        stroke: steelBlue;
        stroke-width: 2;
      }
    ]]>
  </style> 
  <circle id="beispiel3" />
</svg>

Es ist egal, wo Sie das style-Element notieren:

Stylesheets, die auf diese Weise in einem Inline-SVG Element erstellt werden, sind gleichrangig mit allen anderen Stylesheets, die im HTML-Dokument verwendet werden. Sie gehen in der Reihenfolge, wie der HTML Parser sie antrifft, in die Kaskade ein und haben entsprechende Spezifität.

Beachten Sie: Da in CSS-Angaben anders als in XML-Dokumenten ein > vorkommen darf (z.B. beim Kindkombinator E > F, sollten die Stil-Definitionen in CDATA gekapselt werden.
Beachten Sie: SVG-Grafiken im Wiki
SVG-Grafiken werden durch die MediaWiki-Software nicht direkt gerendert.
Es werden als Fallback für ältere (mittlerweile ausgestorbene) Browser Vorschau-Grafiken im png-Format erstellt. Dieses Skript benötigt die in HTML5 eigentlich nicht mehr notwendige Angabe type="text/css", damit die style-Festlegungen berücksichtigt werden.
Beachten Sie: Das Gesagte gilt nur für SVG-Grafiken, die Sie inline im HTML erstellt haben. Wenn Sie eine SVG-Grafik über ein <img>-Element einbetten, können Sie sie aus dem HTML heraus mit CSS nicht beeinflussen. Eine solche Grafik stellt ein Standalone-SVG dar, das ein eigenständiges DOM besitzt und daher eigene Stylesheets braucht.

Präsentationsattribute mit CSS gestalten

Um SVG-Elemente auszuwählen, können Sie fast alle Selektoren sowie dynamische Pseudoklassen :hover, :active und :focus und strukturelle Pseudoklassen wie first- und last-child verwenden und für die Präsentationsattribute CSS-Regeln festlegen.


Eigentlich kennen Sie die meisten Präsentationsattribute bereits aus HTML und CSS. Andere wie die Geometrie-Attribute werden im Anschluss erklärt.

Hauptartikel: SVG/Attribut/Präsentationsattribute


Farben

Sie haben schon im letzten Kapitel gesehen, dass Objekte in SVG mehr Gestaltungsmöglichkeiten haben:

In der HTML-Welt haben Block-Elemente einen Hintergrund und Rand, Text jedoch nur eine Textfarbe color. In SVG wird jedes Objekt, ob Grundform, Pfad oder Text gerendert, indem es mit fill gefüllt oder mit einer Randlinie versehen wird. Dabei gibt es viel mehr Möglichkeiten zur Gestaltung dieser Eigenschaften.

Grundformen - mit CSS formatiert ansehen …
* {
  stroke: steelBlue;
  stroke-width: 5;
}

path {
  fill: #c82f04;	
}

#quadrat {
  fill: gold;	
  stroke-width: 10;
  stroke-opacity: 0.5;
}

Die Grundformen werden über den Universalselektor *ausgewählt und erhalten mit der stroke-Eigenschaft einen blauen Rand, der mit stroke-width eine Breite von 5 erhält. Eine Angabe zur Füllung fehlt, wodurch der Kreis eine schwarze Füllung erhält. Das Dreieck über den Typselektor path ausgewählt und mit fill rot gefüllt (Sollte dort evtl. fill="none" gezeigt werden?)

Das Viereck wird über seine id quadrat angesprochen und gelb gefüllt. Dort wird die Breite der Randlinie auf 10 erhöht. Da die Randlinie mit stroke-opacity durchscheinend ist, sieht man, dass sich die Randlinie sowohl nach innen als auch nach außen ausdehnt. Obwohl das Quadrat ein width="140"-Attribut hat, ist es tatsächlich 150 Pixel dimensionslose Einheiten breit.

Füllung

Wie Sie eben gesehen haben, werden Formen in SVG ohne weitere Festlegung schwarz gefüllt. Deshalb muss man immer die fill-Eigenschaft festlegen.

Mögliche Werte für fill sind:

  • eine Farbangabe
  • die Angabe none, Hintergrund wird transparent dargestellt
  • die Angabe currentColor, weist den Browser an, einen festgelegten Standardfarbwert zu verwenden
  • eine url(#id) um ein Muster oder Verlauf zu referenzieren

Dies ist besonders wichtig für Pfade und Polygonlinie mit offenen Pfaden:

Füllung ansehen …
Überlegen Sie, wie sich eine Füllung auf die Grafik auswirkt!
Svg-path.jpg
.normal {
  stroke: steelBlue;
  stroke-width: 3;
  fill: none;
  }
.normal:hover,
.normal:focus {
  fill: gold;
  }

Aber auch bei sich mehrfach überschneidenden Figuren kann es zu unerwarteten Effekten kommen:

Füllmethoden ansehen …
Überlegen Sie, wie sich eine Füllung auf die Grafik auswirkt!
Svg-path-2.jpg
.normal {
  stroke: steelBlue;
  stroke-width: 3;
  fill: gold;
  fill-rule: evenodd;  
  }
#zwei {
  fill-rule: nonzero;
  }
<svg>
      <polygon class="normal" points="100,10 40,198 190,78 10,78 160,198"/>
      <polygon class="normal" id="zwei" points="300,10 240,198 390,78 210,78 360,198"/>
</svg>

Geometrie-Attribute

Mit SVG 2 werden die XML-Attribute für Abmessungen (width, height bzw. r, rx, ry) und Positionsangaben (x, y bzw. cx, cy) zu Präsentationsattributen und können nun ebenfalls mit CSS festgelegt und dadurch z. B. durch hover verändert werden.[4]

Grundformen - mit CSS formatiert ansehen …
<circle id="kreis" tabindex="1" cx="100" cy="100" />
<path id="dreieck" tabindex="2" d="M200,30 h140 l-70,140 z" />
<rect id="quadrat" tabindex="3" x="380" y="30" width="140" height="140" />
Die Grundformen erhalten neben ihrer id einen tabindex, damit sie auch mit der Tastatur anwählbar sind.
* {
  fill: gold;	
  stroke: steelBlue;
  stroke-width: 3;
  transition: all 0.5s ease-out;
}

#kreis {
  r: 50px;  /* für Firefox */
}
#kreis:hover,
#kreis:focus {
  r: 100px;
  fill: #c82f04;
}

#dreieck:hover,
#dreieck:focus {
  fill: #c82f04;	
  stroke-width: 40;
  stroke: #c82f04;	
}

#quadrat:hover,
#quadrat:focus {
  fill: steelBlue;
  width: 150px;
  height: 50px;	
}

Alle Elemente erhalten über den Universalselektor * eine gelbe Füllung, eine schmale blaue Randlinie und eine transition für weiche Übergänge. Bei :hover und :focus ändern die Grundformen ihre CSS-Eigenschaften:

  • Der Radius des Kreises wird von 50px auf 100px erhöht
Beachten Sie: Als XML-Attribut benötigt r keine Einheit; innerhalb von Style-Regeln empfehlen wir aber die Verwendung der Einheit px, weil es Browser-Versionen gab, die die Angabe ohne Einheit nicht akzeptiert haben.
  • Das Dreieck erhält bei :hover mit der Eigenschaft stroke-width einen breiteren Rand. Da der Rand genau auf der Grenze liegt, teilt sich der Rand von 40 so auf, dass er 20px innerhalb und 20px außerhalb des Dreiecks liegt und so Breite und Höhe scheinbar vergrößert.
  • Das Quadrat hat ein width- und ein height-Attribut. Bei :hover werden die Werte durch die entsprechenden CSS-Regelsätze überschrieben.


Beachten Sie: In Chrome und Opera funktionieren Pseudoklassen wie :hover und :focus beim Aufrufen mit use-Elementen nicht. Verschieben Sie die Kindelemente in das zu animierende Objekt.

Siehe auch:

SVG und Custom Properties

Custom properties ermöglichen es, Werte mehrfach zu verwenden bzw. als Grundlage für Berechnungen zu verwenden. Dies ist auch in SVG möglich - sowohl in den XML-Attributen als auch im Stylesheet:

SVG und Custom Properties ansehen …
<style>
.stylesheet {
	fill: var(--gold);
	stroke: var(--blue);
	stroke-width: calc(1.5px * var(--width));
}

svg {
	--blue: steelBlue;
	--green: #8db243;
	--red: #c82f04;
	--gold: gold;
	--width: 5;
	border: thin dotted var(--blue);
}
</style>

<rect ... fill="var(--gold)" stroke="var(--green)" stroke-width="calc(0.5px * var(--width)"/>

<rect ... style="fill: var(--gold);stroke: var(--red);stroke-width: var(--width);"/>

<rect class="stylesheet" x="400" width="90" height="90"/>

SVG hat keinen :root-Selektor, deshalb sind die Farben und die Stärke der Randlinie als custom properties im Regelsatz für das svg-Element notiert und werden …

  1. im ersten Rechteck, bzw. Kreis als Werte für die XML-Attribute verwendet
  2. im zweiten Rechteck als Werte im Inline-Style des Style-Attributs und …
  3. im dritten Rechteck als Werte im Stylesheet verwendet.

Der blaue Rand rechts ist doppelt so stark, da er mit der calc()-Funktion mit 2 multipliziert wurde; das XML-Attribut für das Rechteck mit grünem Rand entsprechend halbiert.

Beachten Sie: In beiden calc()-Funktionen wurde der Faktor um die Einheit px ergänzt, da das Ergebnis sonst vom Firefox nicht übernommen wird. Eigentlich ist der Wert für stroke-width ja eine dimensionslose Größe, was Chrome und Safari auch so akzeptieren.

Siehe auch:

SVG und Pseudoelemente

Nur der Einsatz von Pseudolementen wie :after und :before ist nicht möglich, da sie in SVG nicht definiert sind. Die Spezifikation ist nicht ganz eindeutig, aber anscheinend werden SVG-Elemente als Grafik wie ein img behandelt, die keine Pseudoelemente erlauben.[5]

Text in SVG

Text in SVG

SVG-Markup ansehen …
<text id="eins" x="10" y="120">
  TEXT 
  <tspan dx="-40" dy=".5em" >in</tspan>
</text>
 
<text id="zwei" x="400 520 620" y="120 170 220">
  SVG
</text>
Der erste Text (id="eins") hat als Inhalt Klartext und ein tspan-Element. Dieses ist mit dem dy-Attribut um 0.5em nach unten verschoben.

Der zweite Text mit der id="zwei" hat mehrere Angaben zu den x- und y-Koordinaten, sodass die einzelnen Zeichen versetzt dargestellt werden.

Des Weiteren sind die text-Elemente mit CSS formatiert:
text {
  font-family:serif;	
  font-size: 120px;
  font-weight: bold;
}
#eins {
  fill: url(#verlauf);
  }
 
#zwei {
  fill: #ffebe6;
  stroke: #c82f04;
  stroke-width: 3;
  font-family: sans-serif;
  font-size: 160px; 
  font-weight: bold;
}

Wie Sie im Beispiel sehen, kann die fill-Eigenschaft viel mehr als eine Farbangabe verarbeiten:

Verlauf ansehen …
<defs>
  <linearGradient id="verlauf">
    <stop offset="0.1" stop-color="#306f91 "/>
    <stop offset="0.1" stop-color="#dfac20 "/>
    <stop offset=".64" stop-color="#dfac20 "/>
    <stop offset=".80" stop-color="#306f91 "/>
  </linearGradient> 
</defs>

Innerhalb des Definitionsabschnitts wird mit linearGradient ein Verlauf festgelegt, der dann im style-Bereich mit seiner id referenziert wird: fill: url(#verlauf);

Der Verlauf hat mehrere stop-Elemente. Da bei den ersten beiden der offset-Wert gleich ist, kommt es zu einem harten Übergang innerhalb des Buchstabens; der dritte und vierte Stop liegen auseinander und sorgen so für einen weichen Übergang.

Hauptartikel: Text-Effekte mit SVG

SVG und die CSS-Kaskade

Wie oben schon erwähnt, überschreiben inline-CSS-Angaben Einstellungen aus externen Stylesheets oder aus dem style-Bereich. Dies entspricht der Spezifität des style-Attributs in HTML.

Inline-Styles werden aufgrund der höheren Spezifität nur durch !important überschrieben.

Während es ziemlich einfach ist, XML-Attribute durch CSS zu überschreiben, benötigen Sie bei Inline-Styles das Schlüsselwort !important.

Auch wenn es scheint, als ob XML-Attribute nun gar nicht mehr verwendet werden müssen, kann es doch empfehlenswert sein, diese zu setzen, um einen FOUSVG (‘Flash Of Unstyled SVG’) zu vermeiden.[6][7][8]

Möglichkeiten und Grenzen

Eigentlich sollten gerade die Präsentationsattribute, die ja Elemente formatieren und die Darstellung festlegen, in einen externen CSS-Bereich ausgelagert werden, um so durch Klassen eine Vielzahl von Objekten zentral zu formatieren.

Andererseits ist z. B. das path-Element eben doch kein immer gleich aussehendes Objekt, sondern eine Möglichkeit eine Vielzahl von verschiedenen Objekten zu erzeugen. Deshalb wäre es nicht zielführend (und auch nicht möglich) das d-Attribut mit den Pfadangaben ins CSS auszulagern.

Hier gilt es abzuwägen, wie oft ein Attribut wiederverwendet werden soll. Will man einheitliche Linien bei mehreren Elementen, ist eine Festlegung im Stylesheet oder zumindest im oberen style-Abschnitt zu empfehlen.

Festlegungen, die nur einmal getroffen werden, können als XML-Attribut oder innerhalb eines style-Attributs ihren Platz finden.

Beachten Sie: Mit dem HTTP-Header Content-Security-Policy kann Browsern das Beachten von Style-Attributen und (Inline-)Stylesheets verboten werden. Das Verhalten unterscheidet sich in dem Fall erheblich zwischen Browsern und Browser-Versionen sowie zwischen eingebundenen und als eigenständiges Dokument geöffneten Grafiken. Sollten in einer Datei nach dem Upload auf einen Webserver z.B. plötzlich alle Füllungen schwarz sein (dies ist der Standardstil), prüfen Sie Ihre Servereinstellungen oder nutzen Sie XML-Attribute.

Weblinks


Quellen

  1. W3C: SVG Styling
  2. Auch in HTML gibt es Attribute; anfangs auch zur Gestaltung - wie z.B. bei <body bgcolor="white">.
    Da diese Attribute aus einer Zeit vor der Einführung von CSS 1996 stammen, gilt dort eine etwas abweichende Syntax.
    (Siehe: SELF-Forum: schwarzer Hintergrund vom 09.11.2021)
  3. tutorials.jenkow: SVG and CSS
  4. Dirk Schulze auf Twitter: x, y, width and height are #SVG "presentation attributes" in @webkit now.
  5. stackoverflow: css-before-on-inline-svg
  6. css-tricks: Presentation Attributes vs Inline Styles Chris Coyier (23.12.2016)
  7. Sara Soueidan: SVG Style Inheritance and the ‘Flash Of Unstyled SVG’ (01.03.2016)
  8. wikibooks.de: CSS: Kaskadierung, Spezifität und Vererbung: Präsentationsattribute