Screenshot Icons Übersicht IcoMoon.io App

SVG Sprites vs. Icon-Fonts

Aktuell stellt sich mir häufiger die Frage „SVG-Icons oder Icon-Fonts” zu verwenden. Wer für ein Multi-Display-Web entwickelt, kommt nicht drumherum Bilder und Icons hochauflösend bereit zu stellen. Mit dem iPhone4 und dem sog. „Retina Display” hat man schnell gemerkt, dass normal auflösende Bildinhalte auf dem Display pixelig aussehen. Bisher war die einfache Lösung, die Icon-Sprites (PNG) in doppelter Auflösung anzulegen bzw. generieren zu lassen. Das Problem, dass die Icons dann trotzdem nur in einer „Ansichtsgröße” vorliegen, bestand weiterhin.

Iconfonts, also Schriften á la Dingbats, die anstatt Buchstaben und Ziffern Symbole haben, wurden bisher als ein adäquates Mittel für skalierbare Icons eingesetzt. Dass das auch immer mit Problemen behaftet ist, werden viele Webentwickler schon festgestellt haben.

Probleme Icon-Fonts:

  • Fallback (-schrift)
  • Zugänglichkeit
  • Positionierung (line-height)
  • Rendering
  • Einfarbigkeit
  • Ladezeit (werden später geladen)

Für einige der Probleme gibt es mittlerweile gute Anleitungen, um dies zu verhindern – oft denkt man sich aber, „das sind doch alles nur Hacks und nichts solides, das muss doch irgendwie einfacher gehen.”

SVG-Sprites

Wir wissen, SVG ist ein Vektor-Grafikformat, das dafür genau das Richtige ist. Eine Option ist natürlich das Icon-Sprite aus SVG-Grafiken zu erstellen und wie gewohnt über background-position anzuzeigen. Allerdings haben wir auch dann kaum Einfluss auf die Größendarstellung der Icons.

SVG-Inhalte können in modernen Browsern auch direkt in HTML integriert werden. Das hat dann den Vorteil, dass wir auf die SVG-Elemente mit CSS und JS zugreifen können und so Veränderung vornehmen könnten.

SVG bietet zudem die Möglichkeit auf ein einzelnes Element zu referenzieren, also einen Inhalt woanders darzustellen. Über <use xlink:href="" /> können die Inhalte an anderer Stelle ausgegeben werden. Das kann ein SVG-Block innerhalb der Seite sein, das kann aber auch eine externe SVG-Datei sein. Extern eingebundene Ressourcen haben natürlich den Vorteil des Browser-Caching.

internes SVG-Element referenzieren

<use xlink:href="#menu"></use>

externe SVG-Datei referenzieren

<use xlink:href="img/all.svg#menu"></use>

Chris Coyier hat dazu in letzter Zeit einiges auf css-tricks.com geschrieben:

Übersicht SVG-Icons / Icon-Fonts
Übersicht SVG-Icons / Icon-Fonts – Foto von Marcel Böttcher (@73inches)

Vorteile SVG-Icons:

  • Semantik
  • barrierefrei(er)
  • Mehrfarbig + Effekte
  • bessere Positionierung
  • mit CSS + SVG-CSS stylebar (win-win ;))

SVG Store – ein Grunt-Task für SVG-Sprites

Mit dem Grunt-Task „SVG-Store” hat man die Möglichkeit aus den einzelnen SVG-Dateien ein „SVG-Sprite” zu erstellen. In Wirklichkeit ist es ja kein richtiges Sprite wie wir es kennen, sondern eher ein Dokument, in dem hintereinander alle einzelnen SVG-Blöcke gepackt werden, die dann über eine ID referenziert werden können.

Installation grunt-svgstore:

npm install grunt-svgstore --save-dev

Grunt-Task:

svgstore: { 
  options: {}, 
  dist: { 
    files: { 
      'dist/img/all.svg': ['source/img/icons/*.svg'] 
    } 
  } 
}

Im Anschluss kann man noch zusätzlich SVGmin zur Komprimierung drüber laufen lassen.

Alternativ sollte man sich auch ’Iconizr’ bzw. ’grunt-iconizr’ anschauen!

Einbindung in HTML und Styling mit CSS

Einbindung in HTML:

<svg class="icon-menu" role="img" title="Menu Icon" 
     viewbox="0 0 75 75" width="25" height="25"> 
  <use xlink:href="img/all.svg#menu"></use> 
