Themen

SVG-Sprites

Ein Sprite ist eine einzige SVG-Datei mit einem Symbol pro Icon. Seiten referenzieren die Symbole mit <use>, der Browser lädt die Datei einmal herunter und speichert sie im Cache, und es läuft überhaupt kein JavaScript.

Das Sprite beziehen

Das Paket liefert unter glyphfox/sprite.svg ein Sprite mit allen Icons. Jedes Icon ist ein <symbol> mit der ID gf- plus Icon-Name, einer eigenen viewBox und den Stricheinstellungen des Sets.

terminal
npm install glyphfox
cp node_modules/glyphfox/dist/sprite.svg public/icons/sprite.svg
sprite.svg
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="gf-home" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">...</symbol>
<symbol id="gf-search" viewBox="0 0 24 24" ...>...</symbol>
...
</svg>

Alternativ können Sie die Datei von Ihrem Bundler kopieren und mit einem Fingerprint versehen lassen. In Vite liefert das Suffix ?url die endgültige URL des Assets:

icons.js
import spriteUrl from 'glyphfox/sprite.svg?url';

export const icon = (name) =>
  `<svg class="icon" width="24" height="24" aria-hidden="true"><use href="${spriteUrl}#gf-${name}"></use></svg>`;

Das vollständige Sprite enthält alle 419 Icons in 117,9 KB, mit gzip sind es 15,7 KB. Ein Sprite mit den 30 Icons, die eine typische App-Shell verwendet, ist 7,5 KB groß, mit gzip 1,3 KB; die CLI erstellt es für Sie, wie unten gezeigt.

Ein Symbol referenzieren

Schreiben Sie ein äußeres svg in der gewünschten Größe und ein use-Element, das auf das Symbol verweist. Das Symbol bringt seine eigene viewBox mit, daher braucht das äußere Element nur Breite und Höhe.

index.html
<button type="button" class="btn">
  <svg class="icon" width="20" height="20" aria-hidden="true">
    <use href="/icons/sprite.svg#gf-download"></use>
  </svg>
  Download
</button>
app.css
.icon {
  width: 1.25em;
  height: 1.25em;
  flex-shrink: 0;
  vertical-align: -0.2em;
}
.btn:hover .icon {
  color: #ff7a1a;
}

Die Symbole zeichnen mit stroke="currentColor", und color wird in den Inhalt von use vererbt. So folgt das Icon der Textfarbe seines Elternelements und jedem color, das Sie am äußeren svg setzen. Breite und Höhe in CSS überschreiben die Attribute, sodass die Größe der Schriftgröße folgen kann.

Nur vom selben Ursprung

Browser folgen einer use-Referenz nur zu einer Datei mit demselben Ursprung wie die Seite. Ein Sprite auf einem CDN wie jsDelivr oder auf einer anderen Subdomain Ihrer Website wird nicht dargestellt, und auch CORS-Header ändern daran nichts. Liefern Sie das Sprite von Ihrem eigenen Ursprung aus, oder rufen Sie es einmalig ab und fügen Sie es in die Seite ein:

inline-sprite.js
// jsDelivr sends CORS headers, so fetch works where <use> across origins does not.
const res = await fetch('https://cdn.jsdelivr.net/npm/glyphfox@1/dist/sprite.svg');
const holder = document.createElement('div');
holder.setAttribute('aria-hidden', 'true');
holder.style.cssText = 'position:absolute;width:0;height:0;overflow:hidden';
holder.innerHTML = await res.text();
document.body.prepend(holder);

// now <use href="#gf-home"></use> works anywhere on the page

Das Sprite inline in die Seite einbetten

Ein Inline-Sprite besteht aus denselben Symbolen, die einmal direkt im HTML stehen, meist gleich nach <body>. Referenzen verwenden dann nur das Fragment #gf-home, es gibt keine zusätzliche Anfrage, und die Icons erscheinen schon beim ersten Paint. Der Preis dafür: Jede Seite enthält die Symbole erneut. Betten Sie daher lieber eine kleine Teilmenge ein als das vollständige Set.

layout.html
<body>
  <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true"
       style="position:absolute;width:0;height:0;overflow:hidden">
    <symbol id="gf-home" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">...</symbol>
    <symbol id="gf-search" viewBox="0 0 24 24" ...>...</symbol>
  </svg>

  <a href="/"><svg class="icon" aria-hidden="true"><use href="#gf-home"></use></svg> Home</a>
