CSS滚动捕捉点,带有导航(下一个,上一个)按钮 [英] CSS Scroll Snap Points with navigation (next, previous) buttons

查看:54
本文介绍了CSS滚动捕捉点,带有导航(下一个,上一个)按钮的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 CSS捕捉点 .对于我来说,只有仅CSS选项很重要,但是我可以通过 javascript (无框架)进行一些增强.>

我正在尝试添加上一个和下一个按钮,以编程方式滚动到下一个或上一个元素.如果禁用了javascript,则按钮将被隐藏,而轮播仍然起作用.

我的问题是关于如何触发滚动到下一个捕捉点?

所有项目的大小均不同,我发现的大多数解决方案要求像素值(例如示例中使用的 scrollBy ). scrollBy 40px 适用于第2页,但不适用于其他页面,因为它们太大(基于视口的大小).

  function goPrecious(){document.getElementById('container').scrollBy({最高:-40,行为:平稳"});}函数goNext(){document.getElementById('container').scrollBy({最高:40行为:平稳"});}  

  #container {scroll-snap-type:y必选;溢出-y:滚动;边框:2px实心var(-gs0);border-radius:8px;高度:60vh;}#container div {scroll-snap-align:开始;显示:flex;证明内容:中心;align-items:居中;字体大小:4rem;}#container div:nth-​​child(1){背景:hotpink;白颜色;高度:50vh;}#container div:nth-​​child(2){背景:天蓝色;高度:40vh;}#container div:nth-​​child(3){背景:blanchedalmond;高度:60vh;}#container div:nth-​​child(4){背景:浅珊瑚色;白颜色;高度:40vh;}  

 < div id ="container">< div> 1</div>< div> 2</div>< div> 3</div>< div> 4</div></div>< button onClick ="goPrecious()">上一个</button>< button onClick ="goNext()"> next</button>  

解决方案

很好的问题!我将此视为挑战.
因此,我增加了 JavaScript 使其可以动态工作.遵循我的详细解决方案(最后是完整的代码):

首先,在 .container 中添加 position:relative ,因为它需要作为 scroll height 的参考code>在 .container 中进行检查.

然后,我们创建3个全局辅助变量 :

1)一种将项目滚动位置(顶部和底部)作为数组放入 array 中.例如: [[[0,125],[125,280],[280,360]] (在这种情况下为3个项目).
3)一种存储 .container高度的一半(稍后会用到的).
2)另一个用于存储 scroll 位置

item index

  var carouselPositions;var halfContainer;var currentItem; 

