svg-loader: Eine andere Art, mit externen SVGs zu arbeiten

Avatar of Shubham Jain
Shubham Jain am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

SVGs sind großartig: Sie sind klein, sehen auf jeder Skala scharf aus und können angepasst werden, ohne eine separate Datei zu erstellen. Allerdings fehlt meiner Meinung nach heute etwas in den Webstandards: eine Möglichkeit, sie als externe Datei einzubinden, die auch die Anpassungsfähigkeiten des Formats beibehält.

Nehmen wir zum Beispiel an, Sie möchten das Logo Ihrer Website, das als web-logo.svg gespeichert ist, verwenden. Sie können tun

<img src="/images/logo.svg" />

Das ist in Ordnung, wenn Ihr Logo überall gleich aussehen soll. Aber in vielen Fällen haben Sie 2-3 Variationen desselben Logos. Slack hat zum Beispiel zwei Versionen.

Selbst die Farben im Hauptlogo sind leicht unterschiedlich.

Wenn wir eine Möglichkeit hätten, die Füllfarbe unseres obigen Logos anzupassen, könnten wir jede beliebige Farbe übergeben, um alle Variationen darzustellen.

Betrachten Sie auch den Fall von Icons. Sie möchten nicht so etwas tun, oder?

<img src="/icons/heart-blue.svg" />
<img src="/icons/heart-red.svg" />

Externe SVGs als Inline-Elemente laden

Um dies zu beheben, habe ich eine Bibliothek namens svg-loader erstellt. Ganz einfach gesagt, sie ruft die SVG-Dateien per XHR ab und lädt sie als Inline-Elemente, wodurch Sie Eigenschaften wie fill und stroke anpassen können, genau wie bei Inline-SVGs.

Zum Beispiel habe ich ein Logo auf meinem Nebenprojekt, SVGBox. Anstatt für jede Variation eine andere Datei zu erstellen, kann ich eine Datei haben und die Füllfarbe anpassen.

Ich habe data-src verwendet, um die URL der SVG-Datei festzulegen. Das fill-Attribut überschreibt das fill der ursprünglichen SVG-Datei.

Um die Bibliothek zu nutzen, muss ich nur sicherstellen, dass die bereitgestellten Dateien über entsprechende CORS-Header verfügen, damit XHRs erfolgreich sind. Die Bibliothek speichert die Dateien auch lokal im Cache, was nachfolgende Aufrufe erheblich beschleunigt. Selbst beim ersten Laden ist die Leistung mit der Verwendung von <img>-Tags vergleichbar.

Dieses Konzept ist nicht neu. svg-inject macht etwas Ähnliches. Allerdings ist svg-loader einfacher zu verwenden, da wir die Bibliothek nur irgendwo in Ihrem Code einfügen müssen (entweder über ein <script>-Tag oder im JavaScript-Bundle). Es ist kein zusätzlicher Code erforderlich.

Dynamisch hinzugefügte Elemente und Änderungen an Attributen werden ebenfalls automatisch verarbeitet, was sicherstellt, dass sie mit allen Web-Frameworks funktionieren. Hier ist ein Beispiel in React

Aber warum?

Dieser Ansatz mag unkonventionell erscheinen, da er eine JavaScript-Abhängigkeit einführt und es bereits mehrere Möglichkeiten gibt, SVGs zu verwenden, einschließlich Inline und aus externen Quellen. Aber es gibt gute Gründe, SVGs auf diese Weise zu verwenden. Untersuchen wir sie, indem wir die häufigsten Fragen beantworten.

Können wir SVG nicht einfach selbst inline einfügen?

