Sprites CSS: cuándo siguen siendo útiles y cómo crear uno
La mayoría de los tutoriales de sprites CSS aún empiezan como en 2009: reducen solicitudes HTTP y, por tanto, aceleran el sitio. Ese argumento dependía de una limitación de HTTP/1.1 que ya no existe en servidores modernos. Esta es la versión honesta: qué justifica todavía un sprite, qué no y el cálculo exacto de background-position y cálculos de retina para crear uno que funcione.
Qué es realmente un sprite CSS
Un sprite CSS es un archivo de imagen que contiene varios gráficos independientes, junto con CSS que muestra solo uno de ellos a la vez. No hay recorte ni interviene JavaScript. Al elemento se le asigna un valor fijo de width y height, toda la hoja se establece como su background-image, y background-position desliza la hoja detrás del elemento para que el icono caiga en la caja visible. La caja es ventana y la hoja, papel arrastrado detrás.
El detalle que confunde al principio es que los desplazamientos son negativos. No estás moviendo la ventana hacia el icono, sino la hoja para que el icono llegue a la ventana. Para mostrar un icono cuya esquina superior izquierda está a 96 píxeles del borde izquierdo de la hoja, desplaza la hoja 96 píxeles hacia la izquierda, lo que corresponde a background-position: -96px 0.
Un ejemplo concreto. Supongamos que empaquetas cinco iconos de 24×24 en una sola fila con 8 píxeles de separación, empezando a 8 píxeles del borde izquierdo y a 8 píxeles del superior. La hoja mide entonces 160×32. El borde izquierdo del tercer icono está en 8 + 24 + 8 + 24 + 8 = 72 píxeles, y su borde superior está a 8 píxeles. La regla es:
| Declaración | Qué hace |
|---|---|
| background-image: url("/sprite.png") | Carga toda la hoja detrás del elemento |
| background-repeat: no-repeat | Evita repetir la hoja y mostrar otros iconos alrededor de los bordes |
| background-position: -72px -8px | Desplaza la hoja 72 px a la izquierda y 8 arriba para situar el tercer icono en el origen |
| width: 24px; height: 24px | Recorta la ventana a exactamente un icono: esto oculta el resto |
| display: inline-block | Permite que un elemento en línea, como span, respete ancho y alto |
No cambies nada salvo los dos números de background-position y obtienes otro icono del mismo archivo. Ese es todo el mecanismo.