现在,一个名为 getCarouselPositions 函数可以创建具有项目位置(存储在 carouselPositions 中)的 array 计算 .container 的一半(存储在 halfContainer 中):

  function getCarouselPositions(){carouselPositions = [];document.querySelectorAll('#container div').forEach(function(div){carouselPositions.push([div.offsetTop,div.offsetTop + div.offsetHeight]);//将位置信息添加到数组中})halfContainer = document.querySelector('#container').offsetHeight/2;}getCarouselPositions();//调用一次 

让我们替换按钮上的功能.现在,当您单击它们时,将调用相同的 function ,但带有"next" "previous" 参数:

 < button onClick ="goCarousel('previous')">上一个</button>< button onClick ="goCarousel('next')"> next</button> 

这里是关于 goCarousel 功能本身的信息:

首先,它创建2个变量,它们存储轮播的顶部滚动位置和底部滚动位置.

然后,有2个条件来查看当前轮播的位置是在大多数 top 还是大多数 bottom 上.
如果它位于 top 上,然后单击"next"按钮,它将转到第二个位置.如果它位于底部上,然后单击上一个"按钮,它将在上一个项目之前移到上一个项目.

如果两个条件均失败,则表示当前项目不是第一个或最后一个.因此,它检查以查看当前位置是什么,然后使用容器的一半与位置数组一起循环计算,以查看项目正在显示.然后,它结合"previous" "next" 检查以设置 currentItem 变量的正确下一个位置.

最后,它使用 currentItem 新值通过 scrollTo 到达正确的位置.

下面是完整的代码:

  var carouselPositions;var halfContainer;var currentItem;函数getCarouselPositions(){carouselPositions = [];document.querySelectorAll('#container div').forEach(function(div){carouselPositions.push([div.offsetTop,div.offsetTop + div.offsetHeight]);//将位置信息添加到数组中})halfContainer = document.querySelector('#container').offsetHeight/2;}getCarouselPositions();//调用一次函数goCarousel(direction){var currentScrollTop = document.querySelector('#container').scrollTop;var currentScrollBottom = currentScrollTop + document.querySelector('#container').offsetHeight;如果(currentScrollTop === 0&&方向==='下一个'){currentItem = 1;}否则,如果(currentScrollBottom === document.querySelector('#container').scrollHeight&& direction ==='previous'){console.log('这里')currentItem = carouselPositions.length-2;} 别的 {var currentMiddlePosition = currentScrollTop + halfContainer;对于(var i = 0; i< carouselPositions.length; i ++){如果(currentMiddlePosition> carouselPositions [i] [0]&& currentMiddlePosition< carouselPositions [i] [1]){currentItem = i;如果(方向==='下一个'){currentItem ++;} else if(direction ==='previous'){currentItem--}}}}document.getElementById('container').scrollTo({顶部:carouselPositions [currentItem] [0],行为:平稳"});}window.addEventListener('resize',getCarouselPositions);  

  #container {scroll-snap-type:y必选;溢出-y:滚动;边框:2px实心var(-gs0);border-radius:8px;高度:60vh;职位:相对}#container div {scroll-snap-align:开始;显示:flex;证明内容:中心;align-items:居中;字体大小:4rem;}#container div:nth-​​child(1){背景:hotpink;白颜色;高度:50vh;}#container div:nth-​​child(2){背景:天蓝色;高度:40vh;}#container div:nth-​​child(3){背景:blanchedalmond;高度:60vh;}#container div:nth-​​child(4){背景:浅珊瑚色;白颜色;高度:40vh;}  

 < div id ="container">< div> 1</div>< div> 2</div>< div> 3</div>< div> 4</div></div>< button onClick ="goCarousel('previous')">上一个</button>< button onClick ="goCarousel('next')"> next</button>  

要添加的另一个很好的细节是,如果窗口调整大小,则再次调用 getCarouselPositions 函数:

  window.addEventListener('resize',getCarouselPositions); 

就是这样.
这样做很酷.我希望它可以有所帮助.

I am building a carousel, very minimalist, using CSS snap points. It is important for me to have CSS only options, but I'm fine with enhancing a bit with javascript (no framework).

I am trying to add previous and next buttons to scroll programmatically to the next or previous element. If javascript is disabled, buttons will be hidden and carousel still functionnal.

My issue is about how to trigger the scroll to the next snap point ?

All items have different size, and most solution I found require pixel value (like scrollBy used in the exemple). A scrollBy 40px works for page 2, but not for others since they are too big (size based on viewport).

function goPrecious() {
  document.getElementById('container').scrollBy({ 
    top: -40,
    behavior: 'smooth' 
  });
}

function goNext() {
  document.getElementById('container').scrollBy({ 
    top: 40,
    behavior: 'smooth' 
  });
}

#container {
  scroll-snap-type: y mandatory;
  overflow-y: scroll;

  border: 2px solid var(--gs0);
  border-radius: 8px;
  height: 60vh;
}

#container div {
  scroll-snap-align: start;

  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 4rem;
}
#container div:nth-child(1) {
  background: hotpink;
  color: white;
  height: 50vh;
}
#container div:nth-child(2) {
  background: azure;
  height: 40vh;
}
#container div:nth-child(3) {
  background: blanchedalmond;
  height: 60vh;
}
#container div:nth-child(4) {
  background: lightcoral;
  color: white;
  height: 40vh;
}

<div id="container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>

<button onClick="goPrecious()">previous</button>
<button onClick="goNext()">next</button>

解决方案

Nice question! I took this as a challenge.
So, I increased JavaScript for it to work dynamically. Follow my detailed solution (in the end the complete code):

First, add position: relative to the .container, because it need to be reference for scroll and height checkings inside .container.

Then, let's create 3 global auxiliary variables:

