CSS e web

Textura de ruído em CSS: grão em gradientes com SVG

Uma camada leve de ruído esconde o banding e faz a cor lisa da tela parecer impressão ou filme. Aqui está o filtro SVG por trás disso, ajustado e pronto para colar.

GradientlyConta verificada do Gradiently··5 min de leitura
Capa: Muslin Anvil · GR·W4AX·4M

Resumindo

  • Uma textura de ruído em CSS costuma ser feita com um filtro SVG feTurbulence, embutido como uma pequena imagem em data URI e repetida sobre um gradiente.
  • O baseFrequency do feTurbulence define o tamanho do grão: valores mais altos dão grão mais fino, valores mais baixos dão ruído grosso e nebuloso.
  • O ruído funciona melhor sobreposto ao gradiente em um pseudoelemento, com um modo de mesclagem como soft-light ou overlay e baixa opacidade.
  • O grão esconde o banding do gradiente porque quebra as bordas visíveis entre tons vizinhos em uma variação fina e aleatória.
  • Uma imagem de ruído em mosaico é barata de renderizar, enquanto aplicar um filtro SVG ao vivo a um elemento grande, ou animá-lo, custa bem mais.
Nesta página

Uma textura de ruído em CSS é um pontilhado fino e aleatório sobreposto a uma cor ou gradiente para dar grão a ele. O CSS não tem função de ruído, então a fonte padrão é o SVG: o filtro feTurbulence gera o ruído, você o envolve em um SVG minúsculo, embute isso como um data URI e o repete sobre o gradiente com baixa intensidade. O resultado lembra grão de filme ou papel impresso e corrige discretamente o banding, os degraus visíveis que aparecem em gradientes grandes e suaves.

Por que o grão faz a cor parecer mais cara é explicado em gradientes com grão. Este guia é a implementação.

O filtro SVG de ruído

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>
Um mosaico de 240 pixels de ruído cinza. Salve como noise.svg ou embuta como mostrado abaixo.
AtributoValor aquiO que controla
typefractalNoiseGrão suave e uniforme. O turbulence dá um ruído mais listrado e ondulado.
baseFrequency0.8Tamanho do grão. Cerca de 0.6 a 0.9 é grão fino; 0.1 a 0.3 é nebuloso.
numOctaves3Camadas de detalhe. Depois de cerca de 4, a diferença é difícil de ver.
stitchTilesstitchFaz as bordas do mosaico combinarem, então as repetições não têm emendas.
feColorMatrix saturate 00Remove a cor aleatória, deixando um grão cinza.
As configurações que importam. A referência do feTurbulence no MDN documenta o resto.

Embutindo o ruído como data URI

Um arquivo separado funciona, mas embutir poupa uma requisição e mantém o efeito em um só lugar. Em um data URI, os caracteres que significam algo em URLs precisam ser codificados: < vira %3C, > vira %3E, # vira %23 e % vira %25. Use aspas simples dentro do SVG para que não briguem com as aspas duplas em volta da 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");
}
O mesmo mosaico como uma propriedade personalizada que você pode reutilizar em qualquer lugar. Esquecer de codificar o # como %23 é o motivo habitual de nada aparecer no Firefox.

Sobrepondo o ruído a um gradiente

Coloque o ruído em um pseudoelemento acima do gradiente e controle-o com dois botões: um modo de mesclagem, que decide como o grão cinza se mistura com a cor abaixo, e a opacidade, que decide a intensidade. O soft-light mantém as cores limpas e é o mais suave; o overlay acrescenta mais contraste. O pointer-events: none impede que a camada bloqueie os cliques.

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;
}
Grão entre o gradiente e o conteúdo: o texto dentro de .grain continua nítido.
Três gradientes que mais ganham com o grão. Esmaecimentos escuros e de baixo contraste, como o do meio, são onde o banding aparece primeiro.

Se você prefere um único elemento sem pseudoelemento, liste o ruído primeiro no background-image e defina background-blend-mode: soft-light, normal. Você perde o botão de opacidade separado, então embuta a intensidade no próprio SVG, por exemplo com opacity='0.5' no rect.

