1

I'm trying to create something like list of options to select so when user scrolls or swipes he will see the option he was looking for.

But if I scroll once, it scrolls more than one position (e.g. I have element with text "1" on top, I scroll once and I get element with text "4" on top, but element with text "2" expected).

The code I have works well on IOS Chrome and Safari (tested on mobile and actually love it).

How to get the same result on desktop using CSS or JS (jQuery)? Or did I miss a mistake somewhere?

Here's basic HTML and CSS (better to check on full page). (HTML can be whatever is needed: divs inside div tag (below), or options inside select tag, or lis inside ul/ol tag)

.box {
  background-color: yellowgreen;
  height: 300px;
  overflow: hidden;
}

.scroll {
  width: 100%;
  height: 100%;
  background-color: aliceblue;
  overflow-y: scroll;
  scroll-snap-type: y mandatory;
  scroll-snap-stop: always;
}

.scroll div {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 40px;
  margin: 5px 0;
  padding: 10px;
  background-color: lightpink;
  scroll-snap-align: center;
}

.scroll div:first-of-type {
  margin-top: calc((50% - 20px));
}

.scroll div:last-of-type {
  margin-bottom: calc((50% - 20px));
}
<div class="box">
  <div class="scroll">
    <div>List item: 1</div>
    <div>List item: 2</div>
    <div>List item: 3</div>
    <div>List item: 4</div>
    <div>List item: 5</div>
    <div>List item: 6</div>
    <div>List item: 7</div>
    <div>List item: 8</div>
    <div>List item: 9</div>
    <div>List item: 10</div>
  </div>
</div>
Dmitry
  • 11
  • 4
  • I think your problem is really similiar to the one referenced here: https://stackoverflow.com/questions/57518428/css-scroll-snap-points-with-navigation-next-previous-buttons – becauseimbored Nov 19 '22 at 02:02
  • Thank you for attention,@becauseimbored. I am not really sure that's pretty similar. The solution in that problem you sent is about making the scrolling effect on button click. Mine problem is there are no buttons to click on. Only scrolling with mousewheel (scroll event) or touchmove (on touch devices). So I don't understand how to implement that solution in my problem. Only reason that carousel is working with scroll like I want to do here is because the items are big enough (height: 60vh, 40 vh etc). If you use {height: 30px} that won't work well (it will scroll few items at once, not one). – Dmitry Nov 23 '22 at 02:05

1 Answers1

0

So after days of trying I came up with this solution:

document.querySelector(".scroll").addEventListener('wheel', (e) => {
  e.preventDefault();
  if (e.deltaY < 0) {
    document.querySelector(".scroll").scrollBy({
      top: -(document.querySelector(".scroll > div").scrollHeight)
    });
  } else if (e.deltaY > 0) {
    document.querySelector(".scroll").scrollBy({
      top: (document.querySelector(".scroll > div").scrollHeight)
    });
  }
});
.box {
  background-color: yellowgreen;
  height: 300px;
  overflow: hidden;
}

.scroll {
  width: 100%;
  height: 100%;
  background-color: aliceblue;
  overflow-y: scroll;
  scroll-snap-type: y mandatory;
  scroll-snap-stop: always;
}

.scroll div {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 40px;
  margin: 5px 0;
  padding: 10px;
  background-color: lightpink;
  scroll-snap-align: center;
}

.scroll div:first-of-type {
  margin-top: calc((50% - 20px));
}

.scroll div:last-of-type {
  margin-bottom: calc((50% - 20px));
}
<div class="box">
  <div class="scroll">
    <div>List item: 1</div>
    <div>List item: 2</div>
    <div>List item: 3</div>
    <div>List item: 4</div>
    <div>List item: 5</div>
    <div>List item: 6</div>
    <div>List item: 7</div>
    <div>List item: 8</div>
    <div>List item: 9</div>
    <div>List item: 10</div>
  </div>
</div>

Don't really like how it works with scrollBy() method's option "behavior: smooth" but still this might help someone.

Dmitry
  • 11
  • 4