SVG/Tutorials/Text/Füllungen und Randlinien
In diesem Kapitel wollen wir Ihnen zeigen, wie Sie SVG-Text mit CSS und XML-Attributen gestalten und animieren können. Dabei wollen wir zuerst die Möglichkeiten verschiedener Füllungen und Randlinien kennen lernen.
Inhaltsverzeichnis
SVG-Markup
Um Text in SVG darzustellen, verwendet man das text-Element. Als Inhalt kann es entweder Klartext, tspan-Elemente als Unterbereiche oder ein textPath-Element für Text entlang eines unregelmäßigen Pfades enthalten.
Anders als in HTML richtet sich SVG-Text nicht am (in SVG nicht vorhandenen) Elementfluss aus, sondern muss immer wieder neu positioniert werden. Dies geschieht mithilfe der x- und y-Attribute:
- x: Koordinate(n) des linken Textrandes (Wenn mehrere Werte in der Form
"x1, x2, x3, ..., xn"
bzw."y1, y2, y3, ..., yn"
angegeben werden, beziehen sie sich auf die einzelnen Zeichen.) - y: Koordinate(n) des Grundlinie des Textes. Die Unterlängen ragen nach unten, der Text nach oben.
<text id="eins" x="10" y="120">
TEXT
<tspan dy=".5em" >in</tspan>
</text>
<text id="zwei" x="430 550 650" y="120 170 220">
SVG
</text>
text {
font-family:serif;
font-size: 120px;
font-weight: bold;
}
#eins {
fill: url(#verlauf);
}
#zwei {
fill: #ffebe6;
stroke: #c32e04;
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: Im ersten Element wird ein Verlauf eingebunden; wie das funktioniert erfahren Sie im 2. Kapitel dieser Seite.
Gestaltung durch CSS
text {
font-family:sans-serif;
font-size: 24px;
}
[role=heading] {
font-size: 50px;
text-anchor: middle;
fill: var(--yellow);
stroke: var(--blue);
stroke-width: 2;
}
[role=heading] >tspan {
fill: var(--accent);
}
.serif {
font-family:courier, serif;
font-weight: bold;
fill: var(--bgcolor);
stroke: var(--blue);
stroke-width: .5;
}
.anders {
text-decoration: underline wavy red;
}
Eigentlich können Sie alle CSS-Eigenschaften zur Textformatierung verwenden. Einige Ausnahmen sind zu beachten:
Da es in SVG (noch) keinen mehrzeiligen Text gibt, wirkt auch keine line-height. Besser als eine absolute Positionierung aller Zeilen ist eine relative Verschiebung mit dy:
<tspan x="20" dy="2em" ...>Textinhalt</tspan>
Bei text-decoration: underline wavy red;
wirkt die Farbangabe red
nicht; der Firefox rendert wie beabsichtigt eine Wellenlinie; Chrome, Edge und Opera nur eine grade Linie.
→ SVG/Tutorials/Einstieg/SVG mit CSS stylen
Gestaltung von Textlinks
In SVG können sowohl grafische Objekte als auch Text mit dem a-Element umschlossen und so zu einem Verweis auf eine andere URL werden.
<a href="https://wiki.selfhtml.org">
<text x="20" y="130">ein Textlink</text>
</a>
<a transform="translate(300,100)" href="https://wiki.selfhtml.org">
<rect width="430" height="30" fill="none" />
<text x="5" y="25">
ein Textlink mit vergrößerter Klickfläche
</text>
</a>
a {
cursor: pointer;
text-decoration: underline;
}
a:focus, a:hover {
fill: var(--bgcolor);
stroke: var(--blue);
stroke-width: 1;
}
a:focus > rect, a:hover > rect {
fill: var(--bgcolor);
stroke: var(--blue);
stroke-width: 1;
}
Der linke Verweis erhält mit der cursor-Eigenschaft einen anderen Zeiger. Bei :hover
erhält der Text eine hellblaue Füllung und einen dunkelblauen Rand. Die mit text-decoration:underline
ausgeführte Unterstreichung wird ebenfalls verdoppelt. Der Klickbereich umfass den gesamten Textbereich inkl. möglicher Unter- und Oberlängen.
Eine Färbung und Umrahmung der Fläche hinter dem Text ist in SVG, anders als in HTML, nur über Umwege möglich.
- In HTML bilden alle Elemente Blöcke (→ Box-Modell) mit einer Breite und Höhe. So kann Text eine Farbe, aber auch eine Hintergrundfarbe oder einen Rand erhalten.
- In SVG besteht Text nur aus den Zeichen oder Glyphen, denen man eine Füllung (fill) oder Randlinie (stroke) geben kann. Ein „Hintergrund“ als solcher existiert nicht und müsste erst erzeugt werden.
Der rechte Verweis enthält deshalb parallel zum text-Element noch ein rect-Element, das unterhalb des Texts gemalt wird. Bei :hover wird es ebenfalls eingefärbt.
Indiesem Tutorial gibt es ein Beispiel, wie Sie mit JavaScript eine Box um Text herumzeichen können:
- SVG und JavaScript/DOM-Scripting Rahmen um Text erzeugen
mehrzeiliger Text
Eines der großen Mankos von SVG ist die Tatsache, dass Sie längere Texte nicht einfach so notieren können, dass er sich mehrzeilig auf den verfügbaren Platz aufteilt. In SVG 2 sollte dies mit dem bisher nicht implementierten inline-size-Attribut erreicht werden.
Bis dahin bleibt keine andere Möglichkeit als jede vorgesehene Textzeile in ein eigenes tspan-Element zu packen.
<text class="mehrzeilig" x="20" y="130">
<tspan x="10" dy="2em">Mehrzeiliger Text ist möglich, wenn Sie</tspan>
<tspan x="10" dy="2em">die einzelnen Zeilen in <tspan>-Elemente notieren.</tspan>
<tspan x="10" dy="2em">Allerdings sind diese Zeilen nicht responsiv.</tspan>
</text>
Jede Zeile des Texts wird von einem eigenen tspan-Element umschlossen und im x-Attribut mit dem jeweils gleichen Wert absolut, mit einer vertikalen Verschiebung durch das dy-Attribut um 2em nach unten relativ positioniert.
text.mehrzeilig tspan {
x: 20;
dy: 2em;
/* funktioniert nicht! */
}
Eine Festlegung mit CSS funktioniert nicht. Der X-Wert würde sich auf das jeweils vorhergehende tspan-Element beziehen. dy ist kein Präsentationsattribut.
Nachteile dieser Methode sind …
- der aufgeblähte Markup durch die zusätzlichen tspan-Elemente
- keine Möglichkeit prozentuale Breitenangaben (und damit einen automatischen Umbruch) zu verwenden.
Füllen des Hintergrunds
Das Füllen des Hintergrunds ist einer der einfachsten Stil-Effekte, geht aber weit über das einfache Festlegen einer Hintergrundfarbe wie in CSS hinaus.
Dabei bleibt zu beachten, dass hier nur die Füllung der Glyphen selbst, nicht des „Hintergrunds“ hinter dem Text gmeint ist.
Verläufe als Hintergrund
Anstelle einer normalen Farbangabe können Sie Text auch mit einem Verlauf füllen. Hier verwenden wir die Farben des Regenbogens:
<defs>
<linearGradient id="verlauf">
<stop offset="0" stop-color="red"/>
<stop offset=".25" stop-color="orange"/>
<stop offset=".45" stop-color="yellow"/>
<stop offset=".65" stop-color="green"/>
<stop offset=".82" stop-color="blue"/>
<stop offset="1" stop-color="purple"/>
</linearGradient>
<linearGradient id="verlaufVertikal" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="red"/>
<stop offset="25%" stop-color="orange"/>
<stop offset="45%" stop-color="yellow"/>
<stop offset="65%" stop-color="green"/>
<stop offset="82%" stop-color="blue"/>
<stop offset="100%" stop-color="purple"/>
</linearGradient>
</defs>
<text id="T" fill="url(#verlauf)" x="2%" y="30%">Regenbogen</text>
<text id="T" fill="url(#verlaufVertikal)" x="2%" y="90%">Regenbogen</text>
Der untere Verlauf
#verlaufVertikal
hat eine Laufrichtung von x1="0%" y1="0%" x2="0%" y2="100%"
; deshalb müssen auch die Werte des offset-Attributs Prozentwerte sein.Verläufe animieren
Sie können einen Verlauf auch mit SMIL animieren, sodass die Farbfüllung erst nach einer gewissen Zeit erscheint:
Achtung!
animate
-Elemente nicht gerendert werden.Öffnen Sie das Beispiel mit einem Klick auf Vorschau in einem neuen Tab!
<defs>
<linearGradient id="verlauf" >
<stop offset="0" stop-color="#dfac20">
<animate attributeName="offset" from="0" to="1" begin="1.5s" dur="3s" fill="freeze"/>
</stop>
<stop offset="0" stop-color="black">
<animate attributeName="offset" from="0" to="1" begin="0.5s" dur="2s" fill="freeze"/>
</stop>
</linearGradient>
<linearGradient id="verlaufVertikal" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#dfac20">
<animate attributeName="offset" from="0" to="1" begin="1.5s" dur="3s" fill="freeze"/>
</stop>
<stop offset="0" stop-color="black">
<animate attributeName="offset" from="0" to="1" begin="0.5s" dur="2s" fill="freeze"/>
</stop>
</linearGradient>
</defs>
<text fill="url(#verlauf)" font-family="sans serif" x="2%" y="30%">waagerecht</text>
<text fill="url(#verlaufVertikal)" font-family="sans serif" x="2%" y="70%">senkrecht</text>
Die beiden Texte sind mit Verläufen gefüllt. Nicht die Verläufe selbst, sondern die beiden color-stops, bzw. ihre offset-Werte werden animiert. Dabei unterscheidet sich der Beginn der beiden Animationen, sodass die Werte immer auseinanderliegen und einen Verlauf erzeugen. Würden die Werte zusammenfallen, ergäbe es einen scharfen Übergang.
Muster als Hintergrund
Sie können Text mit einem gemusterten Hintergrund erzeugen, indem Sie ein Muster in einem pattern-Bereich platzieren und den Text mit diesem Muster füllen.
<defs>
<pattern id="karo" x="10" y="10" width="30" height="30" patternUnits="userSpaceOnUse">
<rect x="0" y="0" width="10" height="10" fill="#dfac20"/>
<rect x="10" y="0" width="10" height="10" fill="#3983ab"/>
<rect x="20" y="0" width="10" height="10" fill="#c32e04"/>
<rect x="0" y="10" width="10" height="10" fill="#c32e04"/>
<rect x="10" y="10" width="10" height="10" fill="#5a9900"/>
<rect x="20" y="10" width="10" height="10" fill="#dfac20"/>
<rect x="0" y="20" width="10" height="10" fill="#3983ab"/>
<rect x="10" y="20" width="10" height="10" fill="#c32e04"/>
<rect x="20" y="20" width="10" height="10" fill="#5a9900"/>
</pattern>
<pattern id="punkte" x="0" y="0" width="30" height="30" patternUnits="userSpaceOnUse">
<rect x="0" y="0" width="30" height="30" fill="#3983ab"/>
<circle cx="15" cy="5" r="3" fill="#dfac20"/>
<circle cx="25" cy="5" r="3" fill="#c32e04"/>
<circle cx="5" cy="15" r="3" fill="#c32e04"/>
<circle cx="15" cy="15" r="3" fill="#5a9900"/>
<circle cx="25" cy="15" r="3" fill="#dfac20"/>
<circle cx="5" cy="25" r="3" fill="#dfac20"/>
<circle cx="15" cy="25" r="3" fill="#c32e04"/>
<circle cx="25" cy="25" rt="3" fill="#5a9900"/>
</pattern>
</defs>
<text fill="url(#karo)" stroke="black" x="0" y="170" >SELFHTML</text>
<text fill="url(#punkte)" stroke="black" x="0" y="350" >SELFHTML</text>
Muster auf Muster
Wo ist denn der Text ?
text {
fill: url(#imagePattern);
}
text:focus, text:hover {
fill: url(#textPattern);
filter: url(#dropShadow);
}
In diesem Beispiel sind sowohl Hintergrund als auch Text mit einem Muster #imagePattern
gefüllt. Erst wenn Sie über der gemusterten Fläche hovern, erscheint der Text. Das Vorbild aus dem Jahre 2009 arbeitete hier noch mit onmouseover, da :hover-Effekte bei SVG damals nicht durchgehend unterstützt wurden.[1]
Bilder als Hintergrund
Sie können Text mit Bildern hinterlegen, indem Sie ein image-Element innerhalb eines pattern-Bereichs platzieren.
In diesem Beispiel [2] wird ein animated GIF eines Feuers eingebunden, das den Text brennen lässt. Das verwendete GIF aus Wikimedia Commons ist mit 1MB relativ groß und für diesen Zweck nicht optimal, da es neben den Flammen viele schwarze Bereiche hat.
<defs>
<pattern id="firePattern" viewBox="20 0 127 177" patternUnits="userSpaceOnUse" width="137" height="177" x="0" y="60">
<image href="https://upload.wikimedia.org/wikipedia/commons/7/78/Fire-animated.gif" width="177" height="177"></image>
</pattern>
</defs>
<text tabindex="1" x="300" y="240">Burn</text>
Die (animierte) Rastergrafik wird über das image-Element eingebunden. Die Größe ist dabei auf 1/4 skaliert.
Im Definitionsabschnitt defs wird ein pattern definiert und mit y so verschoben, dass die Flammen möglichst passend den Text illuminieren. Um die schwarzen Stellen auszublenden, wird die viewBox beschnitten.
Ränder
Das Gestalten der Randlinien einzelner Buchstaben (genauer: Glyphe) ist eine der Eigenschaften, die SVG der CSS-Welt voraus hat. In der CSS3-Spezifikation gab es einen Vorschlag für eine Eigenschaft text-outline
, der jedoch 2011 wieder entfernt wurde. Die Eigenschaft text-stroke entspricht keiner Spezifikation und ist nur mit dem vendor-prefix -webkit-
umgesetzt.
Randlinie hinter der Füllung
Wenn eine Glyphe eine schmale Strichführung hat, kann es schnell vorkommen, dass die begrenzenden Randlinien sich so nahe kommen, dass man die Füllung nicht mehr sieht und das Zeichen kaum noch erkennbar ist. Um dem entgegen zu wirken, können Sie die Reihenfolge ändern, in der Randlinie und Füllung gezeichnet werden. Dazu können Sie die CSS Eigenschaft oder das gleichnamige SVG Attribut paint-order verwenden. Ein Beispiel finden Sie im verlinkten Abschnitt.
Randlinie als Verlauf
Wie bei der Füllung können Sie auch die Randlinie mit einem Verlauf darstellen:
<defs>
<linearGradient id="verlauf">
<stop offset="0" stop-color="red"/>
<stop offset=".25" stop-color="orange"/>
<stop offset=".45" stop-color="yellow"/>
<stop offset=".65" stop-color="green"/>
<stop offset=".82" stop-color="blue"/>
<stop offset="1" stop-color="purple"/>
</linearGradient>
<linearGradient id="verlaufVertikal" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="red"/>
<stop offset="25%" stop-color="orange"/>
<stop offset="45%" stop-color="yellow"/>
<stop offset="65%" stop-color="green"/>
<stop offset="82%" stop-color="blue"/>
<stop offset="100%" stop-color="purple"/>
</linearGradient>
</defs>
<text stroke="url(#verlauf)" x="2%" y="30%">Regenbogen</text>
<text stroke="url(#verlaufVertikal)" x="2%" y="80%">Regenbogen</text>
animinierte Randlinien
Einer der spektakulärsten SVG-Texteffekte sind mit CSS-animation animierte Randlinien.
text {
fill: none;
stroke-width: 5;
stroke-dasharray: 10 50;
animation: strokeAni 2s infinite linear;
}
@ keyframes strokeAni {
0% { stroke-dashoffset: 60; }
100% { stroke-dashoffset: 0; }
}
<svg viewBox="0 0 880 450">
<text id="eins" stroke="#dfac20" x="2%" y="40%">Punkt</text>
<text id="zwei" stroke="#306f91" x="2%" y="40%">Punkt</text>
<text id="drei" stroke="#c32e04" x="2%" y="40%">Punkt</text>
</svg>
- Damit der Text auch in Browsern funktioniert, die keine CSS-Animation von SVG-Attributen unterstützen (IE 9-11), sind die jeweiligen Linien durch das stroke-dashoffset-Attribut versetzt. So ist der Text trotzdem lesbar.
- Wenn Sie versuchen eine gepunktete Randlinie (mit gleichmäßig runden Kreisen) zu erzeugen, stellen die Browser die Länge des Striches unterschiedlich lang dar, sodass die Punkte trotz
stroke-linecap:round;
nie kreisfömig werden. - Sie könnten die Länge einer Randlinie mit den kombinierten Längen der Linien abgleichen; die unterschiedlichen Buchstaben haben aber alle verschiedene Längen, sodass es jeweils an einer Stelle zu einem Bruch der Animation kommt.
Weitere Beispiele finden Sie auf tympanus.net. Eine Variation dieser animierten Randlinien ist diese Demo, in der mit JavaScript Kieselsteine entlang des Pfads der Randlinie erzeugt werden.[3]
Text-Eigenschaften
Nachfolgend finden sich Beschreibungen einiger XML-Attribute, mit denen sich Text formatieren lässt. Viele litten unter mangelnder Browser-Unterstützung, sodass heute eigentlich die oben besprochenen Präsententationseigenschaften verwendet werden.
Rotation
Mit dem rotate-Attribut drehen Sie einzelne bzw. eine Folge von Zeichen.
Folgende Angaben sind möglich:
rotate
: Gradzahl der Drehung, positive oder negative Zahl von 0-360 (einer oder mehrere Werte, die mit einem Komma oder einem Leerzeichen voneinander getrennt sein müssen)
<text x="0" y="100"
dx="10 10 10 10 10 10 10 10 10 10 10 10 15 15 15 15 15 15"
rotate="0 10 -10 10 -10 10 -10 20 -20 20 -20 20 -30 30 -30 30 -30 30">
Jetzt geht's rund!
</text>
Textausrichtung
Mit demt text-anchor-Attribut können Sie Text links-, rechtsbündig und mittig ausrichten.
Folgende Angaben sind möglich:
start
(Standardwert) Text liegt rechts des Ankerpunkts xmiddle
: Ankerpunkt liegt in der Mitte des Textesend
: Text liegt links des Ankerpunktes X
text-anchor="end"
sorgt dafür, dass der Text links der X-Koordinate angezeigt wird. Unter Umständen muss dann der Wert für X verändert werden, damit der Text nicht aus dem sichtbaren Bereich verschwindet.Sinnvoll ist
text-anchor="middle"
, da man damit Text z.B. in Kreisen oder Ellipsen trotz unterschiedlicher Länge mittig ausrichten kann und so einfach den X-Wert des Hintergrund-Elements übernehmen kann. <text x="200" y="50" text-anchor="start">
start
</text>
<text x="200" y="100" text-anchor="middle">
middle
</text>
<text x="200" y="150" text-anchor="end">
end
</text>
<g>
<text x="250" y="250">Anwendungsbeispiel:</text>
<text x="250" y="280">KFZ-Nationalitätenkennzeichen</text>
<ellipse cx="100" cy="400" rx="40" ry="25"/>
<text x="100" y="410">B</text>
</g>
<g>
<ellipse cx="300" cy="350" rx="40" ry="25"/>
<text x="300" y="360">NL</text>
</g>
<g>
<ellipse cx="500" cy="400" rx="40" ry="25"/>
<text x="500" y="410">LUX</text>
</g>
Wortabstand
Mit dem word-spacing-Attribut können Sie wie bei der gleichnamigen CSS-Eigenschaft den Abstand zwischen den Wörtern im Text bestimmen.
Folgende Angaben sind möglich:
- eine numerische Längenangabe, jedoch kein Prozentwert, auch negative Angaben mit Größenangabe
<text x="100" y="100" word-spacing="-5px">
Beispieltext mit geringem Wortabstand
</text>
<text x="100" y="200">
Beispieltext mit normalem Wortabstand
</text>
<text x="100" y="300" word-spacing="1em">
Beispieltext mit großem Wortabstand
</text>
Zeichenabstand
Mit dem letter-spacing können Sie wie bei der gleichnamigen CSS-Eigenschaft den Abstand zwischen den Buchstaben bzw. Zeichen im Text bestimmen.
Folgende Angaben sind möglich:
- eine Längenangabe, jedoch kein Prozentwert, auch negative Angaben
<text x="100" y="100" letter-spacing="-2.5">
Beispieltext
</text>
<text x="100" y="200">
Beispieltext
</text>
<text x="100" y="300" letter-spacing="2.5">
Beispieltext
</text>
Weblinks
- ↑ http://svg-wow.org/blog/2009/10/04/pattern1/ (gemusterter Text über gemustertem Hintergrund)
- ↑ Original gefunden auf: tympanus.net; (dort ist die referenzierte Grafik nicht mehr vorhanden)
- ↑ http://svg-wow.org/blog/2009/10/04/pebbles/
- W3C: text effects
- David Dailey SVG Text Effects
- codepen.io SVG Text Effects (A Collection by yoksel)
- tympanus: AnimatedTextFills
- Gedichte mit SVG auszeichnen (Dr. O Hoffmann]
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
Des Weiteren sind die text-Elemente mit CSS formatiert:id="zwei"
hat mehrere Angaben zu den x- und y-Koordinaten, sodass die einzelnen Zeichen versetzt dargestellt werden.Die Grundlinie ist durch den roten Punkt gekennzeichnet.