DEV Community

Krypton | Madhusudan Babar
Krypton | Madhusudan Babar

Posted on

3 2

How to implement a scroll snap with intersection observer

I am inspired by Rolls Royce website and want to implement the same scroll snapping feature in mine as well, I did it with the HTML default scroll-snap-type but which gives me expected behavior but creates two scrollbars, one for the container and another one for the body, which is not expected so I tried to go with the IntersectionObserver but it causes an issue, I can travel to only adjacent slide when directly jumping from 1st slide to 3rd slide.

Here is the code sandbox link: https://codesandbox.io/s/scrollsnap-forked-pre0c?file=/pages/index.vue

I am inspired by Rolls Royce website and want to implement the same scroll snapping feature in mine as well, I did it with the HTML default scroll-snap-type which gives me expected behavior but creates two scrollbars, one for the container and another one for the body, which is not…

Here is the code that I am working:

<template>
  <main class="landing">
    <nav class="scroller">
      <ul class="scroller__list">
        <li
          class="scroller__item"
          v-for="(slide, index) in slides"
          :key="index"
          @click.prevent="scroll(slide.id)"
        >
          <a
            class="scroller__dot"
            :href="'#' + slide.id"
            @click.prevent="scroll(slide.id)"
          ></a>
        </li>
      </ul>
    </nav>
    <div class="slides-container">
      <slide
        class="slide"
        v-for="(slide, index) in slides"
        :key="index"
        :img="slide.img"
        :id="slide.id"
        :format="slide.format"
        :filter="slide.filter"
        >{{ slide.content }}</slide
      >
    </div>
  </main>
</template>

<script lang="ts">
import Vue from "vue";

export default Vue.extend({
  data() {
    return {
      slides: [
        {
          img: "car-slide-1.png",
          content: "hello world",
          id: "car-slide-1",
          filter: "color-burn",
        },
        {
          img: "car-slide-2.png",
          content: "Second Car",
          id: "car-slide-2",
          filter: "color-burn",
        },
        {
          img: "car-slide-3.png",
          content: "Third slide",
          id: "car-slide-3",
          filter: "color-burn",
        },
      ],
      observer: null as any as IntersectionObserver,
      options: {
        threshold: [0.5],
        root: process.browser
          ? document.getElementsByClassName("slides-container")[0]
          : null,
      } as IntersectionObserverInit,
    };
  },
  methods: {
    scroll(id: string, who: string | null = null) {
      console.log("scrolling to ", id, who ? "by " + who : "");
      document.getElementById(id)?.scrollIntoView({
        behavior: "smooth",
        block: "start",
      });
    },
  },
  mounted() {
    let scrolling = false;
    this.observer = new IntersectionObserver((entries, observer) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting && !scrolling) {
          let top = entry.boundingClientRect.top;
          scrolling = true;
          window.scroll({ behavior: "smooth", top: window.pageYOffset + top });
        }
        scrolling = false;
      });
    }, this.options);
    document
      .querySelectorAll(".slide")
      .forEach((slide) => this.observer.observe(slide));
  },
});
</script>
Enter fullscreen mode Exit fullscreen mode

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (1)

Collapse
 
phaberest profile image
Luca Stefano Sartori

I am trying to implement the same, but I'm afraid your codesandbox is having the same issue I'm experiencing in which the observer is not properly "observing" and thus doesn't highlight the current slide

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay