Clique em div para elementos subjacentes

1593

Eu tenho um divque tem background:transparent, junto com border. Por trás disso div, tenho mais elementos.

Atualmente, posso clicar nos elementos subjacentes quando clico fora da sobreposição div. No entanto, não consigo clicar nos elementos subjacentes ao clicar diretamente na sobreposição div.

Quero poder clicar nisso divpara poder clicar nos elementos subjacentes.

Meu problema

Ryan
fonte

Respostas:

2616

Sim, você pode fazer isso.

Usando pointer-events: nonejuntamente com instruções condicionais CSS para o IE11 (não funciona no IE10 ou abaixo), você pode obter uma solução compatível com vários navegadores para esse problema.

Usando AlphaImageLoader, você pode até colocar .PNG/.GIFs transparentes na sobreposição dive fazer com que os cliques fluam para os elementos abaixo.

CSS:

pointer-events: none;
background: url('your_transparent.png');

IE11 condicional:

filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='your_transparent.png', sizingMethod='scale');
background: none !important;

Aqui está uma página de exemplo básico com todo o código.

LawrenceKSRealEstate
fonte
7
e se eu estiver usando transições ou estados de pairar nessa div?
Manticore 29/10
2
@Manticore Resposta curta: Você não pode. Nesse caso, a resposta fornecida não funciona.
Niels Abildgaard
10
O IE11 suporta totalmente eventos de ponteiro. Isso significa que todos os navegadores modernos são compatíveis. Esta é uma solução viável a partir de final de 2014. caniuse.com/#search=pointer-events
Judah Gabriel Himango
Como observado por @Andy, isso interrompe a rolagem. Eu abri um problema separado para ver se há uma solução para este stackoverflow.com/questions/41592349/… #
Oliver Joseph Ash
1
@ Atlanticore eu achei que você pode substituir "eventos-ponteiro: nenhum;" para o elemento aninhado, assim você pode escrever algo contornado por clique com algo que obter o clique e mais, para as partes sobrescritos que você pode usar efeitos e clique
Luca C.
292

Também é bom saber ...
Você pode desativar os eventos de ponteiro em um elemento pai (provavelmente div transparente), mas ainda assim ele está ativado para seus elementos filhos.
Isso é útil se você trabalha com várias camadas div sobrepostas, nas quais deseja poder clicar em elementos filhos, enquanto as camadas pai não reagem a nenhum evento do mouse.

Para isso, todas as divs parentais recebem pointer-events: nonee seus filhos clicáveis ​​recebem eventos-ponteiro reativados porpointer-events: auto

.parent {
    pointer-events:none;        
}
.child {
    pointer-events:auto;
}

<div class="some-container">
   <ul class="layer-0 parent">
     <li class="click-me child"></li>
     <li class="click-me child"></li>
   </ul>

   <ul class="layer-1 parent">
     <li class="click-me-also child"></li>
     <li class="click-me-also child"></li>
   </ul>
</div>
Tudo é um
fonte
4
Perfeito, é exatamente isso que eu precisava!
RobbyReindeer
1
super útil, obrigado
SpaceBear
43

Permitir que o usuário clique através de um divpara o elemento subjacente depende do navegador. Todos os navegadores modernos, incluindo Firefox, Chrome, Safari e Opera, entendem pointer-events:none.

Para o IE, isso depende do plano de fundo. Se o plano de fundo for transparente, o clique funcionará sem a necessidade de fazer nada. Por outro lado, para algo como background:white; opacity:0; filter:Alpha(opacity=0);, o IE precisa de encaminhamento manual de eventos.

Veja um teste JSFiddle e eventos de ponteiro CanIUse .

Vladimir Prodan
fonte
20

Estou adicionando esta resposta porque não a vi aqui na íntegra. Consegui fazer isso usando o elementFromPoint. Então, basicamente:

  • anexe um clique ao div em que você deseja clicar
  • esconda isso
  • determinar em qual elemento o ponteiro está
  • acionar o clique no elemento lá.
var range-selector= $("")
    .css("position", "absolute").addClass("range-selector")
    .appendTo("")
    .click(function(e) {
        _range-selector.hide();

        $(document.elementFromPoint(e.clientX,e.clientY)).trigger("click");
    });

No meu caso, a div de sobreposição está absolutamente posicionada - não tenho certeza se isso faz diferença. Isso funciona no IE8 / 9, Safari Chrome e Firefox pelo menos.