</svg>

Hier wird auf ein eine SVG-Datei mit allen Icons referenziert und das Element mit der ID „menu” angezeigt. Das SVG-Snippet kann man nun über (SVG-)CSS-Eigenschaft fill einfärben.

.icon-menu { 
  fill: green; 
}
/* other context */
header .icon-menu {
    fill: pink;
}

In der Original SVG-Icon Datei kann man ebenfalls Klassen zum Styling vergeben.

… 
  <path class="original-svg-pin" … /> 
…

Auch das kann man dann über die fill Eigenschaft anders einfärben.

.original-svg-pin { 
  fill: blue; 
}

Andere SVG-Style-Eigenschaften wie stroke oder stroke-width sind natürlich auch möglich.

Chris Coyier beschreibt in seinem Blogpost „Cascading SVG fill color” die Möglichkeit mit currentColor, dazu hab ich aber folgendes Problem auf Stackoverflow gefunden: Geht nicht im iOS Safari, das Beispiel geht aber bei mir, hm…

Probleme & Tipps

  • wird nicht von allen Browsern unterstützt (kein IE9-IE11 Support) – das ist aktuell das größte Problem
  • Es ist nur eine fill-Farbe für alle Pfade (path, polygon, …) in dem verknüpften SVG-Snippet zuweisbar – über Selektoren möglich (werden allerdings nicht in den Developer-Tools angezeigt), sonst nur direkt über Klassen in der SVG-Datei
  • der Attribut-Selektor [viewBox] {} geht nicht in WebKit-based Browsern (hat nix mit den SVG-Icons zu tun, ist aber trotzdem doof)
  • SVGs werden onLoad auf die volle Bildschirmbreite gezogen, deshalb width="" + height="" wie bei Pixelgrafiken setzen, kann anschließend mit CSS überschrieben werden
  • aufpassen bei backface-visibility & z-index –> SVG-Icons auf der gleichen Ebene werden nicht neu hochauflösend gerendert (und wirken also pixelig)

SVG4everybody

Die JS-Library SVG4everybody löst die fehlende Browser-Kompatibilität, so funktioniert die Technik nun auch im IE9-11. Mit ’SVG4everybody’ werden die SVG-Fragmente über Ajax direkt in die Seite geladen, das hat zudem den Vorteil, dass man die SVG-Inhalte besser stylen kann.

CSS styling with ’fill’

/* inherit the fill color from parent */ 
svg { 
  polygon, 
  path, 
  rect { 
    fill: inherit; 
  } 
}

Alle Icon-Pfade sollen die ’fill’-Farbe vom Elternelement erben.

/* fill all elements contains the class „icon” with ’red’ */ 
[class*="icon"] { 
  fill: red; 
}

Alle Icons werden mit ’icon’ benannt und bekommen alle die gleiche Einfärbung.

/* set individual color – cascade after [class*="icon"] */ 
.icon-menu { 
  fill: green; 
}

Individuelle Icons kann man noch individuell färben.

  • Vergibt man wie im obigen Beispiel mehrere CSS-Klassen für die einzelnen Elemente der Originaldatei, dann ist es möglich SVG-Einzelteile einzeln zu stylen/zu färben.
  • Problem, das mir aufgefallen ist: mehrere Requests – für jedes Bild wird je ein Request benötigt bzw. im Network-Panel angezeigt

Blurry Rendering in Firefox (Win)

Fabian Beiner hatte ein Problem mit dem Rendering von SVG im Firefox (Windows) festgestellt. Unter bestimmten Bedingungen wirken harte Kanten unscharf. Dieser Hinweis behebt das Problem:


Try styling your rects with shape-rendering: crisp-edges to remove antialiasing and force the lines to really be 1px. Also try offsetting the rects 1px (<rect x=“1″). The border can be cropped by the border of the svg.

SVG shape-rendering


SVG-Fallback für IE8 & Android 2.3

IE8 sowie Android-Browser der Version 2.x unterstützen kein SVG, hier müsste man, wenn man die Browser unterstützt, einen Fallback mit PNG-Grafiken einsetzen.

  • SVG2PNG – Grunt-Task zum einfachen Umwandeln von SVG zu PNG
  • SVG4everybody stellt einen Fallback für IE8 bereit.
  • Problem: die PNG-Datei hat die originale SVG-fill-Farbe – wenn mit CSS die ’fill’-Color verändert wurde, wird das natürlich nicht erkannt und das icon wird nicht eingefärbt
  • auch hier mehrere Requests (PNG-Sprite wäre besser, Aufwand/Nutzen ist aber vertretbar)

