
Começando com SVG embutido
Como isso…
<!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>
É muito fácil jogar texto no cache do navegador como um arquivo
No HTML acima, o seletor .icon-alarm
nos buscará a parte inteira <svg>
desse ícone.
const iconHTML = document.querySelector(".icon-alarm").outerHTML;
Então, podemos inserir no cache do navegador assim:
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'} }
));
}
}
Veja o caminho do arquivo /icons/icon-wheelchair.svg
? Isso é meio que apenas inventado. Mas realmente será colocado no cache naquele local.#Vamos nos certificar de que o navegador extraia esse arquivo do cache quando solicitado
Vamos registrar um Service Worker em nossas páginas:
if (navigator.serviceWorker) {
navigator.serviceWorker.register('/sw.js', {
scope: '/'
});
}
O próprio service worker será bem pequeno, apenas um correspondente de cache:
self.addEventListener("fetch", event => {
let request = event.request;
event.respondWith(
caches.match(request).then(response => {
return response || fetch(request);
})
);
});
#Mas … nós nunca pedimos esse arquivo, porque nossos ícones são inline.
Verdade. Mas e se outras páginas se beneficiassem desse cache? Por exemplo, um ícone SVG poderia ser colocado na página assim:
<svg class="icon">
<use xlink:href="/icons/icon-alarm.svg#icon-alarm" />
</svg>
Uma vez que /icons/icon-alarm.svg
está pronto para ser colocado em cache, o navegador ficará feliz em removê-lo do cache e exibi-lo.
(Fiquei espantado com o fato de isso funcionar. O Edge não gosta de <use>
elementos que se ligam a arquivos, mas isso acabará em breve.)
E mesmo que o arquivo não esteja no cache, presumindo que nós realmente jogamos esse arquivo no sistema de arquivos, provavelmente o resultado de algum tipo de “include” (usei o Nunjucks na demo).
Mas … <use>
e SVG embutido não são exatamente os mesmos
Verdade. O que eu gosto sobre o acima é que ele está fazendo uso do cache e os ícones devem renderizar perto de imediatamente. E há algumas coisas que você pode estilizar dessa maneira – por exemplo, definir o preenchimento no ícone pai deve passar pelo DOM de sombra que <use>
cria e colorir os elementos SVG dentro dele.
Ainda assim, não é o mesmo. A sombra DOM é uma grande barreira em comparação com o SVG embutido.
Então, aprimore-os! Poderíamos carregar de forma assíncrona um script que encontre cada ícone SVG, Ajaxs para o SVG necessário e substitua o <use>
material …
const icons = document.querySelectorAll("svg.icon");
icons.forEach(icon => {
const url = icon.querySelector("use").getAttribute("xlink:href"); // Might wanna look for href also
fetch(url)
.then(response => response.text())
.then(data => {
// This is probably a bit layout-thrashy. Someone smarter than me could probably fix that up.
// Replace the <svg><use></svg> with inline SVG
const newEl = document.createElement("span");
newEl.innerHTML = data;
icon.parentNode.replaceChild(newEl, icon);
// Remove the <span>s
const parent = newEl.parentNode;
while (newEl.firstChild) parent.insertBefore(newEl.firstChild, newEl);
parent.removeChild(newEl);
});
});
Agora, supondo que esse JavaScript seja executado corretamente, essa página tem o SVG embutido disponível da mesma forma que a página original.