Reputation: 3831
I have a simple overlay that I want to catch click events on. Problem is, I don't want any clicks that occur within the content of the overlay to trigger an event. For example, if you look at my code snippet below, clicking inside the .content
div should not trigger the click event listener that I set on the overlay, but it does.
Basically I want to just know when someone clicks the black background of the overlay. Is there anyway to do this with how I currently have my code?
const overlay = document.querySelector('.overlay')
overlay.onclick = function() {
console.log('click on overlay!')
}
body {
margin: 0;
}
.overlay {
position: fixed;
top: 0;
left: 0;
background-color: rgba(0,0,0,0.5);
width: 100%;
height: 100%;
z-index: 10;
}
.content {
width: 200px;
height: 200px;
position: absolute;
z-index: 11;
top: calc(50% - 100px);
left: calc(50% - 100px);
background: white;
display: flex;
align-items: center;
justify-content: center;
}
<div class="overlay">
<div class="content">Hello World</div>
</div>
Upvotes: 3
Views: 4203
Reputation: 45
I had the same issue and it was resolved by not enclosing the content div within the overlay div:
For instance, instead of:
<div class="overlay">
<div class="content">Hello World</div>
</div>
Did this:
<div class="overlay"></div>
<div class="content">Hello World</div>
Upvotes: 0
Reputation: 539
To solve this problem of yours you need to understand how javascript events works. There are three phases of event:
Capturing phase:
When you trigger some event javascript starts to handle it by passing from the very top element(Window) to children. It happens until target(.content
) element reached. In your case event goes through .overlay
element but event handler not triggered, because by default all event listeners triggers on bubbling or target
phase
Target phase:
The event has arrived at the event's target. The very element on which element was triggered, which in your case is .content
Bubbling phase:
The event is propagating back up through the target's ancestors in reverse order, starting with the parent and eventually reaching the containing Window. During this phase your event passing through .overlay
element and invokes event handler which was registered.
I don't know what is best solution for your problem but it can be solved in several ways:
Solution proposed by @PsiKai and @Joulss where you're checking target element by class name. Registered event listener
Solution proposed by @eMentorship. By changing the markup, event at bubbling phase doesn't touch .overlay
element.
const content = document.querySelector('.element');
content.addEventListener('click', event => event.stopPropagation());
By calling stopPropagation
you stoping event from going to the parent element and as a result .overlay
event handler ignored as event not bubbling to the root element.
Event phase: https://developer.mozilla.org/en-US/docs/Web/API/Event/eventPhase
PS. According to MDN: The addEventListener()
method is the recommended way to register an event listener. The benefits are as follows:
Upvotes: 1
Reputation: 116
Just restructure your HTML code and it will work fine, as you have already set the z-index
for overlay and content as well. so as content has a higher z-index
than the overlay, so it will be hidden by the content.
Demo:
const overlay = document.querySelector('.overlay')
overlay.onclick = function() {
console.log('click on overlay!')
}
body {
margin: 0;
}
.popup {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;;
}
.overlay {
position: fixed;
top: 0;
left: 0;
background-color: rgba(0,0,0,0.5);
width: 100%;
height: 100%;
z-index: 10;
}
.content {
width: 200px;
height: 200px;
position: absolute;
z-index: 11;
top: calc(50% - 100px);
left: calc(50% - 100px);
background: white;
display: flex;
align-items: center;
justify-content: center;
}
<div class="popup">
<div class="overlay"></div>
<div class="content">Hello World</div>
</div>
Upvotes: 0
Reputation: 1189
@PsiKai solution is good.
You can also handle it with closest (and use an event listener instead of onclick
:
document.querySelector('.overlay').addEventListener('click', event => {
if (! event.target.parentElement.closest('.overlay')) {
console.log('click on overlay !')
}
});
body {
margin: 0;
}
.overlay {
position: fixed;
top: 0;
left: 0;
background-color: rgba(0,0,0,0.5);
width: 100%;
height: 100%;
z-index: 10;
}
.content {
width: 200px;
height: 200px;
position: absolute;
z-index: 11;
top: calc(50% - 100px);
left: calc(50% - 100px);
background: white;
display: flex;
align-items: center;
justify-content: center;
}
<div class="overlay">
<div class="content">Hello World</div>
</div>
Upvotes: 1
Reputation: 161
you can disable the click event for the content div
const content = document.querySelector('.content');
content.off('click');
Upvotes: 1
Reputation: 1978
Access the event target in the arguments of your function. From there use a conditional if
statement to ensure that the target clicked is the overlay, and only do your action if the condition is true.
const overlay = document.querySelector('.overlay')
overlay.onclick = function(e) {
if (e.target.classList.contains("overlay")) {
console.log('click on overlay!')
}
}
body {
margin: 0;
}
.overlay {
position: fixed;
top: 0;
left: 0;
background-color: rgba(0,0,0,0.5);
width: 100%;
height: 100%;
z-index: 10;
}
.content {
width: 200px;
height: 200px;
position: absolute;
z-index: 11;
top: calc(50% - 100px);
left: calc(50% - 100px);
background: white;
display: flex;
align-items: center;
justify-content: center;
}
<div class="overlay">
<div class="content">Hello World</div>
</div>
Upvotes: 0