image-set() en CSS: cómo crear imágenes de fondo responsive y nítidas

Ejemplo de image-set() en CSS con imágenes de fondo 1x, 2x y 3x

Hay imágenes de fondo que se ven perfectas en un portátil y, al abrir la misma web en una pantalla Retina o de alta densidad, pierden nitidez. La solución rápida suele ser utilizar una imagen mucho más grande, pero eso tiene un precio: todos los usuarios terminan descargando un archivo más pesado, aunque su pantalla no necesite esa resolución.

En HTML llevamos años resolviendo situaciones parecidas con srcset y <picture>. Para las imágenes utilizadas desde CSS existe otra opción muy interesante: image-set(). Con ella podemos proporcionar varias versiones de una imagen y dejar que el navegador seleccione el candidato adecuado, por ejemplo una versión 1x para una pantalla convencional y otra 2x para una pantalla de mayor densidad.

La idea parece sencilla, y lo es, pero conviene entender bien qué hace image-set() y qué no hace. No sustituye a srcset, no convierte por sí solo cualquier fondo en responsive y tampoco garantiza una mejora de rendimiento. Utilizado en el lugar correcto, sin embargo, es una herramienta muy práctica para conseguir imágenes de fondo nítidas sin servir siempre el archivo de mayor resolución.

Respuesta rápida

image-set() es una función CSS que permite ofrecer al navegador varias versiones de una misma imagen para que seleccione la más apropiada. Podemos declarar, por ejemplo, archivos 1x, 2x y 3x según su resolución. Resulta especialmente útil con background-image para mantener la nitidez en pantallas de alta densidad sin obligar a todos los dispositivos a utilizar siempre la imagen más pesada.

Índice

¿Qué es image-set() en CSS?

image-set() es una función de CSS que permite declarar un conjunto de imágenes candidatas para una propiedad que acepte imágenes. En lugar de indicar una única URL, proporcionamos varias alternativas acompañadas de información que ayuda al navegador a elegir cuál utilizar.

Uno de sus usos más claros está en background-image. Imaginemos un hero cuya imagen de fondo tiene una versión normal y otra preparada para pantallas de alta densidad. En lugar de cargar siempre la segunda, podemos ofrecer las dos.

.hero {
  background-image: image-set(
    url("/img/hero-1x.webp") 1x,
    url("/img/hero-2x.webp") 2x
  );
}

Con esta declaración no estamos diciendo al navegador qué archivo debe descargar en cada dispositivo. Le estamos proporcionando candidatos para que pueda seleccionar el que considere apropiado.

image-set() forma parte de CSS Images Module Level 4 del W3C. Actualmente tiene una compatibilidad suficientemente amplia como para plantearse su utilización en proyectos modernos, aunque siempre conviene revisar los navegadores que necesita soportar cada proyecto.

¿Cómo funciona image-set()?

La lógica se entiende mejor si dejamos de pensar en tamaños de pantalla durante un momento. image-set() trabaja principalmente con candidatos de imagen y su resolución.

Podemos tener tres archivos que representan exactamente el mismo gráfico:

  • hero-1x.webp: resolución estándar.
  • hero-2x.webp: el doble de resolución.
  • hero-3x.webp: el triple de resolución.

CSS permite declararlos de esta manera:

.hero {
  background-image: image-set(
    url("/img/hero-1x.webp") 1x,
    url("/img/hero-2x.webp") 2x,
    url("/img/hero-3x.webp") 3x
  );
}

El navegador dispone entonces de varias alternativas. Esto es bastante mejor que establecer directamente hero-3x.webp como fondo para todo el mundo, porque una pantalla que no pueda aprovechar esa resolución estaría descargando bytes que no aportan una mejora visual equivalente.

Ejemplo práctico de image-set() con background-image

Supongamos que tenemos un hero de una web que ocupa todo el ancho disponible. Queremos mantener la imagen de fondo nítida tanto en una pantalla convencional como en dispositivos de alta densidad.

.hero {
  min-height: 500px;
  background-image: image-set(
    url("/img/hero-1x.webp") 1x,
    url("/img/hero-2x.webp") 2x,
    url("/img/hero-3x.webp") 3x
  );
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
}

