10

A simple stacking context problem HOWTO

 3 years ago
source link: https://dev.to/noneinnon/stacking-context-task-3lh5
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
Cover image for A simple stacking context problem HOWTO
Anton Baranov

Posted on Oct 22

A simple stacking context problem HOWTO

So recently i was asked to solve this simple problem.

The problem goes as follows: given this markup, how can we make a click to div on a button area to trigger button's on click event, with out changing the markup (i.e. changing tags order is not allowed)?

<button>button</button>
<div id="overlay"><div>
Enter fullscreen modeExit fullscreen mode
div#overlay {
  position: absolute;
  background: rgba(255, 85, 23, 0.5);
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 0;
}

button {
  position: relative;
  margin: 10px;
  width: 100px;
  height: 30px;
  border: none;
}
Enter fullscreen modeExit fullscreen mode

You might notice that div tag is positioned below button tag in DOM tree and has position: absolute property which means that it will always be displayed on top of a button.
So how can we solve this? There are at least 2 solutions that i know of.

Javascript solution

To solve this with just javascript, we would need to be familiar with couple of basic DOM api's, such as element.getBoundingClientReact() and mouse event.

First we would need to attach an event handler to root element's click event, next we will need to figure out if user is clicking on area, where our button sits under overlay and finally, if user does click in proper area, call button's on click event.

The key thing to note here, is that top left corner of viewport will always have coordinates of x = 0, y = 0, that's why we add width & height to relative axis, when validating click area.

const button = document.querySelector("button");

button.onclick = () => {
  console.log("im clicked");
};

const { x, y, width, height } = button.getBoundingClientRect();

document.onclick = ({ clientX, clientY }) => {
  const validY = clientY <= y + height && clientY >= y;
  const validX = clientX <= x + width && clientX >= x;
  return validX && validY && button.click();
};
Enter fullscreen modeExit fullscreen mode

CSS solution

If you are familiar with stacking context, you probably guessed already, that this problem can be solved using it. Here's MDN page on stacking context.

Here's what we gonna add to our css:

button:before {
  content: "";
  position: absolute;
  display: block;
  z-index: 1;
  width: 100px;
  height: 30px;
  left: 0;
  top: 0;
}
Enter fullscreen modeExit fullscreen mode

Since we'r using z-index & position property on :before element, it will create a new stacking context button's before element above the overlay.

One thing to note here: we could use position:relative on :before element, that would also work, but in that case, the :before node would not be positioned "above" button, but rather inside, moving all of its children nodes and we don't want that at all.

here's a link to a sandbox with both solutions.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK