¿Atenuar toda la pantalla excepto un área fija?

88

Quiero crear un tutorial que guíe al usuario exactamente donde hacer clic. Estoy tratando de cubrir toda la pantalla con una <div>, que se atenuará todos los elementos excepto una región específica que se encuentra en un fijo width, height, topy left.

El problema es que no puedo encontrar una manera de "cancelar" el de los padres background-color(que también es transparente).

En el recortado a continuación, holeestá el div que se supone que no tiene ninguno background-color, incluido el de su padre.

¿Se puede lograr esto en absoluto? ¿Algunas ideas?

#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>

Aquí hay una imagen de maqueta de lo que estoy tratando de lograr:

ingrese la descripción de la imagen aquí

Koby Douek
fuente
13
Si está creando un recorrido / tutorial de funciones, es posible que le interese una de las bibliotecas js para hacer esto. Tienen algunas características ingeniosas y le ahorrarán la molestia de escribir un montón de efectos CSS únicos. Visite introjs.com o linkedin.github.io/hopscotch .
octern
2
Esto es solo una sugerencia para lib: heelhook.github.io/chardin.js
línea Thomas

Respuestas:

125

Podrías hacerlo con solo uno divy darle un box-shadow.

EDITAR: como señaló @Nick Shvelidze, debería considerar agregarpointer-events: none

vmaxValor agregado para box-shadowcomo sugirió @Prinzhorn

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
fuente
28
Asegúrese de agregar pointer-events: nonesi desea que se pueda hacer clic en el área debajo.
Nick Shvelidze
4
1,000px no me parece suficiente; parece que habría demasiados casos en los que esto no llena la pantalla, de lo contrario, una solución realmente inteligente.
ESR
1
@EdmundReed, puedes ajustar eso a tus necesidades :)
VilleKoo
8
box-shadow: 0 0 0 100vmax rgba(0,0,0,.3);se garantizará que cubra toda la pantalla
Prinzhorn
2
@VilleKoo puede agregarlo detrás de la línea de 1000px y mantenerlo como un respaldo
Prinzhorn
19

Puede crear un SVG que se rellena con una ruta que tiene el agujero donde lo necesita. Pero supongo que necesita encontrar una manera de manejar los clics, ya que todos ellos estarán dirigidos al svg superpuesto. Creo que document.getElementFromPointpuedo ayudarte aquí. mdn

philipp
fuente
Creo que el formulario de comentarios de Google usa svg para atenuar el área de descanso.
Durga
3

Esto también se puede hacer de manera similar a la respuesta de @ VilleKoo, pero con un borde.

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
fuente
2

Puede lograr lo mismo que en la respuesta de VilleKoo usando la outlinepropiedad CSS . Tiene un excelente soporte de navegador (y funciona también en IE8 +). Los contornos tienen la misma sintaxis que los bordes, pero a diferencia del borde, no ocupan espacio, se dibujan sobre el contenido.

También para IE9 + puede reemplazar 99999pxcon calc(100 * (1vh + 1vw - 1vmin)).

La desventaja de este enfoque es que outlineno se ve afectado por border-radius.

Manifestación:

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
fuente
0

Aquí hay un código jQuery simple 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
fuente
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
fuente