Home > Back-end >  Prevent parent element's content movement when a transitioning child is focused
Prevent parent element's content movement when a transitioning child is focused

Time:04-12

Let's say I have a container which contains two divs:

  • the first div is just a text container, no special style applied
  • the second div is a slider which should slide in from the side of the container when necessary (e.g. upon a button click), overlays the text content, and it contains a button (or any other focusable element)

Upon opening the slider, right away as the transition animation begins, the slider's button get focused. This causes the button to be "forced" into the viewport. Because the container's overflow is hidden, it pushes the text content out of the way while animating.

HTML:

<div id="container">
    <div id="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed quis urna eget mi congue dignissim. Vestibulum at enim eu sapien posuere molestie at et nunc. Aenean tempor mi ut volutpat vehicula. Donec ut justo sit amet lectus convallis interdum quis id dui. Nullam lacinia ligula at tortor tristique accumsan. Phasellus nec arcu vel nisl porta vestibulum. Nulla aliquet arcu leo, at auctor orci sagittis quis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</div>
    <div id="slider">
        Slider
        <button id="close_btn" type="button">X</button>
    </div>
</div>
<div>
    <button id="open_btn" type="button">Open</button>
</div>

CSS:

#container {
    height: 200px;
    border: 1px solid red;
    position: relative;
    overflow: hidden;
}

#slider {
    position: absolute;
    right: 0;
    top: 0;
    display: grid;
    background: #ffccaa;
    width: 300px;
    height: 300px;
    animation: anim  10s cubic-bezier(0, 0, 0.2, 1);
    display: none;
}

#close_btn {
    position: absolute;
    right: 0;
    top: 0;
}

@keyframes anim {
    0% {
        transform: translateX(100%);
    }
    0.01% {
        transform: translateX(100%);
    }
    100% {
        transform: translateX(0%);
    }
}

JS:

let openBtn = document.getElementById('open_btn');
let closeBtn = document.getElementById('close_btn');
let slider = document.getElementById('slider');
openBtn.addEventListener('click', (e) => {
  slider.style.display = 'block';
  closeBtn.focus();
});
closeBtn.addEventListener('click', (e) => {
  slider.style.display = 'none';
});

Here is a fiddle, please take a look: https://jsfiddle.net/732go0tx/

Commenting out the focus() on/of the slider's button solves the issue. I know I could just set the focus once the animation finishes but sadly this comes from a 3rd party (and a bit more complicated) code which may change any time, so I am trying to avoid overriding it.

Is there any way to prevent the focused element to be always "pushed" into the viewport? The slider should just slide in nicely, overlaying the text without pushing it out of its containing div.

Thank you.

CodePudding user response:

Try:

  closeBtn.focus({
  preventScroll: true
});

This works for me (Chrome/Edge).

CodePudding user response:

I understand you may not be able to modifie the javascript, so this example may not be valid. I just disabled the buttom so focus won't do anything and turn it to false at the click event...

You may probable find a way to do the same with a new script not changing the actual one.

let openBtn = document.getElementById('open_btn');
let closeBtn = document.getElementById('close_btn');
let slider = document.getElementById('slider');
openBtn.addEventListener('click', (e) => {
  slider.style.display = 'block';
  closeBtn.focus();  
  closeBtn.disabled = false;
});
closeBtn.addEventListener('click', (e) => {
  slider.style.display = 'none';
});
#container {
  height: 200px;
  border: 1px solid red;
  position: relative;
  overflow: hidden;
}

#slider {
  position: absolute;
  right: 0;
  top: 0;
  display: grid;
  background: #ffccaa;
  width: 300px;
  height: 300px;
  animation: anim  10s cubic-bezier(0, 0, 0.2, 1);
  display: none;
}

#close_btn {
  position: absolute;
  right: 0;
  top: 0;
}

@keyframes anim {
  0% {
    transform: translateX(100%);
  }
  0.01% {
    transform: translateX(100%);
  }
  100% {
    transform: translateX(0%);
  }
}
<div id="container">
    <div id="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed quis urna eget mi congue dignissim. Vestibulum at enim eu sapien posuere molestie at et nunc. Aenean tempor mi ut volutpat vehicula. Donec ut justo sit amet lectus convallis interdum quis id dui. Nullam lacinia ligula at tortor tristique accumsan. Phasellus nec arcu vel nisl porta vestibulum. Nulla aliquet arcu leo, at auctor orci sagittis quis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
  </div>
    <div id="slider">
    Slider
    <button id="close_btn" type="button"  disabled>X</button>
  </div>
</div>
<div>
  <button id="open_btn" type="button">Open</button>
</div>

  • Related