從 SVG 元素中的資料網址遷移

小松
Jun Kokatsu

SVG 規格最近已更新,停止支援 SVG <use> 元素中的 data: 網址。 這可以提升網路平台的安全性,且 Webkit 不支援 SVG <use> 元素中的 data: 網址。

移除原因

SVG <use> 元素可以擷取外部的 SVG 圖片,然後複製到目前的文件中。這是一項強大的功能,因此僅限來源相同的 SVG 圖片。不過,系統會將 data: 網址視為相同來源資源,因而導致多項安全性錯誤 (例如規避受信任類型Sanitizer API)。這些安全性錯誤促使我們討論解決的最佳方法。我們也得出了各瀏覽器供應商 (來自 MozillaApple) 的共識,目前最好的做法就是移除 SVG <use> 元素中 data: 網址的支援。

如果網站在 SVG <use> 元素中使用 data: 網址,可以採用幾種替代做法。

使用相同來源的 SVG 圖片

您可以使用 <use> 元素載入相同來源的 SVG 圖片。

<div class="icon">
  <svg width="1em" height="1em">
    <use xlink:href="svgicons.svg#user-icon"></use>
  </svg>
</div>

使用內嵌 SVG 圖片

您可以使用 <use> 元素參照內嵌 SVG 圖片。

<svg style="display:none" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <symbol id="user-icon" viewBox="0 0 32 32">
      <path d="M25.333 9.335c0 5.153-4.179 9.333-9.333 9.333s-9.333-4.18-9.333-9.333c0-5.156 4.179-9.335 9.333-9.335s9.333 4.179 9.333 9.335zM23.203 18.908c-2.008 1.516-4.499 2.427-7.203 2.427-2.707 0-5.199-0.913-7.209-2.429-5.429 2.391-8.791 9.835-8.791 13.095h32c0-3.231-3.467-10.675-8.797-13.092z">
    </symbol>
    <!-- And potentially many more icons -->
  </defs>
</svg>

<div class="icon">
  <svg width="1em" height="1em">
    <use xlink:href="#user-icon"></use>
  </svg>
</div>

使用含有 blob 的 SVG 圖片:網址

如果您無法控管網頁的 HTML 或相同來源資源 (例如 JavaScript 程式庫),可以在 <use> 元素中使用 blob: 網址載入 SVG 圖片。

const svg_content = `<svg style="display:none" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
      <symbol id="user-icon" viewBox="0 0 32 32">
        <path d="M25.333 9.335c0 5.153-4.179 9.333-9.333 9.333s-9.333-4.18-9.333-9.333c0-5.156 4.179-9.335 9.333-9.335s9.333 4.179 9.333 9.335zM23.203 18.908c-2.008 1.516-4.499 2.427-7.203 2.427-2.707 0-5.199-0.913-7.209-2.429-5.429 2.391-8.791 9.835-8.791 13.095h32c0-3.231-3.467-10.675-8.797-13.092z">
      </symbol>
      <!-- And potentially many more icons -->
    </defs>
  </svg>`;
const blob = new Blob([svg_content], {type: 'image/svg+xml'});
const url = URL.createObjectURL(blob);
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
use.setAttribute('href', url + '#user-icon');
svg.appendChild(use);
document.body.appendChild(svg);

現場示範

您可以前往GitHub 查看這些替代方案的即時範例