Özenç B.
Özenç B.

Reputation: 1038

How can I get CSS scroll snap to work with JS scroll event listener?

I am working on this project where I need both scroll listeners and scroll-snapping, so I can make some cool transition effects between section changes.

I could get both of these to work separately, but not together. Scroll snapping requires a container element (main element) to have a height, but when I give it a height: 100%, JavaScript scroll listener stops working.

I tried everything I know, tried changing other containers' height/overflow properties and tried targeting other elements than body or window. What would be the best workaround be?

The snippet here is adjusted to work with listener at the moment. If you go ahead and add height: 100% to main, you will see that scroll snapping starts working, but the event listener breaks.

const scrollEvent = () => {
  const main = document.querySelector('#main');
  const section1 = document.querySelector('#sect1');
  const section2 = document.querySelector('#sect2');

  if (main.scrollTop > 50) {
    section1.style.backgroundColor = "red";

  } else {
    section1.style.backgroundColor = "pink";
  }

  if (main.scrollTop > window.innerHeight / 2) {
    section2.style.backgroundColor = "blue";
  } else {
    section2.style.backgroundColor = "purple";
  }
}


window.addEventListener('scroll', scrollEvent);
* {
  padding: 0;
  margin: 0;
}

html,
body {
  height: 100%;
  width: 100%;
}

body {
  scroll-behavior: smooth;
}

main {
  display: flex;
  flex-direction: column;
  width: 100vw;
  overflow: auto;
  scroll-snap-type: y mandatory;
}

section {
  flex-basis: 100vh;
  flex-grow: 1;
  flex-shrink: 0;
  width: 90vw;
  border: 1px solid red;
  margin: 0 auto;
}

main section {
  scroll-snap-align: start;
}
<!DOCTYPE html>
<html lang="en">

<head>
</head>

<body>
  <main id="main" dir="ltr">
    <section id="sect1">
      <h1>content1</h1>
    </section>
    <section id="sect2">
      <h1>content2</h1>
    </section>
  </main>
</body>

</html>

Upvotes: 8

Views: 13925

Answers (1)

&#214;zen&#231; B.
&#214;zen&#231; B.

Reputation: 1038

In another topic @lawrence-witt stated that I had to add the event listener to main, instead of whole window. With main.addEventListener('scroll', scrollEvent); both scroll snap and scroll event listener work fine.

const scrollEvent = () => {
  const main = document.querySelector('#main');
  const section1 = document.querySelector('#sect1');
  const section2 = document.querySelector('#sect2');

  if (main.scrollTop > 50) {
    section1.style.backgroundColor = "red";

  } else {
    section1.style.backgroundColor = "pink";
  }

  if (main.scrollTop > window.innerHeight / 2) {
    section2.style.backgroundColor = "blue";
  } else {
    section2.style.backgroundColor = "purple";
  }
}


main.addEventListener('scroll', scrollEvent);
* {
  padding: 0;
  margin: 0;
}

html,
body {
  height: 100%;
  width: 100%;
}

body {
  scroll-behavior: smooth;
}

main {
  display: flex;
  flex-direction: column;
  width: 100vw;
  height: 100%;
  overflow: auto;
  scroll-snap-type: y mandatory;
}

section {
  flex-basis: 100vh;
  flex-grow: 1;
  flex-shrink: 0;
  width: 90vw;
  border: 1px solid red;
  margin: 0 auto;
}

main section {
  scroll-snap-align: start;
}
<!DOCTYPE html>
<html lang="en">

<head>
</head>

<body>
  <main id="main" dir="ltr">
    <section id="sect1">
      <h1>content1</h1>
    </section>
    <section id="sect2">
      <h1>content2</h1>
    </section>
  </main>
</body>

</html>

Upvotes: 12

Related Questions