如何使用纯 CSS 创建轮播

Avatar of Robin Rendle
Robin Rendle

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 $200 免费积分!

我们在 最近的新闻通讯中 提到了使用纯 CSS 创建轮播的一种方法,我认为更详细的说明会很有趣,并且可以捕捉我的一些想法。

所以,今天我们要做的是

这里没有 JavaScript,一点都没有!没有 jQuery 插件。没有技巧。只是一些我一直尝试使用的新 CSS 属性以及一些基本的 HTML。

好的,首先,我们需要关注标记。设计包括由图像组成的左侧导航和右侧的大型图像库,我们可以单独滚动浏览每个图像。我们还需要一个包装器来帮助我们整理布局

<div class="wrapper">
  <nav class="lil-nav"></nav>
  <div class="gallery"></div>
</div>

接下来,我们可以添加图像!对于这个小例子,我查看了我们列出的拥有 您可以免费使用的高质量图像 的网站,并选择了 Unsplash

在使用 CodePen 资产管理器保存图像后,我开始将 URL 添加到 nav 元素

<nav class="lil-nav">
  <a href="#image-1">
    <img class="lil-nav__img" src="..." alt="Yosemite" />
  </a>
  <a href="#image-2">
    <img class="lil-nav__img" src="..." alt="Basketball hoop" />
  </a>
  <!-- more images go here --> 
</nav>

请注意,每个链接的 href 都指向一个 ID?这是因为如果我们再次查看演示,我们希望能够点击一个图像,然后我们希望它跳到右侧库中该图像的较大型版本。

所以,现在我们可以开始将这些图像添加到大型库中……

<div class="gallery">
  <img class="gallery__img" id="image-1" src="..." alt="Yosemite" />
  <img class="gallery__img" id="image-2" src="..." alt="Basketball hoop" />
  <!-- more images go here --> 
</div>

漂亮。接下来是乐趣部分:为这个东西添加样式。我们可以使用网格布局作为父 .wrapper 并为 img 元素设置一些智能默认值

img {
  display: block;
  max-width: 100%;
}

.wrapper {
  display: grid;
  grid-template-columns: 1fr 5fr;
  grid-gap: 20px;
}

到目前为止,我们的布局已经排序,链接也已设置好。接下来,让我们处理可能会溢出到包装器外部的溢出,并确保导航和库是可滚动的

.wrapper {
  display: grid;
  grid-template-columns: 1fr 5fr;
  grid-gap: 10px;
  overflow: hidden;
  height: 100vh; 
}

.gallery {
  overflow: scroll;
}

.lil-nav {
  overflow-y: scroll;
  overflow-x: hidden;
}

现在我们可以滚动浏览库中的每个图像,但是如果这是一个生产网站,我们可能希望确保人们可以更轻松地滚动到轮播的前面。 Trent Walton 几年前就写过 这个问题,我认为始终值得牢记。

接下来,让我们关注库中每个图像的轮播捕捉。为此,我们需要使用 scroll-snap-typescroll-snap-align 属性,如下所示

.gallery {
  overflow: scroll;
  scroll-snap-type: x mandatory;
}

.gallery__img {
  scroll-snap-align: start;
  margin-bottom: 10px;
}

现在再次尝试滚动浏览右侧的库

如果您想了解有关这些属性的更多信息,我强烈推荐这篇关于 实用 CSS 滚动捕捉 的文章,它深入探讨了这些属性的细节。

我们已经拥有一个非常实用的轮播!从这里,我们要做的就是整理设计,因为库图像没有占据整个屏幕高度。为此,我们可以使用 object-fit 并使用 vh 单位为每个图像提供一个 min-height,就像这样

.gallery__img {
  scroll-snap-align: start;
  margin-bottom: 10px;
  min-height: 100vh;
  object-fit: cover;
}

现在,大型库图像将始终占据整个屏幕大小,并将按比例调整大小以占据宽度和高度。让我们继续,解决小型导航图像的样式

.lil-nav {
  overflow-y: scroll;
  overflow-x: hidden;
}

.lil-nav a {
  height: 200px;
  display: flex;
  margin-bottom: 10px;
}

.lil-nav__img {
  object-fit: cover;
}

最初,我让这个小导航也像轮播一样工作,但感觉真的很奇怪。目前,我只是保留默认的 scroll 行为。在上面的演示中,尝试点击一个图像。请注意,它如何立即跳到轮播中的该图像?如果我们能够稍微动画化这个过渡,那就太好了 - 我们可以做到!

.gallery {
  overflow: scroll;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
}

那个 scroll-behavior CSS 属性对于这一点非常有用,因此现在如果您点击任何导航项,整个东西都会动画化

很漂亮,对吧?我们可以在这里做的另一件小事是在导航项上添加一个过滤器,使它们变为黑白,然后在悬停时动画化它们

.lil-nav__img {
  object-fit: cover;
  filter: saturate(0);
  transition: 0.3s ease all;
}

.lil-nav__img:hover {
  transform: scale(1.05);
  filter: saturate(1);
}

我确信我们还可以做很多事情,但我认为这已经相当不错了!

我们甚至可以将少量 JavaScript 添加到混合中,以显示哪个图像处于活动状态,但我认为人们只要看看库就能知道。

就这样!我们现在拥有一个对渐进增强非常有利的轮播,这意味着我们不必加载 JavaScript 库或编写比实际需要更多代码。

但让我们更进一步,让它响应式。我们要做的是反转网格的顺序,将我们所有当前的样式移动到仅在大屏幕上激活的媒体查询中。

您可能想要在一个新标签页中打开此演示,并减小/增大浏览器的尺寸以查看更改。

如果您在移动设备上加载此演示,您应该会看到布局如何在两种模式之间切换。这是通过对 .wrapper 元素使用单个媒体查询来实现的。请注意,我们使用的是 Sass

$large: 1200px;

.wrapper {
  overflow: hidden;
  height: 100vh;
  display: grid;
  grid-template-rows: 2fr 1fr;
  grid-gap: 10px;

  @media screen and (min-width: $large) {
    grid-template-columns: 1fr 5fr;
    grid-template-rows: auto;
  }
}

让我们在导航上也添加一个。但是这次,我们需要告诉导航从第二行开始,这样它就会移动到屏幕底部

.lil-nav {
  overflow-x: scroll;
  overflow-y: hidden;
  display: flex;
  grid-row-start: 2;

  @media screen and (min-width: $large) {
    overflow-y: scroll;
    overflow-x: hidden;
    display: block;
    grid-row-start: auto;
  }
}

对于库,我们需要为大屏幕切换 scroll-type 并反转 overflow 属性

.gallery {
  overflow-x: scroll;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  display: flex;

  @media screen and (min-width: $large) {
    display: block;
    overflow-y: scroll;
    overflow-x: hidden;
    scroll-snap-type: y mandatory;
  }
}

这些是我们需要进行的大部分更改,我非常喜欢它!如果我们想让它投入生产,我们会考虑可访问性(例如,我们可能不希望屏幕阅读器读出导航和库中的所有图像)。然后是性能 - 我们可能会考虑延迟加载,以便图像仅在需要时呈现。

无论如何,这是一个好的开始!