SVG und Skalierung
Sie tragen es schon im Namen: SVG, Scalable Vector Graphics,
lassen sich skalieren. Noch besser: sie lassen sich skalieren, ohne an Qualität
zu verlieren – sie verpixeln nicht. Soweit, so gut. Der Traum vom verlustfreien
Skalieren hält allerdings nur solange, wie man das SVG bereits in der
gewünschten Größe importiert. Kommt man jedoch auf die verwegene Idee, ein SVG
in einen Container, beispielsweise ein Div, zu packen, und möchte man dann
vielleicht auch noch, dass sich besagtes SVG an die Größe dieses Containers
anpasst, gerät man leicht in Verzweiflung.
Die Zauberworte, oder vielmehr Zauberattribute, die alles
wieder gut machen können, heißen viewBox und preserveAspectRatio.
Skalieren mit „normalen“ Bildern
Bei den üblichen Bilddateien, beispielsweise .jpg oder .png,
kann man auf ganz einfache Art und Weise dafür sorgen, dass das Bild seine
Größe ändert: Das img selbst bekommt die Anweisung width: 100%; der übergeordnete
Container eine fixe Breite. Die Höhe wird automatisch angepasst. Fertig.

Die Klasse .img-box ist hier für den schwarzen Rahmen und,
viel wichtiger, für die Breite des Containers verantwortlich:

Das Originalbild hat eine Größe von 300 x 294 Pixeln; es
passt sich aber problemlos den veränderten Maßen des übergeordneten Containers
an. Die Seitenverhältnisse werden automatisch dadurch beibehalten, dass
entweder nur die Breite oder nur die Höhe angegeben wird; der andere Wert wird
automatisch angepasst.
SVG an Containergröße anpassen
Versucht man dies mit einer Grafik mit der Dateiendung .svg,
kann es sein, dass man aufgrund der Angaben, die dieses Bild schon mitbringt,
zu einem ähnlich zufriedenstellenden Ergebnis gelangt. Anders jedoch, wenn man
ein SVG direkt mittels HTML-Tag[1]
einbinden möchte.

Mit den gleichen Angaben für das SVG wie oben für das IMG
(einziger Unterschied: grüne Hintergrundfarbe) kommt man nämlich zu einem
anderen Ergebnis:

Das SVG selbst hat einen grünen Hintergrund, darauf befindet sich ein
orangefarbenes Rechteck und ein umrahmter gelber Kreis. Im HTML-Teil sieht das
so aus:

Stimmt, das SVG hat eine Breite und Höhe angegeben. Behält
man alle anderen Settings bei und lässt nur diese width und height weg, ist das Ergebnis allerdings noch
unschöner:

Offensichtlich braucht man also für SVG eine andere
Herangehensweise, um sie ihren übergeordneten Containern anpassen zu können.
Das ViewBox-Attribut
Dafür gibt es das Attribut viewBox. Dieses setzt sich wiederum aus vier Werten zusammen:
min-x, min-y, width und height, die durch Kommata oder mittels Leerzeichen
getrennt werden. Leider sind diese Werte nicht so intuitiv verständlich, wie
man sich das wünschen würde. Beginnen wir mit letzteren beiden.
ViewBox: width und height
Die Werte für width und height im viewBox-Attribut stehen NICHT dafür, wie breit und hoch das
Endergebnis sein soll, sondern werden zur Berechnung des Verhältnisses zur
ursprünglichen Größe gebraucht. Um das etwas anschaulicher zu erklären, nehmen
wir das SVG von weiter oben, allerdings diesmal mit dem orangefarbenen Rechteck
kleiner und in der linken oberen Ecke.

Das Rechteck hat hier eine Breite von 20, das SVG selbst (mit grünem
Hintergrund) eine Breite von 200, das SVG ist also zehnmal so breit wie das
darin liegende Rechteck. Das Ergebnis sieht folgendermaßen aus:

Das SVG selbst hat der besseren Übersichtlichkeit wegen
einen schwarzen Rahmen und eine grüne Hintergrundfarbe (in CSS definiert).
Und nun zum mysteriösen viewBox-Attribut.
In diesem Fall sind width und height im viewBox-Attribut gleich der width
und height des SVG. Das bedeutet, sie
verhalten sich im Verhältnis 1:1. Oder anders ausgedrückt:
SVG-width/viewBox-width = 1.
Möchte man nun skalieren, kann man sich diese width und height der viewBox
zunutze machen: Soll das orangefarbene Quadrat doppelt so breit werden, setzt man die viewBox width auf die Hälfte. Klingt im ersten Moment
vielleicht verwirrend, macht aber aufgrund des Verhältnisses Sinn:
SVG-width/viewBox-width, in diesem Fall 200/100 = 2.

Ergebnis:

Soll sich das orangefarbene Quadrat über das ganze (grüne)
SVG erstrecken, müsste es also 10x so breit sein. Die viewBox width und height
müssten also auf 20 gesetzt werden, denn: 200/20 = 10
(svg-width/viewBox-width).
Ergebnis:

