Categorias
Projetos

CSS mask-image: mascaramento CSS nativo

CSS mask-image (CSS masking) oferece a opção de usar uma imagem como camada de máscara. Isso significa que é possível usar uma imagem, um SVG ou um gradiente como máscara para criar efeitos bem interessantes.

Quando se recorta um elemento usando clip-path, a área recortada se torna invisível (veja nosso tutorial). Se, em vez disso, for preciso tornar parte da imagem opaca ou aplicar algum outro efeito nela, isso é possível de ser feito com CSS masking (“mascaramento CSS”).

Ao saber como usar a propriedade mask-image de CSS, isso permite especificar uma imagem para usar como camada de máscara (mask layer) através de 3 opções: imagem, SVG ou gradiente.

Compatibilidade cross-browser de mask-image

No momento da publicação deste artigo, a maioria dos navegadores oferece somente suporte parcial para a propriedade de mascaramento CSS.

É preciso usar o prefixo -webkit- além da propriedade padrão para obter uma melhor compatibilidade — consulte o Can I Use para informações completas de suporte dos navegadores.

Apesar de o suporte cross-browser já ser decente, ao usar o mascaramento para tornar texto por cima de uma imagem visível, tome cuidado com o que acontecerá se o mascaramento não estiver disponível.

Pode valer a pena usar feature queries para detectar suporte para imagem com mask-image ou -webkit-mask- e fornecer um fallback antes de usar a versão mascarada.

@supports(-webkit-mask-image: url(#mask)) or (mask-image: url(#mask)) {
/* código mask-image aqui */
}

mask-image com imagem

A propriedade mask-image funciona de maneira semelhante à propriedade background-image, usando url() para passar uma imagem — obviamente, a imagem da máscara precisa ter uma área transparente (ou semitransparente).

Uma área totalmente transparente faz com que a parte da imagem sob essa área fique invisível; uma área que é semitransparente permite que parte da imagem original apareça. Veja a diferença abaixo.

A primeira imagem é a imagem original de balões sem máscara. A segunda imagem tem uma máscara aplicada que tem uma estrela branca em um fundo totalmente transparente. A terceira imagem tem uma estrela branca em um fundo com transparência gradiente.

Neste exemplo, também se usa a propriedade mask-size com valor cover. Esta propriedade funciona da mesma maneira que background-size.

É possível usar as palavras-chave cover e contain ou atribuir ao background um tamanho usando qualquer unidade de comprimento CSS válida — também é possível repetir a máscara da mesma forma que faria com uma imagem de fundo, usando uma imagem pequena como padrão de repetição.

mask-image com SVG

Exemplo de CSS mask-image aplicado a uma imagem mostrando balões tripulados voando.

Em vez de usar um arquivo de imagem como máscara, também é admitido usar SVG. Existem algumas maneiras pelas quais isso pode ser alcançado. A primeira é ter um elemento <mask> dentro do SVG e fazer referência ao ID desse elemento na propriedade mask-image.

<svg width="0" height="0" viewBox="0 0 400 300">
<defs>
<mask id="mask">
<rect fill="#000000" x="0" y="0" width="400" height="300"></rect>
<circle fill="#FFFFFF" cx="150" cy="150" r="100" />
<circle fill="#FFFFFF" cx="50" cy="50" r="150" />
</mask>
</defs>
</svg>
<div class="container">
<img src="/images/blog/css-mask-image/balloons.webp" alt="Balloons" />
</div>
.container img {
height: 100%;
width: 100%;
object-fit: cover;
-webkit-mask-image: url(#mask);
mask-image: url(#mask);
}

A vantagem dessa abordagem é que a máscara pode ser aplicada a qualquer elemento HTML, não apenas a uma imagem. Infelizmente, no momento, o Firefox é o único navegador que suporta essa abordagem.

No entanto, nem tudo está perdido, pois para o cenário mais comum de mascaramento de uma imagem, podemos incluir a imagem no próprio SVG.

mask-image com gradiente/degradê

Usar um gradiente/degradê CSS como máscara é uma maneira elegante de obter uma área mascarada sem precisar se dar ao trabalho de criar uma imagem ou SVG.

Um gradiente linear simples usado como máscara pode garantir que a parte inferior de uma imagem não fique muito escura sob uma legenda, por exemplo.

Também é possível usar qualquer um dos tipos de gradiente suportados e ser tão criativo quanto possível. Este próximo exemplo usa um gradiente radial para criar uma máscara circular atrás da legenda.

Múltiplas máscaras

Tal como acontece com imagens de background, é possível especificar várias fontes de máscara, combinando-as para obter o efeito desejado. Isso é particularmente útil se é preciso usar um padrão gerado com gradientes CSS como máscara.

Como exemplo, veja o padrão xadrez a seguir. O código, usando imagens de background, é assim:

background-image:
linear-gradient(45deg, #ccc 25%, transparent 25%),
linear-gradient(-45deg, #ccc 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #ccc 75%),
linear-gradient(-45deg, transparent 75%, #ccc 75%);
background-size:20px 20px;
background-position: 0 0, 0 10px, 10px -10px, -10px 0px;

Para transformar esse, ou qualquer outro padrão de imagens de fundo, em uma máscara, é preciso substituir as propriedades background-* pelas propriedades de máscara relevantes, incluindo as propriedades prefixadas -webkit.

-webkit-mask-image:
linear-gradient(45deg, #000000 25%, rgba(0,0,0,0.2) 25%),
linear-gradient(-45deg, #000000 25%, rgba(0,0,0,0.2) 25%),
linear-gradient(45deg, rgba(0,0,0,0.2) 75%, #000000 75%),
linear-gradient(-45deg, rgba(0,0,0,0.2) 75%, #000000 75%);
-webkit-mask-size:20px 20px;
-webkit-mask-position: 0 0, 0 10px, 10px -10px, -10px 0px;

Existem alguns efeitos possíveis realmente interessantes aplicando padrões de gradiente às imagens. Realmente, a imaginação é o limite.

Conclusão

Como visto, mascaramento CSS com mask-image realmente é um recurso poderoso quando é preciso alcançar efeitos interessantes para apresentar imagens em projetos Web.

O suporte já é mais ou menos decente e, como sabemos, em breve será totalmente cross-browser, permitindo que mask-image seja usado livremente.

E você, já pensou em alguns casos de uso ou lembrou de algum projeto que fez que poderia ter usado? Conta pra gente nos comentários!