不用JS实现轮播图——自动轮播+无缝切换+小圆点切换

12,755 阅读5分钟

基础HTML

先写最基本的HTML代码,后面为了实现无缝切换,还会在前后再加两幅图。另外,简单起见,这里就不用真正的图片了,而是用背景色代替,原理都是相同的,只是把背景色换成图片即可。

  <div class="slide">
    <ul class="list">
      <li class="item">
        1
      </li>
      <li class="item">
        2
      </li>
      <li class="item">
        3
      </li>
    </ul>
  </div>

基本样式

清除一下默认样式,在root中定义两个变量,即为轮播图区域的宽高,将轮播图区域水平垂直居中

    :root {
      --width: 20rem;
      --height: 10rem;
    }
    * {
      margin: 0;
      padding: 0;
      list-style: none;
    }
    body {
      display: flex;
      justify-content: center;
      height: 100vh;
      align-items: center;
    }
    div.slide {
      width: var(--width);
      height: var(--height);
      border: .2rem dashed purple;
    }

给所有图片加背景色加边框,调整文字大小颜色文字水平垂直居中

    li.item {
      width: var(--width);
      height: inherit;
      box-sizing: border-box;
      border: .2rem solid pink;
      background-color: maroon;
      color: #fff;
      font-size: 4rem;
      text-align: center;
      line-height: var(--height);
    }

到目前为止的效果:

将图片排成一排

所有图片左浮动,调整ul.list宽度可以放下三张图片

    li.item {
      width: var(--width);
      height: inherit;
      box-sizing: border-box;
      border: .2rem solid pink;
      background-color: wheat;
      color: #fff;
      font-size: 4rem;
      text-align: center;
      line-height: var(--height);

      /* 新增 */
      float: left;
    }
    ul.list {
      width: calc(var(--width) * 3);
      height: inherit;
      /* 加边框看下ul.list的宽度 */
      border: .5rem dashed blue;
    }

实现轮播效果

接下来要做的就是通过动画让ul.list水平左移,而外部的div.slide的宽度是固定不变的,再将超出div.slide部分隐藏即可

div.slide置于最上

    ul.list {
      width: calc(var(--width) * 3);
      height: inherit;

      /* 新增 */
      /* 以下两行代码是为了让div.slide的边框置于最上,以看到真实的移动效果 */
      position: relative;
      z-index: -1;
    }

ul.list加左移动画,每个关键帧移动整数倍图片宽度。

    ul.list {
      width: calc(var(--width) * 3);
      height: inherit;
      position: relative;
      z-index: -1;

      /* 新增 */
      /* 为了看到完整效果,延时1s */
      animation: move 5s ease 1s infinite;
    }
    @keyframes move {
      0% {
        transform: translate(calc(0 * var(--width)));
      }
      50% {
        transform: translate(calc(-1 * var(--width)));
      }
      100% {
        transform: translate(calc(-2 * var(--width)));
      }
    }

div.slide设置超出部分隐藏

    div.slide {
      width: var(--width);
      height: var(--height);
      border: .2rem dashed purple;

      /* 新增 */
      overflow: hidden;
    }

实现无缝切换

首先在HTML代码中再多增一张编号为1的图片

  <div class="slide">
    <ul class="list">
      <li class="item">
        1
      </li>
      <li class="item">
        2
      </li>
      <li class="item">
        3
      </li>
      
      <!-- 新增 -->
      <li class="item">
        1
      </li>
    </ul>
  </div>

增加ul.list4倍图片宽度

    ul.list {
      /* 修改 */
      width: calc(var(--width) * 4);
      
      height: inherit;
      position: relative;
      z-index: -1;
      animation: move 5s ease 1s infinite;
    }

将动画再添加一个关键帧实现从3过渡到1的效果,从而实现无缝切换效果

    @keyframes move {
      0% {
        transform: translate(calc(0 * var(--width)));
      }
      33% {
        transform: translate(calc(-1 * var(--width)));
      }
      66% {
        transform: translate(calc(-2 * var(--width)));
      }
      100% {
        transform: translate(calc(-3 * var(--width)));
      }
    }

由于是循环播放的动图,请看清动画的开始和结束点。

