0

Even though I have been staring at the JS logic for hours and cannot see anything at all wrong with it, the issue, if not caused by the CSS scroll snapping, must be in the JS.

Intended Behaviour: As the list with the grey background at the bottom of the page is scrolled horizontally, the coloured backgrounds above the grey list should be scrolling in correspondence with it. For example, when the yellow list element ("of") snaps to the start, so too should the yellow background align with the left of the "viewport."

The Issue: The rate at which the coloured backgrounds scroll are different from those of the list elements.

Is scroll-snap-align the culprit or am I blind or missing something?


The demo below is a simplified version of the issue.

const
  listCont = document.querySelector('#list-container'),
  cssVarSpacing = 30,
  bgCont = document.querySelector('#bg-container')
let
  scrollRatio = null,
  focusedEl = listCont.children[0],
  lastScrollPos = 0

listCont.addEventListener('scroll', ()=>{
  let
    sibToFocus = null

  scrollRatio = 240 / (focusedEl.getBoundingClientRect().width + cssVarSpacing)

  // if scrolling to right
  if (listCont.scrollLeft > lastScrollPos) {
    if (focusedEl.getBoundingClientRect().right <= 0) sibToFocus = focusedEl.nextElementSibling
  // if scrolling to left
  } else if (focusedEl.getBoundingClientRect().left >= cssVarSpacing) sibToFocus = focusedEl.previousElementSibling

  // if focusedEl is not first or last child, switch focusedEl to previous/next sibling once prior focusedEl reaches scroll-snap-align: start position
  if (sibToFocus) focusedEl = sibToFocus
  // scroll coloured backgrounds in accordance to the scroll ratio of the focusedEl scroll distance to the "viewport" scroll distance
  bgCont.scrollTo(listCont.scrollLeft * scrollRatio, 0)
  lastScrollPos = listCont.scrollLeft
})
main {width:240px;height:180px;position:relative;font-family:arial;font-size:20px;box-sizing:border-box}

#bg-container {
  width: 100%;
  height: 100%;
  position: relative;
  overflow-x: hidden;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 100%;
}
#bg-container > div {width: 100%; height: 100%}
#bg-container > div:nth-child(1) {background: red}
#bg-container > div:nth-child(2) {background: orange}
#bg-container > div:nth-child(3) {background: yellow}
#bg-container > div:nth-child(4) {background: green}
#bg-container > div:nth-child(5) {background: blue}
#bg-container > div:nth-child(6) {background: indigo}

#list-container {
--spacing: 30px;
  width: 240px;
  position: absolute;
  top: 100%;
  transform: translateY(-100%);
  padding: var(--spacing);
  scroll-padding-inline-start: var(--spacing);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  opacity: .85;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: min-content;
  gap: var(--spacing);
  box-sizing: border-box;
  background: grey;
}
#list-container > div {padding: calc(var(--spacing) / 2) var(--spacing); scroll-snap-align: start; white-space: nowrap; border-radius: var(--spacing); box-sizing:border-box;}
#list-container > div:nth-child(1) {background: red; color: black;}
#list-container > div:nth-child(2) {background: orange; color: black;}
#list-container > div:nth-child(3) {background: yellow; color: black;}
#list-container > div:nth-child(4) {background: green; color: white;}
#list-container > div:nth-child(5) {background: blue; color: white;}
#list-container > div:nth-child(6) {background: indigo; color: white;}
#list-container > div:last-child {
  position: relative;
}
#list-container > div:last-child::after {
  content: '';
  width: calc(240px - 100% - var(--spacing));
  height: 1px;
  position: absolute;
  top: 0;
  left: 100%;
  pointer-events: none;
  opacity:0;
}
<main>
  <div id='bg-container'>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
  </div>
  <div id='list-container'>
    <div>the</div>
    <div>widths</div>
    <div>of</div>
    <div>these</div>
    <div>elements</div>
    <div>varies</div>
  </div>
</main>
oldboy
  • 5,729
  • 6
  • 38
  • 86

0 Answers0