13

You can horizontally scroll my demo page by pressing Space Bar, Page Up / Page Down and Left Arrow / Right Arrow keys. You can also snap scroll with a mouse or trackpad.

But only one or the other works.

Is there a way that keyboard events and CSS scroll snapping can coexist? What am I missing? Any help would be really appreciated, since I’ve been struggling with this problem for over a week.


Check out my demo on CodePen

(Please uncomment the relevant piece of CSS code to enable the scroll snapping effect in order to see that keyboard shortcuts stop working.)


import animate from "https://cdn.jsdelivr.net/npm/animateplus@2/animateplus.js"

const sections = Array.from(document.querySelectorAll("section")).sort(
  (s1, s2) => {
    return s1.getBoundingClientRect().left - s2.getBoundingClientRect().left
  }
)

const getSectionInView = () => {
  const halfWidth = window.innerWidth / 2
  const index = sections.findIndex(
    section =>
      section.getBoundingClientRect().left <= halfWidth &&
      section.getBoundingClientRect().right > halfWidth
  )
  return index
}

const getNextSection = dir => {
  const sectionInViewIndex = getSectionInView()
  const nextIndex = sectionInViewIndex + dir
  const numSections = sections.length
  const nextSectionIndex =
    nextIndex < 0 || nextIndex >= numSections ? sectionInViewIndex : nextIndex
  return sections[nextSectionIndex]
}

const container = document.scrollingElement

const animateScroll = dir => {
  const from = container.scrollLeft
  const { left } = getNextSection(dir).getBoundingClientRect()
  return progress => (container.scrollLeft = from + progress * left)
}

window.onload = () => {
  document.body.onkeydown = event => {
    switch (event.key) {
      case " ": // Space Bar
      case "PageDown":
      case "ArrowRight": {      
        animate({
          easing: "out-quintic",
          change: animateScroll(1)
        })
        break
      }
      case "PageUp":
      case "ArrowLeft":  {      
        animate({
          easing: "out-quintic",
          change: animateScroll(-1)
        })
        break
      }
    }
  }
}

Note: I’m using a small and elegant module called Animate Plus for achieving the smooth scrolling animation.


Update: @Kostja’s solution works in Chrome, but not in Safari for Mac or iOS, and it’s crucial to me that it works in Safari.

Tzar
  • 5,132
  • 4
  • 23
  • 57
  • is your problem solved?? i am also facing same issue... i have used smooth scroll using css.... `html { scroll-behavior: smooth; }` And on using it, arrow keys are not wokring on my page.. can you pls help? is there any alternative for using both the things. Or it is having any error??? – Coder Aug 29 '20 at 06:05
  • @Harshitmishra Unfortunately, no. It seems that it can’t be done cleanly. – Tzar Aug 29 '20 at 20:13
  • ohh... then i might see for any alternate method... Thank you bro. – Coder Aug 30 '20 at 04:02

2 Answers2

4

I guess there is not, the css overwrites the javascript. But you can simply add wheel eventlistener like:

window.addEventListener("wheel", function() {
    if(event.deltaY > 0){
      animate({
        easing: "out-quintic",
        change: animateScroll(1)
      })      
    }
      if(event.deltaY < 0){
      animate({
        easing: "out-quintic",
        change: animateScroll(-1)
      })      
    }      
});

https://codepen.io/kostjaaa/pen/NWWVBKd

Tzar
  • 5,132
  • 4
  • 23
  • 57
kostja
  • 355
  • 1
  • 9
  • Could you please post a link to a fork on CodePen, because I can’t get your solution to work? Thanks. – Tzar Nov 22 '19 at 14:25
  • yes have tried it with Chrome Version 78.0.3904.108 (64Bit) – kostja Nov 25 '19 at 13:02
  • What is not working on your side? the snap or the scroll at all? you have to click in the view before using keyboard btw. Keyboard is not combined with hover as is scroll. – kostja Nov 25 '19 at 13:48
  • I just tested it in Chrome, and it does work! But it doesn’t work in Safari for Mac or iOS, which is way more important to me for this project. Do you know what might be the reason? – Tzar Nov 25 '19 at 16:41
  • I do not have safari, maybe you can try 'mousewheel' instead of 'wheel'? – kostja Nov 26 '19 at 10:12
  • Just tried it and sadly, it still doesn’t work in Safari. Thank you for all your effort. – Tzar Nov 26 '19 at 10:51
  • Although my problem hasn’t been completely solved, I’m going to award you with the bounty for the given effort. Thank you. – Tzar Nov 29 '19 at 13:46
0
window.onload = () => {
  window.addEventListener("wheel", () => {
    const direction = event.deltaY > 0 ? 1 : event.deltaY < 0 ? -1 : false;

    if (direction) {
      animate({
        easing: "out-quintic",
        change: animateScroll(direction)
      });
    }
  });

  document.body.onkeydown = event => {
    switch (event.key) {
      case " ": // Space Bar
      case "PageDown":
      case "ArrowRight": {
        animate({
          easing: "out-quintic",
          change: animateScroll(1)
        });
        break;
      }
      case "PageUp":
      case "ArrowLeft": {
        animate({
          easing: "out-quintic",
          change: animateScroll(-1)
        });
        break;
      }
    }
  };
};    

This should work.

https://codepen.io/JZ6/pen/XWWQqRK

Jay Z
  • 17
  • 2