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?
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!
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>
.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;
}
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>
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%;
}
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:
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 */
}
Só em adicionar o position: relative
no .banner
, já melhoramos nosso resultado:
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>
.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;
}
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>
/* 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;
}
Vocês podem perceber que existem algumas coisas diferentes do nosso exemplo anterior:
Como nossa imagem não está no background, trocamos
background-size
ebackground-position
porobject-fit
eobject-position
, respectivamente, para manter a correta proporção e alinhamento da imagem;Definimos o tamanho da nossa imagem com
width
eheight
em 100% para que ela fique do tamanho dasession.banner
, pois oinset: 0
só vai fazer a imagem ocupar uma parte dasession
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
Top comments (4)
ufaaaaa
😅🧡
Aaaa muito obrigada!!
Obg!! Quebrei a cabeça até dizer chega kkkkkk