</body>

Blenden Sie das Sprite über die Größe null und absolute Positionierung aus, nicht mit display:none. Manche Browser rendern keine Masken mehr, die sich in einem ausgeblendeten SVG befinden, und der Solid-Stil nutzt Masken, um seine inneren Linien auszusparen.

Eine Teilmenge mit der CLI erstellen

glyphfox build schreibt ein Sprite mit genau den Icons, die Sie auflisten, gerendert mit den Props, die Sie übergeben. Die Namen können von der Kommandozeile oder aus einer Datei mit einem Namen pro Zeile stammen; in der Datei sind Leerzeichen, Kommas und Kommentare mit # erlaubt.

terminal
npx glyphfox build home search settings bell user --type sprite --out public/icons
npx glyphfox build --from icons.txt --type sprite --weight 1.5 --out public/icons
npx glyphfox build --from icons.txt --type sprite --variant solid --out public/icons/solid
icons.txt
# app shell
home, search, settings, bell, user
menu x chevron-down

# badges and fusions work too
file+check
cloud&lock:overlap

Einfache Namen behalten ihre ID: Aus home wird gf-home. Angaben mit einem Badge oder einer Fusion erhalten eine ID, in der die Sonderzeichen ersetzt sind: Aus file+check wird gf-file_check und aus cloud&lock:overlap wird gf-cloud__lock-overlap. Öffnen Sie die generierte Datei einmal, um die benötigten IDs zu kopieren.

Erstellen Sie das Sprite in der Größe, in der Sie es anzeigen, erhalten Sie zusätzlich die optische Kompensation der Komponenten: --size 16 schreibt den etwas kräftigeren Strich, den glyphfox für Icons mit 16 Pixeln verwendet. So wirkt ein Sprite für dichte Tabellen genauso kräftig wie der Rest der Oberfläche.

Derselbe Befehl mit --type css schreibt stattdessen ein Stylesheet mit Maskenklassen (<span class="gf gf-home">), für Websites, die Icon-Klassen ohne Tailwind CSS möchten. Der Leitfaden zu Tailwind CSS erklärt, wie sich Masken-Icons verhalten.

Build-Optionen

Ein Sprite ist statisch, deshalb werden die gemeinsamen Props zu Build-Flags. Das sind die Flags, die für ein Sprite relevant sind; jedes Flag hat dieselbe Bedeutung wie die gleichnamige Prop in der Props-Tabelle.

FlagWirkung auf die Symbole
--type spriteschreibt sprite.svg (der Standardtyp); css und package sind die anderen Typen
--out DIRAusgabeverzeichnis, standardmäßig das aktuelle Verzeichnis
--from FILEliest die Namen aus einer Datei
--weight NStrichstärke von 1 bis 3, in jedes Symbol geschrieben
--size Ndie angezeigte Größe in Pixeln, für die optische Strichkompensation unter 24
--corners sharpspitze Linienverbindungen und eckige Linienenden
--variant duotone, --variant solidder Stil aller Symbole
--color C, --secondary-color Cfeste Farben statt currentColor
--secondary-opacity NDeckkraft der Duotone-Ebene oder der Solid-Füllung
--rotate DEG, --flip-x, --flip-yschreibt eine Drehung oder Spiegelung fest in die Symbole

Was CSS ändern kann und was nicht

Was use zeichnet, ist eine Kopie des Symbols. CSS am äußeren svg oder am use-Element erreicht diese Kopie nur über Vererbung, deshalb funktioniert color. Bei Eigenschaften, die das Symbol selbst setzt, funktioniert das nicht: Jedes Symbol trägt stroke-width, stroke-linecap und stroke-linejoin als Attribute, und diese haben Vorrang vor jedem Wert, der von außen geerbt wird. stroke-width auf .icon zu setzen, bewirkt nichts.

Legen Sie Strichstärke, Ecken und Stil beim Erstellen des Sprites fest, und erstellen Sie zwei Sprites, wenn Sie zwei Strichstärken brauchen. Wenn Sie Strichstärke, eine zweite Farbe oder Bewegung pro Instanz steuern möchten, rendern Sie stattdessen Inline-SVG mit einer Komponente oder toSvg.

