Saltar al contenido

CSS, de a poco

Curso de CSS

Filtros y mezclas

Lección 17 de 37 · 5 min

Brillo, contraste, desenfoque, un vidrio esmerilado, tintas que se superponen: muchas cosas que antes se resolvían en un editor de fotos hoy son una línea de CSS, y se pueden cambiar en vivo.

Funciones de filter

filter procesa los píxeles ya dibujados del elemento, con todo lo que tiene adentro. Recibe una lista de funciones separadas por espacios:

  1. Desenfoqueblur(4px)Es el único valor en longitud y no acepta porcentajes.
  2. Luz y colorbrightness() · contrast() · saturate()100% deja la imagen igual; menos baja, más sube.
  3. Tonosgrayscale() · sepia() · invert()De 0% (nada) a 100% (del todo).
  4. Girohue-rotate(90deg)Gira todos los tonos por la rueda de color.
  5. Y ademásopacity() · drop-shadow()opacity() funciona como la propiedad, y drop-shadow() se ve más abajo.

El orden importa: cada función trabaja sobre el resultado de la anterior, de izquierda a derecha. Si el sepia va al final, pisa el giro de tono; si va primero, el giro tiñe el sepia.

filterbrightness(105%) contrast(115%) sepia(35%)
3 funciones en cadena
foto.css
.foto {
filter:
brightness(105%)
contrast(115%)
sepia(35%);
}
foto.html
<img class="brightness-105 contrast-115 sepia-35" src="bowl.jpg" alt="Bowl de verduras">
foto.css
/* marrón: sepia pisa el giro */
.foto { filter: hue-rotate(90deg) sepia(100%); }
/* verdoso: el giro tiñe el sepia */
.foto-verde { filter: sepia(100%) hue-rotate(90deg); }
.boton:disabled {
filter: grayscale(100%) opacity(60%);
}

Un filter distinto de none crea un contexto de apilamiento y pasa a ser el bloque contenedor de sus hijos con position: fixed: un modal fijo adentro de un elemento filtrado se posiciona contra ese elemento, no contra la ventana. Es Baseline desde 2016.

drop-shadow() contra box-shadow

box-shadow dibuja la sombra de la caja: siempre un rectángulo, con el radio que tenga. drop-shadow() dibuja la sombra de los píxeles: sigue el contorno de un PNG o un SVG con transparencia, y aparece también a través de un agujero.

La etiqueta de precio es un SVG con transparencia alrededor, y la línea punteada naranja es la caja del elemento. Cambiá entre las dos sombras y mové el desplazamiento y el desenfoque: una sigue la caja, la otra la forma.

shadow
sombra de la forma
etiqueta.css
.etiqueta {
filter: drop-shadow(0 8px 12px oklch(0 0 0 / 35%));
}
etiqueta.html
<img class="drop-shadow-[0_8px_12px_oklch(0_0_0/35%)]" src="etiqueta.svg" alt="">

A cambio, drop-shadow() no tiene spread ni inset, y acepta una sola sombra por función (para apilar, se encadenan varias). Además es la única sombra que sobrevive a un clip-path: puesta en el padre de un elemento recortado, sigue la forma del recorte.

etiqueta.css
.recorte-con-sombra {
filter: drop-shadow(0 8px 12px oklch(0 0 0 / 35%));
}
.recorte-con-sombra > .etiqueta {
clip-path: polygon(20% 0, 100% 0, 100% 100%, 20% 100%, 0 50%);
}

Vidrio esmerilado con backdrop-filter

backdrop-filter acepta las mismas funciones, pero filtra lo que está detrás del elemento, no el elemento. Así se hace el vidrio esmerilado de una barra o un epígrafe sobre una foto.

El efecto solo se ve a través del fondo del elemento, así que el fondo tiene que ser translúcido. Con un fondo opaco el desenfoque queda tapado; sin fondo, el texto queda sobre la imagen y pierde contraste.

backdrop-filter: blur(12px) saturate(180%)fondo al 45%
se ve la ciudad, desenfocada