Hay un detalle importante aquí. image-set() decide entre los recursos disponibles, mientras que background-size: cover controla cómo se representa la imagen dentro del elemento. Son dos problemas diferentes.

Esta distinción parece menor, pero evita uno de los errores más habituales al hablar de imágenes responsive en CSS: mezclar resolución de imagen, dimensiones del elemento y adaptación del diseño como si fueran exactamente lo mismo.

¿Qué significan 1x, 2x y 3x?

Los valores 1x, 2x y 3x son descriptores de resolución. De forma simplificada, indican para qué densidad está preparado cada recurso.

DescriptorResoluciónUso habitual
1x1 dppxPantallas de densidad estándar
2x2 dppxPantallas de alta densidad
3x3 dppxPantallas de densidad todavía mayor

También podemos utilizar otras unidades de resolución admitidas por CSS, como dppx, dpi o dpcm. En la práctica, la notación con x suele resultar especialmente fácil de leer cuando trabajamos con variantes de una misma imagen.

Un ejemplo para entender el Device Pixel Ratio

Imaginemos una imagen que visualmente ocupa 600 × 300 píxeles CSS. En una pantalla con un Device Pixel Ratio (DPR) de 2, esa superficie puede representarse utilizando aproximadamente 1.200 × 600 píxeles físicos.

Si el recurso original tiene únicamente 600 × 300 píxeles, el navegador no dispone de información visual adicional para aprovechar esa mayor densidad. Una variante 2x de 1.200 × 600 puede conseguir un resultado considerablemente más nítido.

Eso no significa que debamos crear versiones 3x de todas las imágenes de una web. Cada variante añade almacenamiento, mantenimiento y, cuando es seleccionada, transferencia. Hay que utilizar la resolución que aporte una mejora real.

image-set() vs srcset: ¿cuál es la diferencia?

La comparación con srcset ayuda a entender image-set(), pero no son dos nombres para la misma herramienta.

Característicaimage-set()srcset
Se utiliza enCSSHTML
Uso con background-imageSíNo directamente
Selección por densidadSíSí
Candidatos por anchuraNo funciona como srcset con descriptores wSí
Uso con sizesNoSí
Imagen de contenidoNo suele ser la opción adecuadaSí
Imagen decorativa de fondoMuy útilNo

Cuándo utilizar srcset

Si la imagen forma parte del contenido de la página, normalmente deberíamos empezar pensando en HTML. srcset, sizes y el elemento <picture> ofrecen herramientas específicas para servir imágenes adaptadas a diferentes situaciones.

En la guía sobre cómo renderizar imágenes responsive en HTML explico con más detalle cómo funcionan <picture>, srcset y sizes.

Cuándo utilizar image-set()

image-set() tiene mucho más sentido cuando la imagen pertenece a CSS: un fondo decorativo, determinados elementos de interfaz o recursos para los que queremos proporcionar alternativas de resolución.

Una regla práctica que utilizo es sencilla: si quitar la imagen hace que se pierda información necesaria para comprender la página, probablemente debería plantearme si realmente tiene que ser un background-image.

Cómo conseguir imágenes de fondo nítidas en pantallas Retina

Cuando una imagen se ve borrosa en una pantalla Retina, el problema no suele solucionarse añadiendo una propiedad CSS que “aumente la calidad”. Si el archivo no contiene suficiente información visual para la densidad con la que se está mostrando, CSS no puede inventarla.

Por eso image-set() resulta útil. Podemos preparar un recurso de resolución estándar y otro con mayor resolución, manteniendo las mismas proporciones.

.cabecera {
  background-image: image-set(
    url("/img/cabecera.webp") 1x,
    url("/img/cabecera@2x.webp") 2x
  );
}

La versión 2x contiene más píxeles, pero se utiliza para representar el mismo fondo a un tamaño CSS equivalente. Esa mayor cantidad de información es la que permite aprovechar una pantalla de mayor densidad.

No hay que confundir esta técnica con image-rendering: pixelated. Esta última tiene otra finalidad, como explico en la guía sobre cómo mantener pixel art nítido con CSS.

¿image-set() hace realmente responsive un background?

No por sí solo. Y este es probablemente el matiz más importante de toda la explicación.

