Generative Datenintelligenz

Optimieren von SVG-Mustern auf ihre kleinste Größe

Datum:

Ich habe kürzlich ein Backsteinmauermuster als Teil meines erstellt #PetiteMuster Serie, eine Herausforderung, bei der ich innerhalb von 560 Bytes (oder ungefähr der Größe von zwei Tweets) organisch aussehende Muster oder Texturen in SVG erstelle. Um dieser Einschränkung gerecht zu werden, habe ich eine Reise unternommen, die mir einige radikale Methoden zur Optimierung von SVG-Mustern beigebracht hat, sodass sie so wenig Code wie möglich enthalten, ohne die Gesamtbildqualität zu beeinträchtigen.

Ich möchte Sie durch den Prozess führen und Ihnen zeigen, wie wir ein SVG-Muster nehmen können, das bei 197 Byte beginnt, bis hinunter zu nur 44 Byte – eine satte Reduzierung von 77.7 %!

Das SVG-Muster

CodePen Embed-Fallback

Dies ist ein sogenanntes "Running Bond"-Ziegelmuster. Es ist das am weitesten verbreitete Ziegelmuster, das Sie sicherlich schon einmal gesehen haben: Jede Reihe von Ziegeln ist um die Hälfte der Länge eines Ziegels versetzt, wodurch ein sich wiederholendes versetztes Muster entsteht. Die Anordnung ist ziemlich einfach und macht SVGs <pattern> -Element perfekt geeignet, um es im Code zu reproduzieren.

Das SVG <pattern> element verwendet ein vordefiniertes grafisches Objekt, das in festen Abständen entlang der horizontalen und vertikalen Achse repliziert (oder „gekachelt“) werden kann. Im Wesentlichen definieren wir ein rechteckiges Kachelmuster und es wird wiederholt, um den Füllbereich zu malen.

Lassen Sie uns zunächst die Abmessungen eines Steins und den Abstand zwischen den einzelnen Steinen festlegen. Verwenden wir der Einfachheit halber saubere, runde Zahlen: eine Breite von 100 und eine Größe von 30 für den Ziegel, und 10 für die horizontalen und vertikalen Lücken zwischen ihnen.

Zeigt einen hervorgehobenen Teil eines Mauermusters, das das Beispiel ist, das wir zur Optimierung von SVG-Mustern verwenden.

Als nächstes müssen wir unsere „Basis“-Kachel identifizieren. Und mit „Fliesen“ meine ich eher Musterfliesen als physische Fliesen, nicht zu verwechseln mit Ziegelsteinen. Lassen Sie uns den hervorgehobenen Teil des Bildes oben als Musterkachel verwenden: zwei ganze Steine ​​in der ersten Reihe und ein ganzes zwischen zwei halben Steinen in der zweiten Reihe. Beachten Sie, wie und wo die Lücken enthalten sind, da diese in die Kachel mit wiederholtem Muster aufgenommen werden müssen.

Beim Benutzen <pattern>, müssen wir die Muster definieren width und height, die der Breite und Höhe der Basiskachel entsprechen. Um die Abmessungen zu erhalten, brauchen wir ein wenig Mathematik:

Tile Width = 2(Brick Width) + 2(Gap) = 2(100) + 2(10) = 220
Tile Height = 2(Bright Height) + 2(Gap) = 2(30) + 2(10) = 80

Okay, unsere Musterkachel ist es also 220✕80. Wir müssen auch die einstellen patternUnits Attribut, wobei der Wert userSpaceOnUse bedeutet im Wesentlichen Pixel. Zum Schluss fügt man ein hinzu id zum Muster ist notwendig, damit es referenziert werden kann, wenn wir ein anderes Element damit malen.

<pattern id="p" width="220" height="80" patternUnits="userSpaceOnUse"> <!-- pattern content here -->
</pattern>

Nachdem wir nun die Kachelabmessungen festgelegt haben, besteht die Herausforderung darin, den Code für die Kachel so zu erstellen, dass die Grafik mit der kleinstmöglichen Anzahl von Bytes gerendert wird. Das hoffen wir ganz am Ende zu erreichen:

Die Ziegel (in Schwarz) und Lücken (in Weiß) des endgültigen laufenden Verbundmusters

Anfängliches Markup (197 Byte)

Der einfachste und aussagekräftigste Ansatz, um dieses Muster nachzubilden, besteht darin, fünf Rechtecke zu zeichnen. Standardmäßig ist die fill eines SVG-Elements ist schwarz und die stroke ist transparent. Dies funktioniert gut für die Optimierung von SVG-Mustern, da wir diese nicht explizit im Code deklarieren müssen.

Jede Zeile im folgenden Code definiert ein Rechteck. Die width und height sind immer gesetzt, und die x und y Positionen werden nur gesetzt, wenn ein Rechteck davon versetzt wird 0 Position.

<rect width="100" height="30"/>
<rect x="110" width="100" height="30"/>
<rect y="40" width="45" height="30"/>
<rect x="55" y="40" width="100" height="30"/>
<rect x="165" y="40" width="55" height="30"/>

Die obere Reihe der Fliese enthielt zwei Ziegel in voller Breite, der zweite Ziegel ist dazu positioniert x="110" ermöglicht 10 Pixel der Lücke vor dem Backstein. Ebenso gibt es 10 Pixel der Lücke nach, weil der Ziegel bei endet 210 Pixel (110 + 100 = 210) auf der horizontalen Achse, obwohl die <pattern> Breite ist 220 Pixel. Wir brauchen dieses bisschen zusätzlichen Platz; andernfalls würde der zweite Stein mit dem ersten Stein in der angrenzenden Fliese verschmelzen.

Die Steine ​​in der zweiten (unteren) Reihe sind versetzt, sodass die Reihe zwei halbe Steine ​​und einen ganzen Stein enthält. In diesem Fall möchten wir, dass die Steine ​​mit halber Breite zusammenlaufen, sodass am Anfang oder Ende keine Lücke entsteht, sodass sie nahtlos mit den Steinen in angrenzenden Musterkacheln fließen können. Beim Versetzen dieser Steine ​​müssen wir auch halbe Lücken einrechnen, also die x Werte sind 55 und 165, Bzw.

Wiederverwendung von Elementen (-43 B, 154 B insgesamt)

Es erscheint ineffizient, jeden Baustein so explizit zu definieren. Gibt es keine Möglichkeit, SVG-Muster zu optimieren, indem Sie stattdessen die Formen wiederverwenden?

Ich glaube nicht, dass allgemein bekannt ist, dass SVG eine hat <use> Element. Sie können damit auf ein anderes Element verweisen und dieses referenzierte Element überall rendern <use> wird genutzt. Das spart einige Bytes, weil wir auf die Angabe der Breite und Höhe jedes Bausteins, mit Ausnahme des ersten, verzichten können.

Das heißt, <use> kommt mit einem kleinen Preis. Das heißt, wir müssen ein hinzufügen id für das Element, das wir wiederverwenden möchten.

<rect id="b" width="100" height="30"/>
<use href="#b" x="110"/>
<use href="#b" x="-55" y="40"/>
<use href="#b" x="55" y="40"/>
<use href="#b" x="165" y="40"/>

Der kürzeste id Möglich ist ein Zeichen, also habe ich „b“ für Brick gewählt. Die <use> Element kann ähnlich wie positioniert werden <rect>, Mit dem x und y Attribute als Offsets. Da jeder Stein jetzt die volle Breite hat, zu der wir gewechselt haben <use> (Denken Sie daran, wir haben die Steine ​​in der zweiten Reihe der Musterkachel explizit halbiert), wir müssen ein Negativ verwenden x Wert in der zweiten Reihe, stellen Sie dann sicher, dass der letzte Stein aus der Fliese überläuft, um eine nahtlose Verbindung zwischen den Steinen herzustellen. Diese sind jedoch in Ordnung, da alles, was außerhalb der Musterkachel liegt, automatisch abgeschnitten wird.

Können Sie einige sich wiederholende Zeichenfolgen erkennen, die effizienter geschrieben werden können? Lassen Sie uns als nächstes daran arbeiten.

Umschreiben in Pfad (-54B, 100B insgesamt)

<path> ist wahrscheinlich das mächtigste Element in SVG. Sie können so gut wie jede Form mit „Befehlen“ darin zeichnen d Attribut. Es stehen 20 Befehle zur Verfügung, aber wir brauchen nur die einfachsten für Rechtecke.

Hier bin ich damit gelandet:

<path d="M0 0h100v30h-100z M110 0h100v30h-100 M0 40h45v30h-45z M55 40h100v30h-100z M165 40h55v30h-55z"/>

Ich weiß, super seltsame Zahlen und Buchstaben! Sie alle haben eine Bedeutung, selbstverständlich. Folgendes passiert in diesem speziellen Fall:

  • M{x} {y}: Bewegt sich basierend auf Koordinaten zu einem Punkt.
  • z: Schließt das aktuelle Segment.
  • h{x}: Zeichnet vom aktuellen Punkt aus eine horizontale Linie mit der Länge von x in die durch das Vorzeichen definierte Richtung x. Kleinbuchstaben x gibt eine relative Koordinate an.
  • v{y}: Zeichnet vom aktuellen Punkt aus eine vertikale Linie mit der Länge von y in die durch das Vorzeichen definierte Richtung y. Kleinbuchstaben y gibt eine relative Koordinate an.

Dieses Markup ist viel knapper als das vorherige (Zeilenumbrüche und Leerzeichen mit Einrückungen dienen nur der Lesbarkeit). Und, hey, wir haben es geschafft, die Hälfte der ursprünglichen Größe herauszuschneiden und sind bei 100 Byte angekommen. Trotzdem gibt mir etwas das Gefühl, dass dies kleiner sein könnte …

Kachelüberarbeitung (-38 B, 62 B insgesamt)

Hat unsere Musterfliese keine sich wiederholenden Teile? Es ist klar, dass in der ersten Reihe ein ganzer Stein wiederholt wird, aber was ist mit der zweiten Reihe? Es ist etwas schwieriger zu sehen, aber wenn wir den mittleren Stein halbieren, wird es offensichtlich.

Die linke Hälfte vor der roten Linie ist die gleiche wie die rechte Seite.

Nun, der mittlere Stein ist nicht genau in zwei Hälften geschnitten. Es gibt einen leichten Versatz, weil wir auch die Lücke berücksichtigen müssen. Wie auch immer, wir haben gerade ein einfacheres Basiskachelmuster gefunden, was weniger Bytes bedeutet! Das bedeutet auch, dass wir die halbieren müssen width unserer <pattern> Element von 220 bis 110.

<pattern id="p" width="110" height="80" patternUnits="userSpaceOnUse"> <!-- pattern content here -->
</pattern>

Sehen wir uns nun an, wie die vereinfachte Kachel gezeichnet wird <path>:

<path d="M0 0h100v30h-100z M0 40h45v30h-45z M55 40h55v30h-55z"/>

Die Größe wird auf 62 Bytes reduziert, was bereits weniger als ein Drittel der Originalgröße ist! Aber warum hier aufhören, wenn wir noch mehr tun können!

Pfadverkürzungsbefehle (-9B, 53B insgesamt)

Es lohnt sich, etwas tiefer in die Materie einzusteigen <path> -Element, da es weitere Hinweise zur Optimierung von SVG-Mustern enthält. Ein Missverständnis, das ich hatte, als ich damit arbeitete <path> handelt davon, wie die fill Attribut funktioniert. Nachdem ich in meiner Kindheit viel mit MS Paint gespielt habe, habe ich gelernt, dass jede Form, die ich mit einer soliden Farbe füllen möchte, geschlossen sein muss, dh keine offenen Punkte haben muss. Andernfalls tritt die Farbe aus der Form aus und spritzt über alles.

In SVG ist dies jedoch nicht der Fall. Lassen Sie mich zitieren die spezifikation selbst:

Die Fülloperation füllt offene Unterpfade, indem sie die Fülloperation so durchführt, als ob ein zusätzlicher „Pfad schließen“-Befehl zu dem Pfad hinzugefügt würde, um den letzten Punkt des Unterpfads mit dem ersten Punkt des Unterpfads zu verbinden.

Das bedeutet, dass wir die Befehle zum Schließen des Pfads weglassen können (z), da die Teilpfade beim Füllen automatisch als geschlossen gelten.

Eine weitere nützliche Sache, die Sie über Pfadbefehle wissen sollten, ist, dass sie in Variationen von Groß- und Kleinbuchstaben vorliegen. Kleinbuchstaben bedeuten, dass relative Koordinaten verwendet werden; Großbuchstaben bedeuten, dass stattdessen absolute Koordinaten verwendet werden.

Etwas kniffliger ist es mit der H und V Befehle, weil sie nur eine Koordinate enthalten. So würde ich diese beiden Befehle beschreiben:

  • H{x}: Zeichnet eine horizontale Linie vom aktuellen zu koordinierenden Punkt x.
  • V{y}: Zeichnet eine vertikale Linie vom aktuellen zu koordinierenden Punkt y.

Wenn wir den ersten Stein in der Musterkachel zeichnen, beginnen wir mit dem (0,0) Koordinaten. Dann zeichnen wir eine horizontale Linie zu (100,0) und eine vertikale Linie zu (100,30), und zeichnen Sie schließlich eine horizontale Linie zu (0,30). Wir haben die benutzt h-100 Befehl in der letzten Zeile, aber es ist das Äquivalent von H0, also zwei statt fünf Bytes. Wir können zwei ähnliche Vorkommen ersetzen und den Code von unserem parieren <path> bis dahin:

