Passe os eventos do mouse pelo elemento absolutamente posicionado

307

Estou tentando capturar eventos de mouse em um elemento com outro elemento absolutamente posicionado em cima dele.

No momento, os eventos no elemento absolutamente posicionado o atingem e borbulham até o pai, mas quero que seja "transparente" para esses eventos do mouse e encaminhe-os para o que estiver por trás dele. Como devo implementar isso?

s4y
fonte

Respostas:

488
pointer-events: none;

É uma propriedade CSS que faz com que os eventos "passem" pelo elemento ao qual é aplicado e faz com que o evento ocorra no elemento "abaixo".

Veja para detalhes: https://developer.mozilla.org/en/css/pointer-events

Não é suportado até o IE 11; todos os outros fornecedores o suportam há algum tempo (o suporte global foi de ~ 92% em 12/16 ): http://caniuse.com/#feat=pointer-events (obrigado a @ s4y por fornecer o link nos comentários) .

JanD
fonte
3
Obrigado! Esta é uma solução perfeita para navegadores modernos (e não IE). No momento em que essa pergunta foi publicada, acho que não pointer-eventsexistia! Posso mudar a resposta aceita para essa em algum momento.
s4y
16
Uau, isso me salvou horas.
Dan Abramov
2
Acabei de mudar a resposta aceita para esta. O suporte para pointer-events ainda não é super impressionante , mas está ficando melhor. Para uma opção mais compatível, vá com a resposta de @ JedSchmidt.
S4y
1
Obrigado, eu nunca soube que isso realmente existe. ele me salvou horas
Mohammed A. Al Jama
2
Mas e se você quiser deixar passar algum evento, como o evento de rolagem, mas o elemento superior ainda responder a todos os outros eventos. Definir eventos-ponteiro como nenhum mata todos os eventos no elemento superior.
AndroidDev 31/07/19
50

Se tudo o que você precisa é mousedown, você pode se contentar com o document.elementFromPointmétodo:

  1. removendo a camada superior na ratoeira,
  2. passando as coordenadas xe ydo evento para o document.elementFromPointmétodo para obter o elemento abaixo e, em seguida,
  3. restaurando a camada superior.
Jed Schmidt
fonte
9
Mais explicação prolixo aqui: vinylfox.com/forwarding-mouse-events-through-layers
Nathan
2
Incrível, eu nem sabia que esse método existia! Ele pode também ser usado com bastante facilidade para obter todos os elementos sob cursor usando um enquanto loop para obter o elemento superior e depois escondê-lo, a fim de encontrar o próximo. Pegue minha versão aqui: gist.github.com/Pichan/5498404
jpeltoniemi
2
O problema com esta solução alternativa é que ela não funciona com o zoom da página. Para dispositivos móveis ou navegadores de desktop com zoom nas coordenadas XY, isso não significa mais nada e não há uma maneira clara de calcular o zoom. Eu acredito que para pitada de zoom é realmente impossível.
Impossibear
39

Também é bom saber ...
Eventos de ponteiro podem ser desativados para um elemento pai (provavelmente div transparente) e ainda assim serem ativados para elementos filho. Isso é útil se você trabalha com várias camadas div sobrepostas, nas quais deseja poder clicar nos elementos filhos de qualquer camada. Para isso, todas as divs parentais recebem pointer-events: nonee os filhos clicados recebem eventos-ponteiro reativados porpointer-events: all

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

<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
5
Awesome, logo após a alta de descobrir pointer-events:noneea iminente let-down de ter nós filhos afetados, você salvar o dia :)
Juan Cortés
;) muito contente com isso #
Allisone
Pode ser resumido apenas a: .parent * { pointer-events:all; }para crianças?
Dmitry
Deve ser "eventos-ponteiro: auto;". O valor "all" se aplica apenas aos SVGs. Veja developer.mozilla.org/pt-BR/docs/Web/CSS/pointer-events
mattavatar
7

O motivo pelo qual você não está recebendo o evento é porque o elemento absolutamente posicionado não é filho do elemento que você deseja "clicar" (div azul). A maneira mais limpa em que consigo pensar é colocar o elemento absoluto como filho daquele em que você deseja clicar, mas presumo que você não possa fazer isso ou não teria postado essa pergunta aqui :)

Outra opção seria registrar um manipulador de eventos click para o elemento absoluto e chamar o manipulador click para a div azul, fazendo com que ambos piscassem.

Devido à forma como os eventos surgem no DOM, não tenho certeza de que haja uma resposta mais simples para você, mas estou muito curioso se alguém tiver mais truques que eu não conheço!

Loktar
fonte
Obrigado pela resposta, Loktar. Infelizmente, na página real, não vou saber o que há por baixo do elemento absolutamente posicionado, e pode haver mais de um alvo possível. A única solução alternativa em que consigo pensar é pegar as coordenadas do mouse e compará-las com os possíveis alvos para ver se eles se cruzam. Isso seria simplesmente desagradável.
S4y
4

Existe uma versão javascript disponível que redireciona manualmente os eventos de uma div para outra.

Eu limpei e transformei em um plugin jQuery.

Aqui está o repositório do Github: https://github.com/BaronVonSmeaton/jquery.forwardevents

Infelizmente, o objetivo para o qual eu o estava usando - sobrepor uma máscara ao Google Maps não capturava eventos de clique e arraste, e o cursor do mouse não muda, o que prejudica a experiência do usuário o suficiente para que eu decidisse ocultar a máscara no IE e no Opera - os dois navegadores que não suportam eventos de ponteiro.

Mikepote
fonte
1

Se você conhece os elementos que precisam de eventos do mouse e sua sobreposição é transparente, basta definir o índice z deles para algo maior que a sobreposição. Todos os eventos devem, obviamente, funcionar nesse caso em todos os navegadores.

ricosrealm
fonte