Passer des événements de souris à travers un élément absolument positionné

307

J'essaie de capturer les événements de souris sur un élément avec un autre élément absolument positionné au-dessus.

À l'heure actuelle, les événements sur l'élément absolument positionné le touchent et remontent jusqu'à son parent, mais je veux qu'il soit "transparent" à ces événements de souris et les transmette à tout ce qui se trouve derrière. Comment dois-je mettre cela en œuvre?

s4y
la source

Réponses:

488
pointer-events: none;

Est une propriété CSS qui fait que les événements "traversent" l'élément auquel ils sont appliqués et fait que l'événement se produit sur l'élément "en dessous".

Voir pour plus de détails: https://developer.mozilla.org/en/css/pointer-events

Il n'est pas pris en charge jusqu'à IE 11; tous les autres fournisseurs le supportent depuis un certain temps (le support global était de ~ 92% en 12 / '16): http://caniuse.com/#feat=pointer-events (merci à @ s4y pour avoir fourni le lien dans les commentaires) .

JanD
la source
3
Merci! Il s'agit d'une solution parfaite pour les navigateurs modernes (et non IE). Au moment où cette question a été publiée, je ne pense pas qu'elle pointer-eventsexistait! Je pourrais changer la réponse acceptée à celle-ci à un moment donné.
s4y
16
Woah, cela m'a juste fait gagner des heures.
Dan Abramov
2
Je viens de changer la réponse acceptée à celle-ci. Le support pointer-events n'est toujours pas super génial , mais il s'améliore. Pour une option plus compatible, allez avec la réponse de @ JedSchmidt.
s4y
1
Merci, je n'ai jamais su que cela existe réellement. cela m'a fait gagner des heures
Mohammed A. Al Jama
2
Mais que se passe-t-il si vous voulez simplement laisser passer un événement comme l'événement de défilement mais que l'élément supérieur réponde toujours à tous les autres événements. La définition de pointeur-événements sur aucun tue tous les événements de l'élément supérieur.
AndroidDev
50

Si tout ce dont vous avez besoin est de la souris, vous pouvez peut-être vous contenter de la document.elementFromPointméthode, en:

  1. enlever la couche supérieure au mousedown,
  2. en passant les coordonnées xet yde l'événement à la document.elementFromPointméthode pour obtenir l'élément en dessous, puis
  3. restauration de la couche supérieure.
Jed Schmidt
la source
9
Plus d'explications verbeuses ici: vinylfox.com/forwarding-mouse-events-through-layers
Nathan
2
Génial, je ne savais même pas que cette méthode existait! Il peut également être utilisé assez facilement pour obtenir tous les éléments sous le curseur à l' aide d' un en boucle pour obtenir l'élément supérieur, puis le cacher pour trouver le prochain. Prenez ma version ici: gist.github.com/Pichan/5498404
jpeltoniemi
2
Le problème avec cette solution de contournement est qu'elle ne fonctionne pas avec le zoom de la page. Pour les appareils mobiles ou les navigateurs de bureau, les coordonnées XY zoomées ne signifient plus rien et il n'y a pas de moyen clair de calculer le zoom. je crois que pour le zoom pincé, il est en fait impossible.
Impossibear
39

Aussi bon à savoir ... Les
événements de pointeur peuvent être désactivés pour un élément parent (probablement transparent div) et être activés pour les éléments enfants. Cela est utile si vous travaillez avec plusieurs couches div qui se chevauchent, où vous souhaitez pouvoir cliquer sur les éléments enfants de n'importe quelle couche. Pour cela, tous les divs parentaux obtiennent pointer-events: noneet les enfants click obtiennent des événements de pointeur réactivés parpointer-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>
Tout est un
la source
5
Génial, juste après le sommet de la découverte pointer-events:noneet l'abandon imminent d'avoir des nœuds enfants affectés, vous sauvez la journée :)
Juan Cortés
;) très heureux à ce sujet
Allisone
Peut-il se résumer à: .parent * { pointer-events:all; }pour les enfants?
Dmitry
Ce devrait être "pointeur-événements: auto;". La valeur "all" s'applique uniquement aux SVG. Voir developer.mozilla.org/en-US/docs/Web/CSS/pointer-events
mattavatar
7

La raison pour laquelle vous ne recevez pas l'événement est que l'élément positionné de manière absolue n'est pas un enfant de l'élément que vous souhaitez "cliquer" (div bleu). La façon la plus propre à laquelle je peux penser est de mettre l'élément absolu en tant qu'enfant de celui sur lequel vous voulez cliquer, mais je suppose que vous ne pouvez pas faire cela ou que vous n'auriez pas posté cette question ici :)

Une autre option serait d'enregistrer un gestionnaire d'événements de clic pour l'élément absolu et d'appeler le gestionnaire de clics pour le div bleu, les faisant clignoter tous les deux.

En raison de la façon dont les événements se propagent dans le DOM, je ne suis pas sûr qu'il existe une réponse plus simple pour vous, mais je suis très curieux de savoir si quelqu'un d'autre a des astuces que je ne connais pas!

Loktar
la source
Merci pour la réponse, Loktar. Malheureusement, sur la vraie page, je ne vais pas savoir ce qui se trouve sous l'élément absolument positionné, et il peut y avoir plus d'une cible possible. La seule solution de contournement à laquelle je peux penser est de saisir les coordonnées de la souris et de les comparer avec des cibles possibles pour voir si elles se croisent. Ce serait tout simplement méchant.
s4y
4

Il existe une version javascript disponible qui redirige manuellement les événements d'une div à l'autre.

Je l'ai nettoyé et transformé en un plugin jQuery.

Voici le référentiel Github: https://github.com/BaronVonSmeaton/jquery.forwardevents

Malheureusement, l'objectif pour lequel je l'utilisais - superposer un masque sur Google Maps n'a pas capturé les événements de clic et de glisser, et le curseur de la souris ne change pas, ce qui dégrade suffisamment l'expérience utilisateur pour que je décide de masquer le masque sous IE et Opera - les deux navigateurs qui ne prennent pas en charge les événements de pointeur.

Mikepote
la source
1

Si vous connaissez les éléments qui nécessitent des événements de souris et si votre superposition est transparente, vous pouvez simplement définir leur index z à quelque chose de plus élevé que la superposition. Tous les événements devraient bien sûr fonctionner dans ce cas sur tous les navigateurs.

ricosrealm
la source