纯CSS实现微信列表左滑显示按钮的交互效果

这篇文章发布于 2020年12月13日,星期日,00:21,归类于 CSS相关。 阅读 24809 次, 今日 5 次 24 条评论

 

可爱猫咪占位图

一步一步都是源自多年来持之以恒的不断积累。

一、实现效果示意

这个效果大家应该都见过,左滑对话列表,会显示藏在后面的按钮,iOS微信可以看到这种交互效果,大家手上如果有iPhone手机,可以试试。

效果示意

在Web中,是可以纯CSS实现几乎一致的交互效果的。

下面一步一步来。

二、滚动、绝对定位与按钮显示

如果大家认为看过《CSS世界》,应该知道CSS中绝对定位元素有这么一个特性:

绝对定位元素的包含块在滚动容器之外,那么这个容器滚动的时候,绝对定位元素是不会跟着滚动的。

所以,如果我们希望列表左滑的时候背后按钮显示,只需要:

  1. 每个列表元素是个水平滚动容器;
  2. 背后按钮设置position:absolute
  3. 确保列表元素没有设置position:relative或者transform等影响绝对定位包含块的CSS属性。

实地跑一下代码看看:

<div class="list">
    <button class="button" data-type="danger">删除</button>
    <a href="javascript:" class="content">我是列表,试试左滑我</a>
    <s class="space"></s>
</div>

核心CSS如下:

