Modificar imágenes

Una imagen no se maqueta como un párrafo. Llega con un tamaño propio —el del archivo—, y lo que el CSS hace es decidir cuánto sitio ocupa, qué parte de ella se ve y con qué aspecto se dibuja. Este documento recorre esas tres cosas por separado.

Lo que no se toca en ningún caso es el archivo. Todo lo que sigue es presentación: la foto que el navegador descarga es siempre la misma.

La imagen es un elemento de tipo inline

Un <img> es un elemento de tipo inline: se coloca dentro del renglón, como una palabra más, en vez de ocupar un bloque propio. La consecuencia es que debajo de la imagen aparece una franja de unos pocos píxeles que nadie ha pedido.

No es un margen. Es el espacio que toda línea de texto reserva para las letras que bajan del renglón, la p o la g, y la imagen se apoya en ese renglón como si fuera una letra más. Se quita con display: block, que la saca del renglón y la convierte en un bloque.

la franja de debajo, y cómo se quita

<div class="caja">
  <img src="IMG/naturaleza-valle.jpg" alt="Valle con niebla al amanecer">
</div>

<div class="caja">
  <img class="bloque" src="IMG/naturaleza-valle.jpg" alt="Valle con niebla al amanecer">
</div>

El rojo que asoma bajo la primera es el fondo del contenedor. La segunda, con display: block, no deja ninguno.

Imágenes fluidas

Una imagen trae su propio tamaño, el del archivo, y lo conserva aunque no quepa donde se la pone. Si la foto mide 3000 píxeles de ancho y el contenedor 400, la imagen no se achica sola: se sale de la caja y aparece una barra de desplazamiento horizontal.

Los dos recuadros de abajo miden lo mismo. En el primero la imagen va tal como viene; en el segundo lleva max-width: 100%.

una imagen que no cabe

<p class="rotulo">Sin ninguna regla &mdash; la foto no cabe en el recuadro</p>

<div class="ventana">
  <div class="marco">
    <p class="medida">Este recuadro mide 12rem</p>
    <img class="suelta" src="IMG/naturaleza-valle.jpg" alt="Valle con niebla al amanecer">
  </div>
</div>

<p class="rotulo">Con max-width: 100% &mdash; se ajusta</p>

<div class="marco">
  <p class="medida">Este recuadro mide 12rem</p>
  <img class="ajustada" src="IMG/naturaleza-valle.jpg" alt="Valle con niebla al amanecer">
</div>

La primera atraviesa el borde rojo y sigue hacia la derecha. En una página real no hay nada que la detenga: se sale de la pantalla y el navegador pone una barra de desplazamiento horizontal para toda la página.

Se corrige con tres declaraciones, que conviene escribir juntas desde el primer día:

img {
  max-width: 100%;      /* nunca más ancha que su contenedor */
  height: auto;         /* el alto se recalcula solo */
  display: block;
}

max-width y no width: con max-width la imagen se achica si hace falta, pero no se estira por encima de su tamaño real, que la dejaría borrosa. Y height: auto es imprescindible: sin él, al reducirse el ancho el alto se queda como estaba y la foto se aplasta.

con y sin la regla, en un contenedor estrecho

<p class="rotulo">Sin height: auto &mdash; se deforma</p>
<div class="marco">
  <img class="mal" src="IMG/retrato-rizado.jpg" alt="Primer plano de mujer con pelo rizado">
</div>

<p class="rotulo">Con max-width y height: auto</p>
<div class="marco">
  <img class="bien" src="IMG/retrato-rizado.jpg" alt="Primer plano de mujer con pelo rizado">
</div>

Conviene además escribir width y height en el HTML, con las medidas reales del archivo:

<img src="IMG/valle.jpg" alt="Valle con niebla" width="1600" height="900">

No sirven para dar tamaño —de eso se ocupa el CSS— sino para que el navegador conozca la proporción antes de que la foto llegue y reserve el hueco. Sin ellos, el texto que hay debajo da un salto cuando la imagen termina de cargar.

object-fit: qué parte de la foto se ve

Cuando la caja tiene unas medidas y la foto otra proporción, hay que decidir qué pasa. object-fit tiene tres respuestas.

cover
Llena la caja y recorta lo que sobra. La foto no se deforma. Es el valor que se usa casi siempre.
contain
Mete la foto entera dentro de la caja y deja franjas vacías. Tampoco deforma.
fill
Estira la foto hasta llenar la caja. Deforma. Es el valor por defecto, y casi nunca es lo que se quiere.

