css 涉及scrollBy、scroll-snap和scroll-behavior的错误?

vlju58qv  于 12个月前  发布在  其他
关注(0)|答案(3)|浏览(122)

我主要是尝试将页面的垂直滚动绑定为水平滚动,同时使用滚动捕捉和平滑滚动行为来滚动到下一个/上一个“页面”。
请观看视频,看看脚本的奇怪行为,以及它如何与样式表交互,你可以用codepen重新创建bug。我不确定是什么导致了这个小故障。我在代码中添加了400毫秒的超时,这是为了防止用户意外地同时触发两个方向的滚动。
其目的是允许用户仅在当前元素处于视图中时才滚动到下一个元素。
当scroll-snap被禁用时,scrollBy函数不起作用,只是轻微移动(而不是整个窗口。innerWidth)
Video of bug
Link to CodePen

var waiting

if (waiting == null) {
        waiting = 0      
    }

  document.querySelector(".main-nav").addEventListener("wheel", (event) => {
    event.preventDefault();                   
    if (waiting === 0) {
        waiting = 1 
        console.log("started wait");
        if (event.deltaY > 0) {
                scrlFF();
                setTimeout(finishedWaiting, 400);
        } else if (event.deltaY < 0) {                         
                scrlFR();
                setTimeout(finishedWaiting, 400);
        } 
    }
});
    function finishedWaiting() { console.log("finished wait"); waiting = 0 }
    function scrlFF() { document.querySelector(".main-nav").scrollBy({ left: window.innerWidth, behavior: 'smooth' }); }
    function scrlFR() { document.querySelector(".main-nav").scrollBy({ left: -window.innerWidth, behavior: 'smooth' }); }
.a { background: red;
min-width: 100vw; height: 100vh; display: flex; scroll-snap-align: center; scroll-snap-stop: always;}
.a ~ .a { background: blue;}
.a ~ .a ~ .a { background: red;}
.a ~ .a ~ .a ~ .a { background: blue;}
* { overflow-y: hidden }
.main-nav {display: flex;flex-direction: row;height: 100%;scroll-snap-type: x mandatory;overflow-x: scroll;scroll-behavior: smooth;scrollbar-width: none;width: inherit;}
<div class="main-nav"><div class="a"></div><div class="a"></div><div class="a"></div><div class="a"></div></div>
nx7onnlm

nx7onnlm1#