/* 列表仅水平滚动 */
.list { display: flex; overflow-y: hidden;}
/* 主内容宽度100%,白色背景覆盖 */
.content { flex: 0 0 100vw; background-color: #fff; position: relative; }
/* 空标签元素,作用是腾出水平滚动空间 */
.space { flex: 0 0 4rem; }
/* 按钮绝对定位,藏在内容白色背景后面 */
.button { width: 4rem;  position: absolute; right: 0; }

于是就有下图所示的GIF录屏效果:

GIF列表左滑出现删除按钮录屏

不足

虽然交互效果的精髓出来了,但是却有个不好的体验,那就是如果滚动到一半距离再停止,只会显示一半的按钮内容,就像下图这样:

按钮显示一半示意

这样的效果显然无法用在生产环境,不急,有CSS属性可以优化这个交互体验,那就是CSS Scroll Snap

三、Scroll Snap与按钮边缘定位

CSS Scroll Snap是CSS中一个独立的模块,定义了在滚动行为中,滚动停止的位置可以根据子元素的位置决定,之前有专门撰文介绍过,“要不过来了解下CSS Scroll Snap?”。

iOS 11+支持,已经支持很多年了,可以在生产环境使用,不支持的浏览器可以简单几行JS代码Polyfill一下。

回到这里,想让滚动超过一半距离的时候显示完整按钮,滚动不足一半的时候回到初始位置,只需要加几行CSS就可以了,如下所示:

/* 新增的CSS */
.list { scroll-snap-type: x mandatory; }
.space { scroll-snap-align: end; }
.content { scroll-snap-align: start; }

也就是滚动时候,主列表内容左边缘对齐,占位元素(可以看成是按钮)右边缘对齐。

于是就有如下GIF所示的录屏效果:

滚动时候自动边缘位置定位

支持多个按钮

实现了1个按钮的滑动显示效果,2个按钮自然也不在话下,只需要调整.space这个元素的宽度正好是2个按钮的宽度就可以了。

/* 2个按钮宽度 */
.space { flex: 0 0 8rem; }

此时的效果可以参考下图我录屏的GIF:

多个按钮定位滑动示意

不足
然而,仔细观察上面2个按钮的滑动交互效果,发现没有微信效果那么有质感,因为微信列表左滑的时候,后面的几个按钮,是有先后顺序、上下顺序显示的,也就是俗称的“视差”效果,而我这里CSS实现的效果就是硬邦邦的出现。

不急,CSS也是可以实现富有层次的视差滚动效果的。

四、3D透视与按钮视差滚动出现

相关的CSS技术我之前也分享过,都是很棒的技术,可惜很多人都没注意,也没重视,有兴趣可以访问这篇文章:“纯CSS实现视差滚动效果”。

这里不讲原理,只展示实现。

在原来实现的CSS基础上,再新增如下的CSS代码:

/* 视差滚动 */
.list { perspective: 1px; transform-style: preserve-3d; perspective-origin: 100% 50%; }
.button:last-of-type { transform: translate3D(2rem, 0, -1px) scale(2); }
.button:first-of-type { transform: translate3D(2rem, 0, -3px) scale(4); }

也就是把两个按钮放在3D视角上,这样滚动的时候,由于近大远小,视觉上就会有视差滚动效果的。

眼见为实,看看实现的效果吧:

多按钮同时视差滚动gif截图

五、Demo页面及其他说明

上面4个GIF演示效果均可以亲自体验,您可以狠狠地点击这里:纯CSS touch左滑按钮显示demo

如果您是PC电脑访问的demo页面,务必进入移动端模式体验,否则没有效果。

然后为了方便大家手机体验,提供了二维码:

demo页面二维码

demo页面有完整的CSS代码供大家参考与学习,然后点击按钮大家可以看到会有提示出现,类似下图这样,表示按钮并未遮挡,点击行为完全OK的。

按钮可以点击截图示意

其他说明

我自己手机测试了下,Android中完美,和PC Chrome下效果一致;iPhone Safari浏览器效果平平(iOS 12),没有看到滚动停止自动边缘定位。

实际上,按照以外的经验,iPhone设备支持scroll-snap-type/scroll-snap-align是没有任何问题的,因此,我猜想,可能与我这次水平滚动采用的是Flex布局有关,换成inline-block布局应该就妥了,我有6~7成的把握,由于赶着发文,我暂时就没测,日后我看看怎么回事再来补充。

或者在做的各位帮忙测测看inline-block布局是否OK,以及为何Flex布局中iOS Safari滚动停止时候没有Snap定位。

结语

本文背景源自厂子最近的一个项目,设计师设计了左滑出现后面按钮的效果,被我看到了,当时我就琢磨,似乎CSS就可以实现这种交互效果,不需要大动干戈写一段JS代码。

然后今天周末,正好有时间验证自己的想法,于是就有了本文的内容。

大家通过阅读应该可以发现,最终的实现效果,实际上,就是把我以前学到的那些看起来没什么大用处的CSS特性,一个一个累加了起来,对吧。比方说,从基础的CSS绝对定位特性,到CSS Scroll Snap,再到CSS 3D transform在视差滚动中的应用,都是自己以前积累并记录过的内容。

这就是重视基础的好处,当基础足够扎实,积累足够多,这个时候看到某个需求,你就能像电火花一样,一下子迸发出全新的灵感,创造出全新的实现,有助于提升个人成就感和技术热爱度。

好,就说这些。

如果您觉得本文内容还挺不错的,欢迎分享,让更多人看到CSS的潜力。

(本篇完)

分享到:


发表评论(目前24 条评论)

  1. asdfg说道:

    虽然css可以实现,但是感觉js实现更简单些

  2. 涂山苏苏说道:

    视察滚动这一块 不太好理解

  3. 流采说道:

    请教:在视差滚动的介绍中,translateX 偏移 2rem,这个值是怎么计算得来的?

  4. hong说道:

    我来反馈问题因为不能截屏,放一个网页。https://hongweizhu.com/keep/zhangxinxu.php

    • LeonZou说道:

      /* 让红色遮住黄色并且不裂开 */
      .content{z-index:2}
      [data-type=”danger”]{z-index:1;box-shadow: 4rem 0px 0px #eb4646;}
      [data-type=”warning”]{box-shadow: 4rem 0px 0px #f59b00;}

  5. LeonZou说道:

    有两个问题:
    1、请问你的滚动回弹是怎么实现的?
    2、我的浏览器出现了很神奇的渲染错误(动图红框内),但是手机上没有问题,请问你知道为什么吗?(87.0.4280.88 (正式版本) (64 位) (cohort: Stable))
    https://sm.ms/image/mYvNl6AWTGJbgwB

  6. 某某某说道:

    传说IOS政策限制,这些浏览器用的都是Safari的内核……

  7. wangqiling说道:

    每次都有新收获

  8. zhuishao说道:

    css3新世界啥时候出啊?我已经等不及了?

  9. mfk说道:

    ios 10,11下用微信内置浏览器、手机自带sarafi、安装的Chrome均试过,都不行。

  10. 王铁柱说道:

    太棒了,有人知道文中二维码是怎么生成的吗

  11. 说道:

    最后一个例子,加上视差滚动后会导致能往左滑超出滚动距离,两个按钮中间有间隙

  12. banyinglong说道:

    很好,学以致用。很多时候,看了很多学了一些,然后很少用,基本就忘记了,就比方说grid,看完基本没用过,也是不熟练,还是要常用,然后遇到问题,会想到更多的解决方案

  13. 某捣乱的说道:

    题外话,什么时候XHR支持边下载边读取就好了……

  14. 一米说道:

    谢谢大佬,这个太棒了。

  15. flyfish说道:

    这个例子很好

  16. 崮生说道:

    在 Firefox 上好像还是有点问题