la misma foto y la misma caja, con los tres valores

<div class="row">
  <div>
    <p class="rotulo">cover</p>
    <img class="hueco cover" src="IMG/bn-cupula.jpg" alt="Cúpula del Palacio de Bellas Artes">
  </div>
  <div>
    <p class="rotulo">contain</p>
    <img class="hueco contain" src="IMG/bn-cupula.jpg" alt="Cúpula del Palacio de Bellas Artes">
  </div>
  <div>
    <p class="rotulo">fill</p>
    <img class="hueco fill" src="IMG/bn-cupula.jpg" alt="Cúpula del Palacio de Bellas Artes">
  </div>
</div>

object-position: qué trozo se conserva

Con cover el navegador recorta por el centro, y en un retrato eso puede cortar la cabeza. object-position dice qué parte de la foto debe sobrevivir al recorte. Funciona igual que background-position: dos valores, horizontal y vertical, en palabras o en porcentaje.

el mismo recorte, mirando a tres sitios distintos

<div class="row">
  <div>
    <p class="rotulo">top</p>
    <img class="hueco arriba" src="IMG/retrato-contraluz.jpg" alt="Retrato de mujer a contraluz">
  </div>
  <div>
    <p class="rotulo">center (por defecto)</p>
    <img class="hueco centro" src="IMG/retrato-contraluz.jpg" alt="Retrato de mujer a contraluz">
  </div>
  <div>
    <p class="rotulo">bottom</p>
    <img class="hueco abajo" src="IMG/retrato-contraluz.jpg" alt="Retrato de mujer a contraluz">
  </div>
</div>

Dos avisos. object-position no hace nada sin un recorte previo: si la foto cabe entera, no hay nada que desplazar. Y solo desplaza en la dirección en la que sobra foto. Aquí la imagen es vertical y la caja apaisada, así que lo que sobra es alto y top y bottom se notan. Con una foto apaisada en una caja cuadrada ocurriría lo contrario: lo que sobra sería ancho, y habría que escribir left o right.

aspect-ratio: fijar la forma de la caja

Poner un alto en rem funciona hasta que la pantalla cambia de ancho: entonces la caja se vuelve cada vez más apaisada. aspect-ratio declara la forma en vez del alto, y el alto sale del ancho que haya.

tres proporciones, todas con cover

<div class="row">
  <div class="col">
    <p class="rotulo">1 / 1</p>
    <img class="p cuadrada" src="IMG/bn-caballo.jpg" alt="Caballo en blanco y negro">
  </div>
  <div class="col">
    <p class="rotulo">4 / 3</p>
    <img class="p clasica" src="IMG/bn-caballo.jpg" alt="Caballo en blanco y negro">
  </div>
  <div class="col">
    <p class="rotulo">3 / 4</p>
    <img class="p vertical" src="IMG/bn-caballo.jpg" alt="Caballo en blanco y negro">
  </div>
</div>

Estreche la ventana: las tres conservan su forma. Eso es lo que no se consigue con un alto fijo.

border-radius: redondear

Una sola propiedad cubre desde una esquina suavizada hasta el círculo completo. El valor es el radio de la curva; en porcentaje, se mide sobre el tamaño del elemento, de modo que 50% redondea hasta donde se puede: un círculo si la caja es cuadrada, una elipse si no lo es.

cuatro formas con la misma propiedad

<div class="row">
  <div>
    <p class="rotulo">sin nada</p>
    <img class="f" src="IMG/bn-caballo.jpg" alt="Caballo en blanco y negro">
  </div>
  <div>
    <p class="rotulo">esquinas suaves</p>
    <img class="f suave" src="IMG/bn-caballo.jpg" alt="Caballo en blanco y negro">
  </div>
  <div>
    <p class="rotulo">círculo</p>
    <img class="f circulo" src="IMG/bn-caballo.jpg" alt="Caballo en blanco y negro">
  </div>
  <div>
    <p class="rotulo">una esquina</p>
    <img class="f gota" src="IMG/bn-caballo.jpg" alt="Caballo en blanco y negro">
  </div>
</div>

Miniaturas

Una miniatura es una imagen pequeña que representa a una imagen mayor, la cual se abre al pulsarla. Esa es la definición: sin el enlace no hay miniatura, solo una foto pequeña.

El marco no forma parte de la definición, pero es lo que habitualmente permite reconocerla como miniatura. Son tres propiedades: border para la línea, padding para el blanco entre la línea y la foto, y border-radius para suavizar la esquina.

Conviene además que responda al ratón, porque se puede pulsar. Una sombra que aparece con una transition basta.