Wie hier jetzt gut zu sehen ist, betrifft diese Skalierung
auch die anderen Größenangaben, die innerhalb des SVG gemacht wurden; auch der
Rahmen des Kreises ist entsprechend breiter geworden.
Verpackt man nun dieses SVG in ein Div und gibt ihm eine
fixe Breite, kommt zunächst die Enttäuschung: Das SVG hat sich nicht an die
neue Größe angepasst. Dazu bleibt noch eins zu tun: width- und height-Angabe
aus dem <svg>-Tag löschen. Dann kann über die Größenangabe des
übergeordneten Divs skaliert werden.

Dieses einfache Beispiel ist hier auf codepen zu finden.
ViewBox: min-x, min-y
Fein, das mit der Größe funktioniert jetzt schon mal. Wozu
sind aber die ersten beiden Werte da, die dem viewBox-Attribut zugeordnet werden?
Wer jetzt „Koordinatensystem“ gedacht hat, ist schon –
teilweise – auf dem richtigen Weg. Sehen wir uns einmal an, was passiert, wenn
wir diese beiden Werte in unserem Beispiel von eben auf 10 setzen.


Hübsch, aber vermutlich nicht das, was man eigentlich
erwarten würde. Wir verschieben mit diesen beiden Koordinaten nicht den Inhalt
um die angegebenen Werte, sondern definieren einen neuen Startpunkt innerhalb
unseres SVG; dieser Startpunkt liegt dann in der linken oberen Ecke.
Soll der gesamte Bildausschnitt verschoben werden, kann man das
über diese beiden Werte erreichen. Hier können (anders als bei width und height) auch negative Werte vergeben werden. Möchte man das
Ergebnis erreichen, das man aufgrund der Erfahrung mit Koordinatensystemen im
HTML/CSS-Bereich hat, muss man hier umdenken. Um das orangefarbene Rechteck nach unten und nach rechts zu verschieben, müssen in der viewBox negative Werte
für min-x und min-y vergeben werden.
Wieder unlogisch? Nur im ersten Moment. Wir definieren
dadurch einen neuen 0,0-Punkt für unseren Bildausschnitt. Wenn wir negative
Werte verwenden, liegt dieser Startpunkt außerhalb der eigentlichen Grafik. Unser
Rechteck wirkt also, als wäre es nach rechts unten verschoben worden.
Tatsächlich liegt aber der absolute Nullpunkt unseres Koordinatensystems
außerhalb der eigentlichen Grafik.
Ergebnis:

Auch einzelne Elemente innerhalb des SVG lassen sich
positionieren: über die x- und y-Koordinate im jeweiligen Tag. Soll
beispielsweise nur das orangefarbene Rechteck verschoben werden, wird der
entsprechende Startpunkt für das Rechteck über die x- und y-Koordinate direkt
im <rect>-Tag gesetzt.


Bitteschön: orangefarbenes Rechteck verschoben.
preserveAspectRatio
Es gibt noch ein weiteres hilfreiches Attribut, das uns
erlaubt, SVG anzupassen: preserveAspectRatio.
Diese Angabe greift bei SVG nur, wenn auch viewBox
definiert ist; ohne viewBox-Angabe wird preserveAspectRatio
ignoriert.
Das Default-Setting für preserveAspectRatio
ist "xMidYMid meet" und muss nicht explizit gesetzt werden. Es
bedeutet nichts anderes, als dass das Bildseitenverhältnis beibehalten werden
soll.
Möchte man, dass sich das SVG dem übergeordneten Container ohne
Rücksicht auf das Bildseitenverhältnis anpasst, bzw. über width und height Angabe
verzerrt werden kann, kann man das mittels preserveAspectRatio="none"; erreichen.

Dazu braucht man allerdings auch wieder die Breiten- und
Höhenangabe für das SVG; in diesem Fall (mit übergeordnetem Container, der eine
Höhen- und Breitenangabe hat) width="100%" und height="100%".
Auch dieses einfache Beispiel ist auf codepen zu finden: Link zum Beispiel
Wer noch etwas in die Tiefe gehen möchte: Dem preserveAspectRatio-Attribut können
zwei Parameter übergeben werden. Der erste ist der sogenannte align-Parameter. Er ist uns im Beispiel
oben schon begegnet, als Default-Wert "xMidYMid"
und als "none". Der zweite,
optionale, Parameter ist der meetOrSlice-Parameter,
ebenfalls schon kurz erwähnt im Default-Setting.
Für die meisten Anwendungsfälle werden das Default-Setting
oder die Anweisung preserveAspectRatio="none";
völlig ausreichen. Eine vollständige Übersicht über alle möglichen align-Parameter gibt es in der
Dokumentation.
Tipps & Hinweise
*) Grafiken mit der Dateiendung .svg haben normalerweise
schon ein viewBox-Attribut gesetzt.
Da wir hier mit XML zu tun haben, sind ein paar
Kleinigkeiten zu beachten:
*) Alle Tags müssen geschlossen werden.
Bsp.:
<rect fill="blue" />
*) XML ist Case-Sensitive! Schreibweise von Attributen oder
Parametern beachten!
Bsp.: preserveAspectRatio="xMidYMid meet";
[1] SVG basiert
auf XML. Es kann im HTML-Teil mittels <svg>-Tag eingebunden werden.