Как сделать встроенные SVG-иконки повторно используемыми
Когда иконки встраивают прямо в HTML, браузер часто не повторно использует графику, и страницы теряют выгоды кэширования. В статье подробно показаны практики: SVG-спрайты, вынесенные файлы и использование атрибута
Вы получите чёткий алгоритм внедрения: как преобразовать встроенные иконки в спрайт или внешние файлы и адаптировать вызовы через
Начнем со встроенного SVG
Как этот...
<!DOCTYPE html>
<html lang="en">
<head>
<title>Inline SVG</title>
<link rel="stylesheet" href="/styles/style.css">
</head>
<body>
...
<svg width="24" height="24" viewBox="0 0 24 24" class="icon icon-alarm" xmlns="http://www.w3.org/2000/svg">
<path id="icon-alarm" d="M11.5,22C11.64,22 11.77,22 11.9,21.96C12.55,21.82 13.09,21.38 13.34,20.78C13.44,20.54 13.5,20.27 13.5,20H9.5A2,2 0 0,0 11.5,22M18,10.5C18,7.43 15.86,4.86 13,4.18V3.5A1.5,1.5 0 0,0 11.5,2A1.5,1.5 0 0,0 10,3.5V4.18C7.13,4.86 5,7.43 5,10.5V16L3,18V19H20V18L18,16M19.97,10H21.97C21.82,6.79 20.24,3.97 17.85,2.15L16.42,3.58C18.46,5 19.82,7.35 19.97,10M6.58,3.58L5.15,2.15C2.76,3.97 1.18,6.79 1,10H3C3.18,7.35 4.54,5 6.58,3.58Z"></path>
</svg>Легко можно добавить текст в кэш браузера в виде файла
В приведенном ниже HTML-коде селектор .icon-alarm извлекает фрагмент <svg> для иконки.
const iconHTML = document.querySelector(".icon-alarm").outerHTML;Затем мы сможем вставить его в кэш браузера:
if ("caches" in window) {
caches.open('static').then(function(cache) {
cache.put("/icons/icon-wheelchair.svg", new Response(
iconHTML,
{ headers: {'Content-Type': 'image/svg+xml'} }
));
}
}
Видите путь /icons/icon-wheelchair.svg? Это файл будет помещен в кэш.
Удостоверимся, что браузер извлекает этот файл из кэша при запросе
Зарегистрируем Service Worker на страницах:
if (navigator.serviceWorker) {
navigator.serviceWorker.register('/sw.js', {
scope: '/'
});
}
Сам Service Worker будет довольно небольшим:
self.addEventListener("fetch", event => {
let request = event.request;
event.respondWith(
caches.match(request).then(response => {
return response || fetch(request);
})
);
});
Мы никогда не запрашиваем этот файл, потому что наши иконки встроены
Но другие страницы могут извлечь выгоду из этого. Например, SVG-иконка может быть размещена на странице следующим образом:
<svg class="icon">
<use xlink:href="/icons/icon-alarm.svg#icon-alarm" />
</svg>
Поскольку /icons/icon-alarm.svg уже готов к кэшированию, браузер просто вытащит его из кэша и отобразит.
Но <use> и встроенный SVG не совсем то же самое
Описанный выше подход использует кэш, а иконки должны отображаться почти сразу. При этом лучше, если установка заливки для родительской иконки будет происходить через shadow DOM, который создает <use>. Поэтому элементы будут «окрашиваться» внутри него. Так что улучшайте это!
Мы могли бы асинхронно загрузить скрипт, который находит каждую иконку, загружает нужные SVG с помощью Ajax и заменяет элементы в <use>...
const icons = document.querySelectorAll("svg.icon");
icons.forEach(icon => {
const url = icon.querySelector("use").getAttribute("xlink:href"); // Мы можем захотеть найти также href
fetch(url)
.then(response => response.text())
.then(data => {
// Кто-то умнее меня, возможно, сможет это исправить.
// Заменяем <svg><use></svg> встроенным SVG
const newEl = document.createElement("span");
newEl.innerHTML = data;
icon.parentNode.replaceChild(newEl, icon);
// Удаляем <span>
const parent = newEl.parentNode;
while (newEl.firstChild) parent.insertBefore(newEl.firstChild, newEl);
parent.removeChild(newEl);
});
});
Предполагая, что приведенный выше JavaScript-код выполняется правильно, эта страница имеет встроенный SVG, как и оригинальная.
Демо-версии примеров:
- На Netlify
- На GitHub
Комментарии