1) One to get items scroll positions (top and bottom) as arrays into an array. Example: [[0, 125], [125, 280], [280, 360]] (3 items in this case).
3) One that stores half of .container height (it will be useful later).
2) Another one to store the item index for scroll position

var carouselPositions;
var halfContainer;
var currentItem;

Now, a function called getCarouselPositions that creates the array with items positions (stored in carouselPositions) and calculates the half of .container (stored in halfContainer):

function getCarouselPositions() {
  carouselPositions = [];
  document.querySelectorAll('#container div').forEach(function(div) {
    carouselPositions.push([div.offsetTop, div.offsetTop + div.offsetHeight]); // add to array the positions information
  })
  halfContainer = document.querySelector('#container').offsetHeight/2;
}

getCarouselPositions(); // call it once

Let's replace the functions on buttons. Now, when you click on them, the same function will be called, but with "next" or "previous" argument:

<button onClick="goCarousel('previous')">previous</button>
<button onClick="goCarousel('next')">next</button>

Here is about the goCarousel function itself:

First, it creates 2 variables that store top scroll position and bottom scroll position of carousel.

Then, there are 2 conditionals to see if the current carousel position is on most top or most bottom.
If it's on top and clicked "next" button, it will go to the second item position. If it's on bottom and clicked "previous" button, it will go the previous one before the last item.

If both conditionals failed, it means the current item is not the first or the last one. So, it checks to see what is the current position, calculating using the half of the container in a loop with the array of positions to see what item is showing. Then, it combines with "previous" or "next" checking to set the correct next position for currentItem variable.

Finally, it goes to the correct position through scrollTo using currentItem new value.

Below, the complete code:

var carouselPositions;
var halfContainer;
var currentItem;

function getCarouselPositions() {
  carouselPositions = [];
  document.querySelectorAll('#container div').forEach(function(div) {
    carouselPositions.push([div.offsetTop, div.offsetTop + div.offsetHeight]); // add to array the positions information
  })
  halfContainer = document.querySelector('#container').offsetHeight/2;
}

getCarouselPositions(); // call it once

function goCarousel(direction) {
  
  var currentScrollTop = document.querySelector('#container').scrollTop;
  var currentScrollBottom = currentScrollTop + document.querySelector('#container').offsetHeight;
  
  if (currentScrollTop === 0 && direction === 'next') {
      currentItem = 1;
  } else if (currentScrollBottom === document.querySelector('#container').scrollHeight && direction === 'previous') {
      console.log('here')
      currentItem = carouselPositions.length - 2;
  } else {
      var currentMiddlePosition = currentScrollTop + halfContainer;
      for (var i = 0; i < carouselPositions.length; i++) {
        if (currentMiddlePosition > carouselPositions[i][0] && currentMiddlePosition < carouselPositions[i][1]) {
          currentItem = i;
          if (direction === 'next') {
              currentItem++;
          } else if (direction === 'previous') {
              currentItem--    
          }
        }
      }
  } 
  
  document.getElementById('container').scrollTo({
    top: carouselPositions[currentItem][0],
    behavior: 'smooth' 
  });
  
}
window.addEventListener('resize', getCarouselPositions);

#container {
  scroll-snap-type: y mandatory;
  overflow-y: scroll;
  border: 2px solid var(--gs0);
  border-radius: 8px;
  height: 60vh;
  position: relative;
}

#container div {
  scroll-snap-align: start;

  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 4rem;
}
#container div:nth-child(1) {
  background: hotpink;
  color: white;
  height: 50vh;
}
#container div:nth-child(2) {
  background: azure;
  height: 40vh;
}
#container div:nth-child(3) {
  background: blanchedalmond;
  height: 60vh;
}
#container div:nth-child(4) {
  background: lightcoral;
  color: white;
  height: 40vh;
}

<div id="container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>

<button onClick="goCarousel('previous')">previous</button>
<button onClick="goCarousel('next')">next</button>

Another good detail to add is to call getCarouselPositions function again if the window resizes:

window.addEventListener('resize', getCarouselPositions);

That's it.
That was cool to do. I hope it can help somehow.

这篇关于CSS滚动捕捉点,带有导航(下一个,上一个)按钮的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