这年头刷短视频刷到停不下来,连找对象都得靠左滑右滑。但有没有想过,这种丝滑的滑动交互,不用一行JavaScript,光靠CSS能不能整出来?还真有人这么干了——Web-Slinger.css这个纯CSS动画库本来只搞垂直滚动触发,结果被魔改成了水平滑动判断喜欢还是讨厌。下面就把这个蜘蛛猪卡片滑动器的折腾过程掰开揉碎,让小白也能看明白。
啥是纯CSS滑动
所谓纯CSS滑动,就是只用层叠样式表里的滚动驱动动画来实现卡片被划走的效果。Web-Slinger.css原本是替代哇哦.js的玩具,专门监听页面上下滚动来触发动画。但Tinder那种左右划卡,本质上是水平滚动。所以得先给这个库打补丁,让它的触发器从垂直轴改成水平轴。
[class^="scroll-trigger-"] {
view-timeline-axis: x;
}上面这段代码把默认的垂直滚动轴(y)掰成了水平轴(x)。不然的话,那些触发器因为容器宽度被挤到视口外面,但垂直方向其实一开始就在屏幕里,会直接全部跑出来,整个效果就崩了。
搭建滑动环境
从网上找个现成的JavaScript滑动演示库(比如Nikolay Talanov那个),把所有JS代码删干净,卡片只留一张。然后把Web-Slinger.css拽进来,打上刚才的水平补丁。接着把放卡片的容器设成固定定位(position: fixed),再搞三个滚动吸附盒子并排排好,每个都跟视口一样宽高。
<main>
<div class="slide"></div>
<div id="middle" class="slide"></div>
<div class="slide">
<div class="scroll-trigger-1"></div>
</div>
</main>中间那个滑块的scroll-align设成center,这样页面一加载就停在中间,往前滚是左滑(不喜欢),往后滚是右滑(喜欢)。有个小坑得注意:滚动元素不需要真的显示滚动条,就像复选框黑魔法里先把复选框藏起来、用label假装按钮一样。这里只是借用滚动驱动的行为,默认的滚动条UI完全可以干掉。
左滑不喜欢咋做
把带scroll-trigger-1的div塞到第三张幻灯片里,用它触发卡片上的拒绝动画。
<div class="demo__card on-scroll-trigger-1 reject">
<!-- 蜘蛛猪的图片和文字 -->
</div>当页面往前滚动(相当于左滑),.scroll-trigger-1进入视口,那个reject类就开始干活。这个逻辑跑起来很顺,就像白嫖了一个正版。
右滑喜欢的翻车现场
同样的套路复制一份,把类名换成scroll-trigger-2,放到第一张幻灯片里。
<div class="on-scroll-trigger-2 accept">
<div class="demo__card on-scroll-trigger-2 reject"></div>
</div>结果傻眼了——蜘蛛猪卡片一加载就自动被“喜欢”了。这就好比相亲软件还没划呢,系统直接替人说“我愿意”。为啥左滑没问题,右滑就翻车?因为滚动驱动动画的设计逻辑是:元素在滚动方向上穿过视口时完成动画。右滑需要向后滚动(从中间滚回第一张),但浏览器默认只管向前滚,一加载时那个触发器已经在视口里(因为第一张在左边),动画直接跑完了。
解决自动喜欢的骚操作
幸好Chrome开发团队有位大佬Bramus整了个检测滚动方向的CSS黑魔法。核心是用自定义属性–scroll-direction配合样式查询,让右滑触发器在正确的时机才现身。
:root {
animation: adjust-slide-index 3s steps(3, end), adjust-pos 1s;
animation-timeline: scroll(root x);
}
@property --slide-index {
syntax: "<number>";
inherits: true;
initial-value: 0;
}
@keyframes adjust-slide-index {
to {
--slide-index: 3;
}
}
.scroll-trigger-2 {
display: none;
}
@container style(--scroll-direction: -1) and style(--slide-index: 0) {
.scroll-trigger-2 {
display: block;
}
}这里解释一下:–slide-index通过一个3秒的滚动驱动动画来计数当前在第几张幻灯片。样式查询的意思是,只有当滚动方向是向后(-1)并且处于第一张幻灯片(索引0)时,.scroll-trigger-2才会被渲染出来。这样一来,必须得实打实地从中间往左划(向后滚)到第一张,卡片才会被标记为喜欢。稍微手抖往回滚一点点?不好意思,触发器不出现,动画不执行。
统计喜欢和讨厌的人数
为了看看到底多少人爱蜘蛛猪、多少人嫌它丑,搞了两个第三方计数器图片当背景。用样式查询分别控制显示哪个计数器和描述文字。
@container style(--scroll-trigger-1: 1) {
.result {
background-image: url('https://counter6.optistats.ovh/private/freecounterstat.php?c=qbgw71kxx1stgsf5shmwrb2aflk5wecz');
background-repeat: no-repeat;
background-attachment: fixed;
background-position: center;
}
.counter-description::after {
content: 'who like spider pig';
}
.scroll-trigger-2 {
display: none;
}
}
@container style(--scroll-trigger-2: 1) {
.result {
background-image: url('https://counter6.optistats.ovh/private/freecounterstat.php?c=abtwsn99snah6wq42nhnsmbp6pxbrwtj');
background-repeat: no-repeat;
background-attachment: fixed;
background-position: center;
}
.counter-description::after {
content: 'who dislike spider pig';
}
.scroll-trigger-1 {
display: none;
}
}左滑触发–scroll-trigger-1变成1,显示讨厌计数器;右滑触发–scroll-trigger-2变成1,显示喜欢计数器。同时把对方的触发器藏掉,防止重复计数。
备胎方案:不用样式查询的简化版
如果觉得样式查询兼容性还不够广(目前只有Chromium系浏览器支持),还有一个更土但更稳的办法:直接用两个独立的滚动容器。一个管左滑,一个管右滑,中间用绝对定位叠在一起。然后通过监测滚动容器的scroll事件(虽然说了不用JS,但这里可以稍微开个后门)来切换显示。不过纯CSS党肯定瞧不上这种,所以这里还是回到纯CSS路线。
| 方案 | 优点 | 缺点 |
|---|---|---|
| 样式查询+滚动方向 | 纯CSS,无额外依赖 | 浏览器兼容性窄 |
| 独立滚动容器+JS | 兼容性好 | 需要几行JS监听 |
最终这个蜘蛛猪滑动器跑起来的效果:Chrome和Edge里打开,划左划右都能正确记录态度。虽然比预想的多费了不少头发,但证明了CSS规范里藏着的能量超乎想象。哪天浏览器能给个view-timeline-direction属性,直接指定向后滚动才触发,那就不用这么魔改了。
