Saltar al contenido
filtros-y-efectos.css · devschool

Filtros y efectos visuales en CSS

Lección 27 de 50 · 10 min de lectura · Actualizado el

En esta lección
  1. filter: retoques sobre cualquier elemento
  2. backdrop-filter: el efecto cristal
  3. Modos de fusión
  4. clip-path: recortar con formas
  5. Máscaras: mask-image
  6. Rendimiento y efectos secundarios
  7. Errores frecuentes
  8. Resumen

CSS no solo coloca cajas: también puede retocarlas como un programa de edición de imágenes. Puede desenfocar, pasar a blanco y negro, mezclar colores como las capas de un editor, recortar con formas o difuminar los bordes. En esta lección verás filter aplicado a cualquier elemento, el efecto cristal con backdrop-filter, los modos de fusión, los recortes con clip-path y las máscaras. Y, sobre todo, cuándo usarlos sin hundir el rendimiento de la página.

En imágenes en CSS ya viste los filtros sobre fotos, object-fit para encajarlas y una primera mirada a clip-path. Aquí vamos más allá.

filter: retoques sobre cualquier elemento

filter aplica efectos al elemento y a todo lo que contiene: texto, bordes, hijos. No solo sirve para imágenes.

FunciónQué haceValor normal
blur(4px)Desenfoca0
brightness(1.2)Más o menos brillo1
contrast(1.3)Más o menos contraste1
grayscale(1)Blanco y negro0
sepia(0.8)Tono envejecido0
saturate(1.5)Intensidad del color1
invert(1)Negativo0
hue-rotate(90deg)Gira todos los colores del círculo cromático0deg
opacity(0.5)Transparencia1
drop-shadow(...)Sombra con la forma realsin sombra

Los valores numéricos admiten también porcentajes: grayscale(100%) es lo mismo que grayscale(1).

El orden cuenta

Puedes encadenar varias funciones separadas por espacios. Se aplican de izquierda a derecha, cada una sobre el resultado de la anterior:

.a { filter: grayscale(1) sepia(1); }   /* gris y luego sepia: tono marrón */
.b { filter: sepia(1) grayscale(1); }   /* sepia y luego gris: solo gris */

Usos que van más allá de las fotos

/* Un botón desactivado, apagado sin cambiar sus colores uno a uno */
.boton:disabled { filter: grayscale(1) opacity(0.6); }

/* El contenido detrás de un modal, desenfocado (el <dialog> va fuera de <main>) */
body:has(dialog[open]) main { filter: blur(3px); }

/* Iluminar al pasar el ratón, valga el color que valga */
.tarjeta:hover { filter: brightness(1.08); }

/* Un icono SVG o PNG negro convertido en blanco */
.icono-claro { filter: invert(1); }

brightness() al pasar el ratón es muy cómodo cuando tienes botones de muchos colores: una sola regla sirve para todos.

drop-shadow() frente a box-shadow

box-shadow dibuja la sombra de la caja (un rectángulo, o lo que marque border-radius). drop-shadow() dibuja la sombra de lo que se ve: sigue la silueta de un PNG transparente, de un SVG o incluso de un elemento recortado con clip-path, que con box-shadow no tendría sombra. En ese último caso, pon el filtro en el contenedor: el recorte se aplica después del filtro y se llevaría la sombra por delante.

