SVG-Icons barrierefrei einbinden
Ziel
Eine Sammlung von Icons, die man überall auf der Seite mit einer Zeile einsetzen kann, die sich in Farbe und Größe der Umgebung anpassen und die Screenreader richtig ansagen: als Bild mit Namen, wenn das Icon etwas bedeutet, und gar nicht, wenn es nur schmückt.
Voraussetzungen
- SVG-Grundlagen: SVG-Code verstehen.
- Styling, vor allem
currentColorund Custom Properties: SVG mit CSS gestalten.
Getestet mit / Stand
Stand 2026-10-18. In Chrome 155 nachgestellt: Darstellung des Sprites, Größe über em, Tab-Reihenfolge. Nicht getestet: Screenreader, Firefox, Safari. Die Regeln zur Auszeichnung stammen aus MDN und aus Scott O’Haras Tests von 2019 (aktualisiert 2021) mit VoiceOver, NVDA, JAWS, Narrator und TalkBack.1 Ob jemand die Muster seitdem mit aktuellen Screenreadern geprüft hat, weiß ich nicht.
Vorgehen
1. Sprite anlegen
Alle Icons stehen einmal als <symbol> in einem versteckten SVG, am besten direkt nach dem öffnenden <body>:23
<svg style="display: none">
<symbol id="icon-suche" viewBox="0 0 24 24">
<circle cx="11" cy="11" r="7" fill="none" stroke="currentColor" stroke-width="2"/>
<path d="M16 16 L21 21" stroke="currentColor" stroke-width="2"/>
</symbol>
<symbol id="icon-schliessen" viewBox="0 0 24 24">
<path d="M6 6 L18 18 M18 6 L6 18" stroke="currentColor" stroke-width="2"/>
</symbol>
</svg>- Jedes
<symbol>bekommt seine eigeneviewBox, dann skaliert es in jede Größe.2 - Farben als
currentColor, dann übernimmt das Icon die Textfarbe. - Keine
<title>-Elemente in die Symbole. Der Name gehört an die Stelle, an der das Icon eingesetzt wird, weil er dort vom Zusammenhang abhängt. (Eigene Einordnung, gestützt auf O’Hara, der<use>aus genau diesem Grund mitaria-hiddenversieht.1)
Statt inline kann das Sprite auch eine eigene Datei sein: <use href="/icons.svg#icon-suche">. Verweise auf eine fremde Origin können Browser blockieren.4
2. Icon einsetzen und Größe festlegen
<svg class="icon"><use href="#icon-suche"/></svg>.icon {
width: 1em;
height: 1em;
vertical-align: -0.125em; /* optisch auf die Grundlinie setzen */
flex-shrink: 0;
}↗ Beispiel in neuem Tab öffnen
Mit 1em wächst das Icon mit der Schriftgröße, auch beim Zoomen. In Chrome 155 war es bei 16px Schrift genau 16 × 16 groß. Ohne Größenangabe wird ein Inline-SVG dagegen 300 × 150 groß oder so breit wie sein Container (siehe SVG-Code verstehen). vertical-align und flex-shrink sind eigene Ergänzungen.
3. Entscheiden: informativ oder dekorativ?
flowchart TD A["Icon auf der Seite"] --> B{"Steht es in einem<br/>Button oder Link?"} B -- ja --> C{"Hat das Bedienelement<br/>sichtbaren Text?"} C -- ja --> D["Icon dekorativ:<br/>aria-hidden='true'"] C -- nein --> E["Icon dekorativ, Name ans Bedienelement:<br/>aria-label oder versteckter Text"] B -- nein --> F{"Trägt es Information,<br/>die sonst fehlt?"} F -- ja --> G["role='img' + Name<br/>(title oder aria-label)"] F -- nein --> D
Das Diagramm fasst O’Haras Empfehlungen zusammen.1
4. Dekoratives Icon
Steht neben dem Icon schon Text, der dasselbe sagt, ist das Icon Schmuck. Es wird versteckt:1
<a href="/suche">
<svg class="icon" aria-hidden="true"><use href="#icon-suche"/></svg>
Suche
</a>Ohne aria-hidden sagen manche Screenreader ein SVG ohne Rolle und Namen als leere „Gruppe“ an.1
5. Informatives Icon (allein stehend)
Ein Icon, das allein eine Information trägt, etwa ein Warnsymbol neben einem Formularfeld, wird als Bild mit Namen ausgezeichnet:51
<svg class="icon" role="img" aria-labelledby="warn-titel">
<title id="warn-titel">Achtung</title>
<use href="#icon-warnung" aria-hidden="true"/>
</svg>role="img"sorgt dafür, dass das SVG als Bild gilt.5<title>als erstes Kind liefert den Namen und erscheint als Tooltip.6 Wer keinen Tooltip will, nimmtaria-label="Achtung"statt<title>.1aria-hiddenam<use>verhindert doppelte oder unerwünschte Ansagen.1- Gibt es sichtbaren Text, der das Icon beschreibt, verweist man mit
aria-labelledbylieber darauf.6
6. Icon-Button ohne sichtbaren Text
Der robusteste Weg laut O’Hara: Das Icon ist dekorativ, der Name hängt am Button.1
<button type="button" aria-label="Schließen">
<svg class="icon" aria-hidden="true"><use href="#icon-schliessen"/></svg>
</button>Oder mit visuell verstecktem Text, der auch dann noch da ist, wenn das CSS fehlt:1
<button type="button">
<svg class="icon" aria-hidden="true"><use href="#icon-schliessen"/></svg>
<span class="visually-hidden">Schließen</span>
</button>↗ Beispiel in neuem Tab öffnen
Ein SVG mit role="img" und eigenem Namen in einem Button oder Link hatte in O’Haras Tests je nach Kombination aus Browser und Screenreader Lücken.1
7. Fokus und Tastatur
Ein Inline-SVG ist nicht fokussierbar. In Chrome 155 sprang Tab nur die Buttons und Links an, nicht die SVGs darin oder daneben. focusable="false" brauchte man nur für den Internet Explorer.1 Wer alte Muster übernimmt, kann es weglassen.
Der Fokusstil gehört an den Button oder Link, nicht an das Icon, siehe Sichtbare Fokusstile.
Warum funktioniert das?
<symbol>wird selbst nicht gezeichnet, erst jede<use>-Kopie. Dadurch steht der Code jedes Icons nur einmal auf der Seite.2- Die Kopie liegt in einem Shadow DOM. Farbe und Größe kommen über Vererbung hinein (
currentColor, Custom Properties) und über das umgebende<svg>.3 - Kinder eines Buttons gelten als rein darstellend. Deshalb trägt der Button den Namen, und das Icon kann versteckt werden.1
Fallstricke
- Nutzlose Titel aus dem Export. „Created with Sketch“ wird sonst als Name vorgelesen. Exportierte Titel immer prüfen.1
- Name doppelt. Ein Icon mit
aria-label="Suche"neben dem sichtbaren Wort „Suche“ wird zweimal vorgelesen.1 <title>an der falschen Stelle. Er soll das erste Kind sein.6xlink:hrefist seit SVG 2 veraltet,hrefreicht.4- Icons in Forced Colors. Mit
currentColorübernehmen Icons die Systemfarbe des Textes. Feste Farben im SVG können dagegen auf dem Systemhintergrund verschwinden. (Eigene Ableitung, nicht getestet.) - Sprite in eigener Datei und Cache. Eine externe Sprite-Datei wird gecacht, ein Inline-Sprite nicht, dafür braucht es keinen zusätzlichen Request. (Eigene Einordnung, nicht gemessen.)
Browsersupport
<symbol>, <use> und <title> sind laut MDN seit Juli 2015 in allen Browsern verfügbar. Ein ganzes externes Dokument ohne #fragment per <use> zu laden, geht laut MDN-Tabelle nur in Chrome ab 137, nicht in Firefox und Safari.4 Deshalb immer mit #id verweisen.
Siehe auch
Quellen
- Contextually Marking up accessible images and SVGs (Scott O’Hara) — getestete Muster für informative, dekorative und interaktive SVGs
- SVG in HTML (MDN) —
role="img",<title>,<desc>,aria-labelledby - title-Element in SVG (MDN) — Position und Tooltip
- symbol-Element (MDN) und use-Element (MDN) — Sprite-Technik, externe Dateien,
href - Styling SVG use Content with CSS (Sara Soueidan) — Aufbau eines Sprites, Styling der Kopien
Eigene Ergänzungen: die CSS-Regeln für die Icon-Größe, die Regel „keine Titel ins Symbol“, die Fallstricke zu Forced Colors und Cache sowie der Tab-Test in Chrome 155. Die Ansagen in Screenreadern habe ich nicht selbst geprüft. Das verwendete Testwerkzeug zeigt die zugänglichen Namen von SVGs nicht verlässlich an.
Footnotes
-
Contextually Marking up accessible images and SVGs (Scott O’Hara), Abschnitte „SVGs that convey information“, „SVGs that are decorative“, „SVGs within links and buttons“ und „Image elements within buttons“, 2019-05-22, aktualisiert 2021-09-03. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15
-
symbol-Element (MDN), Einleitung und Attribute, Stand 2025-07-01. ↩ ↩2 ↩3
-
Styling SVG use Content with CSS (Sara Soueidan), Abschnitte „Quick Overview“ und „SVG
-
use-Element (MDN), Abschnitte „Attributes“, „Usage notes“ und Kompatibilitätstabelle, Stand 2026-08-14. ↩ ↩2 ↩3
-
SVG in HTML (MDN), Abschnitte „Discussion“ und „Best practices“, Stand 2026-07-30. ↩ ↩2
-
title-Element in SVG (MDN), Einleitung, Stand 2025-06-06. ↩ ↩2 ↩3