【问题标题】:CSS Slider Using `transform: translateX` To Cycle Through ImagesCSS Slider 使用 `transform: translateX` 循环图像
【发布时间】:2021-12-19 04:58:47
【问题描述】:

在使用translateX 转换属性为两张图像设置动画时,是否可以让 CSS 滑块循环显示它们?

我面临几个问题:

  1. 我似乎无法显示第二张图片,即使它在 HTML 中,除非我使用 position: absolute 然后 overflow: hidden 在父级上不起作用?

  2. 如何重置第一张图片以回到开头重新开始?

注意:在动画速记中,动画持续2.5s,初始延迟3s。

我只想使用 translateX 属性来处理这个,因为我想要 60FPS 的平滑度(完成后将使用 translate3d 来完成,但是为了使代码更易于阅读,我使用了 translateX)。我不想为margin: leftleft 属性等设置动画。

任何帮助都会很棒。

代码在下方或链接到 Codepen:https://codepen.io/anna_paul/pen/ZEJrvRp

body {
  position: relative;
  margin: 0;
  display: flex;
  justify-content: center;
}

.container {
  width: 500px;
  height: 333px;
  overflow: hidden;
}

.slider-wrapper {
  display: flex;
}

.image {
  display: block;
}

.hero-image-1 {
  transform: translateX(0);
  animation: slide-out-image-1 2.5s 3s cubic-bezier(0.54, 0.12, 0.44, 1)
    forwards;
}

@keyframes slide-out-image-1 {
  0% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(-100%);
  }
}

.hero-image-2 {
  transform: translateX(100%);
  animation: slide-in-image-2 2.5s 3s cubic-bezier(0.54, 0.12, 0.44, 1) forwards;
}

@keyframes slide-in-image-2 {
  0% {
    transform: translateX(100%);
  }
  100% {
    transform: translateX(0);
  }
}
<div class="container">
  <div class="slider-wrapper">
    <picture>
      <img class="image hero-image-1" src="https://drive.google.com/uc?export=view&id=1l7cTX35wqd-4eYvFL8A5QLZ7LbOF9m4J">
    </picture>
    <picture>
      <img class="image hero-image-2" src="https://drive.google.com/uc?export=view&id=1iB9R1aoeYSmkPX9Ju3NNOZhKylOjCA0y">
    </picture>
  </div>
</div>