Tim
fonte
12
  1. Ocultar sobreposição do elemento
  2. Determinar coordenadas do cursor
  3. Obter elemento nessas coordenadas
  4. Disparar clique no elemento
  5. Mostrar elemento de sobreposição novamente
$('#elementontop').click(e => {
    $('#elementontop').hide();
    $(document.elementFromPoint(e.clientX, e.clientY)).trigger("click");
    $('#elementontop').show();
});
wcloister
fonte
Você esqueceu de fechar os apóstrofos? Talvez $('#elementontop)devesse ser $('#elementontop')?
johannchopin 18/04
10

Eu precisava fazer isso e decidi seguir esse caminho:

$('.overlay').click(function(e){
    var left = $(window).scrollLeft();
    var top = $(window).scrollTop();

    //hide the overlay for now so the document can find the underlying elements
    $(this).css('display','none');
    //use the current scroll position to deduct from the click position
    $(document.elementFromPoint(e.pageX-left, e.pageY-top)).click();
    //show the overlay again
    $(this).css('display','block');
});
Matthew Grima
fonte
6

Atualmente, trabalho com balões de fala em tela. Mas como o balão com o ponteiro está envolvido em uma div, alguns links abaixo dele não podem mais ser clicados. Eu não posso usar extjs neste caso. Veja o exemplo básico do meu tutorial de balão de fala requer HTML5

Então, decidi coletar todas as coordenadas do link de dentro dos balões em uma matriz.

var clickarray=[];
function getcoo(thatdiv){
         thatdiv.find(".link").each(function(){
                 var offset=$(this).offset();           
                 clickarray.unshift([(offset.left),
                                     (offset.top),
                                     (offset.left+$(this).width()),
                                     (offset.top+$(this).height()),
                                     ($(this).attr('name')),
                                     1]);
                                     });
         }

Eu chamo essa função em cada (novo) balão. Ele pega as coordenadas dos cantos esquerdo / superior e direito / baixo de um link.class - adicionalmente, o atributo name para o que fazer se alguém clicar nessas coordenadas e eu adorei definir um 1, o que significa que não foi clicado. . E desvie essa matriz para a matriz de cliques. Você também pode usar push.

Para trabalhar com essa matriz:

$("body").click(function(event){
          event.preventDefault();//if it is a a-tag
          var x=event.pageX;
          var y=event.pageY;
          var job="";
          for(var i in clickarray){
              if(x>=clickarray[i][0] && x<=clickarray[i][2] && y>=clickarray[i][1] && y<=clickarray[i][3] && clickarray[i][5]==1){
                 job=clickarray[i][4];
                 clickarray[i][5]=0;//set to allready clicked
                 break;
                }
             }
          if(job.length>0){   
             // --do some thing with the job --
            }
          });

Essa função prova as coordenadas de um evento de clique no corpo ou se ele já foi clicado e retorna o atributo name. Eu acho que não é necessário ir mais fundo, mas você vê que não é tão complicado. A esperança era enlish ...

BF
fonte
4

não funciona assim. a solução é verificar manualmente as coordenadas do clique do mouse na área ocupada por cada elemento.

a área ocupada por um elemento pode ser encontrada por 1. obtendo a localização do elemento em relação à parte superior esquerda da página e 2. a largura e a altura. uma biblioteca como o jQuery torna isso bastante simples, embora possa ser feito em js simples. adicionar um manipulador de eventos mousemoveno documentobjeto fornecerá atualizações contínuas da posição do mouse na parte superior e esquerda da página. decidir se o mouse está sobre um objeto específico consiste em verificar se a posição do mouse está entre as bordas esquerda, direita, superior e inferior de um elemento.

Lincolnshire
fonte
2
Como mencionado acima, você pode conseguir isso usando CSSs {pointer-events: none;} no seu contêiner transparente.
Empereol
4

Não, você não pode clicar em um elemento. Você pode obter as coordenadas do clique e tentar descobrir qual elemento estava abaixo do elemento clicado, mas isso é realmente tedioso para navegadores que não possuem document.elementFromPoint. Então você ainda precisa emular a ação padrão de clicar, o que não é necessariamente trivial, dependendo de quais elementos você possui.

Como você tem uma área de janela totalmente transparente, provavelmente será melhor implementá-la como elementos de borda separados ao redor do lado de fora, deixando a área central livre de obstruções, para que você possa simplesmente clicar diretamente.

bobince
fonte
4

Outra idéia para tentar (situacionalmente) seria:

  1. Coloque o conteúdo que você deseja em uma div;
  2. Coloque a sobreposição sem cliques em toda a página com um índice z maior,
  3. faça outra cópia recortada da div original
  4. overlay e abs posicionam a cópia div no mesmo local que o conteúdo original que você deseja clicar com um índice z ainda mais alto?

Alguma ideia?

Adão
fonte
2

Eu acho que você pode considerar mudar sua marcação. Se não estiver errado, você gostaria de colocar uma camada invisível acima do documento e sua marcação invisível pode estar precedendo a imagem do documento (isso está correto?).

Em vez disso, proponho que você coloque o invisível logo após a imagem do documento, mas altere a posição para absoluto.

Observe que você precisa de um elemento pai para ter a posição: relativa e, em seguida, você poderá usar essa ideia. Caso contrário, sua camada absoluta será colocada no canto superior esquerdo.

Um elemento de posição absoluto é posicionado em relação ao primeiro elemento pai que possui uma posição diferente de estática. Se nenhum desses elementos for encontrado, o bloco que contém é html

Espero que isto ajude. Veja aqui para mais informações sobre o posicionamento CSS.

julianm
fonte
2

Apenas envolva a atag em todo o extrato HTML, por exemplo

<a href="/categories/1">
  <img alt="test1" class="img-responsive" src="/assets/photo.jpg" />
  <div class="caption bg-orange">
    <h2>
      test1
    </h2>
  </div>
</a>

no meu exemplo, minha classe de legenda tem efeitos de foco, que com eventos-ponteiro: nenhum; você só vai perder

embrulhar o conteúdo manterá seus efeitos de foco e você pode clicar em toda a imagem, incluindo div, cumprimentos!

Alexis
fonte
bom ponto! thnks
Mr.Vertigo 17/04
1

Você pode colocar uma sobreposição de AP como ...

#overlay {
  position: absolute;
  top: -79px;
  left: -60px;
  height: 80px;
  width: 380px;
  z-index: 2;
  background: url(fake.gif);
}
<div id="overlay"></div>

