Esmaecer a tela inteira, exceto uma área fixa?

88

Quero criar um tutorial que levará o usuário exatamente onde clicar. Estou tentando cobrir todo o ecrã com um <div>que irá dim todos os elementos exceto uma região específica que está em um fixo width, height, tope left.

O problema é que não consigo encontrar uma maneira de "cancelar" o do pai background-color(que também é transparente).

No recorte abaixo, holeestá o div que deve estar sem nenhum background-color, incluindo o de seu pai.

Isso pode ser realizado? Alguma ideia?

#bg{
   background-color:gray;
   opacity:0.6;
   width:100%;
   height:100vh;
}
#hole{
   position:fixed;
   top:100px;
   left:100px;
   width:100px;
   height:100px;
}
<div id="bg">
    <div id="hole"></div>
</div>

Aqui está uma imagem maquete do que estou tentando alcançar:

insira a descrição da imagem aqui

Koby Douek
fonte
13
Se você estiver criando um tour / tutorial de recursos, pode estar interessado em uma das bibliotecas js para fazer isso. Eles têm alguns recursos interessantes e vão lhe poupar o trabalho de escrever um monte de efeitos css únicos. Verifique introjs.com ou linkedin.github.io/hopscotch .
outubro de
2
Esta é apenas uma sugestão para uma lib: heelhook.github.io/chardin.js
online Thomas

Respostas:

125

Você poderia fazer isso com apenas um dive dar um box-shadow.

EDITAR: como @Nick Shvelidze apontou, você deve considerar adicionarpointer-events: none

vmaxValor adicionado para box-shadowcomo @Prinzhorn sugerido

div {
  position: fixed;
  width: 200px;
  height: 200px;
  top: 50px;
  left: 50px;
  /* for IE */
  box-shadow: 0 0 0 1000px rgba(0,0,0,.3);
  /* for real browsers */
  box-shadow: 0 0 0 100vmax rgba(0,0,0,.3);
  pointer-events: none;
}
<div></div>

VilleKoo
fonte
28
Certifique-se de adicionar pointer-events: nonese quiser que a área abaixo dela seja clicável.
Nick Shvelidze
4
1.000px não parece o suficiente para mim - parece que haveria muitos casos em que isso não preencheria a tela, caso contrário, uma solução realmente inteligente.
ESR
1
@EdmundReed você pode ajustar isso de acordo com suas necessidades :)
VilleKoo
8
box-shadow: 0 0 0 100vmax rgba(0,0,0,.3);terá a garantia de cobrir a tela inteira
Prinzhorn
2
@VilleKoo, você pode adicioná-lo atrás da linha de 1000px e mantê-lo como um
fallback
19

Você pode criar um SVG que é preenchido com um caminho que tem o buraco onde você precisa. Mas eu acho que você precisa encontrar uma maneira de lidar com os cliques, uma vez que todos eles serão direcionados ao svg sobreposto. Acho que document.getElementFromPointposso te ajudar aqui. mdn

philipp
fonte
Acho que o formulário de feedback do Google usando SVG para escurecer a área de descanso.
Durga
3

Isso também pode ser feito de forma semelhante à resposta de @VilleKoo, mas com uma borda.

div {
    border-style: solid;
    border-color: rgba(0,0,0,.3);
    pointer-events: none;
    position: absolute;
    top: 0; bottom: 0; left: 0; right: 0;
    border-width: 40px 300px 50px 60px;
}
<div></div>

Dan
fonte
2

Você pode conseguir o mesmo que na resposta de VilleKoo usando CSSoutline propriedade . Possui excelente suporte a navegadores (e funciona também no IE8 +). Os contornos têm a mesma sintaxe das bordas, mas, ao contrário das bordas, eles não ocupam espaço, são desenhados acima do conteúdo.

Também para o IE9 + você pode substituir 99999pxpor calc(100 * (1vh + 1vw - 1vmin)).

A desvantagem desta abordagem é que outlinenão é afetada porborder-radius .

Demo:

div {
  position: fixed;
  width: 200px;
  height: 200px;
  top: 50px;
  left: 50px;
  /* IE8 */
  outline: 99999px solid rgba(0,0,0,.3);
  /* IE9+ */
  outline: calc(100 * (1vw + 1vh - 1vmin)) solid rgba(0,0,0,.3);
  /* for other browsers */
  outline: 100vmax solid rgba(0,0,0,.3);
  pointer-events: none;
}
<div></div>

Vadim Ovchinnikov
fonte
0

Aqui está o código jQuery simples usando @VilleKoo css

var Dimmer = (function(){
  var el = $(".dimmer");
  
  return {
    showAt: function(x, y) {
      el
        .css({
          left: x,
          top: y,
        })
        .removeClass("hidden");
    },
    
    hide: function() {
      el.addClass("hidden");
    }
  }
}());


$(".btn-hide").click(function(){ Dimmer.hide(); });
$(".btn-show").click(function(){ Dimmer.showAt(50, 50); });
.dimmer {
  position: fixed;
  width: 200px;
  height: 200px;
  top: 50px;
  left: 50px;
  box-shadow: 0 0 0 1000px rgba(0,0,0,.3); /* for IE */
  box-shadow: 0 0 0 100vmax rgba(0,0,0,.3); /* for real browsers */
  pointer-events: none;
}

.hidden { display: none; }
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>

  <div>
    <input type="text">
    <select name="" id=""></select>
    <input type="checkbox">
  </div>
  <div>
    <input type="text">
    <select name="" id=""></select>
    <input type="checkbox">
  </div>
  <div>
    <input type="text">
    <select name="" id=""></select>
    <input type="checkbox">
  </div>
  <div>
    <input type="submit" disabled>
  </div>
  
  <input type="button" value="Hide" class="btn-hide">
  <input type="button" value="Show" class="btn-show">
  <div class="dimmer hidden"></div>
  <script src="https://code.jquery.com/jquery-2.2.4.js"></script>
</body>
</html>

Buksy
fonte
0
#bg {
   background-color: gray;
   opacity: 0.6;
   position: absolute;
   top: 0;
   left: 0;
   width: 100%;
   height: 100%;
   z-index: 99998;
}
#hole {
   position: fixed;
   top: 100px;
   left: 100px;
   width: 100px;
   height: 100px;
   z-index: 99999;
}
zerdnelemo
fonte