构建“短片故事”组件

简要介绍了如何在网页上打造类似于 Instagram 短片故事的体验。

在本文中,我想分享一下构建适用于网络的自适应、支持键盘导航且可在所有浏览器中运行的短片故事组件的想法。

演示

如果您希望通过动手演示来自行构建此短片故事组件,请查看短片故事组件 Codelab

如果您更喜欢视频,请观看此帖子的 YouTube 版本:

概览

短片故事用户体验的两个热门示例是 Snapchat 故事和 Instagram 短片故事(更不用说舰队了)。从一般用户体验的角度来看,短片故事通常是一种仅适用于移动设备的点按式模式,用于浏览多个订阅。例如,在 Instagram 上,用户打开朋友的故事并浏览其中的照片。他们通常会同时对多位好友执行此操作。通过点按设备的右侧,用户可以跳至该好友的下一个故事。用户可以通过向右滑动跳转到其他好友。 故事组件与轮播界面非常相似,但允许浏览多维数数组,而不是一维数组。这就好像每个轮播界面内都有一个轮播界面一样🥰?

使用卡片可视化多维数组。从左到右是一叠紫色边框卡片,每张卡片中都有 1 多张蓝绿色相框的卡片。列表形式的列表。
第一个好友轮播界面
第二个“堆叠”的短片故事轮播界面
👍? 列表中的列表,也称为多维数组

为工作选择合适的工具

总的来说,得益于一些关键的 Web 平台功能,我发现构建此组件非常简单。我们来了解一下这些问题!

CSS 网格

事实证明,CSS Grid 可以轻松处理我们的布局,因为它提供了一些强大的功能来管理内容。

“好友”页面布局

我们的主要 .stories 组件封装容器是移动优先的水平滚动视图:

.stories {
  inline-size: 100vw;
  block-size: 100vh;

  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;

  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}

/* desktop constraint */
@media (hover: hover) and (min-width: 480px) {
  max-inline-size: 480px;
  max-block-size: 848px;
}
使用 Chrome 开发者工具的设备模式突出显示 Grid 创建的列

我们来详细了解一下 grid 布局:

  • 我们使用 100vh100vw 在移动设备上明确填充视口,并在桌面设备上限制大小
  • / 用于分隔行和列模板
  • auto-flow 解析为 grid-auto-flow: column
  • 自动流模板为 100%,在本例中为滚动窗口宽度

在手机上,您可以将行大小视为视口高度,将每个列视为视口宽度。继续以 Snapchat 故事和 Instagram 快拍为例,每一列都是一位朋友的故事。我们希望好友的故事能够在视口之外继续,这样我们有地方可以滚动到。Grid 会根据需要创建所需数量的列,为每个好友故事布局 HTML,为我们创建一个动态且响应的滚动容器。借助网格,我们可以集中处理整个效果。

堆叠

对于每位好友,我们都需要其故事处于可分页状态。 为了准备动画和其他有趣的模式,我选择了堆栈。 我说“堆叠”的意思是 您是在看三明治,而不是从侧面看

借助 CSS 网格,我们可以定义单元格网格(即正方形),其中行和列共享一个别名 ([story]),然后每个子项都会分配到该别名单元格空间:

.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
.story {
  grid-area: story;
  background-size: cover;
  
}

这样,HTML 就可以控制堆叠顺序,并使所有元素保持流畅。请注意,我们无需对 absolute 定位或 z-index 执行任何操作,也无需使用 height: 100%width: 100% 进行正确的框选。父级网格已定义故事图片视口的大小,因此无需告知这些故事组件来填充它!

CSS 滚动贴靠点

CSS 滚动贴靠点规范要求在滚动时将元素锁定到视口中。在这些 CSS 属性出现之前,您必须使用 JavaScript,而且至少可以说,这很棘手。请参阅 Sarah Drasner 撰写的 Introducing CSS Scroll Snap Points,详细了解如何使用 CSS 滚动贴靠点。

不使用和使用 scroll-snap-points 样式的水平滚动。 没有此属性时,用户可以照常自由滚动。这样,浏览器便会轻轻地放在每个项上。
父级
.stories {
  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}
滚动回弹的父级定义了贴靠行为。
儿童
.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
儿童选择成为贴靠目标。

我选择“滚动贴靠点”的原因有以下几点:

  • 免费访问。“滚动点按点”规范规定,默认情况下,按向左键向右键应会沿点按点移动。
  • 不断完善的规范。滚动贴靠点规范会不断添加新功能并进行改进,这意味着我的短片故事组件今后只会变得更好。
  • 实现难度。实际上,滚动贴靠点是专为以触摸为中心的水平分页用例而构建的。
  • 自由平台式惯性。每个平台都会以自己的风格滚动和休息,而非采用标准惯性,后者可能会出现奇怪的滚动和休息风格。

跨浏览器兼容性

我们在 Opera、Firefox、Safari 和 Chrome 以及 Android 和 iOS 上进行了测试。下面简要介绍了我们发现在功能和支持方面存在差异的网页版功能。

不过,有些 CSS 不适用,因此某些平台目前无法进行用户体验优化。我不喜欢无需管理这些功能,并且确信它们最终会推广到其他浏览器和平台。

scroll-snap-stop

轮播界面是促使创建 CSS 滚动卡顿点规范的主要用户体验用例之一。与短片故事不同,轮播界面在用户与图片互动后,并不总是需要在每张图片上停止。快速轮播轮播界面可能没问题,甚至是受鼓励的。另一方面,最好逐个浏览短片故事,而 scroll-snap-stop 正是为此而提供的。

.user {
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

在撰写本文时,仅基于 Chromium 的浏览器支持 scroll-snap-stop。如需了解最新动态,请参阅浏览器兼容性。但它不是障碍。这只是意味着,在不受支持的浏览器上,用户可能会意外跳过好友。因此,用户只需更加小心,或者我们需要编写 JavaScript 来确保跳过的好友不会被标记为已查看。

如有兴趣,请参阅规范了解详情。

overscroll-behavior

您是否遇到过以下情况:滚动浏览模态窗口,而您突然开始滚动模态窗口后面的内容? overscroll-behavior 可允许开发者陷入滚动操作,绝不让它离开。适合各种场合。“我的短片故事”组件使用它来防止其他滑动和滚动手势离开该组件。

.stories {
  overflow-x: auto;
  overscroll-behavior: contain;
}

Safari 和 Opera 这两款浏览器不支持此功能,这完全没问题。这些用户将获得与以往一样的滚动体验,可能永远不会注意到此增强功能。我个人非常喜欢它,我喜欢将它纳入我实现的几乎所有滚动回弹功能中。这是一项无害的新增功能,只能改善用户体验。

scrollIntoView({behavior: 'smooth'})

当用户点按或点击并到达某位好友的一组故事的末尾时,系统会移至滚动贴靠点集合中的下一位好友。借助 JavaScript,我们能够引用下一位好友并请求滚动到其视图中。它对此类基础组件的支持非常好;每个浏览器都会滚动显示该元素。但并非所有浏览器都执行了 'smooth'。这只是表示它已滚动到视野中,而不是固定到视野中。

element.scrollIntoView({
  behavior: 'smooth'
})

在上述测试中,只有 Safari 不支持 behavior: 'smooth'。如需了解最新动态,请参阅浏览器兼容性

动手操作

现在您已经知道我是如何做到的,您会怎么做呢?让我们多元化我们的方法,了解在 Web 上构建的所有方式。创建 Glitch,然后在推特上向我发送您的版本,我会将其添加到下方的社区混剪作品部分。

社区混剪作品