Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to prevent a parent container from scrolling when a child node is focused?

Situation: there is a fixed-height parent div with overflow: auto and enough child "line-item" divs of sufficient height to trigger the presence of scrollbars. Each of these child divs has tabindex=-1 so can be programmatically focused.

When any of these child divs is programmatically focused, the default behavior of the browser (in this case, Chrome 55) seems to be to scroll the parent div to center the newly-focused child. Is there any way to prevent this behavior?

like image 991
Craig Kovatch Avatar asked Jan 04 '17 00:01

Craig Kovatch


People also ask

How do you make an element not scrollable?

And it is simply by adding the CSS property overflow: hidden; on the element you want to prevent the scroll.

How do I disable parent scroll in CSS?

To do this (in Chrome, Firefox, and Edge), we can add the CSS property overscroll-behavior: contain to the overflow: auto element. This will prevent the "scroll chaining" behavior, which will, in turn, keep the mouse-wheel active within the target element.

How do I stop scrolling when scrolling a div element CSS?

mouseleave(function() { $('body'). bind('mousewheel DOMMouseScroll', function() { return true; }); }); This is stopping all scrolling where as I want scrolling to still be possible inside the container.


1 Answers

Yes and no. There is not a way to prevent the parent element from scrolling to the focused element (that I know of). However, you can undo the scrolling by scrolling the parent element back to the top. Done correctly, it won't be noticeable to the user.

To do this, anytime you programmatically focus an element, retrieve the current scroll offset of the focused element's parent node and set scrollTop to that offset.

var children = document.getElementsByClassName('child')

for (var i = 0; i < children.length; i++) {
  children[i].addEventListener('click', function (e) {
    e.preventDefault
    var focused = document.getElementById('focus')
    var focusedParent = focused.parentNode
    var savedOffset = focusedParent.scrollTop
    focused.focus();
    focused.parentNode.scrollTop = savedOffset;
  })
}
.parent {
  height: 300px;
  overflow: auto;
}

.child {
  height: 50px;
  background-color: gray;
  border-bottom: 1px solid black;
  color: white;
  box-sizing: border-box;
  text-align: center;
  line-height: 50px;
  font-family: Arial;
}
<div class="parent">
  <div class="child" tabIndex="-1">1</div>
  <div class="child" tabIndex="-1">2</div>
  <div class="child" tabIndex="-1">3</div>
  <div class="child" tabIndex="-1">4</div>
  <div class="child" tabIndex="-1">5</div>
  <div class="child" tabIndex="-1">6</div>
  <div class="child" tabIndex="-1">7</div>
  <div class="child" tabIndex="-1">8</div>
  <div class="child" tabIndex="-1" id="focus">9</div>
  <div class="child" tabIndex="-1">10</div>
</div>

Here's the working demo on Codepen.

like image 107
Brett DeWoody Avatar answered Nov 07 '22 09:11

Brett DeWoody