Quanto grão é suficiente

  1. 1

    Comece leve

    Comece com opacity: 0.3 e soft-light. Você mal deve notar a uma distância de um braço.

  2. 2

    Confira a área mais escura

    O banding vive em esmaecimentos escuros e lentos. Aumente a opacidade até os degraus ali se dissolverem e pare.

  3. 3

    Combine o grão com o tamanho

    Heroes de tela cheia aguentam um grão um pouco mais grosso, em torno de 0.6. Cards e botões pedem grão fino, em torno de 0.9.

  4. 4

    Confira em um celular e em um monitor grande

    Um grão que parece certo em uma tela pode parecer poeira em outra. Busque uma textura que você sinta, e não que veja.

  5. 5

    Confira o texto por cima

    O grão não pode reduzir a legibilidade. Se um texto pequeno fica sobre a textura, diminua a intensidade ou mantenha o texto em uma área mais calma.

Demais

  • Grão visível do outro lado da sala
  • As cores ficam cinza e sujas
  • Ruído grosso e nebuloso em componentes pequenos
  • As bordas do texto parecem borradas contra o pontilhado

Na medida

  • Grão percebido só de perto
  • As cores continuam limpas com soft-light
  • Grão fino, do tamanho do elemento
  • Banding sumiu, texto nítido

Desempenho do ruído em CSS

Um data URI em mosaico é barato: o navegador renderiza o pequeno mosaico uma vez e o repete, e uma camada estática é pintada uma vez. A versão cara é aplicar o filtro ao vivo a um elemento grande com filter: url(#noise), o que roda o filtro sobre cada pixel toda vez que a área é repintada. Se você animar o grão, para um visual de filme tremulante, desloque a camada em mosaico com transform em poucos passos bruscos em vez de regenerar o ruído, e desligue-o para movimento reduzido.

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; }
}
Grão animado movendo um mosaico superdimensionado. O inset negativo mantém as bordas cobertas enquanto ele se desloca.

Um mosaico de ruído PNG ou WebP pré-renderizado de cerca de 128 a 256 pixels é uma fonte igualmente boa se você já tiver um. O grão também é um ingrediente de uma família mais ampla de superfícies, do papel ao vidro, tratada em textura de fundo. É também a camada final de um gradiente de malha em CSS.

O grão vem embutido em todo Mark do Gradiently como uma configuração de material, ao lado da luz e do movimento, então os designs feitos com um deles carregam textura sem nenhum código.

Muslin Anvil

GR·W4AX·4M

Muslin Anvil

Ver este Mark
Um Mark com grão como parte do material, renderizado ao vivo e não sobreposto depois.

Perguntas frequentes

Como adiciono uma textura de ruído em CSS?

Embuta um SVG com um filtro feTurbulence como data URI, repita-o em um pseudoelemento sobre o gradiente e defina um modo de mesclagem como soft-light com baixa opacidade.

Por que o data URI do meu ruído SVG não aparece?

Em geral por um caractere sem codificação. No data URI, codifique # como %23, % como %25 e os sinais de menor e maior como %3C e %3E, e use aspas simples dentro do SVG.

O grão corrige o banding em gradientes?

Sim, na maioria dos casos. Uma variação fina e aleatória quebra as bordas duras entre tons vizinhos, então o olho deixa de ver degraus.

Qual baseFrequency devo usar para o grão?

Cerca de 0.6 a 0.9 dá um grão fino, como de filme. Valores menores, como 0.2, dão um ruído grande e nebuloso.

O ruído em CSS é ruim para o desempenho?

Uma pequena imagem de ruído em mosaico é barata. Filtros SVG ao vivo em elementos grandes e ruído regenerado o tempo todo são o que mais custa.

Compartilhar este guia

Escrito pelo GradientlyConta verificada do Gradiently

A equipe por trás do Gradiently, uma ferramenta de design criada em torno dos Marks: gradientes vivos que fazem tudo o que você cria ter a sua cara.

Ver nosso perfil