Cliquez sur div pour accéder aux éléments sous-jacents

1593

J'ai un divqui a background:transparent, avec border. En dessous div, j'ai plus d'éléments.

Actuellement, je peux cliquer sur les éléments sous-jacents lorsque je clique en dehors de la superposition div. Cependant, je ne peux pas cliquer sur les éléments sous-jacents lorsque je clique directement sur la superposition div.

Je veux pouvoir cliquer dessus divpour pouvoir cliquer sur les éléments sous-jacents.

Mon problème

Ryan
la source

Réponses:

2616

Oui, vous POUVEZ le faire.

En utilisant des pointer-events: noneinstructions conditionnelles CSS pour IE11 (ne fonctionne pas dans IE10 ou ci-dessous), vous pouvez obtenir une solution compatible avec plusieurs navigateurs pour ce problème.

À l'aide de AlphaImageLoader, vous pouvez même placer des .PNG/.GIFs transparents dans la superposition divet faire en sorte que les clics traversent les éléments situés en dessous.

CSS:

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

IE11 conditionnel:

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

Voici une page d'exemple de base avec tout le code.

LawrenceKSRealEstate
la source
7
que faire si j'utilise des transitions ou des états de vol stationnaire sur cette div?
Manticore
2
@Manticore Réponse courte: vous ne pouvez pas. Dans ce cas, la réponse fournie ne fonctionne pas.
Niels Abildgaard
10
IE11 prend entièrement en charge les événements de pointeur. Cela signifie que tous les navigateurs modernes le prennent en charge. Il s'agit d'une solution réalisable à la fin de 2014. caniuse.com/#search=pointer-events
Judah Gabriel Himango
Comme indiqué par @Andy, cela interrompt le défilement. J'ai ouvert un problème distinct pour voir s'il existe une solution à ce stackoverflow.com/questions/41592349/…
Oliver Joseph Ash
1
@Manticore J'ai trouvé que vous pouvez remplacer "pointer-events: none;" pour l'élément imbriqué, vous pouvez donc écrire quelque chose contourné par clic avec quelque chose qui obtient le clic et plus, pour les parties écrasées, vous pouvez utiliser des effets et cliquer
Luca C.
292

Aussi agréable à savoir ...
Vous pouvez désactiver les événements de pointeur dans un élément parent (probablement un div transparent) mais le garder activé pour ses éléments enfants.
Cela est utile si vous travaillez avec plusieurs calques div qui se chevauchent, où vous voulez pouvoir cliquer sur les éléments enfants, tout en ne faisant réagir les calques parents sur aucun événement de souris.

Pour cela, tous les divs parentaux obtiennent pointer-events: noneet ses enfants cliquables reçoivent des événements de pointeur réactivés parpointer-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>
Tout est un
la source
4
Parfait, c'est exactement ce dont j'avais besoin!
RobbyReindeer
1
super utile, merci
SpaceBear
43

Autoriser l'utilisateur à cliquer sur un divélément sous-jacent dépend du navigateur. Tous les navigateurs modernes, y compris Firefox, Chrome, Safari et Opera, comprennent pointer-events:none.

Pour IE, cela dépend de l'arrière-plan. Si l'arrière-plan est transparent, le clic fonctionne sans que vous ayez besoin de faire quoi que ce soit. D'un autre côté, pour quelque chose comme background:white; opacity:0; filter:Alpha(opacity=0);, IE a besoin d'un transfert d'événement manuel.

Voir un test JSFiddle et des événements de pointeur CanIUse .

Vladimir Prodan
la source
20

J'ajoute cette réponse parce que je ne l'ai pas vue ici en entier. J'ai pu le faire en utilisant elementFromPoint. Donc en gros:

  • attachez un clic à la div que vous souhaitez cliquer
  • cache le
  • déterminer sur quel élément se trouve le pointeur
  • déclencher le clic sur l'élément là-bas.
var range-selector= $("")
    .css("position", "absolute").addClass("range-selector")
    .appendTo("")
    .click(function(e) {
        _range-selector.hide();

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

Dans mon cas, le div superposé est absolument positionné - je ne sais pas si cela fait une différence. Cela fonctionne sur IE8 / 9, Safari Chrome et Firefox au moins.

Tim
la source
12
  1. Masquer la superposition de l'élément
  2. Déterminer les coordonnées du curseur
  3. Obtenir un élément sur ces coordonnées
  4. Déclencher un clic sur l'élément
  5. Afficher à nouveau l'élément superposé
$('#elementontop').click(e => {
    $('#elementontop').hide();
    $(document.elementFromPoint(e.clientX, e.clientY)).trigger("click");
    $('#elementontop').show();
});
wcloister
la source
Avez-vous oublié de fermer les apostrophes? Ça $('#elementontop)devrait peut -être l'être $('#elementontop')?
johannchopin
10

J'avais besoin de le faire et j'ai décidé d'emprunter cette voie:

$('.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
la source
6

Je travaille actuellement avec des ballons de discours en toile. Mais comme le ballon avec le pointeur est enveloppé dans un div, certains liens en dessous ne sont plus capables de cliquer. Je ne peux pas utiliser extjs dans ce cas. Voir l'exemple de base pour mon tutoriel de bulle de discours nécessite HTML5

J'ai donc décidé de collecter toutes les coordonnées du lien à l'intérieur des ballons dans un tableau.

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]);
                                     });
         }

J'appelle cette fonction sur chaque (nouveau) ballon. Il saisit les coordonnées des coins gauche / haut et droit / bas d'un link.class - en plus l'attribut de nom pour quoi faire si quelqu'un clique sur ces coordonnées et j'ai adoré définir un 1 ce qui signifie qu'il n'a pas été cliqué sur jet . Et décompressez ce tableau dans le tableau de clics. Vous pouvez également utiliser push.

Pour travailler avec ce tableau:

$("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 --
            }
          });

Cette fonction vérifie les coordonnées d'un événement de clic de corps ou s'il a déjà été cliqué et renvoie l'attribut de nom. Je pense qu'il n'est pas nécessaire d'aller plus loin, mais vous voyez que ce n'est pas si compliqué. L'espoir était enlish ...

BF
la source
4

cela ne fonctionne pas de cette façon. la solution consiste à vérifier manuellement les coordonnées du clic de la souris par rapport à la zone occupée par chaque élément.

la zone occupée par un élément peut être trouvée en 1. obtenant l'emplacement de l'élément par rapport au coin supérieur gauche de la page, et 2. la largeur et la hauteur. une bibliothèque comme jQuery rend cela assez simple, bien que cela puisse être fait en js ordinaire. l'ajout d'un gestionnaire d'événements mousemovesur l' documentobjet fournira des mises à jour continues de la position de la souris en haut et à gauche de la page. décider si la souris se trouve sur un objet donné consiste à vérifier si la position de la souris se situe entre les bords gauche, droit, supérieur et inférieur d'un élément.

lincolnk
la source
2
Comme mentionné ci-dessus, vous pouvez y parvenir en utilisant des CSS {pointer-events: none;} sur votre conteneur transparent.
Empereol
4

Non, vous ne pouvez pas cliquer sur un élément. Vous pouvez obtenir les coordonnées du clic et essayer de déterminer quel élément se trouvait sous l'élément cliqué, mais cela est vraiment fastidieux pour les navigateurs qui n'en ont pas document.elementFromPoint. Ensuite, vous devez toujours émuler l'action par défaut de cliquer, ce qui n'est pas nécessairement trivial selon les éléments que vous avez en dessous.

Étant donné que vous avez une zone de fenêtre entièrement transparente, vous feriez probablement mieux de l'implémenter en tant qu'éléments de bordure séparés autour de l'extérieur, laissant la zone centrale libre de toute obstruction afin que vous puissiez vraiment simplement cliquer directement.

bobince
la source
4

