CSS y web

Textura de ruido en CSS: añade grano a los degradados con SVG

Una tenue capa de ruido oculta el banding y hace que un color plano de pantalla se sienta como impreso o película. Este es el filtro SVG que hay detrás, ajustado y listo para pegar.

GradientlyCuenta verificada de Gradiently··5 min de lectura
Portada: Muslin Anvil · GR·W4AX·4M

La versión corta

  • Una textura de ruido en CSS suele hacerse con un filtro SVG feTurbulence, incrustado como una imagen data URI pequeña y repetida en mosaico sobre un degradado.
  • El baseFrequency de feTurbulence fija el tamaño del grano: los valores altos dan un grano fino y los bajos un ruido grueso y nuboso.
  • El ruido funciona mejor sobre el degradado, en un pseudoelemento con un modo de fusión como soft-light u overlay y poca opacidad.
  • El grano oculta el banding del degradado porque rompe los bordes visibles entre tonos vecinos en una variación fina y aleatoria.
  • Una imagen de ruido en mosaico es barata de renderizar, mientras que aplicar un filtro SVG en vivo a un elemento grande, o animarlo, cuesta mucho más.
En esta página

Una textura de ruido en CSS es un moteado fino y aleatorio superpuesto a un color o degradado para darle grano. CSS no tiene función de ruido, así que la fuente estándar es SVG: el filtro feTurbulence genera el ruido, lo envuelves en un SVG diminuto, lo incrustas como data URI y lo repites en mosaico sobre tu degradado con poca intensidad. El resultado parece grano de película o papel impreso, y arregla en silencio el banding, los escalones visibles que aparecen en degradados grandes y suaves.

Por qué el grano hace que el color parezca más caro se explica en los degradados con grano. Esta guía es la implementación.

El filtro de ruido SVG

html
<svg xmlns="http://www.w3.org/2000/svg" width="240" height="240">
  <filter id="n">
    <feTurbulence type="fractalNoise" baseFrequency="0.8" numOctaves="3" stitchTiles="stitch" />
    <feColorMatrix type="saturate" values="0" />
  </filter>
  <rect width="100%" height="100%" filter="url(#n)" />
</svg>
Una tesela de 240 píxeles de ruido gris. Guárdala como noise.svg o incrústala como se muestra abajo.
AtributoValor aquíQué controla
typefractalNoiseGrano suave y uniforme. turbulence da un ruido más rayado y ondulado.
baseFrequency0.8Tamaño del grano. Alrededor de 0,6 a 0,9 es grano fino; de 0,1 a 0,3 es nuboso.
numOctaves3Capas de detalle. A partir de unas 4 la diferencia cuesta verse.
stitchTilesstitchHace que los bordes de la tesela coincidan, así que las repeticiones no tienen costuras.
feColorMatrix saturate 00Elimina el color aleatorio y deja un grano gris.
Los ajustes que importan. La referencia de feTurbulence de MDN documenta el resto.

Incrustar el ruido como data URI

Un archivo aparte funciona, pero incrustarlo ahorra una petición y mantiene el efecto en un solo lugar. En un data URI hay que codificar los caracteres que significan algo en las URL: < pasa a ser %3C, > pasa a ser %3E, # pasa a ser %23 y % pasa a ser %25. Usa comillas simples dentro del SVG para que no choquen con las comillas dobles que rodean la URL.

