无限滚动轮播(仅限 CSS)

Posted

技术标签:

【中文标题】无限滚动轮播(仅限 CSS)【英文标题】:Infinite scrolling carousel (CSS only) 【发布时间】:2022-01-23 07:22:15 【问题描述】:

我正在尝试创建一个自动循环播放的轮播。最初我正在实现slick slider,但后来我遇到了这种仅使用 CSS 的方法:

body 
  align-items: center;
  background: #E3E3E3;
  display: flex;
  height: 100vh;
  justify-content: center;


@keyframes scroll 
  0% 
    transform: translateX(0);
  
  100% 
    transform: translateX(calc(-250px * 7));
  


.slider 
  background: white;
  box-shadow: 0 10px 20px -5px rgba(0, 0, 0, 0.125);
  height: 100px;
  margin: auto;
  overflow: hidden;
  position: relative;
  width: 960px;


.slider::before,
.slider::after 
  background: linear-gradient(to right, white 0%, rgba(255, 255, 255, 0) 100%);
  content: "";
  height: 100px;
  position: absolute;
  width: 200px;
  z-index: 2;


.slider::after 
  right: 0;
  top: 0;
  transform: rotateZ(180deg);


.slider::before 
  left: 0;
  top: 0;


.slider .slide-track 
  animation: scroll 40s linear infinite;
  display: flex;
  width: calc(250px * 14);


.slider .slide 
  height: 100px;
  width: 250px;
<div class="slider">
  <div class="slide-track">
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/1.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/2.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/3.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/4.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/5.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/6.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/7.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/1.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/2.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/3.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/4.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/5.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/6.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/7.png"    />
    </div>
  </div>
</div>

现在,我正在尝试对我的轮播进行逆向工程并实现类似的功能:

@keyframes scroll 
  0% 
    transform: translateX(0);
  
  100% 
    transform: translateX(calc(-250px * 7));
  


.carousel 
  padding: 100px 0;
  background: lightblue;
  overflow: hidden;
  position: relative;


.carousel__wrapper 
  display: flex;
  justify-content: center;
  align-items: center;


.carousel__slide 
  animation: scroll 10s linear infinite;
  display: flex;
  flex-direction: column;
  width: 33%;


.carousel__image 
  background-size: cover;
  background-repeat: no-repeat;
  height: 100px;
  width: 100px;
  margin: 15px 20px;
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">

<section class="carousel">

  <div class="container-fluid px-0">
    <div class="row">
      <div class="col-12">
        <div class="carousel__wrapper">

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/200');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/200');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/200');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/200');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/200');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/200');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/200');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/200');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/200');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/200');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/200');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/200');"></div>
          </div>

        </div>
      </div>
    </div>
  </div>

</section>

在我的演示中,carousel 的末尾有空格。而在上面的工作演示中,徽标循环流畅(从头开始,没有空格)。

现在,在上面的工作演示中,我将所有 CSS 剥离为仅此:

@keyframes scroll 
  0% 
    transform: translateX(0);
  
  100% 
    transform: translateX(calc(-250px * 7));
  


.slide-track 
  animation: scroll 10s linear infinite;
  display: flex;
<div class="slider">
  <div class="slide-track">
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/1.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/2.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/3.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/4.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/5.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/6.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/7.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/1.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/2.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/3.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/4.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/5.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/6.png"    />
    </div>
    <div class="slide">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/7.png"    />
    </div>
  </div>
</div>

上面的工作正常,并且上面的 css 存在于我的演示中,但它不能顺利工作?在显示最后一张幻灯片后如何进行过渡(使其从头开始)?

【问题讨论】:

【参考方案1】:

轮播基于固定宽度工作。如果有 7 张幻灯片:

    他们在 html 中复制了一次幻灯片。确保重复幻灯片。 carousel__wrapper 已提供width: calc(250px * 14);。要显示的幻灯片数量的两倍。请注意,包装器取决于幻灯片宽度,而幻灯片不依赖于包装器。 carousel 的宽度小于包装器 250px * 4 的宽度,溢出被隐藏,因此我们只能看到窗口而不是整个 carousel__wrapper。 动画将幻灯片向左移动calc(-250px * 7)。这里,250px 是幻灯片宽度。请注意,它们仅移动了 7 张幻灯片,而不是全部 14 张。

如果不使用 javascript,您将无法使用相对尺寸。为了只保留 CSS,您需要绝对宽度。 如果你使用变量,那么事情将很容易维护和理解:

:root 
  --no-of-slides: 6;
  --slides-in-view: 4;
  --slide-width: 200px;
  --slide-height: 300px;
  --iteration-time: 10s;


@keyframes scroll 
  0% 
    transform: translateX(0);
  
  100% 
    transform: translateX(calc(var(--slide-width) * var(--no-of-slides)* -1));
  


