paint-brush
So erstellen Sie SVG-Sprite mit Symbolenvon@gmakarov
3,193 Lesungen
3,193 Lesungen

So erstellen Sie SVG-Sprite mit Symbolen

von German Makarov10m2023/12/23
Read on Terminal Reader

Zu lang; Lesen

Entwickler fügen SVG häufig direkt in JSX ein. Dies ist bequem zu verwenden, erhöht jedoch die Größe des JS-Bundles. Im Streben nach Optimierung habe ich beschlossen, eine andere Möglichkeit zu finden, SVG-Symbole zu verwenden, ohne das Paket zu überladen. Wir werden über SVG-Sprites sprechen, was sie sind, wie man sie verwendet und welche Tools für die Arbeit mit ihnen verfügbar sind. Beginnend mit der Theorie schreiben wir ein Skript, das Schritt für Schritt ein SVG-Sprite generiert, und besprechen abschließend Plugins für Vite und Webpack.
featured image - So erstellen Sie SVG-Sprite mit Symbolen
German Makarov HackerNoon profile picture

Entwickler fügen SVG häufig direkt in JSX ein. Dies ist bequem zu verwenden, erhöht jedoch die Größe des JS-Bundles. Im Streben nach Optimierung habe ich beschlossen, eine andere Möglichkeit zu finden, SVG-Symbole zu verwenden, ohne das Paket zu überladen. Wir werden über SVG-Sprites sprechen, was sie sind, wie man sie verwendet und welche Tools für die Arbeit mit ihnen verfügbar sind.


Beginnend mit der Theorie werden wir ein Skript schreiben, das Schritt für Schritt ein SVG-Sprite generiert, und abschließend die Plugins für Vite und Webpack besprechen.

Was ist SVG-Sprite?

Ein Bild-Sprite ist eine Sammlung von Bildern, die in einem einzigen Bild zusammengefasst sind. SVG Sprite wiederum ist eine Sammlung von SVG-Inhalten, verpackt in <symbol /> , die in <svg /> platziert werden.


Wir haben zum Beispiel ein einfaches SVG-Stiftsymbol:


Um ein SVG-Sprite zu erhalten, ersetzen wir das Tag <svg /> durch <symbol /> und umschließen es extern mit <svg /> :

Jetzt ist es ein SVG-Sprite und wir haben darin ein Symbol mit id="icon-pen" .


Ok, aber wir sollten herausfinden, wie wir dieses Symbol auf unserer HTML-Seite platzieren. Wir verwenden das Tag <use /> mit dem Attribut href , geben die ID des Symbols an und duplizieren dieses Element innerhalb von SVG.


Schauen wir uns ein Beispiel an, wie <use /> funktioniert:

In diesem Beispiel gibt es zwei Kreise. Das erste hat einen blauen Umriss und das zweite ist ein Duplikat des ersten, jedoch mit einer roten Füllung.


Kommen wir zurück zu unserem SVG-Sprite. Zusammen mit der Verwendung von <use /> erhalten wir Folgendes:

Hier haben wir eine Schaltfläche mit unserem Stiftsymbol.


Bisher haben wir in <button /> ein Symbol ohne Code verwendet. Wenn wir mehr als eine Schaltfläche auf der Seite haben, wirkt sich dies nicht mehr als einmal auf die Größe unseres HTML-Layouts aus, da alle Symbole aus unserem SVG-Sprite stammen und wiederverwendbar sind.

Erstellen einer SVG-Sprite-Datei

Verschieben wir unser SVG-Sprite in eine separate Datei, damit wir die Datei index.html nicht überladen müssen. Erstellen Sie zunächst eine sprite.svg Datei und fügen Sie darin ein SVG-Sprite ein. Der nächste Schritt besteht darin, mithilfe des href Attributs in <use/> Zugriff auf das Symbol bereitzustellen:

Automatisierung der SVG-Sprite-Erstellung

Um bei der Verwendung von Symbolen viel Zeit zu sparen, richten wir eine Automatisierung für diesen Prozess ein. Um einen einfachen Zugriff auf die Symbole zu erhalten und sie nach unseren Wünschen verwalten zu können, müssen sie getrennt werden, jedes in einer eigenen Datei.


Zuerst sollten wir alle Symbole im selben Ordner ablegen, zum Beispiel:

Schreiben wir nun ein Skript, das diese Dateien erfasst und zu einem einzigen SVG-Sprite zusammenfügt.


  1. Erstellen Sie die Datei generateSvgSprite.ts im Stammverzeichnis Ihres Projekts.


  2. Glob- Bibliothek installieren:

     npm i -D glob


  3. Rufen Sie mit globSync ein Array vollständiger Pfade für jedes Symbol ab:

  4. Jetzt werden wir jeden Dateipfad iterieren und den Dateiinhalt mithilfe der integrierten Bibliothek fs von Node abrufen:

    Großartig, wir haben den SVG-Code jedes Symbols und können sie jetzt kombinieren, aber wir sollten das svg Tag in jedem Symbol durch das symbol Tag ersetzen und nutzlose SVG-Attribute entfernen.


  5. Wir sollten unseren SVG-Code mit einer HTML-Parser-Bibliothek analysieren, um seine DOM-Darstellung zu erhalten. Ich werde node-html-parser verwenden:

    Wir haben den SVG-Code analysiert und das SVG-Element erhalten, als wäre es ein echtes HTML-Element.


  6. Erstellen Sie mit demselben Parser ein leeres symbol , um untergeordnete Elemente von svgElement in das symbol zu verschieben:

  7. Nachdem wir untergeordnete Elemente aus svgElement extrahiert haben, sollten wir auch die Attribute id und viewBox daraus erhalten. Als id legen wir den Namen der Symboldatei fest.

  8. Jetzt haben wir ein symbol , das in einem SVG-Sprite platziert werden kann. Definieren Sie also einfach die Variable symbols , bevor Sie die Dateien iterieren, wandeln Sie das symbolElement in einen String um und schieben Sie es in symbols :

  9. Der letzte Schritt besteht darin, das SVG-Sprite selbst zu erstellen. Es stellt eine Zeichenfolge mit svg in „root“ und Symbolen als untergeordneten Elementen dar:

     const svgSprite = `<svg>${symbols.join('')}</svg>`;


    Und wenn Sie nicht erwägen, Plugins zu verwenden, auf die ich weiter unten eingehen werde, müssen Sie die Datei mit dem erstellten Sprite in einem statischen Ordner ablegen. Die meisten Bundler verwenden einen public Ordner:

     fs.writeFileSync('public/sprite.svg', svgSprite);


Und das ist es; Das Skript ist einsatzbereit:

 // generateSvgSprite.ts import { globSync } from 'glob'; import fs from 'fs'; import { HTMLElement, parse } from 'node-html-parser'; import path from 'path'; const svgFiles = globSync('src/icons/*.svg'); const symbols: string[] = []; svgFiles.forEach(file => { const code = fs.readFileSync(file, 'utf-8'); const svgElement = parse(code).querySelector('svg') as HTMLElement; const symbolElement = parse('<symbol/>').querySelector('symbol') as HTMLElement; const fileName = path.basename(file, '.svg'); svgElement.childNodes.forEach(child => symbolElement.appendChild(child)); symbolElement.setAttribute('id', fileName); if (svgElement.attributes.viewBox) { symbolElement.setAttribute('viewBox', svgElement.attributes.viewBox); } symbols.push(symbolElement.toString()); }); const svgSprite = `<svg>${symbols.join('')}</svg>`; fs.writeFileSync('public/sprite.svg', svgSprite);


Sie können dieses Skript im Stammverzeichnis Ihres Projekts ablegen und es mit tsx ausführen:

 npx tsx generateSvgSprite.ts


