SVG-Fallbacklösungen

Avatar of Chris Coyier
Chris Coyier am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

UPDATE: Hier ist ein umfassenderer Leitfaden zu SVG-Fallbacklösungen, den wir veröffentlicht haben.

Es gibt eine sehr clevere Technik von Alexey Ten, um einen Bild-Fallback für SVG bereitzustellen, die kürzlich im Internet die Runde macht. Sie tut genau das, was Sie in klassischen Browsern ohne SVG-Unterstützung wie IE 8 und älter sowie Android 2.3 wollen. Wenn wir etwas genauer hinschauen, finden wir einige ziemlich interessante Dinge, darunter ein unerwartetes Verhalten, das ein kleiner Wermutstropfen ist.

Alexeys Technik sieht so aus

<svg width="96" height="96">
  <image xlink:href="svg.svg" src="svg.png" width="96" height="96" />
</svg>

Die Idee basierte auf Jake Archibalds Wiederholung der Tatsache, dass Browser das <image>-Tag wie ein <img>-Tag rendern. Es ist nur ein seltsamer Alias aus alten Zeiten, der ausgenutzt werden kann.

Was angezeigt wird

Die Technik ist in Bezug auf das, was unterstützende und nicht unterstützende Browser anzeigen, ziemlich nah an perfekt. IE 8, der SVG nicht unterstützt, zeigt das Fallback-PNG an. Android 2.3, die gleiche Geschichte.

Was mich verwirrte, waren iOS 3 und 4. Der native Browser auf diesen Betriebssystemen unterstützt SVG in Form von <img src="*.svg"> oder als CSS background-image. Aber bei dieser Technik wird das PNG anstelle des SVG angezeigt. Das Problem ist, dass iOS 3 & 4 kein „Inline“-SVG unterstützt (z. B. die Verwendung von SVG mit einem <svg>-Tag direkt im HTML) (Support-Chart). SVG-Unterstützung ist nicht einfach Ja oder Nein. Es hängt davon ab, wie es verwendet wird.

Der Punkt: Es ist seltsam zu sehen, dass <img> in diesen Fällen funktioniert und <image> nicht. Und da diese Browser SVG unterstützen, ist es schade, es nicht zu nutzen.

Was heruntergeladen wird

Natürlich interessiert uns auch, was heruntergeladen wird, denn das wirkt sich auf die Seitenleistung aus. Auch hier hauptsächlich gute Nachrichten. Moderne Browser wie Chrome laden nur das SVG herunter. Android 2.3 lädt nur das PNG herunter.

Aber wir stoßen auf ein Problem mit Internet Explorer Versionen 9, 10 und 11 (zu diesem Zeitpunkt eine Vorschau). In IE 9 können Sie sehen, wie beide Bilder in der Netzwerk-Timeline auftauchen.

Das PNG endet mit dem Ergebnis "Aborted" und wird als 0 B empfangen aufgeführt, beeinflusst aber dennoch die Download-Zeit.

In IE 10 ist es eine ähnliche Geschichte, es scheint einfach schneller abzubrechen und ohne viel Ausfallzeit zum SVG überzugehen.

Scott Jehl schlug vor, Charles Proxy zu verwenden, um genauer zu testen, was heruntergeladen wird. Charles bestätigt, dass das PNG angefordert wird.

Die Größe des Antwortkörpers beträgt tatsächlich 0 B, sodass der Abbruch schnell genug erfolgt, dass nicht viele Daten übertragen werden. Obwohl die kombinierte Anfrage und Antwort-Header 782 B beträgt und es ~300 ms dauert. Wie Yoav Weiss bemerkte, kann das Problem schlimmer sein, wenn blockierende Skripte oben auf der Seite stehen.

Beachten Sie auch, dass die Verwendung eines Proxys die heruntergeladenen und nicht heruntergeladenen Elemente beeinflussen kann, wie Steve Souders in diesem Artikel von Jason Grigsby über Charles Proxy darlegt.