鼠标滚轮和页面滚动通常是一个挑战。
这真的只是一个轻微的扭曲你有什么,但与一些补充,以平滑滚动。不完美,但真的只有奇怪的快速向上/向下轮滚动。
游戏/变化:

  • 使用更干净的CSS来处理偶数/奇数颜色;现在你可以在不改变CSS的情况下拥有任意数量的元素。
  • 设置一个data属性,并使用CSS将其作为指针事件的目标;因此,我们只需设置true/false即可。因此,设置属性值可能会减少DOM命中,并且肯定更容易编码。
  • 窗口“滚轮”上的小事件,使滚动条平滑一点。这是“笨重”滚动条的一部分,所以我们只是防止它。
  • 一些小的逻辑来检测滚动的开始/结束,这样我们就可以在开始/结束时切换它。
  • 不用setTimeout,因为我们可以对一些事件这样做-scrollend是我们在触发时切换的关键。
  • 用一个函数function scrollContainer(main, plus) {而不是两个函数来干燥代码;为左/右传递一个布尔值。
  • 因为我们把toggle移到了data属性,所以没有全局变量,所以更干净;我们可以只把对“main”的引用传递给scroll函数。
  • 许多/大多数let可能是const,但将其作为单独的练习。
// smooths out the scroll on fast wheel up/down
window.addEventListener("wheel", e => e.preventDefault(), {
  passive: false
});

let main = document.querySelector(".main-nav");

main.addEventListener("wheel", (event) => {
  event.preventDefault();
  let ct = event.currentTarget;
  let canScroll = !!ct.dataset.canscroll;
  if (!canScroll) {
    return false;
  }
  let w = ct.scrollWidth - ct.clientWidth;
  let sleft = Math.trunc(ct.scrollLeft);
  let wd = event.wheelDelta;
  scrollContainer(ct, wd < 0);
  if (sleft == 0 || sleft == w) {
    ct.dataset.canscroll = "true";
  }
}, {
  passive: true
});

main.addEventListener("scrollend", (event) => {
  let ct = event.currentTarget;
  ct.dataset.canscroll = "true";
});

main.addEventListener("scroll", (event) => {
  // fires a lot as it scrolls.
  let canScroll = !!event.currentTarget.dataset.canscroll;
  if (canScroll) {
    return false;
  }
});

function scrollContainer(main, plus) {
  main.dataset.canscroll = "false";
  let scroll = plus ? main.clientWidth : -main.clientWidth;
  main.scrollBy({
    left: scroll,
    behavior: 'smooth'
  });
}
* {
  overflow-y: hidden;
  box-sizing: border-box;
  font-size: 16px;
  margin: 0;
  padding: 0;
}

/* hide the scroll bar w/these two */

.main-nav {
  overflow-x: scroll;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.main-nav::-webkit-scrollbar {
  width: 0;
  height: 0;
}

.main-nav {
  display: flex;
  flex-direction: row;
  height: 100vh;
  scroll-snap-type: x mandatory;
  overflow-x: scroll;
  scroll-behavior: smooth;
  width: inherit;
}

.main-nav[data-canscroll="true"] {
  pointer-events: auto;
}

.main-nav[data-canscroll="false"] {
  pointer-events: none;
}

.a {
  display: grid;
  place-items: center;
  text-align: center;
  border: 1px solid yellow;
}

.a:nth-child(even) {
  background: blue;
}

.a:nth-child(odd) {
  background: red;
}

.a {
  min-width: 100%;
  height: 100%;
  scroll-snap-align: center;
  scroll-snap-stop: always;
  color: white;
  font-size: 3em;
}

.scrollR {
  padding: 1em;
}
<div class="main-nav" data-canscroll="true">
  <div class="a">first ONE</div>
  <div class="a">TWO</div>
  <div class="a">THREE</div>
  <div class="a">FOUR</div>
  <div class="a">five</div>
  <div class="a">six</div>
  <div class="a">last one</div>
</div>
fumotvh3

fumotvh32#

虽然嵌入的代码片段似乎在stackoverflow上运行得很顺利,在事件侦听器的查询框中添加了“html,body”,但同样的代码在codepen或我的网站上却不能正常运行?

document.querySelector("html, body, .main-nav").addEventListener("wheel", (event) => {

字符串

var waiting

if (waiting == null) {
        waiting = 0      
    }

  document.querySelector("html, body, .main-nav").addEventListener("wheel", (event) => {
    event.preventDefault();                   
    if (waiting === 0) {
        waiting = 1 
        if (event.deltaY > 0) {
                scrlFF();
                setTimeout(finishedWaiting, 400);
        } else if (event.deltaY < 0) {                         
                scrlFR();
                setTimeout(finishedWaiting, 400);
        } 
    }
});
    function finishedWaiting() { waiting = 0 }
    function scrlFF() { document.querySelector(".main-nav").scrollBy({ left: window.innerWidth, behavior: 'smooth' }); }
    function scrlFR() { document.querySelector(".main-nav").scrollBy({ left: -window.innerWidth, behavior: 'smooth' }); }
.a { background: red;
min-width: 100vw; height: 100vh; display: flex; scroll-snap-align: center; scroll-snap-stop: always;}
.a ~ .a { background: blue;}
.a ~ .a ~ .a { background: red;}
.a ~ .a ~ .a ~ .a { background: blue;}
* { overflow-y: hidden }
.main-nav {display: flex;flex-direction: row;height: 100%;scroll-snap-type: x mandatory;overflow-x: scroll;scroll-behavior: smooth;scrollbar-width: none;width: inherit;}
<div class="main-nav"><div class="a"></div><div class="a"></div><div class="a"></div><div class="a"></div></div>
6uxekuva

6uxekuva3#

我还没有将这个问题标记为已解决,因为我仍然不明白是什么导致了这个问题。然而,我能够为codepen和我的网站找到一个工作但不太理想的解决方案。
CSS:

.main-nav { pointer-events:var(--handlePointer) }

字符串
JavaScript语言:

function finishedWaiting() { console.log("finished wait"); document.querySelector(':root').style.setProperty('--handlePointer', "all"); waiting = 0 }
function scrlFF() { document.querySelector(':root').style.setProperty('--handlePointer', "none"); document.querySelector(".main-nav").scrollBy({ left: window.innerWidth, behavior: 'smooth' }); }
function scrlFR() { document.querySelector(':root').style.setProperty('--handlePointer', "none"); document.querySelector(".main-nav").scrollBy({ left: -window.innerWidth, behavior: 'smooth' }); }


出于某种原因,在滚动过程中添加pointer-events:none;修复了故障。我添加了一个css变量来控制函数中指针事件的属性,以便在延迟结束时恢复为pointer-events:all;
当您将鼠标悬停在.main-nav内部的子元素.a(或任何子元素)上时,滚动无法正常工作。它无法滚动到下一个位置,并产生video中显示的毛刺,除非pointer-events具有属性none
如果有人能解释到底发生了什么,我很感激任何建议?

相关问题