CSS 实现苹果官网的轮播图?

3 阅读5分钟

用CSS实现苹果官网轮播图,我们先分析下要实现的轮播图效果。

image.png

  1. 每屏展示当前轮播图,
  2. 同时显示前一张图,和后一张图,前后图用遮罩盖住
  3. 轮播图下面有指示点 高亮点表明当前是哪一张轮播图
  4. 点击点可以跳转到对应的轮播图
  5. 自动轮播
技术实现思路

我们会用CSS的一些特性如scroll-snap-type,scroll-snap-align, 实现轮播每次切换,都是切换一整张幻灯片,而不是像滚动条自由随意的滚动效果,那样就不像轮播图了;同时我们也会利用CSS动画效果实现自动播放,利用a标签点击跳转实现点击圆点到对应的轮播图

展示当期轮播图 并且显示上一张图,和下一张图
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>用CSS实现苹果官网轮播图</title>
    <style>
      * {
        box-sizing: border-box;
      }

      body {
        margin: 0;
        font-family: sans-serif;
        background: #f0f0f0;
      }

      .carousel {
        display: flex;
        overflow-x: auto;
        scroll-snap-type: x mandatory;
        scroll-behavior: smooth;
        -webkit-overflow-scrolling: touch;
        gap: 1rem;
        padding: 1rem;
      }

      .carousel::-webkit-scrollbar {
        display: none;
      }

      .carousel__slide {
        flex: 0 0 80%;
        scroll-snap-align: center;
        position: relative;
        border-radius: 10px;
        background: #fff;
        box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
        height: 676px;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 2rem;
        background-size: cover;
        background-position: center;
      }

      #slide1 {
        background-image: url('https://is1-ssl.mzstatic.com/image/thumb/hjmYsl20uNCFQ9sqjiQIYw/2500x1406.jpg');
      }
      #slide2 {
        background-image: url('https://is1-ssl.mzstatic.com/image/thumb/Features221/v4/7d/6b/46/7d6b4699-b669-1c1b-7661-d5eae0ff00f8/6832cd56-83a4-43be-9eb0-c1ced85499b9.png/2500x1406.jpg');
      }
      #slide3 {
        background-image: url('https://is1-ssl.mzstatic.com/image/thumb/4UEcdeb6Xoc40fhFSAr3Og/2500x1406.jpg');
      }
      #slide4 {
        background-image: url('https://is1-ssl.mzstatic.com/image/thumb/Features/v4/1e/01/8a/1e018acf-c8ff-1fbe-844d-c7e573dd383a/57c591a9-2c28-4f62-b6ee-c69a3ff56a3d.png/2500x1406.jpg');
      }

      .carousel__nav {
        text-align: center;
      }

      .carousel__nav a {
        display: inline-block;
        width: 12px;
        height: 12px;
        margin: 0 6px;
        background: #ccc;
        border-radius: 50%;
        transition: background 0.3s;
      }

      .carousel__nav a:focus,
      .carousel__nav a:hover {
        background: #333;
      }
    </style>
  </head>
  <body>
    <section class="carousel" aria-label="Gallery">
      <div id="slide1" class="carousel__slide"></div>
      <div id="slide2" class="carousel__slide"></div>
      <div id="slide3" class="carousel__slide"></div>
      <div id="slide4" class="carousel__slide"></div>
    </section>

    <nav class="carousel__nav">
      <a href="#slide1"></a>
      <a href="#slide2"></a>
      <a href="#slide3"></a>
      <a href="#slide4"></a>
    </nav>
  </body>
</html>

上面的代码实现了4张轮播图切换的效果,并且点击圆点可以切换到对应的轮播图

用CSS实现苹果官网轮播图.gif

点击点可以跳转到对应的轮播图
    <section class="carousel" aria-label="Gallery">
      <div id="slide1" class="carousel__slide"></div>
      <div id="slide2" class="carousel__slide"></div>
      <div id="slide3" class="carousel__slide"></div>
      <div id="slide4" class="carousel__slide"></div>
    </section>

    <nav class="carousel__nav">
      <a href="#slide1"></a>
      <a href="#slide2"></a>
      <a href="#slide3"></a>
      <a href="#slide4"></a>
    </nav>

