Можно ли включить тень блока в область div, которая реагирует на событие щелчка?

У меня есть div, действующий как круглая кнопка. Он оформлен так, что значительная часть его общего вида исходит от box-shadow:

<body style="background:black">
<div id="button" style="width: 50px; height: 50px; background: yellow; border: none; border-radius: 50px; box-shadow: 0 0 0 5px #c03, 0 0 2px 7px #fff"></div>
</body>

У меня есть прослушиватель событий щелчка, прикрепленный к кнопке div. К сожалению, он не отвечает, если div щелкнуть по box-shadow, так как box-shadow отображается за пределами div.

Это особенно проблема на сенсорных устройствах, где палец иногда не попадает в центр div. (Конечно, он нормально реагирует, если щелчок находится в пределах области div 50px.)

Можно ли заставить прослушиватель событий реагировать на клики по box-shadow так же, как и по фактическому div?

Я понимаю, что могу использовать отдельный и более крупный прозрачный элемент div поверх кнопки и прикрепить к нему прослушиватель событий, но нужен ли такой обходной путь?

(Кнопка div должна иметь стиль box-shadow. Я не могу использовать свойство border или увеличивать padding.)


person meatsim    schedule 10.07.2015    source источник


Ответы (1)


Да, изменение тени box-shadow на inset сделает область, занимаемую тенью, также доступной для кликов. Box-shadow inset фактически добавляется внутри элемента, поэтому даже щелчок по тени рассматривается как щелчок по div.

window.onload = function() {
  var btn = document.querySelector("#button");
  var btnOriginal = document.querySelector("#button-original");

  btn.addEventListener("click", function() {
    alert("I have been clicked");
  });
  btnOriginal.addEventListener("click", function() {
    alert("I have been clicked");
  });
}
#button {
  width: 64px;
  height: 64px;
  border: none;
  border-radius: 50px;
  box-shadow: inset 0 0 2px 2px #fff, inset 0 0 0 7px #c03;
}
#button-original {
  width: 50px;
  height: 50px;
  border: none;
  border-radius: 50px;
  box-shadow: 0 0 0 5px #c03, 0 0 2px 7px #fff;
}

/* Just for demo */

#button {
  margin: 10px;
}
#button-original {
  margin: 17px;
}
div:hover {
  cursor: pointer;
}
body{
  background: black;
<div id="button"></div><!-- modified version -->

<div id="button-original"></div><!-- original version -->

Ниже приведены некоторые моменты, которые необходимо учитывать при изменении тени на встроенную:

  • Поскольку box-shadow добавляется внутрь, высота и ширина div должны быть немного увеличены, чтобы окончательный результат был того же размера, что и исходная версия. В обычной версии box-shadow размер формы будет равен радиусу контейнера + радиусу распространения.
  • Возможно, вам также придется настроить некоторые поля, как я сделал в примере ниже.
  • Любое размытие, добавленное к тени, теперь будет применяться внутрь (то есть размытие будет смешиваться с внутренней частью контейнера, а не с телом). Мы ничего не можем с этим поделать.

Примечание. В приведенном выше фрагменте я заменил содержимое встроенного атрибута стиля на CSS.


Если вы хотите, чтобы вторая тень (белая) размывалась наружу и сливалась с фоном тела, вы можете заменить box-shadow на radial-gradient, как в приведенном ниже примере. Но у использования radial-gradient есть два недостатка: во-первых, он хуже поддерживается браузерами, а во-вторых, кривые не очень гладкие, когда размер элемента очень мал.

window.onload = function() {
  var btn = document.querySelector("#button");
  var btn2 = document.querySelector("#button-2");

  btn.addEventListener("click", function() {
    alert("I have been clicked");
  });
  btn2.addEventListener("click", function() {
    alert("I have been clicked");
  });
}
#button {
  width: 75px;
  height: 75px;
  border: none;
  border-radius: 50%;
  background-image: radial-gradient(circle at 50% 50%, transparent 57.5%, #c03 57.5%, #c03 65%, #fff 65%, transparent 72%);
}
#button-2 {
  height: 150px;
  width: 150px;
  border: none;
  border-radius: 50%;
  background-image: radial-gradient(circle at 50% 50%, transparent 57.5%, #c03 57.5%, #c03 65%, #fff 65%, transparent 72%);
}
div:hover {
  cursor: pointer;
}
body {
  background: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div id="button"></div>
<div id="button-2"></div>

person Harry    schedule 10.07.2015
comment
Спасибо, это сработало. Чтобы сохранить размытие самой внешней тени, я добавил дополнительную тонкую и размытую тень, которая не была вставлена. - person meatsim; 10.07.2015
comment
@meatsim: Извините, не заметил размытую белую тень из-за фона. Вы также можете добиться этого с помощью вставки. Я обновил фрагмент в ответе. Вам просто нужно изменить порядок и радиус распространения. - person Harry; 10.07.2015
comment
Это выглядит здорово, спасибо. Я должен был включить темный фон в свой фрагмент вопроса. - person meatsim; 10.07.2015
comment
Размытие в вашем примере появляется внутри белой тени и смешивается с красной тенью. Я бы предпочел, чтобы он был снаружи и сливался с фоном тела. - person meatsim; 10.07.2015
comment
@meatsim: Ах, в этом случае я не думаю, что есть какой-либо вариант, кроме как добавить отдельный начальный элемент box-shadow, и, к сожалению, эта его часть не вызовет событие щелчка. - person Harry; 10.07.2015
comment
Но большая красная тень по-прежнему срабатывает, и это важный момент. Я остановился на box-shadow: 0 0 3px 1px #fff, 0 0 1px 2px #fff inset, 0 0 0 7px #c03 inset; - person meatsim; 10.07.2015