Gunnar Bittersmann: SVG mittels CSS färben

Beitrag lesen

@@Gunnar Bittersmann

Aber eigentlich soll gar nicht alles SVG in HTML eingebettet sein. Dazu später mehr …

Im ersten Teil des Tutorials hatten wir ein Haus-Icon erstellt und mehrfach wiederverwendet. Was, wenn wir nun mehrere verschiedene Icons haben: Mein Haus, mein Auto, mein Boot, …?

Die sammeln wir alle als symbols in dem einen svg-Element:

<svg xmlns="http://www.w3.org/2000/svg" style="display: none">
	<symbol id="house" viewBox="8 0 80 80">
		<path d="M48,13 L9,48 H20 V80 H40 V56 H56 V80 H76 V48 H87z"/>
	</symbol>
	<symbol id="car" viewBox="0 0 100 200">
		<path d=""/>
	</symbol>
	<symbol id="boat" viewBox="-21 -21 42 42">
		<path d=""/>
	</symbol>
</svg>

Die Pfade für Auto und Boot habe ich nur angedeutet. You get the picture. (No pun intended.)

Wichtig ist, dass jedes symbol sein eigenes viewBox-Attribut, d.h. sein eigenes Koordinatensystem hat. Das hat nichts mit der Größe zu tun, mit der das Icon dargestellt wird; diese hatten wir im Stylesheet mit svg { width: 1em; height: 1em } angegeben.

(Man kann natürlich auch für verschiedene Icons verschiedene Größen angeben oder dasselbe Icon an verschiedenen Stellen in verschiedenen Größen verwenden.)

Verwendung (der Einfachheit halber hier ohne Namensräume):

<ul>
	<li><svg><use xlink:href="#house"/></svg> mein Haus</li>
	<li><svg><use xlink:href="#car"/></svg>   mein Auto</li>
	<li><svg><use xlink:href="#boat"/></svg>  mein Boot</li>
</ul>

(EDIT: href geändert in xlink:href. Safari will das so.)

Nun wollen wir die Icons nicht nur auf einer Webseite, sondern auf allen Seiten unserer Website einsetzen. Dazu müssten wir das svg-Element mit den symbols in jedes HTML-Dokument hineinkopieren … was wohl keine so gute Lösung wäre.

Sinnvoll ist, das svg-Element mit den symbols in eine Datei auszulagern (bspw. speichern als icons.svg im assets-Ordner). style="display: none" kann dann weg; wichtig ist, dass hier die XML-Namensraumangabe vorhanden ist:

<svg xmlns="http://www.w3.org/2000/svg">

Diese Datei wird nun nicht mit PHP o.ä. in den HTML-Quelltext geschrieben, denn dann müssten ja sämtliche Icons bei jeder Seite erneut übertragen werden. Das würde den Quelltext unnötig aufblähen, insbesondere, wenn wir nicht nur drei, sondern dreiundzwölfzig Icons in unserer Sammlung haben.

Wir wollen, dass diese SVG-Datei mit allen Icons nur einmal übertragen wird und dann im Browsercache liegt. Wir holen uns die Icons deshalb aus der externen Datei:

<ul>
	<li><svg><use xlink:href="/assets/icons.svg#house"/></svg> mein Haus</li>
	<li><svg><use xlink:href="/assets/icons.svg#car"/></svg>   mein Auto</li>
	<li><svg><use xlink:href="/assets/icons.svg#boat"/></svg>  mein Boot</li>
</ul>

bzw.

<ul>
	<li><svg><use xlink:href="https://example.net/assets/icons.svg#house"/></svg> mein Haus</li>
	<li><svg><use xlink:href="https://example.net/assets/icons.svg#car"/></svg>   mein Auto</li>
	<li><svg><use xlink:href="https://example.net/assets/icons.svg#boat"/></svg>  mein Boot</li>
</ul>

Leider wird die Freude durch IrgendEinen Browser getrübt. Internet Explorer kann zwar <use xlink:href="#house"/>, wenn die symbols in derselben HTML-Datei sind; aber nicht <use xlink:href="icons.svg#house"/> mit externer SVG-Datei. (Wohlgemerkt, wir reden von IE, nicht von Edge – der kann das.)

Wenn man die Icons zusätzlich zu vorhandem Text einsetzt (was generell eine gute Idee ist), kann man auf progressive enhancement setzen: Seitenbesucher mit Internet Explorer (3…4%, Tendenz fallend) bekommen die Icons nicht zu sehen. Das sollte nicht tragisch sein; die Icons sind ja „nur“ Zusatz zum Text.

Man kann aber auch einen Polyfill anwenden, um die Icons auch im IE darzustellen. Dazu wird die SVG-Datei per AJAX geladen und als svg-Element ins DOM gepackt, womit die symbols im selben Dokument sind und auch vom IE referenziert werden können. Dazu werden die Referenzen zu lokalen Referenzen umgeschrieben, bspw. icons.svg#house zu #house.

Der Unterschied zur serverseitigen Einbettung ins HTML besteht darin, dass beim zweiten AJAX-Aufruf die dreiundzwölfzig Icons schon im Browsercache liegen und nicht nochmal übers Netzwerk geholt werden müssen.

Das JavaScript sieht in etwa so aus:

