Opacidade em background-image sem afetar textos

sucodelarangela

Angela Caldas

Posted on March 1, 2023

Opacidade em background-image sem afetar textos

Quando a gente trabalha com desenvolvimento front-end, inevitavelmente a gente vai precisar trabalhar opacidade em alguma imagem ou elemento, seja por questões de design, seja por acessibilidade visual. A aplicação de opacidades em imagens é notoriamente comum em banners, por exemplo, que são um recurso visual muito legal pra deixar sua página mais bonita e mais chamativa.

E aí você cria a sua <section class="banner"> todo feliz, insere seu texto, vai no seu CSS e coloca uma background-image bem bonita, um opacity: 0.5 e... o que acontece?

Banner totalmente semi-transparente

Isso mesmo. Você acabou de deixar o seu banner todo semi-transparente com a opacidade aplicada. 🥲

E como resolver isso? Vem comigo que eu te mostro!

Gif do personagem Morpheus do filme Matrix

Sumário
Porque a opacidade afetou tudo?
Criando um pseudo-elemento para o background
Estilizando o ::before
Uma palavra sobre acessibilidade


Porque a opacidade afetou tudo?

No exemplo inicial, apesar de termos colocado a imagem de fundo no background, ela ainda está renderizada no mesmo elemento .banner junto com o seu texto. Dessa forma, a opacidade aplicada na section será aplicada a todos os elementos, mesmo os que estiverem só no background.

<div class="banner">
    <h1>Meu banner bonitão</h1>
</div>
Enter fullscreen mode Exit fullscreen mode
.banner {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 50vh;
  width: 100%;
  background: url("preview.jpg") bottom no-repeat;
  background-size: cover;
  opacity: 0.5;
}
Enter fullscreen mode Exit fullscreen mode

Nesse caso, para que a opacidade seja aplicada unicamente na sua imagem, esta deveria estar em um elemento diferente do que contém o seu texto. Dessa forma, você consegue aplicar opacidade em um sem afetar o outro. E pra fazer isso, vamos precisar criar um pseudo-elemento para exibir nossa imagem de fundo.

Caso queira saber mais sobre as diferenças entre pseudo-elementos e pseudo-classes, você pode ler este outro artigo que escrevi!


Criando um pseudo-elemento para o background

Para esse caso específico, podemos usar tanto o pseudo-elemento ::before quanto o ::after. O que cada um deles faz é criar um "elemento falso" no seu HTML dentro do seletor indicado, mas antes ou depois do conteúdo existente no HTML. Nossa section com ::before e ::after ficaria assim se você inspecionar o código no DevTools:

<div class="banner">
    ::before
    <h1>Meu banner bonitão</h1>
    ::after
</div>
Enter fullscreen mode Exit fullscreen mode

Vamos utilizar no nosso exemplo apenas ::before, não mexeremos no HTML. No nosso CSS, precisamos:

a) definir um tamanho para a nossa section através das propriedades width e height: a largura normalmente fica em 100% (para que o banner ocupe toda a largura da página) e a altura fica à seu critério;

b) posicionar o texto onde desejarmos utilizando um display adequado e suas propriedades de posicionamento. No nosso exemplo, estou centralizando o texto com display: flex e suas propriedades específicas:

.banner {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 50vh;
  width: 100%;
}
Enter fullscreen mode Exit fullscreen mode

Estilizando o ::before

Agora vamos estilizar o nosso pseudo-elemento ::before. Para isso, vamos:

a) Usar o seletor apropriado .banner::before;

b) Adicionar a propriedade content, obrigatória para uso de ::before ou ::after. Como não teremos nenhum conteúdo além da imagem de fundo, essa propriedade vai como uma string vazia;

c) Para manipular nosso pseudo-elemento, precisamos definir ele com position: absolute. Isso vai nos permitir deixar ele do mesmo tamanho do elemento .banner e deixar o texto sobreposto;

d) Adicionar nosso background-image com a url da imagem e definir o tamanho da imagem com inset: 0. Essa propriedade equivale à top: 0; right: 0; bottom: 0; left: 0.

Até agora, nosso resultado está ficando assim:

Resultado parcial da imagem na tela

Parece que vai dar tudo errado, mas confia!

Nossa imagem está pegando a tela inteira, mas porque?

Quando usamos position: absolute o nosso elemento "sai" do fluxo da página, ou seja, é como se ele ficasse "flutuando" acima de todos os outros elementos e ele toma conta de toda a página porque definimos o inset: 0. Para corrigir isso, precisamos dar uma referência para esse elemento absoluto, dizendo pra ele se posicionar em relação à outro elemento na página. Esse elemento que será nossa referência é o nosso .banner, que deverá ter position: relative:

