SVG sprite not work in Safari

2019-07-11 06:50发布

问题:

Safari is not better than IE for a web developer. Here is the issue I saw in Safari.

I am trying to use an SVG sprite to load product icon in my web page.

HTML code:

<img src="https://www.abc123.com/icon_sprite.svg#amex">

SVG Sprite Code:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="276" height="224" viewBox="0 0 276 224" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <view id="affiliate-programs" viewBox="148 0 32 32"/>
    <svg width="32" height="32" viewBox="0 0 32 32" x="148"><path .../></svg>
    <view id="alipay" viewBox="0 64 49 32"/>
    <svg width="49" height="32" viewBox="0 0 49 32" y="64"><path .../></svg>
    <view id="amex" viewBox="50 0 49 32"/>
    <svg width="49" height="32" viewBox="0 0 49 32" x="50"><path .../></svg>
    <view id="auction" viewBox="148 64 32 32"/>
    <svg width="32" height="32" viewBox="0 0 32 32" x="148" y="64"><path .../></svg>
    <view id="backorder-domain-service" viewBox="180 128 32 32"/>
    <svg width="32" height="32" viewBox="0 0 32 32" x="180" y="128"><path .../></svg>
    ...
    ...
</svg>

The <img> in HTML locate the <svg> by appending "#" + id of <view> in the sprite url. This way works in Chrome, Firefox, and even IE, but not in Safari.

How it looks like in Chrome:

And how it looks like in Safari 5 and Safari 9:

So it basically means the appended #viewId in <img> can't recognize the view by ID, which is unacceptable.

I am wondering if anyone has seen similar cases and could help me out.

By the way, I also tried another solution.

<object data="https://www.abc123.com/icon_sprite.svg#amex" type="image/svg+xml"></object>

This solution display the correct svg of the sprite, however it will first disappear and then re-appear during AJAX calls, which is not good user experience either.

回答1:

I answered most of my own questions here by myself. I don't know it is a happy thing or upsetting thing.

I figured out how to fix this issue in the next day after I posted it here.

According to https://www.broken-links.com/2012/08/14/better-svg-sprites-with-fragment-identifiers/, Safari only supports the fragment identifier like xxx.svg#<viewboxId> in Version 7, but not other versions, which I've confirmed in Sauce Labs. It is an even worse browser than IE.

Well, no more complaint. Let's talk about the solution, which is the most important thing.

It is true the fragment identifier xxx.svg#<viewboxId> does not work in most of Safaris. It happens in <img>, but not in <embed>. So for Safari, we can use <embed> to load fragment identifier.

How to differentiate browser:

function isSafari() {
  if (navigator && navigator.userAgent) {
    var userAgent = navigator.userAgent;
    var isChrome = userAgent.indexOf('Chrome') > -1;
    var isSafari = userAgent.indexOf('Safari') > -1;

    if ((isChrome) && (isSafari)) {
      isSafari = false;
    }
    return isSafari;
  }
  return false;
}

In Safari:

<embed id="embedSvg" class="pi_svg" src="https://www.abc123.com/icon_sprite.svg#amex" type="image/svg+xml"></embed>

In non-Safari:

<img class="pi_svg" src="https://www.abc123.com/icon_sprite.svg#amex">