Icomoon

Der Online-Service Icomoon bietet seit einiger Zeit ebenfalls die Möglichkeit die gewählten Icons als SVG(-Sprite) herunterzuladen. Hier hat man nun alle Möglichkeiten, entweder Icon-Font generieren oder SVG-Icons herunterladen – oder beides. Toller Service!

Vorteil Icon-Fonts

„Aber irgendwas gutes müssen Iconfonts doch haben, oder?!” Ja:

  • Browser-Support
  • Hinting
  • Subpixel Rendering

Wer noch nicht überzeugt ist, dass SVG-Icons die bessere Wahl ist, sollte sich den Blogpost Ten reasons we switched from an icon font to SVG von Ian Feather durchlesen.

Das Video von der Beyond Tellerrand Konferenz zum Thema „SVG Is For Everybody” von Chris Coyier ist jetzt online – solltet ihr euch unbedingt (nochmal) anschauen.

Codepen Beispiel:

See the Pen SVG use example by Sven Wolfermann (@maddesigns) on CodePen.

Wer jetzt noch tiefer in die Thematik einsteigen will, dem sei der Artikel Structuring, Grouping, and Referencing in SVG – The <g>, <use>, <defs> and <symbol> Elements von Sara Soueidan ans Herz gelegt.

Habt ihr noch weitere Tipps oder Probleme festgestellt?

Flattr this!