再注释掉div.slide的超出隐藏样式,看下真正的位移过程

原理:因为最后一帧在完成完全展示图1动画后,就是下个动画的开始,将图1左移,又因为动画的开始和结束之间没有时间间隔,正好形成了完美的无缝切换的效果。相反方向的同理可得。

小原点切换

设置鼠标经过轮播图区域时暂停动画。

  .slide:hover .list{
    animation-play-state: paused;
  }

在HTML代码中添加单选按钮,通过单选按钮的选中切换图片,又因为单选按钮无法设置样式,所以使用label标签配合生成圆点样式。

注意:label一定要在ul.list前面,等下需要通过兄弟元素选择ul.list标签内的图片

  <div class="slide">
    <!-- 新增 -->
    <input type="radio" name='pic' id='pic1' checked>
    <input type="radio" name='pic' id='pic2'>
    <input type="radio" name='pic' id='pic3'>
    <div class="labels">
      <label for="pic1"></label>
      <label for="pic2"></label>
      <label for="pic3"></label>
    </div>

    <ul class="list">
      <li class="item">
        1
      </li>
      <li class="item">
        2
      </li>
      <li class="item">
        3
      </li>
      <li class="item">
        1
      </li>
    </ul>
  </div>

将单选按钮隐藏,再把制作好的小圆点定位到图片区域,以及添加选中效果。

    div.slide {
      width: var(--width);
      height: var(--height);
      border: .2rem dashed purple;
      overflow: hidden;

      /* 新增 */
      /* 给input做定位参考 */
      position: relative;
    }
    input {
      display: none;
    }
    .labels {
      position: absolute;
      bottom: .5rem;
      /* 注意层级 */
      z-index: 1;
      width: inherit;
      justify-content: center;
      display: flex;
    }
    .labels label {
      width: .5rem;
      height: .5rem;
      border-radius: 50%;
      margin: 0 .3rem;
      border: .1rem solid #fff;
      background-color: transparent;
      box-sizing: border-box;
      cursor: pointer;
    }
    input[id=pic1]:checked ~ .labels label[for=pic1],
    input[id=pic2]:checked ~ .labels label[for=pic2],
    input[id=pic3]:checked ~ .labels label[for=pic3] {
      background-color: #fff;
      border: .1rem solid #fff;
    }

通过单选按钮和图片对应选中当前要显示的图片

    input[id=pic1]:checked ~ ul.list{
      transform: translate(calc(0 * var(--width)));
    }
    input[id=pic2]:checked ~ ul.list {
      transform: translate(calc(-1 * var(--width)));
    }
    input[id=pic3]:checked ~ ul.list {
      transform: translate(calc(-2 * var(--width)));
    }

此时发现之前的暂停动画是不行的,会影响这里的单选选中对应图片的效果,所以要把之前的暂停动画改为完全清除掉动画

    .slide:hover .list{
      /* animation-play-state: paused; */
      /* 修改为完全清除动画 */
      animation: none;
    }

这时会发现自动手动互不影响,当鼠标离开的时候,又从第一张图开始轮播,而鼠标再次经过轮播图区域的时候,会展示当前单选按钮选中的图片,也就是之前选中的图片展示状态会被保留

但是目前仔细看的话,会发现一个奇怪的问题,就是自动轮播的时候,小圆点不能跟随图片的切换相应的选中,原因可想而知,由于没有用js,所以不可能通过图片的切换来改变单选框的选中。为了解决这个问题,可以默认让小圆点隐藏,鼠标经过的时候再显示出来

    .slide:hover {
      /* 鼠标经过手型 */
      cursor: pointer;
    }
    .slide:hover .labels {
      /* 鼠标经过才展示小圆点 */
      display: flex;
    }
    .labels {
      position: absolute;
      bottom: .5rem;
      z-index: 1;
      width: inherit;
      justify-content: center;

      /* 修改 */
      display: none;
    }

最终效果

总结

这里用CSS实现的轮播图是不能真正在生产环境中使用的,只作为学习和研究CSS特性使用,当然也可以期待着有一天真的可以用CSS完美实现轮播图的到来呀!如果您有更好的创意的话,欢迎评论留言哦!