Un diseño responsive puede tener que reaccionar al ancho del viewport, al tamaño del contenedor, a la orientación, a la relación de aspecto o incluso necesitar una composición visual distinta en móvil y escritorio. image-set() no sustituye todo eso.

Su función es proporcionar candidatos de imagen. Para controlar otros aspectos podemos seguir necesitando propiedades como background-size y background-position, además de media queries cuando el diseño lo requiera.

Por ejemplo, quizá en escritorio queramos una fotografía panorámica y en móvil necesitemos un encuadre vertical completamente diferente. Eso ya no es simplemente un problema de densidad, sino de dirección artística.

Las media queries en CSS siguen teniendo sentido cuando queremos cambiar el diseño o los recursos en función de determinadas características del dispositivo o del viewport.

Cómo utilizar AVIF y WebP con image-set()

Otra posibilidad interesante de image-set() es indicar el tipo MIME de los candidatos mediante type(). Esto permite proporcionar imágenes en diferentes formatos y que el navegador descarte aquellos que no admite. La documentación de image-set() en MDN recoge tanto el uso de descriptores de resolución como la selección de formatos mediante type().

.hero {
  background-image: image-set(
    url("/img/hero.avif") type("image/avif"),
    url("/img/hero.webp") type("image/webp"),
    url("/img/hero.jpg") type("image/jpeg")
  );
}

Resolución y formato son dos cuestiones distintas. Una responde a qué densidad tiene el recurso y la otra a qué formato puede utilizar el navegador. La sintaxis de image-set() permite trabajar con ambas.

Eso tampoco significa que AVIF sea automáticamente mejor en cualquier imagen. El resultado depende del tipo de gráfico, la configuración de compresión y la calidad que necesitemos. Lo importante es comparar el peso y el resultado visual, no escoger un formato únicamente porque sea más moderno.

¿Puede image-set() mejorar el rendimiento web?

Puede ayudar, pero utilizar image-set() no hace que una web sea automáticamente más rápida.

La ventaja aparece cuando evitamos servir innecesariamente un recurso sobredimensionado. Si una versión 1x ofrece toda la resolución que necesita un dispositivo, no tiene mucho sentido obligarlo a descargar la variante 2x o 3x.

Pero podemos implementar perfectamente image-set() y seguir teniendo imágenes demasiado pesadas. Una fotografía 1x mal comprimida puede pesar más que una versión 2x bien optimizada.

Por eso esta técnica debería formar parte de una estrategia más amplia de optimización de imágenes para web: dimensiones razonables, compresión, formatos apropiados y una decisión correcta sobre qué recurso necesita realmente cada contexto.

image-set() y Core Web Vitals

Aquí conviene evitar otra conclusión demasiado rápida: utilizar image-set() no mejora directamente los Core Web Vitals por el simple hecho de estar presente en el CSS.

Puede contribuir a reducir transferencia si permite seleccionar un recurso más apropiado, pero hay que observar el comportamiento completo de la página.

Cuidado si el background es el LCP

Un caso especialmente delicado aparece cuando la imagen de fondo pertenece al elemento que termina siendo el Largest Contentful Paint (LCP). Una imagen referenciada desde CSS puede descubrirse más tarde que una imagen presente directamente en el HTML, porque el navegador necesita encontrar y procesar primero la hoja de estilos.

Por tanto, si la gran imagen del hero es crítica para el LCP, no elegiría background-image simplemente por comodidad. Primero valoraría si puede implementarse correctamente como una imagen HTML responsive.

Cuando reviso este tipo de problemas prefiero analizar el conjunto —recurso LCP, prioridad, peso, CSS, servidor y comportamiento real— en lugar de intentar arreglar una métrica cambiando una sola propiedad. Es el mismo enfoque que aplico al trabajo de optimización y rendimiento web.

Una limitación importante para SEO y accesibilidad

Hay una razón adicional para no convertir todas las imágenes de una página en fondos CSS: Google recomienda utilizar elementos de imagen HTML para las imágenes que queremos que pueda encontrar y procesar como tales, y especifica que no indexa las imágenes CSS. Esta recomendación aparece expresamente en la documentación oficial de Google Search Central sobre SEO para imágenes.

