Scroll snap CSS skipping elements

Viewed 3619

Long story short, on Chrome (81.0.4044.138) scroll snapping skips the middle <div class="item2"> for some reason. On Firefox (76.0.1) it works fine. Any idea why?

 html {
      scroll-snap-type: y mandatory;
    }
    
    body {
      margin: 0;
      padding: 0;
      overflow-x: hidden;
      overflow-y: scroll;
    }
    
    div {
      height: 100vh;
      scroll-snap-align: center;
    }
    
    .item1 {
      background-color: blue;
      font-size: 5rem;
    }
    
    .item2 {
      background-color: yellow;
      font-size: 5rem;
    }
    
    .item3 {
      background-color: red;
      font-size: 5rem;
    }
<body class="container">
        <div class="item1">Hello World</div>
        <div class="item2">Hello World</div>
        <div class="item3">Hello World</div>
    </body>

3 Answers

Actually, there is a bug about it in chrome browsers (The reason behind it, is not clear until now so no one knows why). So you cant apply scroll-snap-type to your html (whilst applying it to body won't work either) tag directly. So instead of it, in order to make it work, you should create another div and wrap your element inside it.

So try this instead:

body {
  margin: 0;
  padding: 0;
  overflow: hidden;
}

.container {
  scroll-snap-type: y mandatory;
  overflow-y: scroll;
}

div {
  height: 100vh;
  scroll-snap-align: center;
}

.item1 {
  background-color: blue;
  font-size: 5rem;
}

.item2 {
  background-color: yellow;
  font-size: 5rem;
}

.item3 {
  background-color: red;
  font-size: 5rem;
}
<body>
  <div class="container">
    <div class="item1">Hello World</div>
    <div class="item2">Hello World</div>
    <div class="item3">Hello World</div>
  </div>
</body>

NOTE: Same problem in CSS-tricks.

Here is a workaround with which I came up after quite some time tinkering. Hope this helpes!

const scrollContainer = document.querySelector('.container')

// don't forget to add "scroll-behavior: smooth;" to the .container CSS

scrollContainer.onwheel = function(event) {
  // use scrollBy using the deltaY just as a direction
  // the exact value is not important because of "scroll-snap-type: y mandatory;"
  scrollContainer.scrollBy(0, event.deltaY);

  // this will stop the original scroll event.
  return false;
};
body {
  margin: 0;
  padding: 0;
  overflow: hidden;
}

.container {
  scroll-snap-type: y mandatory;
  scroll-behavior: smooth;
  overflow-y: scroll;
}

div {
  height: 100vh;
  scroll-snap-align: center;
}

.item1 {
  background-color: blue;
  font-size: 5rem;
}

.item2 {
  background-color: yellow;
  font-size: 5rem;
}

.item3 {
  background-color: red;
  font-size: 5rem;
}
<body>
  <div class="container">
    <div class="item1">Hello World</div>
    <div class="item2">Hello World</div>
    <div class="item3">Hello World</div>
  </div>
</body>

Use scroll-snap-stop: always; on the child Element.

Related