document.addEventListener('DOMContentLoaded', function ()
{
	'use strict';
	
	if (!(window.CSS && 'supports' in CSS))
	{
		var useElements = Array.prototype.slice.call(document.querySelectorAll('use'));
		
		if (useElements)
		{			
			var href = useElements[0].getAttribute('href') || useElements[0].getAttribute('xlink:href');

			var request = new XMLHttpRequest();
			request.open('GET', href.substr(0, href.indexOf('#')), true);
			
			request.addEventListener('load', function ()
			{
				if (request.status >= 200 && request.status < 400)
				{
					document.body.appendChild(request.responseXML.documentElement);
				}
			});
	
			request.send();
	
			useElements.forEach(function (useElement)
			{
				var href = useElement.getAttribute('href') || useElement.getAttribute('xlink:href');
				useElement.setAttribute('xlink:href', href.substr(href.indexOf('#')));
				useElement.removeAttribute('href');
			});
		}
	}
});

Mit if (!(window.CSS && 'supports' in CSS)) wird die Spreu (IE) vom Weizen getrennt und der Polyfill nur in Browsern ausgeführt, die ihn nötig haben. Das ist eher ein Hack; mir ist keine geeignete feature detection eingefallen. Nicht, dass ich nicht gefragt hätte.

Das Script geht davon aus, dass alle Icons in einundderselben Datei sind und lädt nur die SVG-Datei des ersten use-Elements (useElements[0]). Wenn Icons aus verschiedenen SVG-Dateien eingebunden werden, müsste man das entsprechend umschreiben – oder bestehende Polyfills verwenden. Mein geschätzter Kollege wies mich auf svg4everybody und svgxuse hin.

svg4everybody fällt in meinem Test durch.[1] (Im IE ansehen!) Die Icons sind verschoben (Liegt das daran, dass viewBox so gewählt ist, dass der Punkt links oben nicht der Koordinatenursprung ist?) und damit, dass use in einem symbol verwendet wird, kommt das Script nicht klar.

svgxuse tut, was es soll. Damit steht der Verwendung von SVG-Icon auch im Internet Explorer nichts im Wege. Und es gibt keinen Grund für Icon-Fonts mehr. Keinen! Weitere Literatur:

LLAP 🖖

--
„Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann

  1. In der ersten Version hatte ich statt Iframes doch tatsächlich ein Frameset gebaut! 😱😏 ↩︎

0 63

Icon, png mit transperenten Hintergrund mittels CSS färben

Clarissa
  • css
  1. 0
    beatovich
  2. 0
    Robert B.
    • css
    • svg
  3. 0
    beatovich
    1. 0
      Gunnar Bittersmann
      1. 0
        beatovich
        1. 1
          Linuchs
          1. 0
            Regina Schaukrug
  4. 0
    Regina Schaukrug
    1. 0
      Gunnar Bittersmann
      1. 0
        Clarissa
        1. 0
          Regina Schaukrug
          1. 0
            Gunnar Bittersmann
            1. 0

              SVG mittels CSS färben

              Regina Schaukrug
              • css
              • svg
              1. 0

                Icon, png mit transperenten Hintergrund mittels CSS färben

                Matthias Apsel
                • meinung
                • zu diesem forum
                1. 0
                  Regina Schaukrug
              2. 0
                Robert B.
                1. 0
                  Regina Schaukrug
                  1. 0
                    Robert B.
                    1. 0
                      Regina Schaukrug
                      1. 0
                        Robert B.
                    2. 1
                      Gunnar Bittersmann
                      1. 0
                        Regina Schaukrug
                        1. 0

                          Probleme mit use

                          Regina Schaukrug
                          1. 0
                            Robert B.
                            1. 0
                              Regina Schaukrug
              3. 1
                Gunnar Bittersmann
                1. 0
                  Regina Schaukrug
                2. 6
                  Gunnar Bittersmann
                  • css
                  • html
                  • svg
                  1. 1

                    SVG mittels CSS färben - Das geht (THX!)

                    Regina Schaukrug
                    1. 0
                      Auge
                      1. 0
                        Regina Schaukrug
                        1. 0
                          Auge
                          1. 0
                            Regina Schaukrug
                            1. 0
                              beatovich
                              1. 0
                                Regina Schaukrug
                                1. 0
                                  beatovich
                                  1. 0
                                    Regina Schaukrug
                                    1. 0
                                      beatovich
                                      1. 0
                                        Matthias Apsel
                                        1. 0
                                          beatovich
                                      2. 0
                                        Regina Schaukrug
                                        1. 0
                                          Matthias Apsel
                                          1. 0
                                            Regina Schaukrug
                                        2. 0
                                          beatovich
                                          1. 0
                                            Matthias Apsel
                                2. 1
                                  MudGuard
                    2. 0

                      Version mit externem SVG funktioniert in modernen Browsern

                      Regina Schaukrug
                  2. 5
                    Gunnar Bittersmann
                    1. 0
                      Regina Schaukrug
                      1. 0
                        Gunnar Bittersmann
                      2. 0
                        beatovich
                        1. 0
                          Gunnar Bittersmann
                          1. 0
                            beatovich
                    2. 0
                      JürgenB
                      1. 0
                        Gunnar Bittersmann
                        1. 0
                          JürgenB
                    3. 0
                      marctrix
                      1. 0
                        Gunnar Bittersmann
                        1. 0
                          marctrix
                          1. 0
                            Gunnar Bittersmann
                            1. 0
                              marctrix
                    4. 0
                      Gunnar Bittersmann