La realidad: HTTP/2 cambió el cálculo
Los sprites CSS se inventaron para superar una limitación concreta. Con HTTP/1.1, un navegador abría un número pequeño de conexiones TCP por origen —habitualmente seis— y cada conexión solo podía gestionar una solicitud a la vez. Cuarenta archivos de iconos significaban cuarenta solicitudes en cola a través de seis canales, cada una con el coste de establecimiento de conexión y latencia de ida y vuelta. Combinarlos en un archivo convertía cuarenta solicitudes serializadas en una. En conexiones de alta latencia no era una microoptimización: a menudo era la mayor mejora disponible en una página.
HTTP/2 multiplexa. Muchas solicitudes comparten simultáneamente una conexión, sin bloqueo de cabecera en la capa HTTP, y los encabezados se comprimen entre solicitudes. El problema específico que motivó los sprites prácticamente desapareció. Si un tutorial de 2026 afirma que los sprites son más rápidos porque reducen las solicitudes y no explica nada más, está escrito para una web que ya no existe.
Entonces, ¿por qué existe este artículo? Porque «el motivo original desapareció» no significa «no hay ningún motivo». Varias ventajas reales sobreviven a la multiplexación, y son las que merece la pena valorar:
- El coste por solicitud no llega a cero. Las solicitudes multiplexadas son baratas, no gratuitas. Cada una conserva cabeceras, consulta de caché y una posición en el planificador de recursos. Con cinco iconos es insignificante; con doscientos pequeños es medible, y el sprite lo reduce a una entrada.
- La gestión de caché se simplifica. Un archivo significa una entrada de caché, un Cache-Control política y un nombre con hash que invalidar. Doscientos archivos versionados aparte aumentan la superficie de compilación y despliegue que gestionar, y normalmente no se gestiona.
- Versionado atómico. Todos los iconos se distribuyen juntos, así que nunca tendrás un conjunto actualizado a medias en el que tres iconos procedan de la caché con el estilo antiguo y el resto sean nuevos. En el despliegue de un sistema de diseño, esto es una garantía real de coherencia, no solo de orden.
- Sin parpadeo por icono ausente. Cuando se carga la hoja, todos sus iconos quedan disponibles al instante. Los cargados por separado aparecen uno a uno al completarse sus solicitudes, justo donde más molesta: una barra de herramientas o cuadrícula de iconos en la parte visible inicial.
- Cambios de estado sin latencia. Un estado de cursor encima o activo situado en otra parte de la misma hoja ya está descargado. Con archivos separados, la imagen del estado de cursor encima no suele solicitarse hasta la primera interacción, lo que provoca un parpadeo vacío la primera vez que el usuario pasa por el botón. Este siempre fue uno de los argumentos más sólidos a favor de los sprites y HTTP/2 no lo debilitó.
Cuándo no usar un sprite CSS
Una recomendación creíble debe incluir los casos en los que la respuesta es no, y para los sprites CSS hay varios.
- Los iconos monocromos escalables deben ser SVG. Un elemento en línea <svg> o un sprite SVG construido con <symbol> y <use> escala a cualquier tamaño sin cálculos de retina y hereda el color mediante currentColor. Para un conjunto típico de iconos de interfaz, sencillamente es una herramienta mejor, y por eso las hojas de sprites han perdido discretamente la mayor parte de su cuota en los sistemas de iconos.
- Un único icono nunca justifica un sprite. Si tienes una única imagen, usa una única imagen. El sprite añade gestión de coordenadas y un paso de compilación sin ninguna ventaja.
- Iconos que cambian de forma independiente. El versionado atómico tiene dos caras. Si cambia un icono, se invalida la entrada de caché de toda la hoja y todos los usuarios vuelven a descargarla completa. Un conjunto de iconos que cambia con frecuencia es mal candidato para sprites.
- Cualquier elemento que necesite recolorearse o adaptarse a un tema. Un sprite ráster lleva sus colores incorporados. El modo oscuro, los temas de marca y los colores de estado requieren una segunda hoja o trucos de filtros frágiles. Esta es la ventaja estructural más clara de SVG.
- Iconos que deben adaptarse al tamaño de fuente. Los sprites están fijados a dimensiones de píxel. Si deben escalar con em junto al texto, un enfoque vectorial lo gestiona y un sprite te lo dificulta.
Sprite, sprite SVG, SVG en línea o fuente de iconos
| Método | Escala limpiamente | Recolorear mediante CSS | Solicitudes | Caché | Accesibilidad |
|---|---|---|---|---|---|
| Sprite CSS (ráster) | No: píxeles fijos, necesita una hoja 2x | No, solo trucos de filtros | Uno para todos los iconos | Excelente, un archivo de larga duración | Imagen de fondo, invisible para las tecnologías de asistencia: necesita una etiqueta de texto |
| Sprite SVG (symbol + use) | Sí, cualquier tamaño | Sí, mediante currentColor | Uno para todos los iconos | Excelente, un archivo | En el DOM, admite title y ARIA |
| SVG en línea por icono | Sí, cualquier tamaño | Sí, control CSS completo | Cero, incorporado en HTML | Ninguna: se reenvía con cada página | La mejor opción, completamente en el DOM |
| Fuente de iconos | Sí, escala con font-size | Sí, mediante color | Un archivo de fuente | Bueno | Deficiente: se leen los glifos o se sustituyen con fuentes alternativas |
Lee la tabla como una decisión, no una clasificación. Las ilustraciones rasterizadas multicolor —banderas, logotipos, insignias, capturas de iconos— no pueden ser sprites SVG razonablemente. Ahí los sprites CSS siguen siendo la respuesta correcta, no una herencia.
Crear uno
El flujo tiene cuatro pasos y solo el tercero es laborioso a mano.
- Reúne los iconos. Exporta al tamaño final de visualización o al doble; consulta la sección de retina. Mantén los tamaños uniformes cuando puedas: una cuadrícula uniforme simplifica el cálculo de coordenadas y regulariza el CSS.
- Empaquétalos en una hoja. Una fila sencilla o una cuadrícula fija es más fácil de interpretar; un empaquetador aprovecha mejor el espacio cuando los tamaños varían. Deja separación entre los iconos.
- Lee las coordenadas. Cada icono necesita sus valores x, y, ancho y alto en píxeles de la hoja. Medirlos a mano en un editor de imágenes es donde suelen surgir errores, porque una lectura equivocada de un píxel aparece como una franja del icono vecino sin indicar la causa.
- Escribe el CSS. Una regla base compartida y una pequeña regla por icono.
La regla base compartida importa más de lo que parece. Cada icono necesita el mismo background-image, background-repeat: no-repeat, y display: inline-block. Repetir el background-image Repetir la URL en cincuenta reglas no perjudica el rendimiento: se descarga una vez. Sí dificulta mantenerla: renombrar para renovar caché exige cincuenta cambios. Usa una clase base para lo común y clases por icono solo para posición y tamaño:
| Regla | Contenido |
|---|---|
| .sprite | background-image, background-repeat: no-repeat, display: inline-block |
| .sprite-search | background-position: -8px -8px; width: 24px; height: 24px |
| .sprite-settings | background-position: -40px -8px; width: 24px; height: 24px |
En el marcado, eso es <span class="sprite sprite-search"></span>. En Sass, la misma idea suele expresarse como un marcador de posición, %sprite-base, incorporado a cada regla de icono con @extend — genera un selector agrupado en vez de repetir declaraciones y mantiene una clase por icono.
Retina y HiDPI: el truco de background-size
Es donde muchas guías fallan. Un sprite raster a 1x se ve suave en pantalla 2x. No cambies desplazamientos: empaqueta al doble de resolución y dile a CSS que la hoja mide la mitad.
Toma el ejemplo anterior y duplica todo al exportar: iconos de 48×48 píxeles reales, separación de 16 y hoja de 320×64 píxeles reales. Ahora configura background-size: 160px 32px — exactamente la mitad de las dimensiones reales. El navegador reduce la hoja a coordenadas CSS de 160×32 y asigna el detalle adicional a píxeles físicos HiDPI.
La ventaja es que todas las demás cifras CSS permanecen en coordenadas originales 1x. El tercer icono sigue siendo background-position: -72px -8px con width: 24px; height: 24px, sin cambios, aunque sus píxeles reales estén en 144, 16 dentro del archivo. Calculas los desplazamientos una sola vez, en píxeles CSS, y la única background-size la declaración en la clase base gestiona la correspondencia de densidad de todos los iconos a la vez.
De aquí se desprenden dos cosas que conviene decir explícitamente. Primero, background-size va en la regla base compartida, no por icono. No sirvas dos hojas mediante consulta de medios sin buen motivo: la 2x a mitad de tamaño funciona también en 1x, reducida por el navegador. Una hoja cubre ambos a cambio de más bytes, normalmente pocos, y evita proporciones físicas fraccionarias como 1.5 y 2.5 donde elegir una versión siempre falla en algún caso.
Variantes de estados y de cursor encima
El diseño clásico de sprites interactivos usa columnas de iconos y filas de estados: normal en la primera, al pasar el cursor en la segunda y activo o desactivado en la tercera. Como no cambian las columnas, cambiar de estado solo desplaza Y y mantiene X.
Con iconos de 24 px y separación de 8 px, la primera fila está en y = 8 y la segunda en y = 40. La regla del tercer icono es background-position: -72px -8px y su regla de cursor encima es background-position: -72px -40px. Si defines el paso vertical como variable, por ejemplo --sprite-row: 32px — puedes expresar hover una vez en la clase base mediante calc() con una variable X por icono, en vez de escribir una segunda regla para cada uno.
Aquí sí gana el sprite: los píxeles de hover llegaron con los normales y el primer hover es inmediato. Mantén estados en la misma hoja; separarlos devuelve el parpadeo de solicitar al primer hover que querías evitar.
Márgenes y por qué la filtración es menor aquí que en juegos
Colocar imágenes contiguas permite que un muestreo cruce el límite del icono y tome color vecino. En motores es un peligro constante y conocido: las texturas se reducen, usan mipmaps y filtros y se dibujan con transformaciones subpíxel arbitrarias.
Los sprites CSS viven en un entorno menos exigente. No hay mipmaps, los fondos normalmente se componen en posiciones enteras y, exactamente a 1:1 sin transformación, ninguna muestra cruza el límite. Pero «menos exigente» no significa «nunca», y los problemas aparecen en situaciones previsibles: relaciones de píxeles del dispositivo fraccionarias (1.5, 2.25, 3), zoom del navegador en porcentajes irregulares, cualquier transform: scale() en un antecesor, y el background-size reducción de la sección retina: todos sitúan los bordes del icono en límites fraccionarios de píxeles físicos, donde el compositor debe interpolar.
La solución es la misma y barata: deja una separación transparente de 2 a 4 píxeles a 1x —4 a 8 en una hoja 2x— entre iconos y alrededor de la hoja. Apenas cuesta bytes y elimina fallos como «una línea tenue solo en mi portátil». La explicación más profunda sobre extrusión, mipmaps y potencias de dos en motores está en Empaquetado de atlas de sprites: márgenes, potencias de dos y filtración.
Problemas habituales
- Iconos vecinos visibles en los bordes. La caja del elemento es mayor que el icono y deja ver contenido de la hoja fuera de él. El ancho o alto es incorrecto, o el relleno del elemento agranda la caja; comprueba si box-sizing: border-box está activo, porque cambia lo que incluye el ancho declarado.
- Olvidar background-repeat: no-repeat. El valor predeterminado es repeat, por lo que la hoja se repite y aparecen fragmentos de otros iconos rellenando el cuadro. Es fácil pasar por alto este problema cuando el icono está cerca del origen de la hoja y parece casi correcto.
- Un span sin dimensiones. Los elementos en línea ignoran width y height por completo, así que un vacío <span> con una clase de sprite queda con tamaño cero y no se renderiza. Configura display: inline-block (o block, o convertirlo en un elemento flex) en la clase base.
- Hoja desactualizada después de recompilar. Reempaquetas, cambian coordenadas, pero un visitante conserva la hoja antigua con CSS nuevo: ve iconos incorrectos mientras tú los ves bien. Renueva la caché cambiando el nombre en cada reconstrucción, con un hash del contenido, sprite.a1b2c3.png) en lugar de depender de parámetros de consulta o de que los usuarios fuercen la recarga.
- Desplazamientos de medio píxel. Los tamaños de icono, separaciones o márgenes iniciales impares en una hoja 2x producen desplazamientos fraccionarios al reducirla a la mitad, y estos causan halos en los bordes. Mantén pares todas las dimensiones de la hoja 2x.
Preguntas frecuentes
¿Están obsoletos los sprites CSS en 2026?
La justificación original está obsoleta; la técnica no. En HTTP/2 y HTTP/3, reducir solicitudes no basta. Para muchos iconos rasterizados pequeños aún importan una entrada de caché, versiones atómicas, carga conjunta y estados inmediatos. Para iconos monocromos, SVG sí ha sustituido al sprite: usar raster en 2026 es elegir peor.
¿Sprite CSS o sprite SVG: cuál debo usar?
Decide según la ilustración, no según la distribución. Si tus iconos son planos, geométricos y monocromos o de dos tonos, usa un sprite SVG: escala sin una hoja 2x y se recolorea mediante currentColor, y reside en el DOM, donde las tecnologías de asistencia pueden acceder a él. Si tus imágenes son fotografías, tienen muchos degradados o son ilustraciones ráster realmente multicolores —banderas, miniaturas de productos, logotipos de plataformas, pixel art—, SVG no ofrece ninguna ventaja y un sprite CSS ráster es la opción adecuada.
¿Qué tamaño puede alcanzar una hoja antes de perjudicar el rendimiento?
Dos límites. En la práctica, la hoja bloquea todos sus iconos: si retrasa el primer dibujo, deja de ayudar. Mantén unos cientos de kilobytes y separa iconos poco usados en otra hoja bajo demanda. Técnicamente, navegadores y móviles limitan dimensiones y memoria; hojas enormes pueden reducirse o no decodificarse. Más de unos 2000 píxeles por lado merece dividirse; recuerda que una hoja 2x duplica tus dimensiones de diseño.
¿Puedo recolorear un icono de sprite con CSS?
No realmente, y esa es la respuesta honesta, no la cómoda. Los colores están incorporados en el archivo rasterizado. Puedes aproximarte con filter — encadenamiento invert, sepia, saturate, y hue-rotate para acercar negro a un tono, pero es un truco: valores por prueba o solucionador, no color de marca exacto, falla en multicolor y es ilegible para quien mantenga el código. Otra hoja en el color alternativo es más honesta. Si necesitas recolorear, usa SVG.
Empaqueta tus iconos en una hoja de sprites
El generador de sprites empaqueta las imágenes que arrastras en una sola hoja con el relleno elegido y escribe las coordenadas para que no tengas que medir desplazamientos a mano. Elige CSS y obtendrás una regla base compartida que contiene background-image, background-repeat: no-repeat y display: inline-block, más una regla por sprite con su valor negativo de background-position y ancho y alto en píxeles: exactamente la estructura anterior. Elige SCSS y la misma salida llega como un %sprite-base marcador de posición que cada regla de icono incorpora mediante @extend. Elige JSON y obtendrás las coordenadas originales de los fotogramas para usarlas con tus propias herramientas. Todo funciona en tu navegador: no se sube nada a ningún sitio.
Abrir Generador de hojas de sprites