Si tenemos una fotografía de producto, una infografía, una captura que explica un proceso o cualquier imagen con valor propio como contenido, utilizarla exclusivamente mediante background-image puede ser una mala decisión desde el punto de vista de búsqueda de imágenes.

También existe una cuestión de accesibilidad. Una imagen de fondo CSS no dispone del equivalente semántico al atributo alt de un <img>, y los lectores de pantalla no reciben de forma automática la información visual que contiene.

Por eso separaría los casos de esta manera:

Tipo de imagenOpción habitual
Fotografía o gráfico que forma parte del contenido<img>, srcset o <picture>
Imagen importante para Google ImágenesElemento HTML de imagen
Imagen que necesita texto alternativo<img> con un alt apropiado
Fondo puramente decorativobackground-image puede ser adecuado
Fondo decorativo con varias densidadesimage-set() es una buena opción

En otras palabras, la decisión no debería empezar preguntando “¿puedo hacerlo con CSS?”, sino “¿qué función cumple esta imagen?”.

Compatibilidad de image-set() con navegadores

image-set() ya puede considerarse una característica ampliamente disponible en los navegadores modernos. MDN clasifica image-set() como Baseline Widely Available y sitúa su disponibilidad general entre navegadores desde septiembre de 2023.

Eso cambia bastante la situación respecto a años atrás, cuando era habitual encontrar ejemplos con -webkit-image-set() o recomendaciones que trataban la función como algo experimental.

Aun así, no asumiría que absolutamente todas las posibilidades descritas por las especificaciones tienen idéntico soporte. Si el proyecto necesita funcionar en navegadores antiguos o estamos utilizando combinaciones avanzadas de resolución y formatos, merece la pena comprobar la compatibilidad concreta antes de desplegar.

Errores frecuentes al utilizar image-set()

1. Confundir densidad con tamaño de pantalla

Un móvil pequeño puede tener una densidad de píxeles muy superior a la de un monitor grande. 2x no significa “imagen para escritorio” ni 1x significa “imagen para móvil”.

2. Crear siempre versiones 1x, 2x y 3x

No existe ninguna obligación de proporcionar tres archivos. Si 1x y 2x resuelven correctamente el caso de uso, añadir una versión 3x puede aumentar el trabajo y el almacenamiento sin una mejora perceptible que lo justifique.

3. No comprimir las variantes

Generar una versión 2x y guardarla sin optimizar puede disparar su peso. Mayor resolución no debería significar carta blanca para servir archivos enormes.

4. Utilizar un background para una imagen de contenido

Que técnicamente podamos mostrar una imagen mediante CSS no significa que sea la implementación semánticamente correcta. SEO, accesibilidad y rendimiento pueden hacer preferible un elemento <img>.

5. Pensar que image-set() sustituye a las media queries

Si queremos cambiar completamente el encuadre, el diseño o el recurso en función del viewport, podemos seguir necesitando media queries. Resolver densidad y resolver layout son problemas distintos.

6. Utilizarlo en el hero sin comprobar el LCP

Un fondo visualmente perfecto no compensa un hero que comienza a descargarse demasiado tarde. Si la imagen es crítica para la carga inicial, conviene medir el resultado con datos en lugar de asumir que la implementación es óptima.

Buenas prácticas para imágenes responsive en CSS

  • Utiliza image-set() cuando realmente necesites candidatos de diferente resolución o formato.
  • No confundas DPR con anchura del viewport.
  • Genera únicamente las variantes que aporten una diferencia visual útil.
  • Comprime todas las versiones de la imagen.
  • Valora WebP y AVIF, pero compara siempre peso y calidad.
  • Utiliza background-size y background-position para controlar cómo se representa el fondo.
  • Utiliza media queries cuando necesites adaptar el diseño o realizar dirección artística.
  • Prefiere imágenes HTML cuando el recurso forme parte del contenido.
  • No utilices fondos CSS para imágenes que necesiten texto alternativo.
  • Comprueba el LCP cuando la imagen se encuentre en la parte superior de la página.
  • Mide el resultado final en dispositivos y resoluciones diferentes.