css
:root {
  --noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
La misma tesela como una propiedad personalizada que puedes reutilizar en cualquier sitio. Olvidar codificar # como %23 es el motivo habitual de que no se vea nada en Firefox.

Superponer ruido sobre un degradado

Pon el ruido en un pseudoelemento por encima del degradado y contrólalo con dos diales: un modo de fusión, que decide cómo se mezcla el grano gris con el color de debajo, y la opacidad, que decide su intensidad. soft-light mantiene limpios los colores y es el más suave; overlay añade más contraste. pointer-events: none evita que la capa bloquee los clics.

css
.grain {
  position: relative;
  isolation: isolate;
  background: linear-gradient(135deg, #1e1b4b, #7c3aed 55%, #f472b6);
}

.grain::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: var(--noise);
  mix-blend-mode: soft-light;
  opacity: 0.45;
  pointer-events: none;
}
Grano entre el degradado y el contenido: el texto dentro de .grain se mantiene nítido.
Tres degradados que más ganan con el grano. Los desvanecimientos oscuros y de poco contraste, como el del medio, son donde el banding se ve primero.

Si prefieres un solo elemento sin pseudoelemento, pon el ruido primero en background-image y define background-blend-mode: soft-light, normal. Pierdes el dial de opacidad independiente, así que integra la intensidad en el propio SVG, por ejemplo con opacity='0.5' en el rect.

Cuánto grano es suficiente

  1. 1

    Empieza tenue

    Empieza con opacity: 0.3 y soft-light. Apenas deberías notarlo a la distancia del brazo.

  2. 2

    Revisa la zona más oscura

    El banding vive en los desvanecimientos oscuros y lentos. Sube la opacidad hasta que los escalones de ahí se disuelvan y para.

  3. 3

    Ajusta el grano al tamaño

    Los heroes a pantalla completa admiten un grano algo más grueso, de alrededor de 0,6. Las tarjetas y los botones piden grano fino, de alrededor de 0,9.

  4. 4

    Comprueba en un móvil y en un monitor grande

    Un grano que se ve bien en una pantalla puede parecer polvo en otra. Busca una textura que se sienta más que se vea.

  5. 5

    Comprueba el texto encima

    El grano no debe reducir la legibilidad. Si un texto pequeño está sobre la textura, baja la intensidad o mantén el texto en una zona más serena.

Demasiado

  • Grano visible desde el otro lado de la sala
  • Los colores se vuelven grises y sucios
  • Ruido grueso y nuboso en componentes pequeños
  • Los bordes del texto se ven borrosos contra el moteado

Más o menos bien

  • Grano que solo se nota de cerca
  • Los colores se mantienen limpios con soft-light
  • Grano fino ajustado al tamaño del elemento
  • Banding desaparecido, texto nítido

Rendimiento del ruido en CSS

Un data URI en mosaico es barato: el navegador renderiza la pequeña tesela una vez y la repite, y una capa estática se pinta una vez. La versión cara es aplicar el filtro en vivo a un elemento grande con filter: url(#noise), que ejecuta el filtro sobre cada píxel siempre que la zona se repinta. Si animas el grano, para un aire de película parpadeante, desplaza la capa en mosaico con transform en unos pocos saltos en lugar de regenerar el ruido, y desactívalo para el movimiento reducido.

css
.grain {
  overflow: hidden;
}

.grain::after {
  inset: -50%;
  animation: flicker 0.6s steps(3) infinite;
}

@keyframes flicker {
  0%   { transform: translate(0, 0); }
  33%  { transform: translate(-3%, 2%); }
  66%  { transform: translate(2%, -3%); }
}

@media (prefers-reduced-motion: reduce) {
  .grain::after { animation: none; }
}
Grano animado moviendo una tesela sobredimensionada. El inset negativo mantiene cubiertos los bordes al desplazarse.

Una tesela de ruido PNG o WebP prerenderizada de unos 128 a 256 píxeles es una fuente igual de buena si ya la tienes. El grano es también un ingrediente de una familia más amplia de superficies, del papel al cristal, que se trata en la textura de fondo. Es además la capa final de un degradado de malla en CSS.

El grano está integrado en cada Mark de Gradiently como un ajuste de material, junto a la luz y el movimiento, así que los diseños hechos con uno llevan textura sin código.

Muslin Anvil

GR·W4AX·4M

Muslin Anvil

Ver este Mark
Un Mark con grano como parte de su material, renderizado en vivo y no superpuesto después.

Preguntas frecuentes

¿Cómo añado una textura de ruido en CSS?

Incrusta un SVG con un filtro feTurbulence como data URI, repítelo en mosaico en un pseudoelemento sobre tu degradado y define un modo de fusión como soft-light con poca opacidad.

¿Por qué no se ve el data URI de mi ruido SVG?

Normalmente por un carácter sin codificar. En el data URI, codifica # como %23, % como %25 y los corchetes angulares como %3C y %3E, y usa comillas simples dentro del SVG.

¿Arregla el grano el banding de los degradados?

Sí, en la mayoría de los casos. La variación fina y aleatoria rompe los bordes duros entre tonos vecinos, así que el ojo ya no ve escalones.

¿Qué baseFrequency debo usar para el grano?

Alrededor de 0,6 a 0,9 da un grano fino como de película. Los valores más bajos, como 0,2, dan un ruido grande y nuboso.

¿Es malo el ruido CSS para el rendimiento?

Una pequeña imagen de ruido en mosaico es barata. Los filtros SVG en vivo sobre elementos grandes y el ruido regenerado constantemente son lo que más cuesta.

Compartir esta guía

Escrito por GradientlyCuenta verificada de Gradiently

El equipo detrás de Gradiently, una herramienta de diseño creada en torno a los Marks: degradados vivos que hacen que todo lo que diseñas parezca tuyo.

Ver nuestro perfil