De qué tamaño es el archivo

El tamaño en pantalla lo fija el CSS con width, pero eso no cambia el archivo que se descarga. Poner width: 10rem sobre una foto de 3000 píxeles hace que el navegador se baje los dos megas enteros para dibujar 160 píxeles. Con doce miniaturas en una página son veinticuatro megas para enseñar una cuadrícula.

Una miniatura existe precisamente para no cargar la grande. Así que son dos archivos: el pequeño en el src y el grande en el href.

<a href="IMG/arroyo.jpg">
  <img src="IMG/arroyo-mini.jpg"
       alt="Arroyo de montaña en un bosque de Trentino"
       width="320" height="240">
</a>

El archivo pequeño se genera al preparar el sitio, con el mismo programa con que se retoca la foto o con una orden de consola. Conviene que sea del orden del doble del tamaño al que se va a ver, para que no se vea borrosa en una pantalla de alta densidad: para una miniatura de 160 píxeles, un archivo de 320.

El width y el height del HTML son los del archivo pequeño, y sirven para reservar el hueco, como se vio al principio. El tamaño final lo sigue decidiendo el CSS.

En el ejemplo de abajo el src apunta al archivo grande porque es el único que hay en la carpeta. En un sitio real sería el reducido.

la misma miniatura, sin marco y con marco

<div class="row">
  <a href="IMG/naturaleza-arroyo.jpg">
    <img class="thumbnail" src="IMG/naturaleza-arroyo.jpg" alt="Arroyo de montaña en un bosque de Trentino">
  </a>

  <a href="IMG/naturaleza-arroyo.jpg" class="enlace">
    <img class="thumbnail enmarcada" src="IMG/naturaleza-arroyo.jpg" alt="Arroyo de montaña en un bosque de Trentino">
  </a>
</div>

<p class="pie">Las dos son enlaces. Solo la segunda se reconoce como miniatura; pase el
ratón por encima.</p>

Tarjetas con sombra

El paso siguiente es envolver la foto en un contenedor con su propio fondo y un texto debajo. La sombra se le da al contenedor, no a la imagen, para que abarque también el pie.

box-shadow recibe cuatro medidas y un color: desplazamiento horizontal, desplazamiento vertical, desenfoque y extensión. Dos sombras separadas por una coma —una corta y densa, otra larga y difusa— imitan mejor cómo se comporta la luz real que una sola.

una tarjeta con su pie

<div class="row">
  <figure class="card">
    <img src="IMG/ciudad-amanecer.jpg" alt="Rascacielos de Ciudad de México al amanecer">
    <figcaption>Ciudad al amanecer</figcaption>
  </figure>

  <figure class="card">
    <img src="IMG/naturaleza-arroyo.jpg" alt="Arroyo de montaña en un bosque de Trentino">
    <figcaption>Arroyo de montaña</figcaption>
  </figure>
</div>

El elemento es <figure> y el pie <figcaption>, que es el HTML que existe para esto: una imagen con su leyenda. Un <div> se vería igual y diría menos.

Filtros

filter aplica a la imagen el mismo tipo de ajuste que un programa de retoque, pero en el navegador y sin tocar el archivo.

grayscale(100%)
Blanco y negro. Admite valores intermedios.
sepia(100%)
Vira a tonos pardos.
blur(.2rem)
Desenfoca. Lleva una medida, no un porcentaje.
brightness(), contrast(), saturate()
Por encima de 100% aumentan; por debajo, reducen.
hue-rotate(90deg)
Gira la rueda de color los grados que se le digan.
invert(100%)
El negativo.
drop-shadow()
Una sombra que sigue la silueta, no el rectángulo. En un PNG con transparencia es la diferencia entre una sombra correcta y una caja flotando.

los ocho filtros sobre la misma foto

<div class="galeria">
  <div><img class="g" src="IMG/naturaleza-valle.jpg" alt="Valle con niebla"><p>sin filtro</p></div>
  <div><img class="g gris" src="IMG/naturaleza-valle.jpg" alt="Valle con niebla"><p>grayscale(100%)</p></div>
  <div><img class="g sepia" src="IMG/naturaleza-valle.jpg" alt="Valle con niebla"><p>sepia(100%)</p></div>
  <div><img class="g borroso" src="IMG/naturaleza-valle.jpg" alt="Valle con niebla"><p>blur(.15rem)</p></div>
  <div><img class="g claro" src="IMG/naturaleza-valle.jpg" alt="Valle con niebla"><p>brightness(140%)</p></div>
  <div><img class="g duro" src="IMG/naturaleza-valle.jpg" alt="Valle con niebla"><p>contrast(180%)</p></div>
  <div><img class="g vivo" src="IMG/naturaleza-valle.jpg" alt="Valle con niebla"><p>saturate(250%)</p></div>
  <div><img class="g girado" src="IMG/naturaleza-valle.jpg" alt="Valle con niebla"><p>hue-rotate(120deg)</p></div>
  <div><img class="g negativo" src="IMG/naturaleza-valle.jpg" alt="Valle con niebla"><p>invert(100%)</p></div>
</div>

drop-shadow frente a box-shadow

Las dos dibujan una sombra, pero no de lo mismo. box-shadow es una propiedad de la caja y proyecta el rectángulo del elemento. filter: drop-shadow() proyecta lo que de verdad se ve, saltándose las partes transparentes.

Sobre una fotografía rectangular las dos se ven igual. La diferencia aparece con un PNG o un SVG con transparencia, como estos iconos.

la misma sombra sobre una imagen con transparencia

<div class="row">
  <div>
    <p class="rotulo">sin sombra</p>
    <img class="icono" src="IMG/bombilla-on.svg" alt="Bombilla encendida">
  </div>
  <div>
    <p class="rotulo">box-shadow</p>
    <img class="icono caja" src="IMG/bombilla-on.svg" alt="Bombilla encendida">
  </div>
  <div>
    <p class="rotulo">filter: drop-shadow</p>
    <img class="icono silueta" src="IMG/bombilla-on.svg" alt="Bombilla encendida">
  </div>
</div>

En la segunda se ve el recuadro del archivo, que no debería verse. En la tercera, la sombra sigue el contorno de la bombilla. Para iconos y logotipos recortados la buena es siempre drop-shadow.

Los filtros se pueden encadenar separándolos por espacios, y se aplican en el orden escrito:

filter: grayscale(100%) contrast(130%) brightness(90%);

Un filtro es una propiedad animable, así que admite transition. El recurso más común en una galería es tener las fotos en blanco y negro y devolverles el color cuando el ratón pasa por encima.

el color vuelve al pasar el ratón

<div class="row">
  <img class="apagada" src="IMG/naturaleza-arroyo.jpg" alt="Arroyo de montaña en un bosque de Trentino">
  <img class="apagada" src="IMG/ciudad-amanecer.jpg" alt="Rascacielos de Ciudad de México al amanecer">
  <img class="apagada" src="IMG/retrato-rizado.jpg" alt="Primer plano de mujer con pelo rizado">
</div>

Centrar una imagen

Una imagen de tipo block se centra como cualquier otro elemento de tipo block: con márgenes laterales automáticos. No funciona mientras siga siendo de tipo inline, así que display: block va primero.

img {
  display: block;
  margin-inline: auto;     /* margen izquierdo y derecho automáticos */
  max-width: 100%;
}

Si la imagen está dentro de un contenedor flex o grid, no hace falta nada de esto: justify-content: center en el padre hace el trabajo.

<img> o background-image

Una foto puede ponerse de dos maneras, y la elección no es de gusto.

<img>background-image
Qué es Contenido del documento Decoración de una caja
Texto alternativo Sí, con alt No existe
La encuentra un buscador Sí No
Sale al imprimir Sí A menudo no
Encaje en la caja object-fit background-size
Para qué sirve Una fotografía que importa Texturas, degradados, adornos

La regla práctica: si quitando la imagen la página pierde información, es un <img>. Si solo pierde adorno, es un fondo.

Resumen

  1. display: block en las imágenes, siempre: un <img> nace de tipo inline, y eso deja una franja debajo e impide centrarlo con márgenes automáticos.
  2. max-width: 100% con height: auto. Un alto fijo deforma.
  3. width y height en el HTML reservan el hueco y evitan el salto al cargar; el tamaño lo sigue dando el CSS.
  4. object-fit: cover llena sin deformar; object-position decide qué trozo se conserva.
  5. aspect-ratio en lugar de un alto fijo.
  6. border-radius: 50% da un círculo solo si la caja es cuadrada.
  7. filter es animable, de ahí el blanco y negro que recupera el color.
  8. Lo que es contenido va en <img> con su alt; lo que es adorno, en background-image.

Reconocimientos

Las fotos son de Pexels, con licencia libre: se pueden usar y modificar sin pagar y sin citar la fuente. Citarla no es obligatorio, pero es lo correcto, y aquí sirve además de ejemplo de cómo se hace.