.banner {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 50vh;
  width: 100%;
  position: relative; /* agora o ::before usa o .banner de referência, e não a página toda */
}
Enter fullscreen mode Exit fullscreen mode

Só em adicionar o position: relative no .banner, já melhoramos nosso resultado:

Resultado parcial com posição relativa

Agora vamos apenas finalizar os ajustes da imagem e colocar ela por trás do texto:

e) usamos background-size: cover para fazer com que a imagem ocupe toda a área da session.banner sem distorcer e sem repetir;

f) posicionamos a imagem com background-position. Nesse exemplo, posicionar pelo bottom ficou mais legal;

g) colocamos um z-index: -1 pra forçar a imagem a ir "pra baixo" do texto (nem sempre isso é necessário, mas é sempre bom garantir que a imagem fique sempre abaixo); e

h) finalmente, aplicamos a opacidade desejada na imagem! Agora a imagem ficará semi-transparente sem afetar o texto.

Nosso código final ficou assim:

<div class="banner">
    <h1>Meu banner bonitão</h1>
</div>
Enter fullscreen mode Exit fullscreen mode
.banner {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 50vh;
  width: 100%;
  position: relative;
}

.banner::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("preview.jpg");
  background-size: cover;
  background-position: bottom;
  z-index: -1;
  opacity: 0.5;
}
Enter fullscreen mode Exit fullscreen mode

E aqui você pode ver o código em ação:


Forma alternativa com a tag img

Uma forma bem mais fácil de ter o mesmo resultado acima seria adicionar a imagem de fundo usando uma tag <img> diretamente no seu HTML e fazendo alguns ajustes no CSS (ainda assim, usando position para fazer a sobreposição de imagem e texto). O código seria mais ou menos assim:

<div class="banner">
  <img src="preview.jpg" alt="Pessoa contemplando uma paisagem psicodélica em um lugar remoto">
  <h1>Meu banner bonitão</h1>
</div>
Enter fullscreen mode Exit fullscreen mode
/* Nosso banner continua igual */
.banner {
  position: relative;
  height: 50vh;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Estilizando a tag img */
img {
  position: absolute;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: bottom;
  z-index: -1;
  opacity: 0.5;
}
Enter fullscreen mode Exit fullscreen mode

Vocês podem perceber que existem algumas coisas diferentes do nosso exemplo anterior:

  • Como nossa imagem não está no background, trocamos background-size e background-position por object-fit e object-position, respectivamente, para manter a correta proporção e alinhamento da imagem;

  • Definimos o tamanho da nossa imagem com width e height em 100% para que ela fique do tamanho da session.banner, pois o inset: 0 só vai fazer a imagem ocupar uma parte da session por não estar no background.

Então se assim foi mais fácil, porque não fazer sempre assim?

Por uma simples questão: Nem sempre uma img direto no HTML atende às melhores práticas de acessibilidade!

Na maioria das vezes, imagens de banners são meramente ilustrativas, não contendo significado semântico para a página. Se esse é o seu caso, opte por usar as imagens por meio do CSS, através do background-image. Dessa forma, os leitores de tela não farão a leitura da imagem para o usuário que necessita desse recurso (vale ressaltar que a acessibilidade da página deve deixar a leitura por parte desses dispositivos o mais clara possível).

Porém, se você está colocando uma imagem que tem importância em ser descrita para o usuário, agregando valor semântico ao conteúdo da sua página, então a melhor opção é usar a tag <img>, não esquecendo de usar o atributo alt para dar uma descrição completa e semântica do que a imagem representa. E nada de escrever "imagem de coisa tal" ou "foto de uma coisa": os leitores de tela já leem pro usuário que ele está vendo uma imagem, então escrever "imagem", "foto" ou "ilustração" no alt só vai deixar o seu conteúdo redundante!


É importante que nós, enquanto desenvolvedores front-end, tenhamos cada vez mais conhecimento nas boas práticas de escrita de código, acessibilidade e também SEO. Espero que este artigo traga um pouco mais de conhecimento e dê aquela forcinha nos seus projetos futuros! E se Acessibilidade é um assunto que chamou sua atenção, dá uma olhada no conteúdo abaixo da Alura #paz

💖 💪 🙅 🚩
sucodelarangela
Angela Caldas

Posted on March 1, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related