Animationen des ganzen Icons funktionieren trotzdem, weil sie auf das äußere Element wirken: .icon.spin { animation: spin 1s linear infinite } dreht ein Sprite-Icon wie jedes andere Element.

Barrierefreiheit

Ein Sprite-Icon ist ein äußeres svg, das Sie selbst schreiben, daher legen Sie auch seine Semantik selbst fest. Verbergen Sie dekorative Icons mit aria-hidden="true". Bei einem Icon, das für sich allein eine Bedeutung trägt, machen Sie das äußere Element zu einem Bild mit Namen:

status.html
<svg class="icon" role="img" aria-label="Payment failed">
  <use href="/icons/sprite.svg#gf-circle-alert"></use>
</svg>

Buttons, die nur aus einem Icon bestehen, brauchen die Beschriftung am Button selbst, wie im Leitfaden zur Barrierefreiheit beschrieben.

Caching

Ein externes Sprite ist eine einzige Anfrage, die sich alle Seiten teilen. Liefern Sie es mit einer langen Cache-Dauer und einem Fingerprint im Dateinamen aus, etwa sprite.3f9a1c.svg, damit ein neuer Build die URL ändert, statt darauf zu warten, dass Caches ablaufen. Bundler erledigen das für Sie, wenn Sie die Datei importieren. Jede einzelne Sprite-URL wird pro Seite nur einmal heruntergeladen, egal wie viele Icons darauf verweisen.

Stolperfallen

Ein Sprite von einem anderen Ursprung
Ein externes use, das auf ein CDN oder eine andere Subdomain zeigt, rendert nur eine leere Fläche; der Browser meldet die blockierte Anfrage lediglich in der Konsole. Hosten Sie die Datei auf dem Ursprung der Seite, oder betten Sie sie inline ein.
Duotone-Ebenen im vollständigen Sprite
Die 42 Icons mit einer handgezeichneten Duotone-Ebene behalten diese in glyphfox/sprite.svg, als durchscheinende Füllung in der aktuellen Farbe. Wenn Sie reine Konturen möchten, erstellen Sie eine Teilmenge: Der Standardstil outline lässt die Ebene weg, und --variant duotone behält sie bei.
Masken in ausgeblendeten oder externen Sprites
Symbole im Solid-Stil verwenden eine mask, um ihre inneren Linien auszusparen. Masken werden unter Umständen nicht gerendert, wenn das Sprite mit display:none ausgeblendet ist, und die Unterstützung für Masken in einer externen Sprite-Datei unterscheidet sich je nach Browser. Testen Sie den Solid-Stil in Ihren Zielbrowsern, oder betten Sie dieses Sprite inline ein.
Lebendige Zustände in einem Sprite
Presets wie spin oder draw sind auf eine Klasse am Wurzelelement svg begrenzt, die in einem Symbol nicht erhalten bleibt. Daher hat --animate in einem Sprite keine sichtbare Wirkung. Animieren Sie das äußere Element mit eigenem CSS, oder verwenden Sie Inline-SVG.
Kollidierende IDs
Ein Inline-Sprite bringt IDs wie gf-home in die Seite. Zwei Inline-Sprites mit demselben Icon oder ein eigenes Element mit derselben ID machen Referenzen mehrdeutig. Betten Sie pro Seite nur ein Sprite inline ein.

Häufige Fragen

Wann ist ein Sprite besser als Komponenten?

Auf serverseitig gerenderten oder statischen Websites ohne JavaScript-Framework und auf Seiten, die viele Icons wiederholen: Die Symbole werden einmal heruntergeladen, und jede Verwendung kostet nur wenige Byte Markup. Komponenten sind im Vorteil, wenn sich Icons mit dem Zustand ändern, morphen, animiert werden oder eine zweite Farbe brauchen, denn ein Sprite ist zur Build-Zeit festgelegt.

Kann ich das Sprite direkt auf jsDelivr referenzieren?

Nicht mit use, denn Browser blockieren externe Referenzen auf andere Ursprünge. Rufen Sie die Datei ab und fügen Sie sie wie oben gezeigt in die Seite ein, oder kopieren Sie sie auf Ihren eigenen Server.

Icons in diesem Leitfaden