How to stop scrollIntoView() from scrolling container to top of page?

1k views Asked by At

I'm trying to build a simple, "mostly-css" image carousel that uses scroll-snap, but also has navigation buttons to control which slide is currently in view. The only solution I've found is to use scrollIntoView() on the target element, which does what I want but it also always scrolls the target element to the top of the page. I want the target carousel slide and container to stay where they are, and I just want the slide to scroll horizontally into view. I'm looking at an example by Adam Argyle where he does just this, and the container stays where it is, and I can't what's different about his demo.

I made a codepen to demonstrate.

https://codepen.io/krjo-the-decoder/pen/dyjPrLy

Clicking the numbered buttons on the bottom will correctly scroll to the right slide, but also scrolls the whole container up the page.

I've tried using scrollTo() just before and just after scrollIntoView() to set the y axis scroll of the container to it's existing position, and that had no effect.

<!-- Using tailwind.css -->
<div class="py-48 bg-gray-200">
  <h1 class="text-center font-bold mb-5 text-2xl">Scroll-snap Carousel</h1>
  <div class="grid grid-flow-col overflow-x-auto snap-x snap-mandatory overscroll-x-contain auto-cols-[100%] mx-auto w-[500px]">
    <img src="https://via.placeholder.com/500" width="500" height="500" class="block snap-center w-auto h-auto" data-slide>
    <img src="https://via.placeholder.com/500" width="500" height="500" class="block snap-center w-auto h-auto" data-slide>
    <img src="https://via.placeholder.com/500" width="500" height="500" class="block snap-center w-auto h-auto" data-slide>
    <img src="https://via.placeholder.com/500" width="500" height="500" class="block snap-center w-auto h-auto" data-slide>
  </div>
  <nav class="flex justify-center mt-4">
    <button class="p-2 border rounded-full border-solid border-black w-12 h-12 mx-2" type="button" data-index="0">1</button>
    <button class="p-2 border rounded-full border-solid border-black w-12 h-12 mx-2" type="button" data-index="1">2</button>
    <button class="p-2 border rounded-full border-solid border-black w-12 h-12 mx-2" type="button" data-index="2">3</button>
    <button class="p-2 border rounded-full border-solid border-black w-12 h-12 mx-2" type="button" data-index="3">4</button>
  </nav>
</div>

<script>
const slides = document.querySelectorAll('[data-slide]');
document.querySelectorAll('button').forEach(button => {
  button.addEventListener('click', event => {
    console.log('event',event);
    slides[event.target.dataset.index].scrollIntoView({
      behavior: 'smooth',
      inline:   'center',
    });
  });
});
</script>
1

There are 1 answers

1
Jostein S On BEST ANSWER

Try adding block: 'nearest' to your scrollIntoView options, like this:

document.querySelectorAll('button').forEach(button => {
  button.addEventListener('click', event => {
    console.log('event',event);
    slides[event.target.dataset.index].scrollIntoView({
      behavior: 'smooth',
      inline:   'center',
      block:    'nearest',
    });
  });
});