.logo   { filter: drop-shadow(0 4px 6px rgb(0 0 0 / 0.3)); }
.flecha { filter: drop-shadow(2px 2px 0 #1b2d34); }

backdrop-filter: el efecto cristal

filter afecta al elemento. backdrop-filter afecta a lo que hay detrás del elemento, visto a través de él. Es lo que crea el efecto de cristal esmerilado de muchas barras de navegación y menús:

.barra {
  position: sticky;
  top: 0;
  background: rgb(255 255 255 / 0.6);   /* imprescindible: semitransparente */
  backdrop-filter: blur(12px) saturate(1.5);
}

Para que funcione, el fondo del elemento tiene que ser semitransparente. Si es opaco, tapa lo de detrás y no hay nada que desenfocar.

Unas notas prácticas:

  • Admite las mismas funciones que filter. blur() con un poco de saturate() da el aspecto más vistoso.
  • Safari lo admitía con prefijo durante años. Si necesitas cubrir iPhones antiguos, añade también -webkit-backdrop-filter.
  • Piensa en la legibilidad: si detrás pasa una foto muy clara, el texto blanco del cristal desaparece. Ajusta la opacidad del fondo.
  • Es caro de calcular. Úsalo en pocos elementos y no lo animes.

Si el navegador no lo admite, el elemento se queda con su fondo semitransparente. Puedes reforzarlo con @supports:

.barra { background: rgb(255 255 255 / 0.95); }

@supports (backdrop-filter: blur(1px)) {
  .barra { background: rgb(255 255 255 / 0.6); backdrop-filter: blur(12px); }
}

Modos de fusión

Un modo de fusión decide cómo se combinan los colores de una capa con los de la capa de debajo. Si has usado un editor de imágenes, son los mismos nombres.

ModoEfectoUso típico
multiplyMultiplica: siempre oscurece; el blanco desapareceLogos con fondo blanco sobre fondos claros
screenLo contrario: siempre aclara; el negro desapareceLuces, brillos
overlayMás contraste: oscuro donde es oscuro, claro donde es claroTexturas
darken / lightenSe queda con el más oscuro o el más claroEfectos de color
differenceResta los colores; sobre blanco, invierteTexto que se ve sobre cualquier fondo
color / luminosityCombina el tono de una capa con la luz de la otraTeñir fotos

mix-blend-mode: un elemento con lo que tiene detrás

.logo-jpg { mix-blend-mode: multiply; }  /* el recuadro blanco del logo se funde con el fondo */

.titulo-portada {
  color: white;
  mix-blend-mode: difference;             /* se invierte según la foto de detrás */
}

Si no quieres que la mezcla llegue más allá de un contenedor (por ejemplo, hasta el fondo del <body>), pon isolation: isolate en ese contenedor. Crea un grupo aparte y la fusión solo se hace con lo que hay dentro. Lo entenderás mejor en z-index y capas.

background-blend-mode: entre los fondos de un elemento

Mezcla las capas de background de un mismo elemento entre sí. Es la forma más limpia de teñir una foto con el color de tu marca:

.cabecera {
  background:
    url("img/rocodromo.jpg") center / cover,
    #2563eb;
  background-blend-mode: luminosity;   /* la foto toma el color azul */
}
.duotono {
  background: url("img/ruta.jpg") center / cover, #f97316;
  background-blend-mode: multiply;     /* foto oscurecida en naranja */
}

Recuerda que la primera capa de background queda encima: la foto se mezcla con el color de debajo.

clip-path: recortar con formas

clip-path recorta el elemento: solo se ve lo que queda dentro de la forma, y solo esa parte recibe clics.

.circulo   { clip-path: circle(40% at 50% 50%); }
.elipse    { clip-path: ellipse(50% 35%); }
.marco     { clip-path: inset(10px round 16px); }   /* recorta 10px por cada lado, con esquinas redondas */
.triangulo { clip-path: polygon(50% 0, 100% 100%, 0 100%); }
.flecha    { clip-path: polygon(0 0, 85% 0, 100% 50%, 85% 100%, 0 100%); }
.corte     { clip-path: polygon(0 0, 100% 0, 100% 85%, 0 100%); }

En polygon() das los vértices como pares x y en porcentajes del elemento, empezando por cualquier esquina y siguiendo el contorno. Las DevTools de Firefox y Chrome muestran los puntos sobre el elemento y permiten arrastrarlos, que es la forma más cómoda de ajustarlos.

Animar recortes

Puedes hacer transiciones entre dos polygon() siempre que tengan el mismo número de puntos:

.foto {
  clip-path: polygon(0 0, 100% 0, 100% 80%, 0 100%);
  transition: clip-path 0.4s ease;
}
.foto:hover {
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);   /* cuatro puntos en ambos */
}

Un efecto de “revelar” muy usado: de inset(0 100% 0 0) (todo recortado desde la derecha) a inset(0).

Máscaras: mask-image

Una máscara decide qué partes de un elemento se ven usando una imagen: donde la máscara es opaca, el elemento se ve; donde es transparente, desaparece. Y en medio, se ve a medias. Esa es la diferencia con clip-path, que solo recorta con bordes nítidos.

La máscara más útil es un degradado. Difumina un borde para que el contenido “se desvanezca”:

.resumen {
  max-height: 120px;
  overflow: hidden;
  mask-image: linear-gradient(to bottom, black 60%, transparent);
}

El texto de la tarjeta se va aclarando hasta desaparecer: una pista visual de que hay más. Lo que cuenta en la máscara es la transparencia, no el color: black significa “visible” y transparent, “invisible”.

También puedes usar una imagen o un SVG como máscara, para dar a un elemento la forma de un icono:

.icono-color {
  width: 24px;
  aspect-ratio: 1;
  background: #2563eb;                 /* el color que quieras */
  mask: url("img/icono-montania.svg") center / contain no-repeat;
}

mask funciona sin prefijo en todos los navegadores desde finales de 2023. En código antiguo verás -webkit-mask-image.

Rendimiento y efectos secundarios

Estos efectos se calculan al pintar la página. Unas pautas:

  • blur() y backdrop-filter son los más costosos. Cuanto mayor el radio y el elemento, peor. Evita animarlos y no los pongas en listas largas.
  • Animar filter: brightness() o opacity sobre un elemento pequeño suele ir bien; animar blur() en una foto a pantalla completa, no.
  • filter, backdrop-filter, mix-blend-mode, clip-path y mask crean un contexto de apilamiento nuevo, igual que opacity o transform. Si de repente un menú queda por debajo de otra cosa, sospecha de ellos.
  • filter (y backdrop-filter) también hacen que los hijos con position: fixed se fijen al elemento en lugar de a la ventana.

Errores frecuentes

  • backdrop-filter sin fondo semitransparente. Con un fondo opaco no ves nada detrás; con ningún fondo, el desenfoque se nota poco. Usa un color con alfa.
  • Confundir filter con backdrop-filter. filter: blur() desenfoca el propio elemento y su texto; backdrop-filter: blur(), lo que hay detrás.
  • Usar opacity o filter en el padre y esperar que un hijo se libre. El efecto se aplica a todo el grupo; un hijo no puede “deshacerlo”.
  • Animar entre polígonos con distinto número de puntos. El navegador no sabe emparejarlos y salta de golpe.
  • Pensar en colores en una máscara. En mask-image solo importa la transparencia: un degradado de rojo a azul opacos no oculta nada.
  • Texto ilegible por los modos de fusión. difference o overlay pueden dejar el texto con poco contraste en algunas zonas. Revísalo con fotos distintas.
  • Abusar de los efectos. Un desenfoque aquí y un tinte allá dan carácter; todos a la vez, ruido y lentitud.

Resumen

PropiedadPara qué sirveEjemplo
filterRetocar el elemento y su contenidograyscale(1), brightness(1.1)
drop-shadow()Sombra con la silueta realdrop-shadow(0 4px 6px #0004)
backdrop-filterRetocar lo que hay detrás (cristal)blur(12px) saturate(1.5)
mix-blend-modeMezclar el elemento con lo de detrásmultiply, difference
background-blend-modeMezclar las capas de fondo entre síTeñir una foto
isolation: isolateLimitar dónde se mezclaEn el contenedor
clip-pathRecortar con una formapolygon(...), inset(10px round 8px)
mask-imageOcultar con transparencia graduallinear-gradient(black, transparent)
object-fitEncajar imágenes sin deformarVer imágenes en CSS

En la siguiente lección volvemos a contenidos más cotidianos: listas y tablas.

Pruébalo tú

Cambia el código y pulsa Ejecutar (o Ctrl + Enter).

filtros-y-efectos.html
Resultado

Pon a prueba lo que has aprendido

[CSS] ¿Qué diferencia hay entre filter: blur(8px) y backdrop-filter: blur(8px)?

[CSS] ¿Cuándo es mejor drop-shadow() que box-shadow?

[CSS] ¿Qué hace mix-blend-mode: multiply sobre un logo con fondo blanco colocado sobre un fondo de color?

[CSS] En una máscara con mask-image, ¿qué importa del degradado utilizado?

¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.