DEV Community

Anilson Lopes
Anilson Lopes

Posted on • Edited on

Overlay com cor sobre imagem no CSS: pseudo-element ou element? Analisando os métodos

Como fazer um overlay sobre uma imagem, mas por baixo de um texto, e que altere a opacidade no hover? Talvez com pseudo-elements, se o HTML já estiver montado, sendo necessário apenas alterar o CSS ou usando elementos básicos.

A primeira vista, usar :pseudo-elements me parece mais prático, já que preciso mexer apenas no CSS do projeto, evitando qualquer modificação no HTML. Mas sabemos que é possível obter o mesmo resultado usando elementos básicos, e com o mesmo (quase o mesmo) CSS obter visualmente o mesmo resultado.

Mira:
resultado final

Vale ressaltar que esse post não faz um comparativo de performance (mas poderia), tão pouco irá apontar a melhor maneira ou a correta de resolver esse problema. Esse comparativo é apenas para fins didáticos.


Ponto de partida

A partir de dois cards idênticos, onde o card recebe uma imagem de fundo e comporta apenas duas div, sendo respectivamente título e subtitulo.
O texto no rodapé do card com a cor branca é apenas para ficar elegante :)

Veremos então como fazer um overlay sobre uma imagem, mas por baixo de um texto, e que altere a opacidade no hover...


Pseudo-element

O pseudo-element :before e :after para ser visível é necessário especificar um conteúdo, sendo essa a dificuldade mais corriqueira, já que é bem fácil esquece-lo.

Nesse caso, como não precisamos de conteúdo, adicionamos uma string vazia apenas para o mesmo ser inserido no DOM:

content: '';
Enter fullscreen mode Exit fullscreen mode

Para estilizar e posicionar afim de obter o overlay, é necessário aplicar o pseudo-element no próprio card, além de alterar a posição do mesmo para relative, dessa maneira:

Acrescentei uma classe modificadora no primeiro card chamada card--pseudo-elements, para diferencia-lo do padrão.

.card--pseudo-elements {
  position: relative;
}

.card--pseudo-elements:before {
  /* requerido */
  content: '';

  /* estilo de preto quase transparente */
  background-color: black;
  opacity: 0.5;

  /* posiciona nos limites do elemento pai */
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;

  /* suavização básica */
  transition: 200ms all;
}
Enter fullscreen mode Exit fullscreen mode

Feito isso, para fazer o efeito de escurecer o overlay, é necessário apenas aplicar o hover no card, e manipular o pseudo-element, assim:

.card--pseudo-elements:hover:before {
  opacity: 1;
}
Enter fullscreen mode Exit fullscreen mode

Estaria pronto se não fosse por um problema: o overlay cobre todo o conteúdo do card. Isso ocorre por quê (de modo resumido) o elemento com posição absoluta fica numa camada superior (z-index).

aplicando :pseudo-element

Contornamos isso apenas definindo o z-index dos elementos, dentro do card:

.card--pseudo-elements .card__title,
.card--pseudo-elements .card__subtitle {
  z-index: 1;
}
Enter fullscreen mode Exit fullscreen mode

Nesse estágio você pode ter se questionado ou tentado aplicar um z-index negativo para o seu :pseudo-element, afim de empurra-lo para trás do texto, mas isso não funciona. Veja mais sobre z-index para entender melhor.

O resultado final com :pseudo-elements você confere abaixo:


Elemento

Neste método, precisamos acrescentar um elemento no HTML. Além da classe módificadora card--element para diferenciar do outro método. O código fica assim:

<div class="card">
  <div class="card__title">
    Maceió
  </div>
  <div class="card__subtitle">
    Alagoas
  </div>
  <span class="card__overlay">
    <!-- div overlay vazia -->
  </span>
  </div>
Enter fullscreen mode Exit fullscreen mode

Você pode inserir no início ou no final do card, pessoalmente prefiro inserir no final e como span visando reduzir o risco de interferência no layout atual.

No CSS o código é quase idêntico, mudando apenas os seletores, e a não obrigatoriedade do content. Veja:

.card--element .card__overlay {
  background-color: black;
  opacity: 0.5;
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  transition: 200ms all;
}

/* aplicando o hover */
.card--element:hover .card__overlay {
  opacity: 0.9;
}
Enter fullscreen mode Exit fullscreen mode

Aqui encontramos o mesmo problema do :pseudo-element, o overlay sobrepõe todo o conteúdo do card, sendo assim a solução é a mesma:

.card--element .card__title,
.card--element .card__subtitle {
  z-index: 1;
}
Enter fullscreen mode Exit fullscreen mode

Abaixo você confere o resultado final com elemento básico:

Conclusão

Nota-se que a diferença entre os métodos é mínima, como o seletor diferente para o CSS e, de modo geral, uma linha a mais de código para ambos.

Se com o :pseudo-element é necessário adicionar o content à sua regra de estilo e dispensa a marcação HTML, com elemento básico não precisamos do content, mas é necessário adicionar o elemento ao HTML. O estilo e posicionamento do overlay é feito exatamente da mesma maneira.

Abaixo deixo o resultado final com os dois métodos:


Não esqueça de comentar com suas dúvidas e/ou sugestões. Obrigado.
Talvez continue com a parte 2, abordando acessibilidade e performance.

Top comments (4)

Collapse
 
erivaldolourenco profile image
erivaldolourenco

Muito bom, esclarecedor e de fácil entendimento. Parabéns pela didática, continue, por favor.

Collapse
 
smallkan profile image
Jhol H Winchester

Show, muito bom!!

Collapse
 
pauloafonsodev profile image
Paulo Afonso

show! me ajudou bastante, já apliquei, valeu!

Collapse
 
andersonmfjr profile image
Anderson Feitosa

Massa