我们用锚点跳转(Anchor Link / Fragment Identifier),实现点击圆点可以切换到对应的轮播图,可以看到a标签的#slide1和id="slide1"是对应的

给前后图添加遮罩
.carousel {
  /* 现有属性保留 */
  display: flex;
  ...
  /* 添加遮罩渐变 */
  -webkit-mask-image: linear-gradient(to right, transparent 0%, black 20%, black 80%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0%, black 20%, black 80%, transparent 100%);
}

黑色表示完全可见,白色表示完全不可见。这与直觉相反,因为我们通常认为黑色是 "遮挡" 的颜色,但在 CSS 遮罩系统中,逻辑是反向的。

用CSS实现苹果官网轮播图 0.gif

这样有2个问题

  1. 第一张图/最后一张图我们不需要遮罩
  2. 遮罩是固定不变的,这不是我们要的效果,我们要的是当一个图离开中心区域,变成上一张或下一张的时候加上遮罩

image.png

苹果官网用的应该是不透明度遮罩,我们把渐变换成不透明度效果

/* 添加遮罩渐变 */
-webkit-mask-image: linear-gradient(
  to right,
  rgba(0, 0, 0, 0.5) 0%,
  rgba(0, 0, 0, 0.5) 7%,
  black 7%,
  black 93%,
  rgba(0, 0, 0, 0.5) 93%,
  rgba(0, 0, 0, 0.5) 100%
);
mask-image: linear-gradient(
  to right,
  rgba(0, 0, 0, 0.5) 0%,
  rgba(0, 0, 0, 0.5) 7%,
  black 7%,
  black 93%,
  rgba(0, 0, 0, 0.5) 93%,
  rgba(0, 0, 0, 0.5) 100%
);
实现自动轮播

我们用CSS动画实现轮播,这里我们多加了一个div, carousel__track,

 <section class="carousel" aria-label="Gallery">
      <div class="carousel__track">
        <div class="carousel__slide" id="slide1"></div>
        <div class="carousel__slide" id="slide2"></div>
        <div class="carousel__slide" id="slide3"></div>
        <div class="carousel__slide" id="slide4"></div>
      </div>
    </section>

样式更改主要是在最外层增加了position: relative;overflow: hidden;

 .carousel {
        position: relative;
        overflow: hidden;
        width: 100%;
      }

  .carousel__track {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    gap: 1rem;
    padding: 1rem;
    /* 添加遮罩渐变 */
    -webkit-mask-image: linear-gradient(
      to right,
      rgba(0, 0, 0, 0.5) 0%,
      rgba(0, 0, 0, 0.5) 7%,
      black 7%,
      black 93%,
      rgba(0, 0, 0, 0.5) 93%,
      rgba(0, 0, 0, 0.5) 100%
    );
    mask-image: linear-gradient(
      to right,
      rgba(0, 0, 0, 0.5) 0%,
      rgba(0, 0, 0, 0.5) 7%,
      black 7%,
      black 93%,
      rgba(0, 0, 0, 0.5) 93%,
      rgba(0, 0, 0, 0.5) 100%
    );
  }

  .carousel__track::-webkit-scrollbar {
    display: none;
  }

  .carousel__slide {
    flex: 0 0 87%;
    scroll-snap-align: center;
    position: relative;
    border-radius: 0px;
    background: #fff;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
    height: 676px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 2rem;
    background-size: cover;
    background-position: center;
    animation: slide 6s infinite;
  }
  
  @keyframes slide {
    0%,
    20% {
      transform: translateX(0);
    }
    25%,
    45% {
      transform: translateX(-90%);
    }
    50%,
    70% {
      transform: translateX(-180%);
    }
    75%,
    95% {
      transform: translateX(-270%);
    }
    100% {
      transform: translateX(0);
    }
  }

GIF 上传不不成功,可以点击预览看下最终效果