.carousel__wrapper 
  display: flex;
  /*justify-content: center;*/
  align-items: center;
  
  width: calc(var(--slides-in-view) * var(--slide-width));
  overflow: hidden;
  border: 1px dashed gray;
  margin: 0 auto;


.carousel 
  padding: 100px 0;
  background: lightblue;
  
  overflow: hidden;
  width: calc(2 * var(--no-of-slides));


.carousel__slide 
  animation: scroll var(--iteration-time) linear infinite;
  display: flex;
  flex-direction: column;
  
  flex: 0 0 auto;
  width: var(--slide-width);
  height: var(--slide-height);
  box-sizing: border-box;
  /*border: 1px dotted darkblue;*/


.carousel__image 
  background-size: cover;
  background-repeat: no-repeat;
  
  height: 50%;
  /*width: 100px;*/
  margin: 15px 20px;



/* just for analysis remove this 3 rules later*/
    .carousel__slide 
      position: relative;
    

    .carousel 
      counter-reset: slideNo;
    

    .carousel__slide::before 
      counter-increment: slideNo;
      content: counter(slideNo);
      position: absolute;
      top: 0%;
      left: 50%;
      font-size: 2rem;
      color: lime;
    
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">

<section class="carousel">

  <div class="container-fluid px-0">
    <div class="row">
      <div class="col-12">
        <div class="carousel__wrapper">

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/1/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/1/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/2/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/2/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/3/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/3/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/4/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/4/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/5/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/5/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/picsum/200/300');">
            </div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/picsum/200/300');">
            </div>
          </div>

          <!--#### repeat ####-->
          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/1/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/1/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/2/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/2/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/3/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/3/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/4/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/4/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/5/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/5/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/picsum/200/300');">
            </div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/picsum/200/300');">
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>
在上述 CSS 规则中,我的更改位于空行之后。请参阅代码中的 cmets。

如果您想要基于视口的尺寸,那么您可以使用vwvh 单位:

:root 
  --no-of-slides: 6;
  --slides-in-view: 4;
  --slide-width: 33vw;
  --slide-height: 50vh;
  --iteration-time: 10s;


@keyframes scroll 
  0% 
    transform: translateX(0);
  
  100% 
    transform: translateX(calc(var(--slide-width) * var(--no-of-slides)* -1));
  


.carousel__wrapper 
  display: flex;
  /*justify-content: center;*/
  align-items: center;
  
  width: calc(var(--slides-in-view) * var(--slide-width));
  overflow: hidden;
  border: 1px dashed gray;
  margin: 0 auto;


.carousel 
  padding: 10px 0;
  background: lightblue;
  
  overflow: hidden;
  width: calc(2 * var(--no-of-slides));


.carousel__slide 
  animation: scroll var(--iteration-time) linear infinite;
  display: flex;
  flex-direction: column;
  
  flex: 0 0 auto;
  width: var(--slide-width);
  height: var(--slide-height);
  box-sizing: border-box;
  /*border: 1px dotted darkblue;*/


.carousel__image 
  background-size: cover;
  background-repeat: no-repeat;
  
  height: 50%;
  /*width: 100px;*/
  margin: 15px 20px;



/* just for analysis remove this 3 rules later*/
    .carousel__slide 
      position: relative;
    

    .carousel 
      counter-reset: slideNo;
    

    .carousel__slide::before 
      counter-increment: slideNo;
      content: counter(slideNo);
      position: absolute;
      top: 0%;
      left: 50%;
      font-size: 2rem;
      color: lime;
    
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">

<section class="carousel">

  <div class="container-fluid px-0">
    <div class="row">
      <div class="col-12">
        <div class="carousel__wrapper">

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/1/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/1/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/2/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/2/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/3/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/3/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/4/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/4/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/5/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/5/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/picsum/200/300');">
            </div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/picsum/200/300');">
            </div>
          </div>

          <!--#### repeat ####-->
          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/1/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/1/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/2/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/2/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/3/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/3/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/4/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/4/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/5/200/300');"></div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/5/200/300');"></div>
          </div>

          <div class="carousel__slide">
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/picsum/200/300');">
            </div>
            <div class="carousel__image" style="background-image: url('https://picsum.photos/seed/picsum/200/300');">
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>

【讨论】:

特别感谢使用vars 的可重用性:) 非常感谢!

以上是关于无限滚动轮播(仅限 CSS)的主要内容,如果未能解决你的问题,请参考以下文章

Jquery+css实现图片无缝滚动轮播

iOS UICollectionView无限轮播

iOS UICollectionView无限轮播

滚动轮播效果,.net 没得混看来只能去写js 了

横向滚动轮播图

无限轮播的实现,未加自动轮播效果(非原创)