La ciudad a la nocheAutopista y rascacielos, 21:40 · foto de la semana

epigrafe.css
.epigrafe {
background: rgb(255 255 255 / 45%);
-webkit-backdrop-filter: blur(12px) saturate(180%); /* Safari 17 */
backdrop-filter: blur(12px) saturate(180%);
}
epigrafe.html
<figcaption class="bg-white/45 backdrop-blur-[12px] backdrop-saturate-180">
La ciudad a la noche
</figcaption>

Lo que hay que saber:

  1. Raíz de fondobackdrop rootEl elemento solo ve hasta el ancestro más cercano con filter, opacity menor a 1, mask, clip-path, mix-blend-mode u otro backdrop-filter. Un vidrio adentro de otro vidrio solo desenfoca lo del vidrio de afuera.
  2. Apilamientostacking contextComo filter, crea un contexto de apilamiento y es el bloque contenedor de sus hijos fijos.
  3. CostorendimientoEl navegador vuelve a desenfocar el fondo en cada cuadro de scroll. Un radio grande sobre una superficie grande se nota en celulares modestos.

Es Baseline desde septiembre de 2024, cuando Safari 18 lo aceptó sin prefijo. Para Safari 17 y anteriores todavía conviene repetirlo como -webkit-backdrop-filter.

Modos de mezcla

mix-blend-mode decide cómo se combinan los colores de un elemento con lo que tiene detrás, como las capas de un editor de imágenes:

  1. MultiplicarmultiplySiempre oscurece, y el blanco desaparece. Es como superponer tintas en papel.
  2. TramascreenLo contrario: siempre aclara, y el negro desaparece.
  3. SuperponeroverlayMultiplica los oscuros del fondo y aclara los claros: sube el contraste.
  4. DiferenciadifferenceResta un color del otro: el negro no cambia nada y el blanco invierte.

El elemento se mezcla con todo lo que hay detrás dentro de su contexto de apilamiento. isolation: isolate crea un contexto nuevo en el grupo: las tintas se siguen mezclando entre sí, pero ya no con la foto. Probá cada modo y activá el aislamiento para verlo.

mix-blend-mode
con la foto también
tinta.css
.tintas {
isolation: auto;
}
.tinta {
mix-blend-mode: multiply;
}
tinta.html
<div class="isolation-auto">
<span class="mix-blend-multiply bg-[#00a0e3]"></span> <!-- cyan -->
<span class="mix-blend-multiply bg-[#e5007d]"></span> <!-- magenta -->
<span class="mix-blend-multiply bg-[#ffe600]"></span> <!-- yellow -->
</div>

Cualquier cosa que cree un contexto de apilamiento aísla igual (opacity menor a 1, un transform, un z-index en un elemento posicionado); isolation: isolate es la forma de hacerlo sin efectos secundarios.

background-blend-mode mezcla las capas de fondo de un mismo elemento entre sí y con su background-color, sin tocar lo que hay detrás. Las tres propiedades son Baseline desde 2020.

portada.css
.portada {
background:
url(foto.jpg) center / cover,
oklch(0.7 0.15 40); /* naranja */
background-blend-mode: multiply;
}

En Tailwind

Cada función de filtro tiene su clase, y Tailwind las junta en un solo filter. Los valores fuera de la escala van entre corchetes.

CSSTailwind
blur(4px) · brightness(105%)blur-[4px] · brightness-105
grayscale(100%) · sepia(35%)grayscale · sepia-35
filter: drop-shadow(…)drop-shadow-md
backdrop-filter: blur(12px)backdrop-blur-[12px]
mix-blend-mode: multiplymix-blend-multiply
isolation: isolateisolate
foto.html
<!-- orden de Tailwind: hue-rotate antes que sepia -->
<img class="hue-rotate-90 sepia" src="foto.jpg" alt="…">
<!-- otro orden: el filter entero entre corchetes -->
<img class="[filter:sepia(100%)_hue-rotate(90deg)]" src="foto.jpg" alt="…">