Eigentlich verwende ich hier tsx , weil ich früher überall Code in TypeScript geschrieben habe und diese Bibliothek es Ihnen ermöglicht, in TypeScript geschriebene Knotenskripte auszuführen. Wenn Sie reines JavaScript verwenden möchten, können Sie es ausführen mit:

 node generateSvgSprite.js


Fassen wir also zusammen, was das Skript tut:

  • Es durchsucht den Ordner src/icons nach .svg Dateien.


  • Es extrahiert den Inhalt jedes Symbols und erstellt daraus ein Symbolelement.


  • Es fasst alle Symbole in einem einzigen <svg />.


  • Es erstellt die Datei sprite.svg im public Ordner.

So ändern Sie die Symbolfarben

Lassen Sie uns einen häufigen und wichtigen Fall behandeln: Farben! Wir haben ein Skript erstellt, in dem das Symbol in ein Sprite eingefügt wird. Dieses Symbol kann jedoch im gesamten Projekt unterschiedliche Farben haben.


Wir sollten bedenken, dass nicht nur <svg/> Elemente Füll- oder Strichattribute haben können, sondern auch path , circle , line und andere. Es gibt eine sehr nützliche CSS-Funktion, die uns helfen wird – currentcolor .


Dieses Schlüsselwort stellt den Wert der Farbeigenschaft eines Elements dar. Wenn wir beispielsweise die color: red für ein Element verwenden, das den background: currentcolor hat, hat dieses Element einen roten Hintergrund.


Grundsätzlich müssen wir jeden Strich- oder Füllattributwert in die currentcolor ändern. Ich hoffe, Sie sehen nicht, dass es manuell erledigt wird, heh. Und selbst das Schreiben von Code, der SVG-Strings ersetzt oder analysiert, ist im Vergleich zu einem sehr nützlichen Tool, SVGO, nicht sehr effizient.


Dabei handelt es sich um einen SVG-Optimierer, der nicht nur bei den Farben, sondern auch beim Entfernen redundanter Informationen aus SVG helfen kann.


Lassen Sie uns SVGo installieren:

 npm i -D svgo


svgo verfügt über integrierte Plugins, und eines davon ist convertColors mit der Eigenschaft currentColor: true . Wenn wir diese SVG-Ausgabe verwenden, werden die Farben durch currentcolor ersetzt. Hier ist die Verwendung von svgo zusammen mit convertColors :

 import { optimize } from 'svgo'; const output = optimize( '<svg viewBox="0 0 24 24"><path fill="#000" d="m15 5 4 4" /></svg>', { plugins: [ { name: 'convertColors', params: { currentColor: true, }, } ], } ) console.log(output);


Und die Ausgabe wird sein:

 <svg viewBox="0 0 24 24"><path fill="currentColor" d="m15 5 4 4"/></svg>


Fügen wir svgo zu unserem magischen Skript hinzu, das wir im vorherigen Teil geschrieben haben:

 // generateSvgSprite.ts import { globSync } from 'glob'; import fs from 'fs'; import { HTMLElement, parse } from 'node-html-parser'; import path from 'path'; import { Config as SVGOConfig, optimize } from 'svgo'; // import `optimize` function const svgoConfig: SVGOConfig = { plugins: [ { name: 'convertColors', params: { currentColor: true, }, } ], }; const svgFiles = globSync('src/icons/*.svg'); const symbols: string[] = []; svgFiles.forEach(file => { const code = fs.readFileSync(file, 'utf-8'); const result = optimize(code, svgoConfig).data; // here goes `svgo` magic with optimization const svgElement = parse(result).querySelector('svg') as HTMLElement; const symbolElement = parse('<symbol/>').querySelector('symbol') as HTMLElement; const fileName = path.basename(file, '.svg'); svgElement.childNodes.forEach(child => symbolElement.appendChild(child)); symbolElement.setAttribute('id', fileName); if (svgElement.attributes.viewBox) { symbolElement.setAttribute('viewBox', svgElement.attributes.viewBox); } symbols.push(symbolElement.toString()); }); const svgSprite = `<svg xmlns="http://www.w3.org/2000/svg">${symbols.join('')}</svg>`; fs.writeFileSync('public/sprite.svg', svgSprite);


