Filtros y efectos visuales en CSS
En esta lección
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ón | Qué hace | Valor normal |
|---|---|---|
blur(4px) | Desenfoca | 0 |
brightness(1.2) | Más o menos brillo | 1 |
contrast(1.3) | Más o menos contraste | 1 |
grayscale(1) | Blanco y negro | 0 |
sepia(0.8) | Tono envejecido | 0 |
saturate(1.5) | Intensidad del color | 1 |
invert(1) | Negativo | 0 |
hue-rotate(90deg) | Gira todos los colores del círculo cromático | 0deg |
opacity(0.5) | Transparencia | 1 |
drop-shadow(...) | Sombra con la forma real | sin 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 desaturate()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.
| Modo | Efecto | Uso típico |
|---|---|---|
multiply | Multiplica: siempre oscurece; el blanco desaparece | Logos con fondo blanco sobre fondos claros |
screen | Lo contrario: siempre aclara; el negro desaparece | Luces, brillos |
overlay | Más contraste: oscuro donde es oscuro, claro donde es claro | Texturas |
darken / lighten | Se queda con el más oscuro o el más claro | Efectos de color |
difference | Resta los colores; sobre blanco, invierte | Texto que se ve sobre cualquier fondo |
color / luminosity | Combina el tono de una capa con la luz de la otra | Teñ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()ybackdrop-filterson los más costosos. Cuanto mayor el radio y el elemento, peor. Evita animarlos y no los pongas en listas largas.- Animar
filter: brightness()oopacitysobre un elemento pequeño suele ir bien; animarblur()en una foto a pantalla completa, no. filter,backdrop-filter,mix-blend-mode,clip-pathymaskcrean un contexto de apilamiento nuevo, igual queopacityotransform. Si de repente un menú queda por debajo de otra cosa, sospecha de ellos.filter(ybackdrop-filter) también hacen que los hijos conposition: fixedse fijen al elemento en lugar de a la ventana.
Errores frecuentes
backdrop-filtersin 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
filterconbackdrop-filter.filter: blur()desenfoca el propio elemento y su texto;backdrop-filter: blur(), lo que hay detrás. - Usar
opacityofilteren 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-imagesolo importa la transparencia: un degradado de rojo a azul opacos no oculta nada. - Texto ilegible por los modos de fusión.
differenceooverlaypueden 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
| Propiedad | Para qué sirve | Ejemplo |
|---|---|---|
filter | Retocar el elemento y su contenido | grayscale(1), brightness(1.1) |
drop-shadow() | Sombra con la silueta real | drop-shadow(0 4px 6px #0004) |
backdrop-filter | Retocar lo que hay detrás (cristal) | blur(12px) saturate(1.5) |
mix-blend-mode | Mezclar el elemento con lo de detrás | multiply, difference |
background-blend-mode | Mezclar las capas de fondo entre sí | Teñir una foto |
isolation: isolate | Limitar dónde se mezcla | En el contenedor |
clip-path | Recortar con una forma | polygon(...), inset(10px round 8px) |
mask-image | Ocultar con transparencia gradual | linear-gradient(black, transparent) |
object-fit | Encajar imágenes sin deformar | Ver 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).
Pon a prueba lo que has aprendido
¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.