Click through div to underlying elements

Viewed 906858

I have a div that has background:transparent, along with border. Underneath this div, I have more elements.

Currently, I'm able to click the underlying elements when I click outside of the overlay div. However, I'm unable to click the underlying elements when clicking directly on the overlay div.

I want to be able to click through this div so that I can click on the underlying elements.

My Problem

17 Answers

Yes, you CAN do this.

Using pointer-events: none along with CSS conditional statements for IE11 (does not work in IE10 or below), you can get a cross browser compatible solution for this problem.

Using AlphaImageLoader, you can even put transparent .PNG/.GIFs in the overlay div and have clicks flow through to elements underneath.

CSS:

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

IE11 conditional:

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

Here is a basic example page with all the code.

I think the event.stopPropagation(); should be mentioned here as well. Add this to the Click function of your button.

Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.

An easier way would be to inline the transparent background image using Data URIs as follows:

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

This is not a precise answer for the question but may help in finding a workaround for it.

I had an image I was hiding on page load and displaying when waiting on an AJAX call then hiding again however...

I found the only way to display my image when loading the page then make it disappear and be able to click things where the image was located before hiding it was to put the image into a DIV, make the size of the DIV 10x10 pixels or small enough to prevent it causing an issue then hiding the containing div. This allowed the image to overflow the div while visible and when the div was hidden, only the divs area was affected by inability to click objects beneath and not the whole size of the image the DIV contained and was displaying.

I tried all the methods to hide the image including CSS display=none/block, opacity=0, hiding the image with hidden=true. All of them resulted in my image being hidden but the area where it was displayed to act like there was a cover over the stuff underneath so clicks and so on wouldn't act on the underlying objects. Once the image was inside a tiny DIV and I hid the tiny DIV, the entire area occupied by the image was clear and only the tiny area under the DIV I hid was affected but as I made it small enough (10x10 pixels), the issue was fixed (sort of).

I found this to be a dirty workaround for what should be a simple issue but I was not able to find any way to hide the object in its native format without a container. My object was in the form of etc. If anyone has a better way, please let me know.

I couldn't always use pointer-events: none in my scenario, because I wanted both the overlay and the underlying element(s) to be clickable / selectable.

The DOM structure looked like this:

<div id="outerElement">
   <div id="canvas-wrapper">
      <canvas id="overlay"></canvas>
   </div>
   <!-- Omitted: element(s) behind canvas that should still be selectable -->
</div>

(The outerElement, canvas-wrapper and canvas elements have the same size.)

To make the elements behind the canvas act normally (e.g. selectable, editable), I used the following code:

canvasWrapper.style.pointerEvents = 'none';

outerElement.addEventListener('mousedown', event => {
    const clickedOnElementInCanvas = yourCheck // TODO: check if the event *would* click a canvas element.
    if (!clickedOnElementInCanvas) {

        // if necessary, add logic to deselect your canvas elements ...

        wrapper.style.pointerEvents = 'none';
        return true;
    }

    // Check if we emitted the event ourselves (avoid endless loop)
    if (event.isTrusted) {
        // Manually forward element to the canvas
        const mouseEvent = new MouseEvent(event.type, event);
        canvas.dispatchEvent(mouseEvent);
        mouseEvent.stopPropagation();
    }
    return true;
});

Some canvas objects also came with input fields, so I had to allow keyboard events, too. To do this, I had to update the pointerEvents property based on whether a canvas input field was currently focused or not:

onCanvasModified(canvas, () => {
    const inputFieldInCanvasActive = // TODO: Check if an input field of the canvas is active.
    wrapper.style.pointerEvents = inputFieldInCanvasActive  ? 'auto' : 'none';
});
Related