【问题讨论】:

    标签: css slider css-animations transform translate


    【解决方案1】:

    我设法创建了一个可扩展的纯 CSS 轮播。它基于 Christian Schaefer 使用带有 shift 的滚动捕捉的想法。

    以下是 5 个幻灯片轮播。为了使其正常工作,您需要确保:

    • 您将第一个 .carousel-slide 元素的副本放在列表末尾。
    • 设置变量:
      • --无幻灯片:6; //包括重复的第一张幻灯片 = 5+1
      • --滑动时间:4s; // 停留时间 75% + 滑动时间 25%
    • 修改tostart关键帧规则,根据相应的计算设置时间。

         /* variables */
          :root {
            --no-slides: 6;  /* including duplicated first slide */
            --slide-time: 4s; /* stay time 75% + transition time 25% */
          }
    
    
          /* document styles */
          body {
            max-width: 400px;
            margin: 0 auto;
          }
    
          * {
            box-sizing: border-box;
            scrollbar-color: transparent transparent;
            scrollbar-width: 0px;
          }
    
          *::-webkit-scrollbar {
            width: 0;
          }
    
          *::-webkit-scrollbar-track {
            background: transparent;
          }
    
          *::-webkit-scrollbar-thumb {
            background: transparent;
            border: none;
          }
    
          * {
            -ms-overflow-style: none;
          }
    
          
          /* carousel styles */
          .carousel {
            position: relative;
            padding-top: 75%;
            perspective: 100px;
          }
    
          .carousel-viewport {
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
            display: flex;
            overflow-x: scroll;
            scroll-behavior: smooth;
            scroll-snap-type: x mandatory;
          }
    
          .carousel-viewport,
          .carousel-slide {
            list-style: none;
            margin: 0;
            padding: 0;
          }
    
          .carousel-slide {
            position: relative;
            flex: 0 0 100%;
            width: 100%;
            background: linear-gradient(90deg,#ff4e50, #f9d423);
          }
    
          
    
          .carousel-pusher {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            scroll-snap-align: center;
          }
    
          /* animations */
          @media (hover: hover) {
            .carousel-pusher {
              animation-delay: 0s;
              animation-name: tonext, snap;
              animation-timing-function: ease;
              animation-duration: var(--slide-time);
              animation-iteration-count: infinite;
            }
    
            .carousel-slide:last-child .carousel-pusher {
              animation-name: tostart, snap;
              animation-duration: calc(var(--slide-time) * (var(--no-slides) - 1)), var(--slide-time);
              animation-delay: var(--slide-time), 0s;
            }
          }
    
          @keyframes tonext {
            0% {
              filter: opacity(0);
            }
            75% {
              transform: translateX(0);
            }
            95% {
              transform: translateX(100%);
            }
            98% {
              transform: translateX(100%);
            }
            99% {
              filter: opacity(1);
              transform: translateX(0%);
            }
          }
    
          @keyframes snap {
            96% {
              scroll-snap-align: center;
            }
            97% {
              scroll-snap-align: none;
            }
            99% {
              scroll-snap-align: none;
            }
            100% {
              scroll-snap-align: center;
            }
          }
    
          @keyframes tostart {
            95.8% {     /* some fractions less than next frame time */
              transform: translateX(0%);
            }
            95.823% { /* 0.75 * (100%/--no-slides) + 100% - (100%/--no-slides) +-0.500 adjustment*/
          transform: translateX(calc((var(--no-slides)) * -100%));
        }
        99.5% {  /* 0.99 * (100%/--no-slides) + 100% - (100%/--no-slides)  +-0.500 adjustment*/
          transform: translateX(calc((var(--no-slides) - 2) * -100%));
        }
          }
    
    
          /* slide content styles */
          .content {
            padding: 20px ;
            font-size: 150px;
            text-align: center;
          }
    <div class="carousel">
          <ul class="carousel-viewport">
    
            <li class="carousel-slide">
              <div class="carousel-pusher"></div>
              <div class="content">1 &#128522;</div>
            </li>
    
            <li class="carousel-slide">
              <div class="carousel-pusher"></div>
              <div class="content">2 &#128521;</div>
            </li>
    
            <li class="carousel-slide">
              <div class="carousel-pusher"></div>
              <div class="content">3 &#128516</div>
            </li>
    
            <li class="carousel-slide">
              <div class="carousel-pusher"></div>
              <div class="content">4 &#128580;</div>
            </li>
    
    
            <li class="carousel-slide">
              <div class="carousel-pusher"></div>
              <div class="content">5 &#128526;</div>
            </li>
    
            <!-- repeat first slide -->
            <li class="carousel-slide">
              <div class="carousel-pusher"></div>
              <div class="content">1 &#128522;</div>
            </li>
          </ul>
        </div>

    要获得正确和平滑的过渡,请修改 tostart 关键帧更改时间或添加更多帧。

    注意:如果动画停止,您必须在重新开始动画之前将轮播设置为第一张幻灯片。三个动画同步运行。


    2幻灯片版

    <!DOCTYPE html>
    <html>
      <head>
        <style>
          /* variables */
          :root {
            --no-slides: 3; /* including duplicated first slide */
            --slide-time: 4s; /* stay time 75% + transition time 25% */
          }
    
          /* document styles */
          body {
            max-width: 400px;
            margin: 0 auto;
          }
    
          * {
            box-sizing: border-box;
            scrollbar-color: transparent transparent;
            scrollbar-width: 0px;
          }
    
          *::-webkit-scrollbar {
            width: 0;
          }
    
          *::-webkit-scrollbar-track {
            background: transparent;
          }
    
          *::-webkit-scrollbar-thumb {
            background: transparent;
            border: none;
          }
    
          * {
            -ms-overflow-style: none;
          }
    
          /* carousel styles */
          .carousel {
            position: relative;
            padding-top: 75%;
            perspective: 100px;
          }
    
          .carousel-viewport {
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
            display: flex;
            overflow-x: scroll;
            scroll-behavior: smooth;
            scroll-snap-type: x mandatory;
          }
    
          .carousel-viewport,
          .carousel-slide {
            list-style: none;
            margin: 0;
            padding: 0;
          }
    
          .carousel-slide {
            position: relative;
            flex: 0 0 100%;
            width: 100%;
            background-color: #f995;
          }
    
          .carousel-slide:nth-child(odd) {
            background-color: cadetblue;
          }
          .carousel-pusher {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            scroll-snap-align: center;
          }
    
          /* animations */
          @media (hover: hover) {
            .carousel-pusher {
              animation-delay: 0s;
              animation-name: tonext, snap;
              animation-timing-function: ease;
              animation-duration: var(--slide-time);
              animation-iteration-count: infinite;
            }
    
            .carousel-slide:last-child .carousel-pusher {
              animation-name: tostart, snap;
              animation-duration: calc(var(--slide-time) * (var(--no-slides) - 1)),
                var(--slide-time);
              animation-delay: var(--slide-time), 0s;
            }
          }
    
          @keyframes tonext {
            0% {
              filter: opacity(0);
            }
            75% {
              transform: translateX(0);
            }
            95% {
              transform: translateX(100%);
            }
            98% {
              transform: translateX(100%);
            }
            99% {
              filter: opacity(1);
              transform: translateX(0%);
            }
          }
    
          @keyframes snap {
            96% {
              scroll-snap-align: center;
            }
            97% {
              scroll-snap-align: none;
            }
            99% {
              scroll-snap-align: none;
            }
            100% {
              scroll-snap-align: center;
            }
          }
    
          @keyframes tostart {
            74.999% {
              /* some fractions less than next frame */
              transform: translateX(0%);
            }
            75% {
              /* 0.75 * (100%/--no-slides) + 100% - (100%/--no-slides) */
              transform: translateX(calc((var(--no-slides)) * -100%));
            }
            99.3% {
              /* 0.99 * (100%/--no-slides) + 100% - (100%/--no-slides)  -  <1.0 - 0.0 adjustment>*/
              transform: translateX(calc((var(--no-slides) - 2) * -100%));
            }
          }
    
          /* slide content styles */
          .content {
            object-fit: fill;
          }
          .image {
            padding: 0px;
            margin: 0px;
            width: 100%;
            height: 100%;
            object-fit: fill;
          }
        </style>
      </head>
    
      <body>
        <div class="carousel">
          <ul class="carousel-viewport">
            <li class="carousel-slide">
              <div class="carousel-pusher"></div>
              <div class="content"
                ><img
                  class="image"
                  src="https://drive.google.com/uc?export=view&id=1l7cTX35wqd-4eYvFL8A5QLZ7LbOF9m4J"
              /></div>
            </li>
    
            <li class="carousel-slide">
              <div class="carousel-pusher"></div>
              <div class="content"
                ><img
                  class="image"
                  src="https://drive.google.com/uc?export=view&id=1iB9R1aoeYSmkPX9Ju3NNOZhKylOjCA0y"
              /></div>
            </li>
    
            <!-- repeat first slide -->
            <li class="carousel-slide">
              <div class="carousel-pusher"></div>
              <div class="content"
                ><img
                  class="image"
                  src="https://drive.google.com/uc?export=view&id=1l7cTX35wqd-4eYvFL8A5QLZ7LbOF9m4J"
              /></div>
            </li>
          </ul>
        </div>
      </body>
    </html>

    【讨论】:

      【解决方案2】:

      要创建滑块循环,您需要在滑块移动和停止时定义动画点。在你的情况下,它看起来


      2.5s + 3s +2.5s +3s = 11s移动 + 暂停(容器外)+ 移动 + 暂停 = 总计


      对于第一个图像,我们需要在容器外进行动画处理,然后移动到开始位置(容器外),等待(第二个图像动画处理),然后动画到初始位置并暂停。

      对于第二张图片,我们只是显示然后隐藏。

      body {
        height: 100vh;
        background-color: hsl(201, 27%, 10%);
        color: white;
        display: grid;
        place-items: center;
        position: relative;
      }
      
      :root {
        --animate: 2.5s;
        --pause: 3s;
        --totall-duration: calc(var(--animate) * 2 + var(--pause) * 2);
      }
      
      .container {
        width: 500px;
        height: 333px;
        overflow: hidden;
      }
      
      .slider-wrapper {
        width: 200%;
        display: flex;
        position: relative;
      }
      
      .image {
        display: flex;
        width: 100%;
        height: 100%;
      }
      
      .hero-image-1 {
        top: 0;
        left: 0;
        position: absolute;
        animation: slide-out-image-1 var(--totall-duration) 3s
          cubic-bezier(0.54, 0.12, 0.44, 1) infinite;
      }
      /* start + pause + start + pause = totall */
      /* 2.5s + 3s + 2.5s + 3s = 11s*/
      @keyframes slide-out-image-1 {
        0% {
          transform: translateX(0);
        }
        25% {
          transform: translateX(-100%);
        }
        25.0001% {
          transform: translateX(100%);
        }
        50% {
          transform: translateX(100%);
        }
        75% {
          transform: translateX(0%);
        }
        100% {
          transform: translateX(0%);
        }
      }
      
      .hero-image-2 {
        top: 0;
        right: 0;
        position: absolute;
        animation: slide-in-image-2 var(--totall-duration) 3s
          cubic-bezier(0.54, 0.12, 0.44, 1) infinite;
      }
      
      /* start + pause + start + pause = totall */
      /* 2.5s + 3s + 2.5s + 3s = 11s*/
      @keyframes slide-in-image-2 {
        0% {
          transform: translateX(0);
        }
        25% {
          transform: translateX(-100%);
        }
        50% {
          transform: translateX(-100%);
        }
        75% {
          transform: translateX(-200%);
        }
        100% {
          transform: translateX(-200%);
        }
      }
      <div class="container">
        <div class="slider-wrapper">
          <picture class="hero-image-1">
            <img class="image" src="https://drive.google.com/uc?export=view&id=1l7cTX35wqd-4eYvFL8A5QLZ7LbOF9m4J" />
          </picture>
          <picture class="hero-image-2">
            <img class="image" src="https://drive.google.com/uc?export=view&id=1iB9R1aoeYSmkPX9Ju3NNOZhKylOjCA0y" />
          </picture>
        </div>
      </div>

      【讨论】:

        【解决方案3】:

        我们可以使用background 属性来做滑块。

        <!DOCTYPE html>
        <html>
          <head>
            <style>
              body { background-color: wheat; }
              h1 {
                text-align: center;
                color: tomato;
              }
              .slider {
                width: 60vw;
                margin: 0 auto;
                aspect-ratio: 485/323;
        
                transform: translate3d(0, 0, 0);
                background-image: url("https://drive.google.com/uc?export=view&id=1l7cTX35wqd-4eYvFL8A5QLZ7LbOF9m4J"),
                  url("https://drive.google.com/uc?export=view&id=1iB9R1aoeYSmkPX9Ju3NNOZhKylOjCA0y");
                background-attachment: scroll, scroll;
                background-position: 0% 50%, 100% 50%;
                background-repeat: no-repeat, no-repeat;
                background-size: 100%, 100%;
        
                animation: slide-background 11s cubic-bezier(0.50, 0.0, 0.50, 1) 3s infinite;
              }
              @keyframes slide-background {
                0% { background-position: 0% 50%, 60vw 50%; }
                25% { background-position: -60vw 50%, 0% 50%; }
                25.01% { background-position: 60vw 50%, 0% 50%; }
                50% { background-position: 60vw 50%, 0% 50%; }
                75% { background-position: 0% 50%, -60vw 50%; }
                100% { background-position: 0% 50%, 60vw 50%; }
              }
            </style>
          </head>
        
          <body>
            <div class="slider"><h1>Cars!</h1></div>
          </body>
        </html>

        如果您更改浏览器大小,它会调整大小。

        我知道您想使用 translate 来提高性能。 不知道transform: translate3d(0, 0, 0); 技巧对这里的background-* 属性的动画效果有多大。它是否获得相同的硬件加速?

        【讨论】:

        • 是的。我也不能使用我需要使用&lt;img/&gt;元素的背景属性。
        【解决方案4】:

        您可以给.container 一个position:relative 以使溢出生效。绝对定位元素要求其容器为a positioned element

        body {
          position: relative;
          margin: 0;
          display: flex;
          justify-content: center;
        }
        
        .container {
          width: 500px;
          height: 333px;
          overflow: hidden;
          position:relative;
        }
        
        .slider-wrapper {
          display: flex;
        }
        
        .image {
          position:absolute;
          display: block;
        }
        
        .hero-image-1 {
          transform: translateX(0);
          animation: slide-out-image-1 2.5s 3s cubic-bezier(0.54, 0.12, 0.44, 1)
            forwards;
        }
        
        @keyframes slide-out-image-1 {
          0% {
            transform: translateX(0);
          }
          100% {
            transform: translateX(-100%);
          }
        }
        
        .hero-image-2 {
          transform: translateX(100%);
          animation: slide-in-image-2 2.5s 3s cubic-bezier(0.54, 0.12, 0.44, 1) forwards;
        }
        
        @keyframes slide-in-image-2 {
          0% {
            transform: translateX(100%);
          }
          100% {
            transform: translateX(0);
          }
        }
        <div class="container">
          <div class="slider-wrapper">
            <picture>
              <img class="image hero-image-1" src="https://drive.google.com/uc?export=view&id=1l7cTX35wqd-4eYvFL8A5QLZ7LbOF9m4J">
            </picture>
            <picture>
              <img class="image hero-image-2" src="https://drive.google.com/uc?export=view&id=1iB9R1aoeYSmkPX9Ju3NNOZhKylOjCA0y">
            </picture>
          </div>
        </div>

        【讨论】:

          【解决方案5】:

          不,没有position:absolute 是不可能的。

          对于位置重置,您可以使用 Javascript。这是一个例子;

          var counter = 1;
          setInterval(function()
          {
            document.getElementById('radio' + counter).checked=true;
            counter++;
            if(counter>4){
              counter=1;
            }
          }, 5000);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-07-22
            • 2022-08-11
            • 2017-10-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-03-27
            • 1970-01-01
            相关资源
            最近更新 更多