Zeichnen in SVG
SVG-Grafikobjekte wie Pfade, Rechtecke oder auch Text beschreiben geometrische Formen. Anders als bei Pixelgrafiken werden dabei nicht einzelne Bildpunkte gespeichert, sondern mathematische Beschreibungen von Linien, Kurven und Flächen.
Eine Linie in SVG ist zunächst nur die Verbindung zwischen zwei Punkten und besitzt keine eigene Dicke. Erst durch das Zeichnen einer Kontur (Stroke) erhält sie eine sichtbare Breite. Auch Text besteht in SVG aus geometrischen Formen, die auf den Kurven der Schriftdatei basieren.
Damit eine Form im Browser sichtbar wird, wird sie gerendert: Das Innere eines Objekts wird gefüllt (Fill) und optional entlang des Umrisses eine Randlinie gezeichnet (Stroke). Diese beiden Eigenschaften bestimmen einen großen Teil der Darstellung von SVG-Grafiken.[1][2]
Inhaltsverzeichnis
Wie wird in SVG „gemalt“?
Die Funktionsweise lässt sich mit dem Malen auf einer Leinwand vergleichen: SVG-Elemente werden in der Reihenfolge ihres Auftretens gezeichnet. Später gezeichnete Elemente liegen über früher gezeichneten und können diese teilweise oder vollständig verdecken.
Auch die einzelnen Bestandteile einer Form werden wie Farbschichten betrachtet: Zuerst wird die Füllung gezeichnet, anschließend die Kontur und gegebenenfalls weitere Effekte wie Markierungen oder Filter.
Der entscheidende Unterschied zu klassischen Bildern bleibt jedoch bestehen: SVG speichert keine fertigen Pixel, sondern die Beschreibung der Formen. Dadurch können Grafiken ohne Qualitätsverlust vergrößert oder verkleinert werden.
Füllungen mit fill
Eine SVG-Form besteht zunächst nur aus einer geometrischen Beschreibung. Damit sie als Fläche sichtbar wird, benötigt sie eine Füllung. Diese wird mit dem fill-Attribut festgelegt.
<rect x="350" y="30" />
<rect fill="blue" x="470" y="30" />
<rect fill="none" x="420" y="100" />
Die drei Rechtecke werden unterschiedlich gezeichnet:
- Wird keine Füllung angegeben, verwendet SVG den Standardwert
black. Deshalb erscheint beispielsweise ein Rechteck ohne weitere Angaben als schwarze Fläche. -
fill="steelblue": Die Füllfarbe kann durch eine Farbangabe geändert werden: -
fill="none": Soll das Innere einer Form nicht dargestellt werden, wird die Füllung mit none abgeschaltet.
Dabei bleibt die Form selbst erhalten. Sie besitzt weiterhin eine geometrische Ausdehnung und kann beispielsweise mit einer Kontur (stroke) gezeichnet werden.
Erlaubt sind dabei folgende Werte:
- eine Farbangabe
(SVG verwendet die gleichen Farbangaben wie HTML und CSS!) - die Angabe
nonedeaktiviert die Füllung. Der Bereich innerhalb der Form bleibt ungezeichnet. - eine
url(#id)um …
Anders als bei der background-Eigenschaft in CSS ist es in SVG nicht möglich mehrere Füllungen (multiple fills), die nacheinander ausgeführt werden, zu verwenden. So könnte man ein Objekt mit einer Hintergrundfarbe füllen und ein oder mehrere Muster oder Schraffuren darüber legen.
Dies soll in SVG 2 kommen.[3]
fill-opacity – Füllungen transparent machen
Mit der fill-opacity-Eigenschaft (engl. für Deckkraft) lässt sich über den Alphakanal der Grad der Transparenz eines Elementes steuern.
circle {
fill-opacity: .5;
}
#eins {
fill: steelblue;
}
#zwei {
fill: gold;
}
#drei {
fill: #c82f04;
}
Ein Wert von eins bedeutet dabei eine 100 %ige Deckkraft, also vollständig deckend,
ein Wert von null entsprechend keinerlei Deckkraft, also vollständige Transparenz.
opacity eine prozentuale Angabe ist, sind Prozentwerte in XML-Attributen nicht erlaubt – im CSS jedoch schon.Wenn du die Transparenz eines Objekts veränderst, vermischen sich die übereinanderliegenden Farben. Wie diese vermischt werden, kann man mit mix-blend-mode genauer festlegen.
Konturen mit stroke
Mit der Eigenschaft stroke legt man die Farbe einer Kontur fest. Die Kontur wird entlang des mathematischen Umrisses eines SVG-Objekts oder Pfades gezeichnet.
circle {
fill: gold;
stroke: steelblue;
}
Ohne eine Angabe für stroke wird keine Umrandung dargestellt. Eine vorhandene Kontur kann mit stroke="none" oder stroke: none entfernt werden.
stroke keine Kurzschreibweise für Eigenschaften wie stroke-width, stroke-linecap oder stroke-dasharray.
Mit stroke wird lediglich festgelegt, womit die Kontur gezeichnet wird – beispielsweise mit einer Farbe, einem Verlauf oder einem Muster. stroke funktioniert dabei wie ein virtueller Stift, dessen Eigenschaften mit weiteren Attributen angepasst werden können:
- stroke-width bestimmt die Breite der Linie,
- stroke-linecap legt die Form der Linienenden fest,
- stroke-linejoin bestimmt das Verhalten an Ecken,
- stroke-dasharray erzeugt gestrichelte Linien,
- stroke-opacity verändert die Transparenz der Kontur.
Breite der Kontur mit stroke-width
Mit stroke-width wird die Stärke einer Linie oder Umrandung festgelegt.
circle {
fill: gold;
stroke: steelblue;
}
#eins {
stroke-width: 5;
}
#zwei {
stroke-width: 10;
}
#drei {
stroke-width: 20;
}
Der Rand einer Form ist zunächst nur die mathematische Grenze zwischen dem Inneren und der Umgebung der Form.
Die sichtbare Größe eines Objekts nimmt mit zunehmender stroke-width zu. Die Kontur wird dabei mittig auf dem mathematischen Pfad gezeichnet und verteilt sich gleichmäßig nach innen und außen.
Transparente Konturen mit stroke-opacity
Mit der Eigenschaft stroke-opacity lässt sich die Deckkraft einer Kontur steuern. Die Eigenschaft wirkt nur auf die gezeichnete Linie, nicht auf die Füllung des Objekts.
Der Wert liegt zwischen 0 und 1:
- 1 bedeutet eine vollständig deckende Kontur,
- 0 eine vollständig transparente Kontur.
circle {
fill: gold;
stroke: steelblue;
stroke-width: 10;
stroke-opacity:1;
}
#zwei {
stroke-opacity: .5;
}
#drei {
stroke-width: 20;
stroke-opacity: .2;
}
Durch die Transparenz werden darunterliegende Farben sichtbar und mehrere Konturen können sich optisch mischen.
Konturen gestalten / Linienmuster und Strichelungen
Linienenden mit stroke-linecap
Die Eigenschaft stroke-linecap kann das Aussehen von Linien- und Pfadenden verändern.
line {
stroke: steelblue;
stroke-width: 20;
}
#eins {
stroke-linecap: butt;
}
#zwei {
stroke-linecap: round;
}
#drei {
stroke-linecap: square;
}
round und square ragen über die Endpunkte hinaus.Ecken mit stroke-linejoin
Mit der Eigenschaft stroke-linejoin legt man fest, wie die Spitzen, die durch das Aufeinandertreffen zweier Pfadsegmente (Knick) entstehen, gezeichnet werden sollen. So kann man bei Dreiecken und anderen Formen abgerundete Ecken realisieren.
.spitz {
stroke-linejoin: miter;
}
.rund {
stroke-linejoin: round;
}
.bevel {
stroke-linejoin: bevel;
}
polyline,.line {
fill: none;
stroke: steelblue;
stroke-width: 40;
}
Folgende Angaben sind möglich:
-
miter: eckige Spitzen, Standardwert; (miter, engl. für Gehrung) miter-clip: SVG2! wie miter, aber bei einer Angabe von stroke-miterlimit wird die Gehrung (miter) abgeschnitten-
round: abgerundete Spitzen -
bevel: abgeschnittene Spitzen; (bevel, engl. für Fase) arcs: SVG2! Die äußeren Ränder der Kontur erhalten dieselbe Krümmung wie der Pfad, sodass ein natürlicheres Aussehen erzielt wird.
Spitz zulaufende Ecken mit stroke-miterlimit
Die Wertzuweisung stroke-linejoin: miter erzeugt spitze Linienverbindungen, die für kleine Schnittwinkel eine sehr große Gehrungslänge haben.
Mit der Eigenschaft stroke-miterlimit kann man eine maximale Gehrungslänge festlegen. Würde also eine Spitze länger als die maximale Gehrungslänge werden, ignoriert der Browser die Anweisung miter und stellt den Winkel angefast (bevel) dar.[4][5]
polyline {
fill:none;
stroke: steelblue;
stroke-width: 35;
}
#eins {
stroke-miterlimit: 2;
}
#zwei {
stroke-miterlimit: 3;
}
#drei {
stroke-miterlimit: 6;
}
#vier {
stroke-miterlimit: 7;
}
#fuenf {
stroke-miterlimit: 11;
}
Im zweiten bis fünften Beispiel wurde die Werte für stroke-miterlimit jeweils so erhöht, dass der Winkel nicht abgeflacht wird.
Je spitzer der Winkel, desto höher muss der Wert für stroke-miterlimit sein.
Folgende Angabe ist nötig:
- eine
Zahl, die gleich oder größer als 1 ist (Standardwert = 4)
Mit dem Standardwert 4 werden Schnittwinkel kleiner als 29° trotz miter angefast (bevel) dargestellt.
Je spitzer die Schnittwinkel ausfallen, desto höher muss stroke-miterlimit gewählt werden.
Falls sich zwei gleichbreite Linien schneiden, ist der Sinus des halben Schnittwinkels θ das Verhältnis von Linienbreite und Gehrungslänge. Es gilt
sin(θ/2) = stroke-width / miterLength
Wenn die miter-Länge geteilt durch die Randlinienstärke (stroke-width) den Wert für stroke-miterlimit übertrifft, dann gilt für:
-
miter: Die Verbindung wird abgeflacht (bevel) dargestellt -
miter-clip: Die Gehrung (miter) wird von einer senkrechten Linie abgeschnitten, die entsprechend dem Wert von stroke-miterlimit vom Schnittpunkt der Linien entfernt ist.
Gestrichelte Linien mit stroke-dasharray
Mit der Eigenschaft stroke-dasharray kann man die Umrandung auch gepunktet oder gestrichelt ausführen. Dabei können Länge und Rhythmus der Strichelung frei gestaltet werden.
Erlaubt sind dabei folgende Werte:
none: durchgehende Linie (Standardwert)- Liste von Längenangaben oder Prozentwerten. Jeder zweite Wert gilt als Lücke. Zwischen den Werten steht ein Komma oder Leerzeichen.
- Prozentwerte, beziehen sich auf die normierte Bilddiagonale. Das ist die Quadratwurzel des Durchschnitts aus den Quadraten von Länge und Breite.
line {
stroke: steelblue;
stroke-width: 5;
}
.eins {
stroke-dasharray: 1%, 1%;
}
.zwei {
stroke-dasharray: 1%, 5%;
}
.drei {
stroke-dasharray: 100 10 10 10;
}
.vier {
stroke-dasharray: 90, 20, 0, 20, 0, 20;
stroke-linecap: round;
stroke-width: 8;
stroke-dashoffset: -4;
}
Das vierte Beispiel zeigt eine Strich-Zweipunktlinie mit Kreisen. Die Punkte haben die Länge 0 und abgerundete Enden mit stroke-linecap: round.
Position der Strichelung mit stroke-dashoffset
Mit der Eigenschaft stroke-dashoffset kann man den Beginn der Umrandung nach vorne oder hinten schieben.
Erlaubt sind dabei folgende Werte:
- eine Längenangabe (Standardwert: 0) negative oder positive Werte
- eine Prozentangabe, bezogen auf die normierte Bilddiagonale
Im folgenden Beispiel wird mit dieser Eigenschaft der sichtbare Teil des Strichmusters aus dem Viewport verschoben und dann mit einer Animation bis 0 reduziert. Die Linie wird wie „von Zauberhand“ gezeichnet:
path {
fill: none;
stroke: steelBlue;
stroke-width: 5;
stroke-dasharray: 900 900;
stroke-linejoin: round;
stroke-linecap: round;
animation: strokeAni 5s infinite linear;
}
@keyframes strokeAni {
0% {
stroke-dashoffset: 900;
}
100% {
stroke-dashoffset: 0;
}
}
Komplexe Formen
In den vorherigen Abschnitten ging es darum, wie man eine Randlinie erzeugt und formatiert. Bei der Darstellung auf Webseiten ergaben sich Darstellungsprobleme, die mit folgenden Eigenschaften gelöst werden konnten.
Selbstüberschneidende Formen mit fill-rule
Normalerweise füllt SVG die Fläche, die von einem Pfad eingeschlossen wird. Bei einfachen Formen ist eindeutig, welcher Bereich innerhalb der Form liegt. Bei sich selbst überschneidenden Pfaden gibt es jedoch mehrere mögliche Interpretationen.
Mit der fill-rule-Eigenschaft wird festgelegt, welche Bereiche eines solchen Pfades gefüllt werden.
Die beiden wichtigsten Werte sind:
-
nonzero(Standardwert): Ein Bereich gilt als innerhalb der Form, wenn die Pfadrichtung eine bestimmte Orientierung ergibt. -
evenodd: Jeder zweite Bereich wird als außerhalb betrachtet. Dadurch entstehen transparente Aussparungen.
Im folgenden Beispiel überschneiden sich die Linien der Formen. Mit evenodd bleiben die inneren Bereiche transparent. Wird auf nonzero gewechselt, werden diese Bereiche ebenfalls gefüllt.
.normal {
stroke: steelblue;
stroke-width: 3;
fill: gold;
fill-rule: evenodd;
}
.normal:hover,
.normal:focus {
fill-rule: nonzero;
}
Bei :hover (oder dank tabindex :focus) wird der Hintergrund mit nonzero vollständig ausgefüllt.
fill-rule wird vor allem bei komplexeren Pfaden benötigt, beispielsweise bei Sternen, Logos oder Schriftzügen.
paint-order
Mit der Eigenschaft paint-order legt man die Reihenfolge fest, in der Füllungen, Umrandungen und Marker gezeichnet werden.[6] Diese Reihenfolge bestimmt, welches dieser drei Gestaltungselemente die anderen überdecken kann, oder selbst überdeckt wird.
Die Standardreihenfolge für die Zeichnung ist:
- mit Farbe füllen (fill)
- Randlinien zeichnen (stroke)
- Markierungen zeichnen (markers)
Um diese Standardreihenfolge auszuwählen, gibt man der Eigenschaft den Wert normal.
Eine andere Zeichenreihenfolge lässt sich festlegen, indem die Gestaltungselemente – durch Leerzeichen getrennt – in der gewünschten Reihenfolge angegeben werden. Dafür stehen die Schlüsselwörter fill, stroke und markers zur Verfügung.
Man muss nicht alle drei Schlüsselwörter auflisten. Diejenigen, die man weglässt, fügt der Browser in der Standardreihenfolge der Liste hinzu.
<g fill="gold" stroke="#306f91" stroke-width="6" stroke-linejoin="round"
text-anchor="middle" font-family="sans-serif" font-size="100px" font-weight="bold">
<text x="200" y="75">stroke over</text>
<text x="200" y="175" paint-order="stroke">stroke under</text>
</g>
In der oberen Textzeile wird der Text zuerst gefüllt und dann mit einer 6 Einheiten breiten Randlinie versehen. Eine solche Linie befindet sich zur Hälfte außerhalb des umrandeten Zeichnungselements, die andere Hälfte ist innerhalb. Je nach Verhältnis von stroke-width und font-size führt das dazu, dass die Füllung der Schriftzeichen kaum noch erkennbar ist.
In der unteren Textzeile wird durch paint-order="stroke" zuerst die Randlinie gerendert, die dann durch die Füllung verdeckt wird, sodass nur die außenliegenden 3 dargestellt werden. Damit ist gewährleistet, dass die Glyphen des ausgegebenen Texts nicht durch die Randlinien verzerrt oder sogar unlesbar gemacht werden.
Das folgende Bild stammt vom W3C Konsortium und demonstriert die Auswirkung von paint-order:
Der rechte Text erhält zuerst seine Kontur und dann erst die Füllung, sodass die Proportionen der Zeichen erhalten bleiben.
vector-effect
Bei Landkarten werden oft Symbole und Grafik-Objekte verwendet, die in verschiedenen Zoom-Stufen beliebig skaliert werden. Allerdings soll eine Straße eben doch ein Strich in der Landschaft bleiben und nicht endlos breit dargestellt werden.
Die Eigenschaft vector-effect legt fest, ob Randlinien beim Zoomen skaliert werden oder nicht. Mit dem Wert non-scaling-stroke verhindert man dies.
<path vector-effect="non-scaling-stroke" id="p1" ... />
<g stroke="steelblue">
<use href="#p1" x="100" y="100" />
<use href="#p1" x="120" y="100" transform="scale(2)" />
<use href="#p1" x="200" y="-300" transform="scale(0.4 -0.6)" />
<use href="#p1" x="-650" y="-200" transform="scale(-0.4) skewX(-30)" />
</g>
Die Randlinie bleibt immer 2 Einheiten breit, egal wie stark gezoomt wird. Dies ist z.B. bei Landkarten, in denen die Randlinie eine Straße darstellen soll, wichtig.
vector-effect nicht implizit an Kindelemente vererbt, sondern muss für jedes Kindelement einzeln gesetzt werden. Das Setzen beispielsweise in einem g- oder svg-Element hat somit keinen direkten Effekt, allerdings kann in diesem Fall bei Kindelementen inherit verwendet werden.In der Spec gibt es viele weitere Werte, die aber von den Browserherstellern nicht implementiert wurden.
Siehe auch
- Zeichnen in SVG
Finetuning- color-interpolation
- color-rendering
- image-rendering
- Markierungen in SVG
- Farben wiederverwenden
- context-fill und context-stroke
- color
- Marker ausrichten
- Farben wiederverwenden
- Verläufe in SVG
- linearGradient
- stop
- radialGradient
- linearGradient
- Muster in SVG
- pattern
Weblinks
- ↑ W3C: Chapter 13: Painting: Filling, Stroking and Marker Symbols
Scalable Vector Graphics (SVG) 2
W3C Candidate Recommendation (04 October 2018) - ↑ Die hier besprochenen Technologien sind im CSS Fill and Stroke Module Level 3festgelegt. Als CSS-Modul soll es zukünftig auch für HTML-Elemente verfügbar gemacht werden, damit nicht standardisierte Versuche wie -webkit-text-stroke aus der Chrome-Welt dann vereinheitlicht werden können.
Allerdings haben die Browserhersteller nur einen (kleineren) Teil implementiert, sodass die Spec hier eher ein Blick in die fernere Zukunft ist. - ↑ W3C: SVG 2 Addition: Allow multiple paints in fill and stroke.
- ↑ css-tricks: Tight Fitting SVG Shapes, the Present and Future von Ana Tudor
erklärt, welche Probleme die Gehrung von Ecken beim passgenauen Zuschneiden von Objekten verursacht. - ↑ codepen.io: stroke-miterlimit-Animation von Ana Tudor
- ↑ W3C: PaintOrder
