Scalable Vector Graphics
Mehr als Logos und Icons
Vektorgrafiken werden immer häufiger im Web eingesetzt. Allerdings beschränkt sich das oft noch darauf, Logos oder Icons einzubauen. Dabei verfügen SVG über eine ganze Reihe nützlicher Funktionen, die Webworker noch lange nicht ausgereizt haben. Zum Beispiel bietet uns Text in SVG Möglichkeiten, die uns über reines CSS nicht zur Verfügung stehen.
Dank SVG gibt es einen Webstandard, mit dem wir Logos, Illustrationen und Infografiken als echte Vektorgrafiken im Web abbilden können. Der Vorteil ist natürlich, dass sich die Grafiken verlustfrei skalieren lassen. Als grundlegende Formen stehen uns zur Verfügung:
- rect
- für ein Rechteck,
- circle
- für einen Kreis,
- ellipse
- für eine Ellipse,
- line
- zieht eine Linie zwischen zwei Punkten,
- polyline
- zieht eine Linie von Punkt zu Punkt zu Punkt…,
- polygon
- ist ähnlich zu polyline, nur werden hier der erste und der letzte Punkt miteinander verbunden,
- path
- für eine beliebige Form.
Text in SVG
Neben diesen Formen ist es auch möglich, über das text
-Element reinen Text zu setzen. Um diesen Text zu stylen, habt ihr mehrere Möglichkeiten. Dabei müsst ihr beachten, dass sich die Eigenschaften von den üblichen CSS-Text-Eigenschaften teilweise etwas unterscheiden. Statt color
setzt ihr eine Textfarbe etwa über fill
.
- <svg width="100%" height="30" xmlns="http://www.w3.org/2000/svg" version="1.2" xmlns:svg="http://www.w3.org/2000/svg">
- <text class="headline1" x="0" y="30">
- Eine einfache Überschrift
- </text>
- </svg>
- .headline1 {
- font-size: 30px;
- fill: #000;
- font-family: Calibri, Arial, Verdana, sans-serif;
- }
Das SVG lässt sich nun als echte Überschrift beispielsweise in eine h1 packen. Der Text kann ganz normal markiert und kopiert werden.
Das Beispiel oben ist in dieser Form natürlich sinnfrei. Nützlich wird das Konstrukt erst, wenn andere Fähigkeiten von SVG ins Spiel kommen. Zum Beispiel könnt ihr den Text mit einer Outline versehen.
- <svg width="100%" height="42" xmlns="http://www.w3.org/2000/svg" version="1.2" xmlns:svg="http://www.w3.org/2000/svg">
- <text class="headline2" x="10" y="40">
- Eine einfache Überschrift
- </text>
- </svg>
- .headline2 {
- font-size: 40px;
- fill: none;
- stroke: #000000;
- font-family: Calibri, Arial, Verdana, sans-serif;
- }
text-stroke: In den offiziellen Spezifikationen des W3C gibt es keine Möglichkeit, solch eine Outline zu erzeugen. Allerdings haben die Webkit-Browser hier vorgelegt und mit der Eigenschaft text-stroke
solch eine Möglichkeit geschaffen. Das unterstützen laut Can I use auch einige Browser, allerdings weder IE noch Firefox.
Die Variante über das SVG funktioniert hingegen in allen modernen Browser runter bis zum IE9. Der IE8 kann zwar kein SVG, ignoriert diese Tags aber einfach und stellt zumindest den Text dar. Das führt in diesem Beispiel (zufällig) zu willkommener Graceful Degradation.
Neben der durchgezogenen Linie bieten SVG weitere Optionen für die Outline. Mit stroke-dasharray
legt ihr etwa Muster fest. Die Eigenschaft erwartet immer paarweise zwei Werte, die für gesetzte Pixel und Lücken stehen. Ein stroke-dasharray: 20 4 10 4
sorgt etwa für 20 Pixel Linie, 4 Pixel Lücke, 10 Pixel Linie, 4 Pixel Lücke.
- <svg width="100%" height="42" xmlns="http://www.w3.org/2000/svg" version="1.2" xmlns:svg="http://www.w3.org/2000/svg">
- <text class="headline3" x="10" y="40">
- Eine einfache Überschrift
- </text>
- </svg>
- .headline3 {
- font-size: 40px;
- fill: none;
- stroke: #000000;
- font-family: Calibri, Arial, Verdana, sans-serif;
- stroke-dasharray: 20 4 10 4;
- }
Das funktioniert ebenfalls in allen modernen Browsern, allerdings nervt die Darstellung im Opera etwas. Solange sich die Outline eines Buchstabens mit einer einzigen Linie darstellen lässt, ist alles in Ordnung (etwa bei einem W). Sobald aber zwei getrennte Linien gezogen werden müssen (z.B. bei einem o) verbindet Opera diese beiden Linien, was zu einem falsch gesetzten Strich führt.
Gehen wir einen Schritt weiter und versuchen es mit einer CSS-Animation. Zum Beispiel können wir das stroke-dasharray
per @keyframes
von 0 500 auf 500 0 verändern. Als Ergebnis werden die Buchstaben des Textes gleichzeitig gemalt. Am Ende bleibt der Text einen Moment stehen (weil die 500 etwas über die benötigte Länge hinaus gehen). Die Animation funktioniert direkt allerdings nur im Firefox. Mit Browser-Prefixes auch in Chrome. Im IE, Safari und Opera sehen Besucher die durchgezogene Linie ohne Animation.
- <svg width="100%" height="42" xmlns="http://www.w3.org/2000/svg" version="1.2" xmlns:svg="http://www.w3.org/2000/svg">
- <text class="headline4" x="10" y="40">
- Eine einfache Überschrift
- </text>
- </svg>
- /* Für Animationen in Chrome benötigt ihr
- noch das -webkit-Prefix
- Siehe http://caniuse.com/#feat=css-animation */
- .headline4 {
- font-size: 40px;
- fill: none;
- stroke: #000000;
- font-family: Calibri, Arial, Verdana, sans-serif;
- animation: moveit 10s infinite;
- }
- @keyframes moveit {
- 0% { stroke-dasharray: 0 500; }
- 100% { stroke-dasharray: 500 0; }
- }
Typografische Feinheiten: Hier kann es zu Sonderfällen kommen, die von der genutzten Schrift und dem Browser abhängen. Unter Windows wird die Schrift Calibri verwendet. Firefox setzt hierbei das »ft« als Ligatur, also als ein einzelnes Zeichen. Andere Browser zeichnen das f und das t jedoch getrennt.
Neben stroke-dasharray
gibt es auch stroke-dashoffset
, das festlegt, an welcher Stelle mit dem dasharray begonnen werden soll. So könnten wir etwa mit der Lücke anfangen. Wenn die beiden Werte aufeinander abgestimmt werden, lässt sich auch der stroke-dashoffset
animieren, so dass sich die Linien der Outline gleichmäßig bewegen. Auch hier ist die Animation auf Firefox und (mit Prefix) Chrome beschränkt. Die anderen Browser zeigen die statische Outline.
- <svg width="100%" height="90" xmlns="http://www.w3.org/2000/svg" version="1.2" xmlns:svg="http://www.w3.org/2000/svg">
- <rect height="90" width="100%" y="0" x="0" fill="#EEE"/>
- <text class="headline5" x="10" y="80">
- Weihnachtsaktion
- </text>
- </svg>
- /* Für Animationen in Chrome benötigt ihr
- auch hier das -webkit-Prefix */
- .headline5 {
- font-size: 80px;
- fill: none;
- stroke: #F00;
- stroke-width: 3px;
- font-family: Calibri, Arial, Verdana, sans-serif;
- stroke-dasharray: 9 3;
- animation: moveit2 1s infinite linear;
- }
- @keyframes moveit2 {
- 0% { stroke-dashoffset: 12; }
- 100% { stroke-dashoffset: 0; }
- }
In Kombination mit einem textPath
folgt Text einem beliebigen Pfad. Das wiederum funktioniert in allen modernen Browsern.
- <svg width="100%" height="100" xmlns="http://www.w3.org/2000/svg" version="1.2" xmlns:svg="http://www.w3.org/2000/svg">
- <defs>
- <path id="textPath" d="M75,20 a1,1 0 0,0 130,0" />
- </defs>
- <text class="headline6" x="0" y="0">
- <textPath xlink:href="#textPath">
- Immer nur lächeln
- </textPath>
- </text>
- </svg>
- .headline6 {
- font-size: 28px;
- fill: #000;
- font-family: Calibri, Arial, Verdana, sans-serif;
- }
Barrierefreiheit: SVG können unterschiedlich komplex sein. Insofern sind sie auch nicht generell barrierefrei oder nicht. Einige Aspekte funktionieren recht gut, bei anderen können wir mit WAI-ARIA etwas nachhelfen. Siehe etwa »Tips for Creating Accessible SVG«. Das text-Element innerhalb von SVG wird Screenreadern als reiner Text übermittelt. Dabei spielt es keine Rolle, ob wir die Outline hervorheben, Animationen nutzen oder den Text an einem Pfad ausrichten.
Links in SVG
Neben Text ist es auch erlaubt, übliche Links in SVG-Dateien einzusetzen. Allerdings müsst ihr das Attribut href
hier durch xlink:href
ersetzen. Das Schöne daran: Die Links verhalten sich wie gewöhnliche Links außerhalb eines SVG. Sie können also mit Pseudoklassen wie :hover, :focus und :target angesprochen werden und bekommen auch den Fokus, wenn ein Nutzer durch die Website tabbt.
- <svg width="100%" height="20" xmlns="http://www.w3.org/2000/svg" version="1.2" xmlns:svg="http://www.w3.org/2000/svg">
- <text x="0" y="15">
- <a xlink:href="#ademo1" class="ademo" id="ademo1">Link 1</a>,
- <a xlink:href="#ademo2" class="ademo" id="ademo2">Link 2</a> und
- <a xlink:href="#ademo3" class="ademo" id="ademo3">Link 3</a>.
- </text>
- </svg>
- .ademo {
- fill: #000;
- text-decoration: underline;
- }
- .ademo:hover {
- text-decoration: none;
- fill: #F00;
- }
- .ademo:focus {
- text-decoration: none;
- fill: #0F0;
- }
- .ademo:target {
- text-decoration: none;
- fill: #00F;
- }
Das lässt sich ideal in Infografiken verwenden. Mit richtig genutzten Links ist die Infografik für Tastaturnutzer besser bedienbar. Und durch den Einsatz von :target ist es möglich, Deep Links auf bestimmte Informationen innerhalb der Infografik zu setzen. Ein nettes Extra: In der Deutschlandkarte sind die Länder als Pfade innerhalb eines Links eingebunden. Die Linkfläche orientiert sich nun am tatsächlichen Pfad, nicht etwa an einem Rechteck um den Pfad herum.
Bei der Infografik sind einige Dinge zu beachten:
Innerhalb eines SVG können Elemente nicht mit z-index
nach vorne geholt werden. Es gilt die Reihenfolge, in der die Elemente in dem SVG stehen. Deshalb müssen erst die 16 Länder gezeichnet werden, danach folgen die 16 Infokästen. Um :target zu nutzen, steckt der Umriss des Landes bereits in einem Link mit der id des Landes (#berlin). Die Infos zu einem Land sind in einem g
-Element gruppiert, das die Klasse des Landes trägt (.berlin). Dann können wir die Klasse über den general sibling combinator ~ ansprechen.
- #berlin:hover ~ g.berlin,
- #berlin:focus ~ g.berlin,
- #berlin:target ~ g.berlin
- {
- opacity: 1;
- transition: all 0.3s linear;
- }
Bewegt ein Nutzer die Maus über einen Land, erscheint der Infokasten. Bewegt er die Maus nun über den Kasten, verliert das Land den :hover-Status und der Infokasten verschwindet. Das führt zu einem lästigen Flackern des Infokastens. Abhilfe schafft der Tipp von Sascha Postner zu Pointer-Events.
- .landinfo
- {
- pointer-events: none;
- }
Bei solchen interaktiven SVG kommt es darauf an, wie diese jeweils ins HTML-Dokument eingebunden sind. Über das img-Element wird das SVG zwar angezeigt, ist aber nicht interaktiv. Als object-Element oder in einem iframe funktionieren die Zustände der Pseudoklassen, doch die URL ändert sich nicht, was aber sinnvoll sein kann, wenn ihr Nutzern den Deep Link zugänglich machen möchtet. Für dieses Beispiel ist es also am besten, das SVG direkt in die HTML-Datei zu schreiben.
- <object type="image/svg+xml" data="bundeslaender.svg">
- <!-- Fallback Text oder Bild -->
- Beispiel für ein SVG
- </object>
HTML in SVG
Die SVG-Beispiele oben mit reinem Text lassen sich noch in andere HTML-Elemente einsetzen, damit der Text eine semantische Bedeutung bekommt. Was aber, wenn das SVG mehrere Texte enthält, die semantisch unterschiedlich ausgezeichnet werden müssten? Zum Beispiel für erklärende Texte innerhalb einer Infografik? Für diesen Fall gibt es das foreignObject
-Element, das HTML innerhalb eines SVG erlaubt.
- <svg width="100%" height="200" xmlns="http://www.w3.org/2000/svg" version="1.2" xmlns:svg="http://www.w3.org/2000/svg">
- <foreignObject width="100%" height="200">
- <h1>Überschrift 1. Ordnung</h1>
- <p>Ein Beispieltext mit einer <em>Betonung</em>.</p>
- <h1>Überschrift 1. Ordnung</h1>
- <p>Ein Beispieltext mit einer <strong>starken Betonung</strong>.</p>
- </foreignObject>
- </svg>
Das klappt in allen modernen Browsern, allerdings nicht im Internet Explorer. Hier habt ihr zwei Möglichkeiten. Zum einen könnt ihr das switch-Element benutzen, um verschiedene Inhalte auszugeben. Zum anderen besteht natürlich auch hier die Möglichkeit, Conditional Comments einsetzen, wenn es nur darum geht, dem IE andere Inhalte zu liefern.
Kleine Korrektur nach dem Kommentar von Florence: Für die IE9+ könnt ihr das switch-Element einsetzen, um verschiedene Inhalte auszugeben. Statt des Attributs requiredExtensions
müsst ihr allerdings das Attribut requiredFeatures
nutzen. Für den IE8 wird auch hier ein Conditional Comment die beste Lösung sein.
- <switch>
- <foreignObject width="100" height="50"
- requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
- <!-- Das gewünschte HTML -->
- </foreignObject>
- <!-- Alternativer SVG-Inhalt,
- falls foreignObject nicht unterstützt wird -->
- </switch>
Responsive Webdesign: Alle gezeigten SVG-Techniken funktionieren auch in Safari unter iOS sowie in Chrome unter Android; dabei laufen die Animationen etwas langsamer ab. Allerdings ist bei den Beispielen auf dieser Seite noch kein responsives Verhalten berücksichtigt. Natürlich wäre es am einfachsten, alle SVG kleiner zu skalieren. Allerdings sieht die Outline in zu kleinen Größen nicht mehr ordentlich aus, und die kleinen Länder lassen sich in der Karte nicht mehr gut auf dem Touchscreen treffen. Sinnvoller kann es also sein, stattdessen reinen Text oder eine Tabelle der Einwohnerzahlen anzubieten.
SVG bieten noch viele anderen Eigenschaften, die sich an der einen oder anderen Stelle lohnen können. Zum Beispiel Animationen mit SMIL oder via snap.svg, Muster, Gradienten, Masken und Filter. Die Optionen sind zahlreich und sicher auch nicht ausgereizt. Leider nützen euch bei den Details die allgemeinen Infos auf Can I use nicht mehr viel, und es gilt, die benötigten Funktionen selbst in den Browsern zu testen. Zum Einarbeiten in SVG gibt es ein paar gute Anlaufstellen:
- Der »Pocket Guide to Writing SVG« von Joni Trythall gibt einen guten ersten Einblick. Das Büchlein könnt ihr mittlerweile kostenlos bekommen.
- Das SVG Tutorial von Jakob Jenkov enthält einige Aspekte, die im Pocket Guide fehlen.
- Generell alle Artikel von Sara Soueidan zum Thema SVG.
- Wer den Effekt des langsamen Zeichnens mag, kann zum Beispiel vivus.js dafür einsetzen.
- Und ein schönes Beispiel, was mit SVG (und viel Arbeit) möglich ist. Das digitale Pop-Up-Buch zum Beercamp 2012 von nclud.
Kommentare
Marty
am 22.12.2014 - 11:07
Das ist ja wirklich erstaunlich was mit SVG alles möglich ist mittlerweile.
Frage(n):
1. Kann man eine Überschrift zentrieren? Wenn ja wie?
2. Kann man bei einer Überschrift jeden Buchstaben in einer anderen Farbe färben? Wie?
Danke und super Artikel!
+1
Nicolai Schwarz (Autor)
am 22.12.2014 - 12:38
Ja, das geht über
text-anchor
. Zum Beispiel:Ergibt:
Auch das geht. Innerhalb eines
text
-Elements kannst du weiteretspan
-Elemente für die Buchstaben nutzen. Mit unterschiedlichen Klassen färbst du die Buchstaben ein. Innerhalb einesforeignObject
-Elements klappt das ebenso mit einfachenspan
-Elemente für die Buchstaben.Florence Maurice
am 22.12.2014 - 15:03
schöne Beispiele und Ausführungen!
.... kleiner Hinweis: der Link bei "das switch-Element benutzen, um verschiedene Inhalte auszugeben" geht nicht, weil aus dem href- ein hef-Attribut geworden ist ...
Jens Grochtdreis (Webkraut)
am 22.12.2014 - 15:25
Danke für den Hinweis, Florence, ich habe es korrigiert.
Florence Maurice
am 22.12.2014 - 15:08
... und noch ne Ergänzung wegen dem fehlenden Support für foreignObject im IE: Conditional Comments funktionieren nicht mehr im IE10 und größer, sind hier also keine Möglichkeit.
Nicolai Schwarz (Autor)
am 23.12.2014 - 01:24
Danke, stimmt. Macht aber nix. Aber IE9 klappt die Lösung per switch und alternativem Inhalt. Darunter könnte man auf Conditional Comments setzen. Ich habe den Artikel korrigiert.
Florence Maurice
am 23.12.2014 - 01:30
danke für die Detailklärung. Das mit switch scheint echt interessant, muss mir das mal genauer ansehen ...
Thomas Meinike
am 22.12.2014 - 15:49
Eine weitere u. a. für Text interessante Technik ist das für SVG 2 vorgesehene Attribut paint-order="stroke", aktuell mindestens von Firefox und Opera unterstützt (siehe Material zu einem kürzlich gehaltenen Vortrag).
Philip
am 03.01.2015 - 16:46
Cooler Artikel! Was ich bisher noch nicht geschafft habe ist die Manipulation von SVG Icons via Pseudo-Klasse (:hover) in einem SVG-Sprite, das über ein CSS Pseudo-Element eingebunden wird. Kennt da jemand von euch zufälliger Weise eine Möglichkeit? Bisher klappt es nur, wenn ich das SVG-Sprite direkt ins HTML-Markup einbinde, aber das finde ich doof.
Viele Grüße
Philip
Georgios
am 17.02.2015 - 15:41
Animierter SVG Text: http://tympanus.net/Tutorials/AnimatedTextFills/
Die Kommentare sind geschlossen.