Forschungen von Andy Davies legen nahe, dass die PNG-Anfrage in IE 11 unter Windows 7 überhaupt nicht abgebrochen wird.

Ergebnisse

Ich habe die Anzeigetests aus diesem Pen durchgeführt, aber die Download-Tests habe ich mit nur einer der Techniken auf der Seite und unter Verwendung von Debug View durchgeführt, sodass nichts anderes auf der Seite war als die reine Technik.

Sehen Sie sich den Pen SVG Tests von Chris Coyier (@chriscoyier) auf CodePen an

Also, Fallbacks

Alexey Tens Technik ist immer noch clever, und wenn das iOS-Anzeigeproblem und das IE-Downloadproblem für Sie akzeptabel sind, ist sie immer noch nutzbar. Hier sind einige weitere Fallback-Techniken, die davon abhängen, wie Sie SVG verwenden.

Wenn Sie SVG als Hintergrundbild verwenden...

Modernizr hat einen SVG-Test. Sie könnten also einen Fallback mit den Klassennamen deklarieren, die es dem HTML-Element hinzufügt.

.my-element {
  background-image: url(image.svg);
}
.no-svg .my-element {
  background-image: url(image.png);
}

Das sollte keine Doppel-Download-Probleme verursachen, aber es hat keine Modernizr-Abhängigkeit.

Eine sehr clevere Technik ohne jegliche Abhängigkeit ist die Verwendung eines kleinen CSS-Tricks mit mehreren Hintergründen und alten linearen Gradienten.

.my-element {
  background-image: url(fallback.png);
  background-image: 
    linear-gradient(transparent, transparent),
    url(image.svg);
}

Es gab eine Technik, die nur mehrere Hintergründe verwendete. Aber das hat nicht ganz funktioniert, weil Android 2.3 das unterstützte, aber nicht SVG, und somit kaputt ging. Dies kombiniert alte Gradienten mit mehreren Hintergründen, sodass es überall funktioniert. Referenz.

Wenn beide Dinge unterstützt werden, verwendet der Browser die zweite Deklaration (mit SVG), andernfalls wird auf die erste Deklaration (mit PNG) zurückgegriffen.

Wenn Sie SVG als Inline-<svg> verwenden...

David Ensinger postete eine Technik, die das <foreignObject>-Tag in <svg> verwendet. Das Problem dabei ist jedoch, dass der Fallback immer geladen wird, was zu einem doppelten Download führt, anstatt nur manchmal wie bei der <image>-Technik.

Das wird etwas kompliziert, aber Artur A postete diese Idee, die den doppelten Download zu lösen und überall zu funktionieren scheint

<!DOCTYPE html>
<html>

<head>
    <title>HTML5 SVG demo</title>
    <style>
     .nicolas_cage {
         background: url('nicolas_cage.jpg');
         width: 20px;
         height: 15px;
     }
     .fallback {
     }
    </style>
</head>

