viewBox und Koordinatensysteme
Die viewBox ist der Grund, warum SVG-Grafiken in jeder Größe scharf bleiben. Sie legt fest, welcher Ausschnitt der unendlichen Zeichenfläche auf den verfügbaren Platz gebracht wird.
Vier Zahlen, ein Ausschnitt
Das Attribut viewBox hat vier Werte: min-x min-y Breite Höhe. Sie beschreiben ein Rechteck im Koordinatensystem der Grafik. Der Browser nimmt genau diesen Ausschnitt und skaliert ihn so, dass er in den Platz passt, den width und height oder das CSS-Layout vorgeben.
Stell dir die viewBox wie das Sucherfenster einer Kamera vor. Die Zeichnung liegt fest auf dem Tisch. Mit den ersten beiden Werten verschiebst du die Kamera, mit den letzten beiden zoomst du: Eine kleinere viewBox zeigt weniger von der Zeichnung, die dadurch größer erscheint.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 330 110" width="330" height="110">
<defs>
<g id="vb-motiv">
<rect x="0" y="0" width="100" height="100" fill="#eef1f5"/>
<circle cx="50" cy="50" r="30" fill="#1f5fd1"/>
<rect x="45" y="45" width="10" height="10" fill="#c2410c"/>
</g>
</defs>
<svg x="0" y="5" width="100" height="100" viewBox="0 0 100 100"><use href="#vb-motiv"/></svg>
<svg x="115" y="5" width="100" height="100" viewBox="25 25 50 50"><use href="#vb-motiv"/></svg>
<svg x="230" y="5" width="100" height="100" viewBox="0 0 200 200"><use href="#vb-motiv"/></svg>
</svg>
Das Beispiel zeigt nebenbei, dass <svg>-Elemente verschachtelt werden dürfen. Jedes innere SVG bildet ein eigenes Koordinatensystem mit eigener viewBox.
Responsive Grafiken
Lässt du width und height am Wurzelelement weg und gibst nur eine viewBox an, verhält sich eine inline eingebettete Grafik wie ein flexibles Bild: Sie wird so breit wie ihr Container, und die Höhe ergibt sich aus dem Seitenverhältnis der viewBox. Für Diagramme und Illustrationen in Layouts mit wechselnder Breite ist das die einfachste Lösung. Bei Icons gibst du dagegen meist feste Maße oder eine Größe per CSS an, damit sie nicht plötzlich die ganze Zeile füllen.
Ohne viewBox skaliert nichts. Dann gilt eine Einheit als ein Pixel, und ändert man width, wird die Grafik nur beschnitten oder bekommt Leerraum, aber nicht größer.
Wenn die Seitenverhältnisse nicht passen
Hat die viewBox ein anderes Seitenverhältnis als der verfügbare Platz, entscheidet preserveAspectRatio. Der Standard ist xMidYMid meet: Die Grafik wird so groß wie möglich, ohne verzerrt oder beschnitten zu werden, und mittig ausgerichtet. Mit slice statt meet füllt sie die Fläche komplett aus, und was übersteht, wird abgeschnitten, ähnlich wie object-fit: cover in CSS. Der Wert none verzerrt die Grafik, bis sie genau passt.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 330 80" width="330" height="80">
<defs>
<g id="vb-quadrat">
<rect width="100" height="100" fill="#cfdcf7"/>
<circle cx="50" cy="50" r="40" fill="none" stroke="#1f5fd1" stroke-width="8"/>
</g>
</defs>
<svg x="0" y="0" width="100" height="80" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet"><use href="#vb-quadrat"/></svg>
<svg x="115" y="0" width="100" height="80" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice"><use href="#vb-quadrat"/></svg>
<svg x="230" y="0" width="100" height="80" viewBox="0 0 100 100" preserveAspectRatio="none"><use href="#vb-quadrat"/></svg>
<rect x="0.5" y="0.5" width="99" height="79" fill="none" stroke="#c2410c"/>
<rect x="115.5" y="0.5" width="99" height="79" fill="none" stroke="#c2410c"/>
<rect x="230.5" y="0.5" width="99" height="79" fill="none" stroke="#c2410c"/>
</svg>
Transformationen
Neben der viewBox gibt es einen zweiten Weg, Koordinaten zu verändern: das Attribut transform. Es nimmt eine Liste von Funktionen an, die nacheinander angewendet werden.
translate(x, y)verschiebt.rotate(Winkel, cx, cy)dreht um einen Punkt, ohne Angabe um den Ursprung.scale(sx, sy)vergrößert oder verkleinert, auch gespiegelt mit negativen Werten.skewX(Winkel)undskewY(Winkel)neigen.matrix(a, b, c, d, e, f)fasst alles in einer Matrix zusammen. Diese Form schreiben vor allem Zeichenprogramme.
Die Reihenfolge spielt eine Rolle. translate(100 0) rotate(45) verschiebt zuerst das Koordinatensystem und dreht dann an der neuen Stelle. Umgekehrt würde erst gedreht und dann entlang der gedrehten Achse verschoben, und die Form landet woanders.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 330 110" width="330" height="110">
<g fill="#1f5fd1" fill-opacity="0.85">
<rect x="20" y="30" width="50" height="50"/>
<rect x="20" y="30" width="50" height="50" transform="translate(80 0)"/>
<rect x="20" y="30" width="50" height="50" transform="rotate(30 195 55) translate(150 0)"/>
<rect x="20" y="30" width="50" height="50" transform="translate(250 30) scale(1.2 0.5) translate(-20 -30)"/>
</g>
</svg>
Gruppen
Das Element <g> fasst mehrere Elemente zusammen. Eine Transformation oder eine Farbe am g gilt für alle Kinder. Wer eine Zeichnung aus vielen Teilen als Ganzes verschieben will, packt sie in eine Gruppe und setzt ein einziges transform. Zeichenprogramme nutzen Gruppen auch für Ebenen.
Ganze Zahlen für scharfe Kanten
Liegt eine 1 Einheit breite Linie genau auf einer ganzzahligen Koordinate, verteilt sich der Strich auf zwei Pixelreihen und wirkt grau und unscharf. Bei einer viewBox, die eins zu eins auf Pixel abgebildet wird, hilft es, solche Linien auf halbe Werte wie 10,5 zu legen.
Die viewBox spielt auch bei Icon-Sammlungen eine Rolle: Jedes <symbol> kann eine eigene viewBox haben. Wie das funktioniert, zeigt das nächste Kapitel über use, symbol, Links und Bilder.