11 Gedanken zu „SVG Sprites vs. Icon-Fonts“

  1. Weiterer Vorteil gegenüber Iconfonts ist ja der volle Zugriff auf das SVG :)

    Dennoch bin ich kritisch wenn da noch ein IE8 auf die Entwickler lauert. PNG Fallbacks gehen einfach von der Hand, mit Grunt wenn die SVGs sauber vorbereitet wurden. Das Problem ist vielmehr, auf modernen Browsern genießen wir alle Vorteile wie mal eben skalieren, einfärben, umbauen whatever, das macht man einfach mit CSS, nur hat der Grunt Task wenig davon der wandelt das Rastert das vorhandene SVG ja recht stumpf.
    Oder ist das mittlerweile auch gelöst?

    War für mich bislang auch immer der Grund warum ich lieber mit einer Iconfont arbeite, auch wenn die Vorbereitung (alles gleiche Größe, Ebenenstruktur kontrollieren, überflüssige Ebenen Kombinieren etc) Zeitaufwenig ist

  2. Vielen Dank für den Artikel – ist ein wichtiges Thema heute!

    Ein Hinweis der Klarheit halber, das Problem der mangelnden IE9-11-Unterstützung hat man nicht, wenn man die SVG-Definitionen im Kopf des HTML-Dokuments schreibt, statt mit einer externen SVG-Datei zu arbeiten; dann muss man beim Verwenden entsprechend auch auf die ID des SVG-Elements im Dokument selbst verweisen, bei deinem Beispiel entsprechend:

    (Deswegen funktioniert dein Codepen-Beispiel auch im IE ab Version 9). Aber natürlich sind externe SVG-Dateien wegen Caching usw. besser.

    Ein interessantes Tool ist auch http://filamentgroup.com/lab/grunticon.html, von dem es auch eine Online-Version gibt: http://www.grumpicon.com/, erzeugt einem auch PNG-Fallbackgrafiken, und den Data-URL-Code für SVG und PNG ….

  3. Ich seh das immer so: wenn eine Technik für 90% der Browser super funktioniert (mit kleinem Polyfill in dem Fall) und sie meine Arbeit leichter macht, dann setze ich sie auch ein. Wenn ich mich für 10% der Browser oder je nach Projekt noch weniger dann einen sinnvollen Fallback überlegen muss, ist das ok. Das hindert mich aber nicht daran 90% der optimal zu bedienen. ;)

  4. Ich versteh das noch nicht so ganz, kann ich mir beispielsweiße in Illustrator ein ganzes Set von SVG´s anlegen und dieses dann einbinden? Und dann wie auch bei CSS background-position sagen wo das einzelne Element liegt?

  5. @Stefan der Weg den du meinst, ist der Weg wenn man einfach Vektoricons anstatt Grafikicons nutzt – da schau dir mal iconizr.com an. Der Weg, den ich hier beschreibe, ist, dass man anstatt ein Icon-Font eine Datei mit mehreren „SVG-Ebenen“ (das aus einzelnen SVGs zusammen gesetzt/generiert ist), zu verwenden.

  6. Zunächst danke für den guten Überblick und die öffentliche Ermutigung, mit SVG-Icons zu arbeiten! :)

    Dann in eigener Sache, weil es ein bißchen wirr rüberkommt:

    1. Als Alternative zu grunt-svgstore wären nicht iconizr bzw. grunt-iconizr zu nennen, sondern besser svg-sprite (bzw. grunt-svg-sprite), auf dem die Node- / Grunt-Versionen von iconizr intern aufbauen. Im Unterschied zu grunt-svgstore ist in svg-sprite die SVG-Optimierung direkt integriert, außerdem können verschiedenste CSS-Flavours zum Sprite generiert werden (CSS, Sass, LESS, Stylus etc.).

    2. iconizr dagegen produziert komplette CSS-Icon-Kits, die sowohl einen SVG-, als auch einen PNG-Sprite sowie verschiedene CSS-Ausgabeformate enthalten. Seit neuestem kann die Node- / Grunt-Version von iconizr auch eine „Inline-Version“ des SVG-Sprites erzeugen, die sich für die direkte Einbettung in HTML und die von Dir beschriebenen Referenzierung per <use> eignet (intern oder externe Resource). Am leistungsfähigsten und vielseitigsten ist iconizr derzeit als Node- / Grunt-Modul. Daneben gibt es die ursprüngliche, featureärmere PHP-Kommandozeilenversion sowie die darauf basierende Online-Version unter iconizr.com, die man ohne jede Installation oder Registrierung nutzen kann.

  7. So habe die Zeit gefunden das einmal durchzutesten und wirklich zufrieden bin ich nicht :D

    SVGStore produziert ungültige SVG Sprites jedenfalls ist es auf dem Mac. Da fehlt schon der Header in der SVG Datei. Also hab ich Grunt-SVG-Sprite von Joschi verwendet. Ist eine gültige SVG Datei die man dann verwenden kann – heißt über HTML kann ich das entsprechende Image „Triggern“.
    Objekt Gruppen hat er seine liebe Not, im Klartext wird nicht dargestellt.

    Dazu kommen dann die erwähnten Nachteile mit IE8, jedesmal manuell eine Fallback Grafik zu generieren, die wegen SVG4Everybody auch noch einen spezielleren Dateinamen benötigt (Dateiname SVG Sprite + Sprite + .png) ist müßig, mit Grunt/Gulp zwar nicht unmöglich. Im Agenturbetrieb kommt es häufig vor das UI Elemente angepasst werden, wäre mit reinem SVG eine feine Sache, wer aber den IE8 noch beliefern muss, der kommt nicht drum rum jedes mit dem Vector Programm die Rohdaten zu modifizeren um dann über Grunt ein PNG zu generieren (was auch schon Quatsch ist, das kann man in Sketch schon alles parallel exportieren).

    Und zu guter Letzt ist es eine wackelige Angelegenheit, wer schon mal PSDs von Designern auf den Tisch bekommen hat, weis wie unsauber es da zu gehen kann. Das wird bei Vektor noch schlimmer, nicht nur das der Developer einen Anfall bekommt sondern weil einem die SVG Images auch gerne auseinander fliegen.

    Mein Fazit. Solange ich den ‚gammligen‘ IE8 mitbeliefern muss, sind SVG Sprites viel zu aufwendig. Wobei der Aufwand erst dann anfängt nach oben zu schnellen wenn der Kunde mit seinem „Ach ich hab mir das überlegt sie könnten die Farbe dieses Icons noch mal ändern das gefällt mir nun doch nicht mehr“ kommt. Progressive Enhancement hin oder her, man kommt nicht drum herum das SVG zu modifizieren um daraus ein neues PNG zu generieren. Wer seinen Kunden natürlich voll im Griff hat, kann es vielleicht versuchen :)

    Da bleib ich lieber bei Iconfonts, und einzelnen SVG Images (entweder Einzel oder Base64 Kodiert im CSS/extra CSS File) :)

Kommentare sind geschlossen.