Al final, la optimización técnica rara vez depende de una única propiedad. Una implementación limpia consiste en elegir la herramienta adecuada para cada problema. Es también la filosofía que aplico en SEO técnico, rendimiento y desarrollo web: antes de optimizar algo hay que entender qué está ocurriendo realmente y qué impacto tiene.

Preguntas frecuentes sobre image-set() en CSS

¿Qué es image-set() en CSS?

image-set() es una función CSS que permite proporcionar varias imágenes candidatas para que el navegador seleccione la opción apropiada. Puede utilizar información como la resolución de los recursos y también permite declarar tipos de imagen mediante type().

¿Para qué sirven 1x, 2x y 3x?

Son descriptores de resolución. 1x equivale a 1 dppx, 2x a 2 dppx y 3x a 3 dppx. Permiten identificar variantes de una imagen preparadas para distintas densidades.

¿Cuál es la diferencia entre image-set() y srcset?

image-set() pertenece a CSS y resulta útil para propiedades como background-image. srcset se utiliza en HTML con imágenes de contenido y puede combinarse con sizes para proporcionar candidatos según el tamaño que ocupará la imagen.

¿Se puede utilizar srcset con background-image?

No directamente. srcset es un atributo HTML asociado a elementos de imagen. Para proporcionar diferentes candidatos dentro de propiedades CSS puede utilizarse image-set() o recurrir a media queries dependiendo del problema que queramos resolver.

¿Cómo evito que una imagen de fondo se vea borrosa en una pantalla Retina?

Una opción es proporcionar una variante con mayor resolución mediante image-set(). Por ejemplo, podemos declarar una imagen estándar como 1x y una versión con el doble de resolución como 2x, manteniendo el tamaño visual que debe ocupar el fondo.

¿El navegador descarga todas las imágenes de image-set()?

La finalidad de image-set() es permitir que el navegador seleccione una imagen entre los candidatos disponibles, en lugar de necesitar todos los recursos para representar el mismo fondo. La selección concreta corresponde al agente de usuario.

¿image-set() mejora los Core Web Vitals?

No de forma automática. Puede evitar transferir una imagen de resolución innecesariamente alta, pero métricas como LCP dependen también de cuándo se descubre el recurso, su prioridad, peso, respuesta del servidor y otros factores de carga.

¿Puedo utilizar AVIF y WebP con image-set()?

Sí. image-set() permite declarar el tipo MIME de los candidatos mediante type(), por ejemplo type("image/avif") o type("image/webp").

¿image-set() sustituye a las media queries?

No. image-set() permite ofrecer candidatos de imagen, mientras que las media queries permiten aplicar reglas según características como el viewport. Pueden utilizarse para resolver necesidades diferentes dentro del mismo diseño.

¿Google indexa las imágenes utilizadas como background CSS?

Google indica en su documentación de SEO para imágenes que no indexa imágenes CSS y recomienda utilizar elementos de imagen HTML estándar para ayudar a sus rastreadores a descubrir y procesar imágenes. Si una imagen tiene valor como contenido o queremos que pueda aparecer en Google Imágenes, no conviene depender exclusivamente de background-image.

Conclusión: image-set() es útil cuando se utiliza para el problema correcto

image-set() resuelve de una forma bastante elegante algo que durante años ha requerido soluciones más manuales: proporcionar diferentes versiones de una imagen utilizada desde CSS y permitir que el navegador escoja entre ellas.

Para un fondo decorativo que debe verse nítido tanto en una pantalla convencional como en una Retina, tiene mucho sentido. Podemos preparar variantes 1x y 2x, optimizarlas correctamente y evitar servir siempre el archivo de mayor resolución.

Lo que no haría es convertir image-set() en la respuesta universal para las imágenes responsive. Si la imagen forma parte del contenido, <img>, srcset, sizes y <picture> siguen siendo herramientas fundamentales. Si necesitamos adaptar el diseño al viewport, las media queries siguen ahí. Y si el fondo es responsable del LCP, merece la pena estudiar cómo y cuándo empieza a cargarse.

La ventaja de conocer image-set() no está en utilizarlo en todas partes, sino en saber que existe y reconocer cuándo es exactamente la herramienta que necesitamos.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *