Передавать события мыши через абсолютно позиционированный элемент

307

Я пытаюсь захватить события мыши на элементе с другим абсолютно позиционированным элементом поверх него.

Прямо сейчас события в абсолютно позиционированном элементе попадают на него и всплывают до его родителя, но я хочу, чтобы он был «прозрачным» для этих событий мыши и направлял их во все, что за ним стоит. Как мне это реализовать?

s4y
источник

Ответы:

488
pointer-events: none;

Свойство CSS, которое заставляет события «проходить» через элемент, к которому оно применяется, и заставляет событие происходить в элементе «ниже».

Подробности см .: https://developer.mozilla.org/en/css/pointer-events.

Это не поддерживается до IE 11; все остальные поставщики поддерживают его уже довольно давно (глобальная поддержка составила ~ 92% в 12/16): http://caniuse.com/#feat=pointer-events (спасибо @ s4y за предоставленную ссылку в комментариях) ,

Jand
источник
3
Спасибо! Это идеальное решение для современных (и не IE) браузеров. В то время, когда этот вопрос был опубликован, я не думаю, что pointer-eventsсуществовал! Я могу переключить принятый ответ на этот в какой-то момент.
s4y
16
Вау, это только сэкономило мне часы.
Дан Абрамов
2
Я просто переключил принятый ответ на этот. Поддержка по- pointer-events прежнему не супер круто , но становится все лучше. Для более совместимого варианта, воспользуйтесь ответом @ JedSchmidt.
s4y
1
Спасибо, я никогда не знал, что это на самом деле существует. это спасло мне часы
Мохаммед А. Аль Джама
2
Но что делать, если вы просто хотите, чтобы какое-то событие, например, событие прокрутки, проходило, но верхний элемент по-прежнему реагировал на все другие события. Установка указателя-события в none убивает все события в верхнем элементе.
AndroidDev
50

Если все, что вам нужно, это mousedown, вы можете обойтись этим document.elementFromPointметодом:

  1. удаление верхнего слоя на mousedown,
  2. прохождения xи yкоординаты от случая к document.elementFromPointспособу , чтобы получить элемент под ним, а затем
  3. восстановление верхнего слоя.
Джед Шмидт
источник
9
Более многословное объяснение здесь: vinylfox.com/forwarding-mouse-events-through-layers
Натан
2
Круто, я даже не знал, что этот метод существует! Он может быть также использован довольно легко получить все элементы под курсором , используя то время как цикл , чтобы получить верхний элемент , а затем скрыть его, чтобы найти следующую. Возьмите мою версию здесь: gist.github.com/Pichan/5498404
jpeltoniemi
2
Проблема с этим обходным решением заключается в том, что он не работает с масштабированием страницы. Для мобильных устройств или настольных браузеров масштабирование по координатам XY больше ничего не значит, и нет четкого способа вычислить масштаб. я считаю, что для масштабирования это невозможно.
Impossibear
39

Также приятно знать ...
Pointer-events можно отключить для родительского элемента (возможно, прозрачного div) и все же включить для дочерних элементов. Это полезно, если вы работаете с несколькими перекрывающимися слоями div, где вы хотите иметь возможность щелкать дочерние элементы любого слоя. Для этого все родительские div-ы get pointer-events: noneи click-children получают указатели-события, которые можно включитьpointer-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>
Allisone
источник
5
Круто, сразу после пика открытий pointer-events:noneи неизбежного поражения детей узлами вы спасаете день :)
Хуан Кортес,
;) очень рад этому
Allisone
Можно ли его сводить к простому: .parent * { pointer-events:all; }для детей?
Дмитрий
Это должно быть "pointer-events: auto;". Значение «all» применяется только к SVG. См developer.mozilla.org/en-US/docs/Web/CSS/pointer-events
mattavatar
7

Причина, по которой вы не получаете событие, заключается в том, что абсолютно позиционированный элемент не является потомком элемента, который вы хотите «щелкнуть» (синий div). Самый чистый способ, который я могу придумать, - это поместить абсолютный элемент как дочерний элемент того, на который вы нажали, но я предполагаю, что вы не можете этого сделать, иначе вы бы не разместили этот вопрос здесь :)

Другой вариант - зарегистрировать обработчик события щелчка для абсолютного элемента и вызвать обработчик щелчка для синего элемента div, что приведет к их миганию.

Из-за того, что события происходят в DOM, я не уверен, что для вас есть более простой ответ, но мне очень любопытно, есть ли у кого-нибудь еще какие-то хитрости, о которых я не знаю!

Loktar
источник
Спасибо за ответ, Локтар. К сожалению, на реальной странице я не буду знать, что находится под абсолютно позиционированным элементом, и может быть более одной возможной цели. Единственный обходной путь, который я могу придумать, - это захват координат мыши и сравнение их с возможными целями, чтобы увидеть, пересекаются ли они. Это было бы просто противно.
s4y
4

Доступна версия javascript, которая вручную перенаправляет события из одного div в другой.

Я очистил его и превратил в плагин jQuery.

Вот хранилище Github: https://github.com/BaronVonSmeaton/jquery.forwardevents

К сожалению, цель, для которой я его использовал - наложение маски на Google Maps не захватывало события нажатия и перетаскивания, и курсор мыши не менялся, что настолько ухудшало пользовательский опыт, что я просто решил скрыть маску под IE и Opera - два браузера, которые не поддерживают события указателя.

Mikepote
источник
1

Если вы знаете элементы, для которых нужны события мыши, и если ваше наложение прозрачно, вы можете просто установить для их z-index значение, превышающее наложение. Все события должны, конечно, работать в этом случае во всех браузерах.

ricosrealm
источник