<body>
  
  <svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
    <style>
    <![CDATA[ 
      .fallback { background: none; background-image: none; display: none; }
    >
    </style>
  </svg>

  <!-- inline svg -->
  <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40">
  <switch>
     <circle cx="20" cy="20" r="18" stroke="grey" stroke-width="2" fill="#99FF66" />
     <foreignObject>
         <div class="nicolas_cage fallback"></div>
     </foreignObject>
  </switch>
  </svg>

  <!-- external svg -->
  <object type="image/svg+xml" data="circle_orange.svg">
    <div class="nicolas_cage fallback"></div>
  </object>

</body>

</html>

Alternativ könnten Sie etwas tun wie

<svg> ... inline SVG stuff ... </svg>
<div class="my-svg-alternate"></div>

Verwenden Sie dann erneut den Modernizr SVG-Test, um die Support-HTML-Klasse zu erhalten, und dann...

.my-svg-alternate {
  display: none;
}
.no-svg .my-svg-alternate {
  display: block;
  width: 100px;
  height: 100px;
  background-image: url(image.png);
}

Oder umschließen Sie das SVG in diesem div, damit das div für eine konsistente Größenanpassung verwendet werden kann.

Wenn Sie Inline-SVG verwenden, ist die Wahrscheinlichkeit groß, dass Sie dies mit <use> tun. In diesem Fall leistet das Skript svg3everybody ziemlich gute Arbeit. Wenn SVG auf die von Ihnen verwendete Weise unterstützt wird, funktioniert es einfach. Wenn es in IE (was nicht funktioniert) extern referenziert wird, sorgt es dafür, dass es per Ajax geladen wird. Wenn es überhaupt nicht funktioniert, gibt es eine Syntax, mit der Sie eine PNG-Fallback angeben können.

Wenn Sie SVG als <object> verwenden...

Sie könnten das object-Tag selbst als Element zum Stylen nach dem Modernizr-Test verwenden.

<object type="image/svg+xml" data="image.svg" class="logo"></object>
.no-svg .logo {
  display: block;
  width: 100px;
  height: 100px;
  background-image: url(image.png);
}

Wenn Sie SVG als <img> verwenden...

Es gibt eine Technik, bei der eine fehlerhafte SVG-Datei im laufenden Betrieb ausgetauscht werden kann.

<img src="image.svg" onerror="this.src='image.png'">

Das erfordert spezielles HTML, wie Sie sehen können. Wenn das nicht möglich oder praktikabel ist, könnten Sie Quellen mit Modernizr austauschen. Dies verwendet die JS-API von Modernizr, nicht die Klassennamen.

if (!Modernizr.svg) {
  $("img[src$='.svg']")
    .attr("src", fallback);
}

Wobei fallback ein String mit einer URL ist, wo das Nicht-SVG-Bild als Fallback dient. Sie könnten es in einem data-fallback-Attribut belassen, ein konsistentes URL-Muster verwenden, das einfach .svg durch .png ersetzt oder eine andere clevere Sache tun, die Ihnen einfällt. SVGeezy ist eine Bibliothek, die genau das tut und eine clevere Erkennungsmethode verwendet.

Das Problem bei diesen Methoden ist, dass sie ein <img src> erfordern und dieser src vorab geladen wird und es keine Möglichkeit gibt, dies zu verhindern. Sie müssen also mit potenziellen Doppel-Downloads rechnen, was immer schlecht ist.

Oder Sie könnten eine ähnliche Technik wie bei Inline-SVG und Objekttechniken verwenden, bei der ein verstecktes DIV angezeigt wird, das einen Fallback enthält.

Eine weitere ziemlich gute Option ist die Verwendung von Picturefill. Das <picture>-Element ermöglicht Content-Type-Fallbacks. Sie benötigen das Polyfill, da Picture noch nicht sehr gut unterstützt wird. Dies löst zwar das Problem des Doppel-Downloads, funktioniert aber nicht ohne JavaScript. Aber dann tun es die anderen Methoden auch nicht. Es sieht so aus:

<picture>

  <source srcset="graph.svg" type="image/svg+xml">

  <img srcset="graph-small.png, graph-medium.png 400, graph-large.png 800" alt="A lovely graph.”>

</picture>

Denken Sie daran, dass eine Art von Fallback nichts ist

Wenn Sie SVG als Hintergrundbild verwenden, ist das wahrscheinlich dekorativ und nicht essenziell für die Funktionsfähigkeit der Website, sodass kein Fallback wahrscheinlich in Ordnung ist.

Ähnlich wie bei SVG-Verschönerungen jeder Art, wie einem Symbol, das von einem Wort in einem Button begleitet wird. Ohne dieses SVG ist es immer noch ein Button mit einem Wort, also ein akzeptabler Fallback.

Nun denn

Wenn Ihnen dieser Beitrag nicht viel bedeutet, weil Sie noch kein SVG verwenden, sollten Sie es tun, denn es ist großartig. Dieser Beitrag könnte Ihnen den Einstieg erleichtern.

Wenn Sie mehr Daten zum Teilen haben, würden wir uns freuen, davon zu hören.

Viel Glück!