Und führen Sie das Skript aus:

 npx tsx generateSvgSprite.ts


Infolgedessen enthält das SVG-Sprite Symbole mit currentColor . Und diese Symbole können überall im Projekt in jeder gewünschten Farbe verwendet werden.

Plugins

Wir haben ein Skript und können es jederzeit ausführen, aber es ist etwas unpraktisch, es manuell zu verwenden. Daher empfehle ich ein paar Plugins, die unsere .svg Dateien ansehen und unterwegs SVG-Sprites generieren können:


  1. vite-plugin-svg-spritemap (für Vite- Benutzer)

    Dies ist mein Plugin, das im Wesentlichen dieses Skript enthält, das wir gerade in diesem Artikel erstellt haben. Für das Plugin ist die currentColor Ersetzung standardmäßig aktiviert, sodass Sie das Plugin ganz einfach einrichten können.

     // vite.config.ts import svgSpritemap from 'vite-plugin-svg-spritemap'; export default defineConfig({ plugins: [ svgSpritemap({ pattern: 'src/icons/*.svg', filename: 'sprite.svg', }), ], });


  2. svg-spritemap-webpack-plugin (für Webpack- Benutzer)

    Ich habe dieses Webpack-Plugin verwendet, bis ich zu Vite gewechselt bin. Aber dieses Plugin ist immer noch eine gute Lösung, wenn Sie Webpack verwenden. Sie sollten die Farbkonvertierung manuell aktivieren, dann sieht es so aus:

     // webpack.config.js const SVGSpritemapPlugin = require('svg-spritemap-webpack-plugin'); module.exports = { plugins: [ new SVGSpritemapPlugin('src/icons/*.svg', { output: { svgo: { plugins: [ { name: 'convertColors', params: { currentColor: true, }, }, ], }, filename: 'sprite.svg', }, }), ], }

Verwendung im Layout

Ich werde ein Beispiel in React bereitstellen, aber Sie können es implementieren, wo Sie möchten, da es hauptsächlich um HTML geht. Da wir also sprite.svg in unserem Build-Ordner haben, können wir auf die Sprite-Datei zugreifen und die grundlegende Icon Komponente erstellen:

 const Icon: FC<{ name: string }> = ({ name }) => ( <svg> <use href={`/sprite.svg#${name}`} /> </svg> ); const App = () => { return <Icon name="pen" />; };

Das Endergebnis

Um also viel manuelle Arbeit mit Symbolen zu vermeiden, fassen wir Folgendes zusammen:

  • Sie können Symbole ganz einfach mit gewünschten Namen im Projekt speichern und organisiert aufbewahren


  • Wir verfügen über ein Skript, das alle Symbole in einem einzigen Sprite in einer separaten Datei zusammenfasst, wodurch die Bundle-Größe reduziert wird und wir diese Symbole überall im Projekt verwenden können


  • Wir verfügen über ein nützliches Tool, das uns hilft, Symbole von unnötigen Attributen zu befreien und die Farben am Verwendungsort zu ändern


  • Wir verfügen über ein Plugin, das unsere Symboldateien ansehen und im Rahmen des Build-Prozesses unterwegs Sprites generieren kann


  • haben eine Icon-Komponente, die das Sahnehäubchen darstellt

Abschluss

Bei der Effizienz in der Entwicklung geht es nicht nur um Zeitersparnis; Es geht darum, unser kreatives Potenzial freizusetzen. Die Automatisierung wichtiger Aufgaben wie der Verwaltung von Symbolen ist nicht nur eine Abkürzung; Es ist ein Tor zu einem reibungsloseren und wirkungsvolleren Codierungserlebnis. Und Sie sparen Zeit für solche Routineaufgaben, können sich auf komplexere Aufgaben konzentrieren und sich als Entwickler schneller weiterentwickeln.