结论: 花了挺长时间,用了各种大模型,还是实现不了,只用CSS 实现苹果官网那种带有前后图预览,遮罩,自动轮播,无缝切换的效果,需要Javascript,简单的轮播用CSS还是很容易实现的

附上完整代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>用CSS实现苹果官网轮播图</title>
    <style>
      * {
        box-sizing: border-box;
      }

      body {
        margin: 0;
        font-family: sans-serif;
        background: #f0f0f0;
      }
      .carousel {
        position: relative;
        overflow: hidden;
        width: 100%;
      }

      .carousel__track {
        display: flex;
        overflow-x: auto;
        scroll-snap-type: x mandatory;
        scroll-behavior: smooth;
        -webkit-overflow-scrolling: touch;
        gap: 1rem;
        padding: 1rem;
        /* 添加遮罩渐变 */
        -webkit-mask-image: linear-gradient(
          to right,
          rgba(0, 0, 0, 0.5) 0%,
          rgba(0, 0, 0, 0.5) 7%,
          black 7%,
          black 93%,
          rgba(0, 0, 0, 0.5) 93%,
          rgba(0, 0, 0, 0.5) 100%
        );
        mask-image: linear-gradient(
          to right,
          rgba(0, 0, 0, 0.5) 0%,
          rgba(0, 0, 0, 0.5) 7%,
          black 7%,
          black 93%,
          rgba(0, 0, 0, 0.5) 93%,
          rgba(0, 0, 0, 0.5) 100%
        );
      }

      .carousel__track::-webkit-scrollbar {
        display: none;
      }

      .carousel__slide {
        flex: 0 0 87%;
        scroll-snap-align: center;
        position: relative;
        border-radius: 0px;
        background: #fff;
        box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
        height: 676px;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 2rem;
        background-size: cover;
        background-position: center;
        animation: slide 6s infinite;
      }

      @keyframes slide {
        0%,
        20% {
          transform: translateX(0);
        }
        25%,
        45% {
          transform: translateX(-90%);
        }
        50%,
        70% {
          transform: translateX(-180%);
        }
        75%,
        95% {
          transform: translateX(-270%);
        }
        100% {
          transform: translateX(0);
        }
      }

      #slide1 {
        background-image: url('https://is1-ssl.mzstatic.com/image/thumb/hjmYsl20uNCFQ9sqjiQIYw/2500x1406.jpg');
      }
      #slide2 {
        background-image: url('https://is1-ssl.mzstatic.com/image/thumb/Features221/v4/7d/6b/46/7d6b4699-b669-1c1b-7661-d5eae0ff00f8/6832cd56-83a4-43be-9eb0-c1ced85499b9.png/2500x1406.jpg');
      }
      #slide3 {
        background-image: url('https://is1-ssl.mzstatic.com/image/thumb/4UEcdeb6Xoc40fhFSAr3Og/2500x1406.jpg');
      }
      #slide4 {
        background-image: url('https://is1-ssl.mzstatic.com/image/thumb/Features/v4/1e/01/8a/1e018acf-c8ff-1fbe-844d-c7e573dd383a/57c591a9-2c28-4f62-b6ee-c69a3ff56a3d.png/2500x1406.jpg');
      }

      .carousel__nav {
        text-align: center;
      }

      .carousel__nav a {
        display: inline-block;
        width: 10px;
        height: 10px;
        margin: 0 6px;
        background: #ccc;
        border-radius: 50%;
        transition: background 0.3s;
      }

      .carousel__nav a:focus,
      .carousel__nav a:hover {
        background: #333;
      }
    </style>
  </head>
  <body>
    <section class="carousel" aria-label="Gallery">
      <div class="carousel__track">
        <div class="carousel__slide" id="slide1"></div>
        <div class="carousel__slide" id="slide2"></div>
        <div class="carousel__slide" id="slide3"></div>
        <div class="carousel__slide" id="slide4"></div>
      </div>
    </section>

    <nav class="carousel__nav">
      <a href="#slide1"></a>
      <a href="#slide2"></a>
      <a href="#slide3"></a>
      <a href="#slide4"></a>
    </nav>
  </body>
</html>