1

早些时候有看到过一个 纯CSS轮播图 的文章,当时有研究过实现,大概是利用了 hash (锚标记) 和 scroll-snap 来实现的,但是具体实现已经回忆不起来了。

正好现在分享群组里边暂时没有主题了,就想着可以当成一个常驻的补位小环节,大家一起浏览 CodePen 之类的社区找一个大家都感兴趣的 Demo 来研究。
在分享前还是需要自己重新研究一遍的,不然在讲述的时候出错可太 “甜蜜的” 尴尬了。

首先呢,先实现一个简易的的可控轮播示例

在样例的实现中我将会使用到一下技术栈,希望你可以稍微了解一下

  1. Pug (HTML预处理器)
  2. Stylus (CSS预处理器)

P.S. 以下笔记内容将逐步实现目标文章示例,会复原目标文章内的元素样式,稍微有点改动但变化不大,因为自己想的样式太丑了。

🌰CodePen Demo

💭 讲解:

可以点开上方示例中的选项卡查看实现代码,

  1. html 中书写了 5 个 <div 并且声明了对应的 ID
  2. 并且在后续添加了 <a> 标签来改变URL当中的 hash 值来控制卡片的切换;
  3. css 利用 scroll-behavior:smooth 这个属性,来达到切换卡片的平滑滚动效果。

但是缺少了切换前进后退按钮,接下来我们就来实现这个功能:

🌰CodePen Demo2

💭 讲解:

其实很憨,直接为每一个卡片添加了前进后退按钮的 <a> 标签而已。
稍微有点麻烦的就是 如何让这两个按钮随着卡片的切换而改变,而不被后一个卡片的按钮所覆盖,因为这两个按钮是不会随着卡片切换所移动的,这里就需要脑洞大开了!

正常思路来说,肯定是会尝试修改 前进后退按钮 的父级的定位方式。
确实,会需要修改成 position:relative,但是这个其实是为了每次切换卡片后变更对应的锚链接的。

原示例是从轮播组件的最外层容器创建了 ::before::after 两个伪类,给他们设置的切换按钮的样式,并且设置为点击穿透,然后把轮播卡片内的 前进后退按钮透明 底色。
这样所展示的 “按钮” 就不会随卡片所以移动了,而实际的切换按钮会随着卡片所移动,只是不会被浏览者发现。

功能基本实现了,然后我们复原一下原示例的样式。

🌰CodePen Demo3

对照一下原示例,除了自动播放外还差了些什么呢?emmmm.....自动播放

💥 尾关BOSS 💥 自动轮播

最后来看一下她是如何实现自动播放的,这里的实现方式如果他不讲我直接就蒙圈了,但是确实很赞!👍

  1. First I slowly offset the scroll snap points to the right, making the scroll area follow along due to being snapped to them.
    首先我缓慢地将滚动捕捉点向右偏移,使滚动区域由于捕捉它们而跟随。
  2. After having scrolled the width of a whole slide, I deactivate the snapping. The scroll area is now untied from the scroll snap points.
    在滚动整个幻灯片宽度后,我停用了捕捉。 滚动区域现在与滚动捕捉点解除绑定。
  3. Now I let the scroll snap points jump back to their initial positions without them “snap-dragging” the scroll area back with them
    现在我让滚动捕捉点跳回到它们的初始位置,而不用它们 “捕捉拖动” 滚动区域
  4. Then I re-engage the snapping which now lets the scroll area snap to a different snap point 🤯
    然后我重新启用捕捉,让滚动区域捕捉到不同的捕捉点

看起来有点不易懂,但是其实并不复杂的。

其实就是利用了 scroll-snap 会使滚动容器的捕捉点变更为你设定的元素对齐位置(scroll-snap-align),然后通过修改 left 属性值使滚动容器向右滚动实现向后滚动的效果,然后通过修改当前元素的对齐位置为 none, 让滚动容器捕捉到下一个元素的对齐位置,以此来达到自动轮播的效果,那么让我们来实现一下吧!

🌰CodePen Demo 4

但是我还没有增加悬停停止自动轮播和一些其他的优化,有兴趣的可以自己实现一下,用到的CSS属性:

完整复现一下原示例吧!

🌰CodePen Demo 5

尾声

其实一开始我是不知道他如何实现的视差滚动的,结果在研究自动轮播的时候,突然就通了,所以就加上来了

通过 transform:translate3d() 给中间的元素,增加了 Z轴 属性,使其脱离了平面 “悬浮” 在轮播卡片上,然后在最外层容器的 “轮播器” 设置了 perspective 指定了容器平面与 视窗Z轴 距离。

但是有点问题,只有在自动播放动画执行时才会体现出来,手动控制切换是感觉不出来的,因为手动滚动时无法应用 scroll-snap

⚡ 兼容性

什么?你问我兼容性?友尽了啊!

别想了,scroll-snap 属性都是 CR 阶段,也就是候选,具体正式上线还有2个阶段要走,
并且scroll-behavior (平滑滚动)属性 Safari 是不支持的,

"scroll-behavior" | Can I use
"scroll-snap" | Can I use

所以移动端的兼容有很大问题,毕竟还有一个毒瘤 —— 微信内置浏览器,也是不支持这些属性的,
我在制作的过程中都没有考虑过移动端的适配,直接放弃了,PC端还是可以玩玩的。

自动轮播实现不了,那么视差滚动也就没办法实现了,

闹这么大一圈,其实就是个图个乐子,不过尝一下鲜,学习到别人的脑洞就好了。


文档链接

scroll-behavior - CSS | MDN
perspective - CSS | MDN
scroll-snap-type - CSS | MDN
scroll-snap-align - CSS | MDN
hover - CSS | MDN
:focus-within - CSS | MDN
prefers-reduced-motion - CSS | MDN

CSS-Only Carousel | CSS-Tricks
You can get pretty far in making a slider with just HTML and CSS | CSS-Tricks
大侠,请留步,要不过来了解下CSS Scroll Snap? « 张鑫旭-鑫空间-鑫生活

本文参与了SegmentFault 思否写作挑战赛,欢迎正在阅读的你也加入。

陟上晴明
21.1k 声望15.8k 粉丝

你必坚固,无所惧怕。