4

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>
Roy
  • 7,811
  • 4
  • 24
  • 47
Sam
  • 375
  • 1
  • 5
  • 15

3 Answers3

4

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.

SMAKSS
  • 9,606
  • 3
  • 19
  • 34
  • You can attach `scroll-snap-type` to `body`. Unfortunately, however you do it, this is unusable IRL since mobile browsers break 100vh. Scrolling on `html` is the only thing they keep stable. – lawrence-witt Jul 27 '20 at 15:58
  • 1
    @lawrence-witt Well, as you said we can use it in body, but unfortunately it does not work on Chrome browsers and its nothing about viewport or other stuff. Also in some cases attaching it to `html` will not work in safari, so it's better to attach it is other elements. – SMAKSS Jul 27 '20 at 16:04
4

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>
GDur
  • 59
  • 4
1

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