Los SVGs son ubicuos en la web: iconos, ilustraciones, logos, gráficas. Pero pocas veces nos paramos a pensar que la forma en que los cargamos tiene un impacto real en rendimiento. No es lo mismo un SVG inline en el HTML que uno referenciado desde un <img>: cambia la caché, el renderizado, las peticiones de red y hasta cómo el navegador los prioriza.
En este artículo analizo las principales técnicas de carga de SVG desde el punto de vista del rendimiento, con sus ventajas, sus limitaciones y los anti-patterns más habituales que encuentro en auditorías.
Table of Contents
Open Table of Contents
- Las formas de cargar un SVG
- SVG inline: máximo control, sin caché
<img>: simple, cacheado, pero opaco<object>: documento embebido- CSS
background-image: SVGs decorativos - SVG sprite +
<use>: el mejor de ambos mundos - Anti-pattern: imágenes de bits incrustadas en SVG
- ¿Cómo detectarlo?
- Comparativa de rendimiento: cuándo usar cada método
- Conclusión
Las formas de cargar un SVG
Hay cinco formas principales de incluir un SVG en una página web, y cada una tiene un comportamiento diferente:
| Método | Caché | Petición de red | Acceso CSS/JS | Reusable |
|---|---|---|---|---|
Inline <svg> | ❌ No | ❌ No | ✅ Sí | ❌ No |
<img src="icon.svg"> | ✅ Sí | ✅ Sí | ❌ No | ✅ Sí |
<object data="icon.svg"> | ✅ Sí | ✅ Sí | Limitado | ✅ Sí |
CSS background-image | ✅ Sí | ✅ Sí | ❌ No | ✅ Sí |
SVG sprite + <use> | ✅ Parcial | ✅ Sí | ✅ Sí | ✅ Sí |
SVG inline: máximo control, sin caché
Incrustar el SVG directamente en el HTML es la técnica que más control ofrece: acceso total desde CSS y JavaScript, sin peticiones adicionales, compatible con animaciones y con currentColor.
<!-- ✅ Ventajas: acceso CSS/JS, sin petición de red -->
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
>
<path d="M12 2L2 7l10 5 10-5-10-5z" />
</svg>
El problema: cada vez que la página se carga, el SVG se parsea de nuevo. No hay caché del SVG en sí: está embebido en el HTML. Si el mismo icono aparece en 50 páginas distintas, se descarga y parsea 50 veces.
<!-- ❌ Repetir el mismo SVG en cada página tiene coste de parseo -->
<!-- página-1.html -->
<svg>...</svg>
<!-- página-2.html -->
<svg>...</svg>
<!-- el navegador no lo cachea entre páginas -->
Cuándo tiene sentido: SVGs únicos por página (logos, ilustraciones hero), cuando necesitamos animarlos con CSS o JS, o cuando el SVG es el LCP candidate y quieres evitar la petición de red.
<img>: simple, cacheado, pero opaco
Referenciar un SVG desde <img> es la forma más limpia para iconos y gráficas que no necesitan interacción:
<!-- ✅ Cacheado, sin bloquear el parser -->
<img
src="/icons/arrow.svg"
width="24"
height="24"
alt="Siguiente"
loading="lazy"
/>
El navegador lo trata como cualquier imagen: lo cachea, lo prioriza según loading y fetchpriority, y lo puede compartir entre páginas. El SVG no tiene acceso a los estilos del documento: currentColor no funciona, y no es posible manipularlo con JavaScript.
<!-- ❌ currentColor no hereda el color del documento -->
<img src="/icons/icon.svg" style="color: red" />
<!-- El fill del SVG no cambiará -->
<object>: documento embebido
<object> carga el SVG como un documento independiente con su propio contexto. Tiene caché, pero el acceso desde el documento padre es limitado y requiere scripting adicional. En la práctica, es la opción menos usada y con más fricción.
<object data="/graphic.svg" type="image/svg+xml" width="200" height="200">
<!-- Fallback para navegadores sin soporte -->
<img src="/graphic.png" alt="Gráfico" />
</object>
Para la mayoría de casos, <img> o inline son mejores alternativas.
CSS background-image: SVGs decorativos
Para SVGs puramente decorativos (separadores, patrones, fondos) que no necesitan texto alternativo ni interacción, background-image es válido:
/* ✅ Para elementos decorativos */
.divider {
background-image: url("/decorative/wave.svg");
background-size: cover;
height: 80px;
}
Sin acceso CSS ni JS al contenido interno del SVG, y sin semántica para lectores de pantalla. Bien para decoración, mal para iconos con significado.
SVG sprite + <use>: el mejor de ambos mundos
El sprite SVG es la técnica más eficiente para iconos reutilizables: un único archivo con todos los símbolos, referenciado desde <use>. Una sola petición, cacheada, compartida entre páginas.
<!-- sprite.svg (cargado una vez) -->
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
<symbol id="icon-arrow" viewBox="0 0 24 24">
<path fill="currentColor" d="M5 12h14M12 5l7 7-7 7" />
</symbol>
<symbol id="icon-close" viewBox="0 0 24 24">
<path fill="currentColor" d="M18 6L6 18M6 6l12 12" />
</symbol>
</svg>
<!-- Uso en cualquier parte del HTML -->
<svg width="24" height="24" aria-hidden="true">
<use href="/sprite.svg#icon-arrow" />
</svg>
El sprite se cachea en el navegador. Cada <use> solo referencia un símbolo, no descarga el archivo de nuevo. Además, mantiene acceso a currentColor para colorear con CSS.
/* ✅ currentColor funciona con <use> si el SVG usa fill="currentColor" */
.icon {
color: var(--color-primary); /* se hereda como currentColor */
}
Limitación a tener en cuenta: <use> con referencia externa (href apuntando a otro dominio) puede tener restricciones de CORS.
Anti-pattern: imágenes de bits incrustadas en SVG
Este es uno de los anti-patterns que más impacto tiene en rendimiento y que encuentro con frecuencia en auditorías. Un SVG puede contener imágenes rasterizadas (WebP, JPEG, PNG) codificadas en base64 dentro del propio archivo:
<!-- ❌ Anti-pattern: imagen rasterizada embebida en SVG -->
<svg xmlns="http://www.w3.org/2000/svg">
<image href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." />
</svg>
¿Por qué es un problema?
- Tamaño disparado: base64 añade un 33% de overhead al peso del archivo
- Sin optimización: el navegador no puede aplicar compresión adaptativa ni negociación de formato (AVIF, WebP)
- Sin caché granular: la imagen rasterizada no se cachea por separado; si cambia, se invalida todo el SVG
- Bloquea el renderizado: el SVG no se muestra hasta que se descarga y decodifica la imagen embebida
<!-- ✅ Referencia externa: la imagen se cachea y optimiza por separado -->
<svg xmlns="http://www.w3.org/2000/svg">
<image href="/photos/team-photo.jpg" width="800" height="600" />
</svg>
Los exportadores de herramientas de diseño como Figma o Illustrator a veces generan este patrón cuando el diseño incluye imágenes rasterizadas. Revísalo siempre antes de publicar.
¿Cómo detectarlo?
En DevTools puedes ver el tamaño real de los SVGs en el panel Network. Un SVG de más de 50KB suele ser sospechoso. Para analizarlo directamente en el navegador, el snippet SVG Embedded Bitmap Analysis de WebPerf Snippets recorre todos los SVGs de la página e identifica los que contienen imágenes rasterizadas embebidas. También puedes buscarlo en los archivos del proyecto:
# Busca SVGs con imágenes embebidas en base64
grep -rl "data:image" ./public --include="*.svg"
Comparativa de rendimiento: cuándo usar cada método
- SVG inline → LCP candidates, SVGs únicos con animación CSS/JS
<img>→ Iconos y gráficas sin interacción, con lazy loading- SVG sprite +
<use>→ Sistemas de iconos reutilizables en toda la web background-image→ Elementos puramente decorativos<object>→ Casos muy específicos, generalmente lo podemos evitar
Conclusión
La elección del método de carga de SVG no es cosmética: afecta directamente a la caché, al número de peticiones, al parseo y al rendimiento percibido. El sprite con <use> es la opción más eficiente para sistemas de iconos. Para ilustraciones únicas con animación, el inline tiene sentido. Y siempre, siempre, evita incrustar imágenes de bits en SVGs.