Une autre idée à essayer (situationnellement) serait de:

  1. Mettez le contenu que vous voulez dans une div;
  2. Placez la superposition sans clic sur toute la page avec un z-index supérieur,
  3. faire une autre copie recadrée du div original
  4. la superposition et les abs positionnent le div de copie au même endroit que le contenu original sur lequel vous voulez être cliquable avec un z-index encore plus élevé?

Des pensées?

Adam
la source
2

Je pense que vous pouvez envisager de modifier votre balisage. Si je ne me trompe pas, vous souhaitez mettre un calque invisible au-dessus du document et votre balisage invisible peut précéder l'image de votre document (est-ce correct?).

Au lieu de cela, je vous propose de mettre l'invisible juste après l'image du document mais en changeant la position en absolu.

Notez que vous avez besoin d'un élément parent pour avoir position: relative et vous pourrez ensuite utiliser cette idée. Sinon, votre couche absolue sera placée juste dans le coin supérieur gauche.

Un élément de position absolue est positionné par rapport au premier élément parent qui a une position autre que statique. Si aucun élément de ce type n'est trouvé, le bloc contenant est html

J'espère que cela t'aides. Voir ici pour plus d'informations sur le positionnement CSS.

julianm
la source
2

Il suffit d'enrouler la abalise autour de tous les extraits HTML, par exemple

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

dans mon exemple, ma classe de sous-titres a des effets de survol, avec des événements de pointeur: aucun; tu vas juste perdre

Envelopper le contenu gardera vos effets de survol et vous pouvez cliquer sur toute l'image, div incluse, salut!

Alexis
la source
bon point! thnks
Mr.Vertigo
1

Vous pouvez placer une superposition AP comme ...

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

il suffit de le mettre là où vous ne voulez pas, c'est-à-dire cliked. Fonctionne en tout.

eric
la source
1

Un moyen plus simple consisterait à aligner l'image d'arrière-plan transparente à l'aide des URI de données comme suit:

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

Je pense que le event.stopPropagation();devrait également être mentionné ici. Ajoutez ceci à la fonction Click de votre bouton.

Empêche l'événement de se propager dans l'arborescence DOM, empêchant les gestionnaires parents d'être notifiés de l'événement.

kenny
la source
0

Ce n'est pas une réponse précise à la question, mais peut aider à trouver une solution de contournement.

J'avais une image que je cachais lors du chargement de la page et que j'affichais lorsque j'attendais un appel AJAX puis que je me cachais à nouveau cependant ...

J'ai trouvé le seul moyen d'afficher mon image lors du chargement de la page, puis de la faire disparaître et de pouvoir cliquer sur les éléments où l'image se trouvait avant de la cacher, c'était de mettre l'image dans un DIV, de faire la taille du DIV 10x10 pixels ou petit assez pour l'empêcher de provoquer un problème, puis masquer le div contenant. Cela a permis à l'image de déborder de la div lorsqu'elle était visible et lorsque la div était cachée, seule la zone des div était affectée par l'impossibilité de cliquer sur les objets en dessous et non par toute la taille de l'image que la DIV contenait et affichait.

J'ai essayé toutes les méthodes pour masquer l'image, y compris CSS display = none / block, opacity = 0, cachant l'image avec hidden = true. Tous ont entraîné la dissimulation de mon image, mais la zone où elle était affichée pour agir comme s'il y avait une couverture sur le truc en dessous, donc les clics et ainsi de suite n'agiraient pas sur les objets sous-jacents. Une fois que l'image était à l'intérieur d'un minuscule DIV et que j'ai caché le minuscule DIV, toute la zone occupée par l'image était claire et seule la minuscule zone sous le DIV que j'ai cachée a été affectée mais comme je l'ai rendue suffisamment petite (10x10 pixels), le problème a été corrigé (en quelque sorte).

J'ai trouvé que c'était une solution de contournement pour ce qui devrait être un problème simple, mais je n'ai pas trouvé de moyen de masquer l'objet dans son format natif sans conteneur. Mon objet était sous la forme de etc. Si quelqu'un a une meilleure solution, faites-le moi savoir.

David Crawford
la source