Imágenes en CSS
En esta lección
Las imágenes suelen ser lo que más pesa y lo que más se “rompe” en una web: se salen de su caja, se deforman, dejan huecos raros. En esta lección aprenderás a hacer que se adapten al espacio disponible, a recortarlas sin deformarlas, a reservar su hueco con aspect-ratio y a aplicarles filtros y formas. Terminarás montando una galería de miniaturas.
Lo que toca al HTML (el atributo alt, srcset, <picture>, la carga diferida) está en las lecciones de imágenes e imágenes responsive del curso de HTML.
La base: imágenes que no se salen
Por defecto, una imagen se muestra a su tamaño real. Si mide 2000 px y el móvil 400 px, se sale de la pantalla y aparece scroll horizontal. La solución es esta regla, que casi todos los proyectos incluyen al principio:
img {
max-width: 100%; /* nunca más ancha que su contenedor */
height: auto; /* el alto se ajusta para no deformar */
display: block; /* quita el hueco de debajo */
}
Por qué max-width y no width
width: 100%estira la imagen hasta ocupar todo el ancho, aunque sea un icono de 32 px. Queda pixelada.max-width: 100%solo la encoge si no cabe. Si es pequeña, se queda a su tamaño.
Por qué height: auto
Si en el HTML pusiste width="800" height="600" (y deberías, porque ayuda al navegador a reservar espacio), al encoger la imagen con CSS el alto seguiría siendo 600 px y la foto se aplastaría. height: auto recalcula el alto manteniendo la proporción.
Por qué display: block
<img> es un elemento en línea, como una letra. Se coloca sobre la línea base del texto y deja debajo un hueco de unos pocos píxeles reservado para las letras que bajan (como la “g” o la “p”). Ese hueco misterioso bajo las fotos desaparece al hacerla de bloque. Tienes más sobre esto en display.
object-fit: encajar sin deformar
Cuando fuerzas un ancho y un alto que no respetan la proporción original, la imagen se deforma:
.miniatura {
width: 200px;
height: 200px; /* la foto era apaisada: ahora sale aplastada */
}
object-fit decide cómo se encaja la imagen dentro de esa caja, igual que background-size con los fondos:
.miniatura {
width: 200px;
height: 200px;
object-fit: cover;
}
| Valor | Qué hace |
|---|---|
fill | Estira la imagen hasta llenar la caja. Deforma (por defecto) |
cover | Llena la caja manteniendo la proporción. Recorta lo que sobra |
contain | Muestra la imagen entera. Puede dejar bandas vacías |
none | Tamaño original, recortado por la caja |
scale-down | Como none o contain, el que dé la imagen más pequeña |
cover es el que usarás el 90 % de las veces: avatares, tarjetas de producto, miniaturas. contain va mejor con logos, donde recortar sería un desastre.
object-position: qué parte se ve
Con cover se recorta algo. Por defecto, el centro. Si lo importante está arriba (una cara, por ejemplo), muévelo:
.avatar {
width: 80px;
height: 80px;
border-radius: 50%;
object-fit: cover;
object-position: center top; /* o 50% 20% */
}
Funciona igual que background-position: palabras (top, left…) o porcentajes.
aspect-ratio: la proporción de la caja
aspect-ratio fija la relación entre ancho y alto. Tú das el ancho y el navegador calcula el alto:
.video { aspect-ratio: 16 / 9; width: 100%; }
.miniatura { aspect-ratio: 1; } /* cuadrada: equivale a 1 / 1 */
.retrato { aspect-ratio: 3 / 4; }
Combinado con object-fit, es la forma moderna de conseguir imágenes todas iguales aunque las fotos originales tengan tamaños distintos:
.producto img {
width: 100%;
aspect-ratio: 4 / 3;
object-fit: cover;
}
Cada tarjeta de la tienda tendrá una foto de 4:3, venga como venga el archivo.
aspect-ratio sirve para cualquier caja, no solo imágenes: un <iframe> de YouTube, un mapa, un <div> con fondo. Antes se usaba un truco con padding-top: 56.25%; ya no hace falta.
Consejo: poner
widthyheighten la etiqueta<img>hace que el navegador calcule solo elaspect-ratioy reserve el hueco antes de que llegue la imagen. Así el texto no “salta” al cargar la página.
Filtros: filter
filter aplica efectos de edición de fotos directamente desde CSS. La imagen original no cambia; el navegador la retoca al pintarla.
.gris { filter: grayscale(1); } /* blanco y negro: 0 a 1 */
.borrosa { filter: blur(4px); } /* desenfoque */
.clara { filter: brightness(1.2); } /* 1 = normal, más = más brillo */
.contraste { filter: contrast(1.3); }
.sepia { filter: sepia(0.8); }
.saturada { filter: saturate(1.5); }
.negativo { filter: invert(1); }
.tono { filter: hue-rotate(90deg); } /* gira los colores */
Puedes encadenar varios, separados por espacios:
.antigua { filter: sepia(0.6) contrast(1.1) brightness(0.95); }
Efecto al pasar el ratón
Un uso clásico: fotos del equipo en gris que recuperan el color al pasar por encima.
.equipo img {
filter: grayscale(1);
transition: filter 0.3s;
}
.equipo img:hover {
filter: grayscale(0);
}
La transición se explica en transiciones y animaciones.
drop-shadow: sombra con la forma real
box-shadow siempre dibuja una sombra rectangular (o con la forma del border-radius). Si tienes un PNG o un SVG con transparencia, como un logo, drop-shadow sigue el contorno real del dibujo:
.logo {
filter: drop-shadow(0 4px 6px rgb(0 0 0 / 0.3));
}
Sus valores son los de box-shadow, pero sin expansión ni inset.
Cuidado:
blur()ydrop-shadow()sobre imágenes grandes o muchos elementos cuestan rendimiento, sobre todo si se animan. Úsalos con mesura.
Mezclas y recortes
mix-blend-mode en pocas palabras
Decide cómo se mezclan los colores de un elemento con lo que tiene detrás, como los modos de capa de un programa de edición:
.titulo-sobre-foto {
color: white;
mix-blend-mode: difference; /* invierte según el fondo */
}
.logo-con-fondo-blanco {
mix-blend-mode: multiply; /* el blanco desaparece sobre fondos claros */
}
multiply es el más práctico: hace que el fondo blanco de un logo en JPG se “funda” con un fondo de color claro. Para fondos múltiples existe también background-blend-mode.
clip-path: recortar con formas
clip-path recorta el elemento con una forma. Lo que queda fuera no se ve (ni recibe clics):
.circulo { clip-path: circle(50%); }
.elipse { clip-path: ellipse(50% 35%); }
.rombo { clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%); }
.diagonal { clip-path: polygon(0 0, 100% 0, 100% 85%, 0 100%); } /* cabecera con corte inclinado */
En polygon() das los puntos de la forma como pares x y, en porcentajes del elemento, empezando arriba a la izquierda. Para formas sencillas como un círculo es más fácil border-radius: 50%; clip-path brilla con polígonos y cortes diagonales.
Imagen de fondo o <img>: cuándo usar cada una
Ya viste las imágenes de fondo en fondos, bordes y sombras. La pregunta clave es: ¿la imagen es contenido o decoración?
<img> en el HTML | background-image en el CSS | |
|---|---|---|
| Qué es | Contenido: aporta información | Decoración |
| Texto alternativo | Sí, con alt | No: los lectores de pantalla la ignoran |
| La indexa Google Imágenes | Sí | Normalmente no |
| Carga diferida | loading="lazy" | No de forma nativa |
| Imágenes según pantalla | srcset y <picture> | Media queries o image-set() |
| Recorte | object-fit | background-size |
| Ejemplos | Foto de un producto, gráfico, foto de una noticia | Textura, portada decorativa detrás de un titular |
Regla práctica: si al quitar la imagen se pierde información, va en <img>. Si solo se pierde “ambiente”, puede ir de fondo.
Ejemplo completo: galería de miniaturas
Juntamos todo: una rejilla que se adapta al ancho, miniaturas cuadradas sin deformar y un efecto al pasar el ratón.
<ul class="galeria">
<li><a href="img/sala-1.jpg"><img src="img/sala-1-mini.jpg" alt="Sala de musculación" width="400" height="300"></a></li>
<li><a href="img/sala-2.jpg"><img src="img/sala-2-mini.jpg" alt="Sala de spinning" width="400" height="300"></a></li>
<li><a href="img/piscina.jpg"><img src="img/piscina-mini.jpg" alt="Piscina climatizada" width="400" height="600"></a></li>
</ul>
.galeria {
list-style: none;
padding: 0;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 12px;
}
.galeria img {
display: block;
width: 100%;
aspect-ratio: 1;
object-fit: cover;
border-radius: 8px;
transition: transform 0.3s, filter 0.3s;
}
.galeria a:hover img,
.galeria a:focus-visible img {
transform: scale(1.03);
filter: brightness(1.1);
}
Fíjate en tres detalles:
- La foto de la piscina es vertical (400 x 600), pero
aspect-ratio: 1yobject-fit: coverla dejan cuadrada como las demás. repeat(auto-fill, minmax(150px, 1fr))crea tantas columnas como quepan, sin media queries. Lo tienes explicado en Grid.- El efecto también se activa con
:focus-visible, para quien navega con el teclado.
Errores frecuentes
- Poner
widthyheightfijos sinobject-fit. La imagen se deforma. Añadeobject-fit: cover. - Usar
width: 100%en todas las imágenes. Los iconos pequeños se estiran y pixelan. Usamax-width: 100%. - Olvidar
height: autocuando el HTML tieneheight. La foto se aplasta al encogerse. - El hueco de unos píxeles bajo la imagen. Es por ser en línea:
display: blocklo elimina. - Poner fotos importantes como fondo. Se pierde el
alty la accesibilidad. - Confundir
object-fitconbackground-size. El primero es para<img>y<video>; el segundo, para fondos. - Recortar con
object-fit: covery cortar la parte importante. Ajustaobject-position. - Animar
blur()en muchas imágenes. Va lento en móviles modestos.
Resumen
| Propiedad | Para qué sirve | Ejemplo |
|---|---|---|
max-width: 100% | Que la imagen no se salga | En la regla base de img |
height: auto | Mantener la proporción | Junto a max-width |
display: block | Quitar el hueco inferior | En la regla base de img |
object-fit | Encajar sin deformar | cover, contain |
object-position | Qué parte se ve al recortar | center top |
aspect-ratio | Proporción de la caja | 16 / 9, 1 |
filter | Efectos de color y desenfoque | grayscale(1) blur(2px) |
drop-shadow() | Sombra con la forma real | Logos PNG o SVG |
mix-blend-mode | Mezclar con lo de detrás | multiply |
clip-path | Recortar con una forma | polygon(...), circle(50%) |
Con las imágenes bajo control, el siguiente paso es dar estilo a otros elementos muy comunes: listas y tablas.
Pruébalo tú
Cambia el código y pulsa Ejecutar (o Ctrl + Enter).
Pon a prueba lo que has aprendido
¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.