<path d="M0 0h100v30H0 M0 40h45v30H0 M55 40h55v30H55"/>

Weitere 9 Bytes wegrasiert – wie viel kleiner können wir gehen?

Überbrückung (-5B, 48B insgesamt)

Die längsten Befehle, die einem vollständig optimierten SVG-Muster im Wege stehen, sind die „move to“-Befehle, die 4, 5 bzw. 6 Bytes beanspruchen. Eine Einschränkung, die wir haben, ist die:

Ein Pfaddatensegment (sofern vorhanden) muss mit einem „moveto“-Befehl beginnen.

Aber das ist OK. Der erste ist sowieso der kürzeste. Wenn wir die Reihen vertauschen, können wir auf eine Pfaddefinition kommen, bei der wir uns nur entweder horizontal oder vertikal zwischen den Steinen bewegen müssen. Was wäre, wenn wir die nutzen könnten h und v Befehle dort statt M?

Der Pfad beginnt am roten Punkt in der oberen linken Ecke. Rot sind die mit Pfeilen unterstützten Pfadbefehle, schwarz sind die Koordinaten, auf die die Pfeile zeigen.

Das obige Diagramm zeigt, wie die drei Formen mit einem einzigen Pfad gezeichnet werden können. Beachten Sie, dass wir die Tatsache nutzen, dass die fill Betrieb schließt automatisch den offenen Teil zwischen (110,0) und (0,0). Mit dieser Neuanordnung haben wir auch die Lücke links vom Ziegel in voller Breite in der zweiten Reihe verschoben. So sieht der Code aus, immer noch in einen Baustein pro Zeile unterteilt:

<path d="M0 0v30h50V0 h10v30h50 v10H10v30h100V0"/>

Sicherlich haben wir jetzt die absolut kleinste Lösung gefunden, da wir nur noch 48 Bytes haben, oder?! Brunnen…

Stellen trimmen (-4B, 44B insgesamt)

Wenn Sie bei den Abmessungen etwas flexibel sein können, gibt es noch eine andere Möglichkeit, SVG-Muster zu optimieren. Wir haben mit einer Ziegelbreite von gearbeitet 100 Pixel, aber das sind drei Bytes. Ändern Sie es zu 90 bedeutet ein Byte weniger, wann immer wir es schreiben müssen. In ähnlicher Weise haben wir eine Lücke von verwendet 10 Pixel — aber wenn wir es ändern zu 8 Stattdessen speichern wir bei jedem dieser Vorkommnisse ein Byte.

<path d="M0 0v30h45V0 h8v30h45 v8H8v30h90V0"/>

Das bedeutet natürlich auch, dass wir die Schnittmaße entsprechend anpassen müssen. Hier ist der endgültige optimierte SVG-Mustercode:

<pattern id="p" width="98" height="76" patternUnits="userSpaceOnUse"> <path d="M0 0v30h45V0h8v30h45v8H8v30h90V0"/>
</pattern>

Die zweite Zeile im obigen Ausschnitt – die Einrückungen nicht mitgezählt – ist 44 bytes. Wir sind in sechs Iterationen von 197 Bytes hierher gekommen. Das ist ein Brocken 77.7 % Größenreduzierung!

Ich frage mich aber … ist das wirklich die kleinstmögliche Größe? Haben wir alle Möglichkeiten zur Optimierung von SVG-Mustern untersucht?

Ich lade Sie ein, diesen Code weiter zu verkleinern oder sogar mit alternativen Methoden zur Optimierung von SVG-Mustern zu experimentieren. Ich würde gerne sehen, ob wir mit der Weisheit der Masse das wahre globale Minimum finden könnten!

Mehr zum Erstellen und Optimieren von SVG-Mustern

Wenn Sie mehr über das Erstellen und Optimieren von SVG-Mustern erfahren möchten, lesen Sie meinen Artikel über Erstellen von Mustern mit SVG-Filtern. Wenn Sie sich eine Galerie mit über 60 Mustern ansehen möchten, können Sie sich die ansehen PetitePatterns CodePen-Sammlung. Zu guter Letzt dürfen Sie gerne zuschauen Meine Tutorials auf YouTube um Ihnen zu helfen, noch tiefer in SVG-Muster einzusteigen.


Optimieren von SVG-Mustern auf ihre kleinste Größe ursprünglich veröffentlicht am CSS-Tricks.. Du solltest erhalten Sie den Newsletter.

spot_img

Neueste Intelligenz

spot_img

Chat mit uns

Hallo! Wie kann ich dir helfen?