Tzar
Tzar

Reputation: 4789

Horizontally scrolling by a full page on key press

I have an entirely horizontally spread page that one can scroll by pressing, for example, Space Bar, Page Down, Right Arrow, Home, End, and etc, to navigate.

I currently have two problems that I would like to solve:

  1. When pressing Right Arrow or Left Arrow keys, the page is moved slightly more than 100vw, but the goal for it is to have perfectly aligned page edges with the window.

  2. If for instance, you press the Page Down key multiple times when you reach the end of the page, it will take you the same number of Page Up presses to scroll back.

I would greatly appreciate any help in solving this.

Here is my code:

let scrollAmount = 0
const container = document.documentElement

window.onload = () => {
  document.body.onkeyup = event => {
    switch (event.code) {
      case "Space":
      case "PageDown":
      case "ArrowRight": {
        scrollAmount += window.innerWidth
        break
      }
      case "PageUp":
      case "ArrowLeft": {
        scrollAmount -= window.innerWidth
        break
      }
      case "Home":
      case "ArrowUp": {
        scrollAmount = 0
        break
      }
      case "End":
      case "ArrowDown": {
        scrollAmount = container.scrollWidth
        break
      }
    }

    container.scrollTo({
      top: 0,
      left: scrollAmount,
      behavior: "smooth"
    })
  }
}

// Reset the scrollAmount if the user scrolls back manually.
window.onscroll = event => {
  scrollAmount = container.scrollLeft
}
* {
  margin: 0;
  padding: 0
}

html { height: 100% }

html, body, section {
  display: flex;
  flex-grow: 1
}

body {
  scroll-snap-type: x mandatory;
  scroll-snap-points-x: repeat(100%);
  overflow-x: auto
}

section {
  display: grid;
  place-items: center;
  flex: 1 0 100%;
  scroll-snap-align: center
}

section:nth-of-type(1) { background: orange }
section:nth-of-type(2) { background: limeGreen }
section:nth-of-type(3) { background: royalBlue }

h2 { color: white }
<section><h2>1</h2></section>
<section><h2>2</h2></section>
<section><h2>3</h2></section>

Upvotes: 1

Views: 1492

Answers (1)

Fdebijl
Fdebijl

Reputation: 1041

Adding event.preventDefault() and changing the listener to keydown instead of keyup will prevent the default continuous scrolling for the arrow keys. This works because the arrow key scrolling is triggered while it's held down (which we've now prevented), while the event listener was only being triggered when the arrow key is lifted.

You could do the same (add event.preventDefault(), that is) for Home and End to prevent all horizontal scrolling.

let scrollAmount = 0
const container = document.documentElement

window.onload = () => {
  document.body.onkeydown = event => { // <-----------
    switch (event.code) {
      case "Space":
      case "PageDown":
      case "ArrowRight": {
        event.preventDefault(); // <-----------
        scrollAmount += window.innerWidth
        break
      }
      case "PageUp":
      case "ArrowLeft": {
        event.preventDefault(); // <-----------
        scrollAmount -= window.innerWidth
        break
      }
      case "Home":
      case "ArrowUp": {
        scrollAmount = 0
        break
      }
      case "End":
      case "ArrowDown": {
        scrollAmount = container.scrollWidth
        break
      }
    }

    container.scrollTo({
      top: 0,
      left: scrollAmount,
    })
  }
}

// Reset the scrollAmount if the user scrolls back manually.
window.onscroll = event => {
  scrollAmount = container.scrollLeft
}
* {
  margin: 0;
  padding: 0
}

html { height: 100% }

html, body, section {
  display: flex;
  flex-grow: 1
}

body {
  scroll-snap-type: x mandatory;
  scroll-snap-points-x: repeat(100%);
  overflow-x: auto
}

section {
  display: grid;
  place-items: center;
  flex: 1 0 100%;
  scroll-snap-align: center
}

section:nth-of-type(1) { background: orange }
section:nth-of-type(2) { background: limeGreen }
section:nth-of-type(3) { background: royalBlue }

h2 { color: white }
<section><h2>1</h2></section>
<section><h2>2</h2></section>
<section><h2>3</h2></section>

Upvotes: 1

Related Questions