basta colocá-lo onde você não quer, ou seja, clicou. Funciona em todos.

Eric
fonte
1

Uma maneira mais fácil seria alinhar a imagem de plano de fundo transparente usando os URIs de dados da seguinte maneira:

.click-through {
    pointer-events: none;
    background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
}
MathuSum Mut
fonte
0

Eu acho que o event.stopPropagation();deve ser mencionado aqui também. Adicione isso à função Click do seu botão.

Impede que o evento borbulhe na árvore DOM, impedindo que qualquer manipulador pai seja notificado sobre o evento.

kenny
fonte
0

Esta não é uma resposta precisa para a pergunta, mas pode ajudar a encontrar uma solução alternativa para ela.

Eu tinha uma imagem que eu estava escondendo no carregamento da página e exibindo ao esperar uma chamada AJAX e depois me ocultar novamente ...

Encontrei a única maneira de exibir minha imagem ao carregar a página e depois fazê-la desaparecer e poder clicar nas coisas em que a imagem estava localizada antes de ocultá-la, era para colocar a imagem em um DIV, fazer o tamanho do DIV 10x10 pixels ou pequeno o suficiente para evitar que isso cause um problema e ocultar a div que contém. Isso permitiu que a imagem transbordasse da div enquanto visível e quando a div estava oculta, apenas a área divs foi afetada pela incapacidade de clicar nos objetos abaixo e não no tamanho total da imagem que o DIV continha e estava sendo exibido.

Eu tentei todos os métodos para ocultar a imagem, incluindo CSS display = none / block, opacity = 0, ocultando a imagem com hidden = true. Todos eles resultaram na ocultação da minha imagem, mas a área em que ela foi exibida agia como se houvesse uma cobertura sobre o material por baixo, para que cliques e assim por diante não atuassem nos objetos subjacentes. Quando a imagem estava dentro de um DIV minúsculo e eu o escondi, toda a área ocupada pela imagem ficou nítida e apenas a pequena área sob o DIV que eu escondi foi afetada, mas como a tornei pequena o suficiente (10x10 pixels), o problema foi corrigido (mais ou menos).

Achei que era uma solução alternativa suja para o que deveria ser um problema simples, mas não consegui encontrar nenhuma maneira de ocultar o objeto em seu formato nativo sem um contêiner. Meu objeto estava na forma de etc. Se alguém tiver uma maneira melhor, informe-me.

David Crawford
fonte