Inlining ist die einfachste Methode, SVGs zu verwenden. Kopieren und fügen Sie einfach den SVG-Code in das HTML ein. Das ist es, was svg-loader letztendlich tut. Warum also die zusätzlichen Schritte, um eine SVG-Datei von woanders zu laden? Es gibt zwei Hauptgründe

  1. Inline-SVGs machen den Code ausführlich: SVGs können von wenigen Zeilen bis zu mehreren hundert Zeilen lang sein. Inline-SVGs können gut funktionieren, wenn Sie nur ein paar Icons benötigen und diese alle winzig sind. Aber es wird zu einem großen Problem, wenn sie groß oder zahlreich sind, denn dann werden sie zu langen Textstrings im Code, der keine „Geschäftslogik“ ist. Der Code wird schwer zu parsen.

    Es ist dasselbe, als würde man eine externe Stylesheet-Datei einem <style>-Tag vorziehen oder Bilder anstelle von Daten-URIs verwenden. Kein Wunder, dass in React-Codebasen der bevorzugte Ansatz darin besteht, SVG als separate Komponente zu verwenden, anstatt es als Teil von JSX zu definieren.
  1. Externe SVGs sind viel bequemer: Kopieren und Einfügen erledigt oft die Arbeit, aber externe SVGs können sehr praktisch sein. Sagen wir, Sie experimentieren damit, welches Icon Sie in Ihrer App verwenden möchten. Wenn Sie Inline-SVGs verwenden, bedeutet das, hin und her zu gehen, um den SVG-Code zu erhalten. Aber mit externen SVGs müssen Sie nur den Dateinamen kennen.

    Schauen Sie sich dieses Beispiel an. Eines der umfangreichsten Icon-Repositories auf GitHub ist Material Design Icons. Mit svg-loader und unpkg können wir sofort mit über 5.000 Icons beginnen.

Ist es nicht ineffizient, für jedes SVG eine HTTP-Anfrage auszulösen, anstatt ein Sprite zu erstellen?

Nicht wirklich. Mit HTTP2 ist die Kosten für eine HTTP-Anfrage weniger relevant geworden. Ja, es gibt immer noch Vorteile beim Bündeln (z. B. bessere Komprimierung), aber für nicht blockierende Ressourcen und XHRs sind die Vorteile in realen Szenarien fast nicht vorhanden.

Hier ist ein Pen, der 50 Icons auf ähnliche Weise wie oben lädt. (Im Inkognito-Modus öffnen, da die Dateien standardmäßig zwischengespeichert werden)

Was ist mit dem <use>-Tag (SVG-Symbole)?

SVG-Symbole trennen die Definition der SVG-Datei von ihrer Verwendung. Anstatt das SVG überall zu definieren, können wir so etwas haben

<svg>
  <use xlink:href="#heart-icon" />
</svg>

Das Problem ist, dass keiner der Browser die Verwendung von Symboldateien unterstützt, die auf einer Drittanbieterdomäne gehostet werden. Daher können wir nicht so etwas tun

<svg>
  <use xlink:href="https://icons.com/symbols.svg#heart-icon" />
</svg>

Safari unterstützt nicht einmal Symboldateien, die auf derselben Domäne gehostet werden.

Können wir nicht ein Build-Tool verwenden, das die SVGs inline einfügt?

Ich konnte keine offensichtliche Möglichkeit finden, SVGs von einer URL abzurufen und sie in gängigen Bundlern wie webpack und Grunt einzufügen, obwohl es sie zum Inline-Einfügen lokal gespeicherter SVG-Dateien gibt. Selbst wenn ein Plugin existiert, das dies tut, ist die Einrichtung von Bundlern nicht gerade einfach. Tatsächlich vermeide ich sie oft, bis das Projekt ein bestimmtes Komplexitätsniveau erreicht hat. Wir müssen auch bedenken, dass die Mehrheit des Internets mit Dingen wie webpack und React fremd ist. Einfache Skripte können eine viel größere Reichweite haben.

Was ist mit dem <object>-Tag?

Das <object>-Tag ist eine native Möglichkeit, externe SVG-Dateien einzubinden, die in allen Browsern funktioniert.

<object data="https://unpkg.com/[email protected]/svg/access-point-network.svg" width="32" height="32"></object>

Der Nachteil ist jedoch, dass wir die Attribute des SVG nicht anpassen können, es sei denn, es wird auf derselben Domäne gehostet (und das <object>-Tag beachtet keine CORS-Header). Selbst wenn die Datei auf derselben Domäne gehostet wird, benötigen wir JavaScript, um das fill wie folgt zu manipulieren

<object data="https://unpkg.com/[email protected]/svg/access-point-network.svg" width="32" height="32" onload="this.contentDocument.querySelector('svg').fill = 'red'"></object>

Kurz gesagt, die Verwendung externer SVG-Dateien auf diese Weise macht die Verwendung von Icons und anderen SVG-Assets extrem bequem. Wie bereits erwähnt, können wir mit unpkg jedes Icon auf GitHub nutzen, ohne zusätzlichen Code zu benötigen. Wir können vermeiden, eine Pipeline in einem Bundler zum Verarbeiten von SVG-Dateien oder eine Komponente für jedes Icon zu erstellen, und die Icons einfach auf einem CDN hosten.

Das Laden von SVG-Dateien auf diese Weise bietet viele Vorteile bei sehr geringen Kosten.