构建媒体滚动条组件

有关如何为电视、手机、桌面设备等设备构建自适应水平滚动视图的基础概览。

在这篇博文中,我想分享一些创建水平滚动的想法 提供极简、响应迅速、易于访问,并可跨各种平台运行, 浏览器和平台(例如电视!)。试用 演示

<ph type="x-smartling-placeholder">
</ph>
演示

如果你更喜欢视频,可以参阅此博文的 YouTube 版本:

概览

我们将构建一个水平滚动布局,用于托管 媒体或产品。该组件以一个简单的 <ul> 列表开始,但 通过 CSS 实现流畅的滚动体验 并将它们贴靠到网格上。添加了 JavaScript 漫游索引交互,帮助键盘用户跳过 100 多个项的遍历。 此外,我们还使用一个实验性媒体查询 prefers-reduced-data 来 转换为轻量级标题滚动条体验

从可访问的标记入手

媒体滚动条由几个核心组件组成,即一个包含项目的列表。答 列表的形式最为简单,可以在世界各地推广,而且明确 到达此页面的用户可以浏览列表并点击链接 查看某项。这是我们的无障碍基地。

提交包含 <ul> 元素的列表:

<ul class="horizontal-media-scroller">
  <li></li>
  <li></li>
  <li></li>
  ...
<ul>

使用 <a> 元素使列表项可交互:

<li>
  <a href="#">
    ...
  </a>
</li>

使用 <figure> 元素从语义上表示图片及其说明:

<figure>
  <picture>
    <img alt="..." loading="lazy" src="https://picsum.photos/500/500?1">
  </picture>
  <figcaption>Legends</figcaption>
</figure>

请注意 <img> 中的 altloading 属性。媒体的替代文本 滚动条是一种用户体验机会,有助于为缩略图提供额外的背景信息,或者 后备文字(如果图片未加载),或为用户提供语音界面 依靠屏幕阅读器等辅助技术。通过 Five golden 了解详情 “合规”替代规则 文本

loading 属性接受关键字 lazy 作为表示此图片的信号 仅当图片位于视口内时才提取来源。可以是 非常适合大型列表,因为用户只会下载自己希望展示的商品的图片 滚动进入视图。

支持用户的配色方案偏好设置

使用 color-scheme 作为 <meta> 标记,向浏览器表明您的网页 需要同时采用浅色和深色的用户代理样式。这是一种免费的深色模式 或浅色模式:

<meta name="color-scheme" content="dark light">

元标记会提供尽可能早的信号,因此浏览器 如果用户偏好深色主题,可以选择深色的默认画布颜色。 这意味着在网站页面之间的导航不会闪烁白色画布 加载背景。在两次加载间无缝切换深色主题,呈现效果更佳 眼睛。

要了解更多信息,请访问 Thomas Steiner https://web.dev/color-scheme/.

添加内容

基于上述 ul > li > a > figure > picture > img 内容结构, 下一项任务是添加要滚动浏览的图片和标题。我已将演示放入了 静态占位符图片和文本,但您也可以随时通过 喜爱的数据源

使用 CSS 添加样式

现在,CSS 可以获取这一通用内容列表,并将其转换为 体验Netflix、应用商店以及许多其他网站和应用均采用横屏展示 滚动区域,使用类别和选项打包视口。

创建滚动条布局

务必避免截断版式或依赖文本 并用省略号截断。许多电视都有媒体滚动条,就像 但往往采用省略内容。但这种布局却不然! 它还允许媒体内容替换列大小,从而生成 1 个布局 足够灵活,能够处理许多有趣的组合。

2 次
滚动行显示次数。其中一个没有省略号,表示个个更高
标题完全清晰可辨。另一则内容较短,许多标题都以
省略号。

该容器允许通过提供默认大小来替换列大小,如下所示: 自定义属性这种网格布局以列大小为主, 仅管理间距和方向:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2); /* parent owned value for children to be relative to*/
  margin: 0;
}

然后,<picture> 元素使用该自定义属性来创建基本宽高比:方框:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  & picture {
    inline-size: var(--size);
    block-size: var(--size);
  }
}

只需再添加几个小样式,即可完成媒体滚动条的基本功能:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  & > li {
    display: inline-block; /* removes the list-item bullet */
  }

  & picture {
    inline-size: var(--size);
    block-size: var(--size);
  }
}

设置 overflow 会将 <ul> 设置为允许滚动和键盘导航 其列表中,则每个直接子 <li> 元素的 ::marker 都会移除 方法是获取新的显示类型 inline-block

但图片还不具有自适应能力,它们是开箱即刻突显出来的 以及它们所处的环境调整它们的尺寸、大小和边框样式 延迟加载时的背景渐变:

img {
  /* smash into whatever box it's in */
  inline-size: 100%;
  block-size: 100%;

  /* don't squish but do cover the space */
  object-fit: cover;

  /* soften the edges */
  border-radius: 1ex;
  overflow: hidden;

  /* if empty, show a gradient placeholder */
  background-image:
    linear-gradient(
      to bottom,
      hsl(0 0% 40%),
      hsl(0 0% 20%)
    );
}

滚动内边距

与网页内容的对齐方式以及无边框滚动区域 对和谐、最小的组件至关重要。

为了实现与我们的排版一致的全屏滚动布局 和布局行,请使用与 scroll-padding 匹配的 padding

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  padding-inline: var(--gap);
  scroll-padding-inline: var(--gap);
  padding-block: calc(var(--gap) / 2); /* make space for scrollbar and focus outline */
}

水平滚动内边距 bug 修复 上面的代码展示了 但该滚动容器存在明显的兼容性问题 (不过,在 Chromium 91 及更高版本中已修复!)。请参阅 此处 但简而言之,填充并不总是会被考虑 滚动视图中的内容

答
框在最后一个列表项的内嵌端突出显示,显示
内边距和元素的宽度与创建所需的对齐方式相同。

为了诱骗浏览器在滚动条的末尾放置内边距,我将 定位每个列表中的最后一个数字,并附加一个伪元素, 所需的内边距。

.horizontal-media-scroller > li:last-of-type figure {
  position: relative;

  &::after {
    content: "";
    position: absolute;

    inline-size: var(--gap);
    block-size: 100%;

    inset-block-start: 0;
    inset-inline-end: calc(var(--gap) * -1);
  }
}

使用逻辑属性可让媒体滚动条在任何写入模式下运行 和文档方向

贴靠滚动

具有 overflow 的滚动容器可以成为具有一行 CSS 的贴靠视口,然后由子元素指定它们与该视口的对齐方式。

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  padding-inline: var(--gap);
  scroll-padding-inline: var(--gap);
  padding-block-end: calc(var(--gap) / 2);

  scroll-snap-type: inline mandatory;

  & figure {
    scroll-snap-align: start;
  }
}

专注

这个组件的灵感来自于它在电视机上极受欢迎 App Store 等。许多视频游戏平台都非常使用媒体滚动条 用作主主屏幕布局。专注可带来极大的用户体验 而不是仅仅增加一点点想象一下,在 拿出遥控器,就对这种互动进行一些细微的增强:

.horizontal-media-scroller a {
  outline-offset: 12px;

  &:focus {
    outline-offset: 7px;
  }

  @media (prefers-reduced-motion: no-preference) {
    & {
      transition: outline-offset .25s ease;
    }
  }
}

这会使焦点轮廓样式 7px 远离框,从而为其提供一些不错的 空间。如果用户对减少动作没有偏好,则偏移 过渡效果,为焦点事件赋予微妙的运动效果。

漫游索引

在这些长长的列表中,游戏手柄和键盘用户需要特别注意 滚动内容和选项解决此问题的常见模式称为 漫游索引。每次 项容器获得键盘焦点,但只允许 1 个子项持有焦点 。这个每次可聚焦项的体验旨在 无需按 Tab 50+ 到达结尾的次数。

该演示的第一个滚动条中有 300 个项。我们可以做得比 它们将遍历所有位置,直至到达下一部分。

为了打造这种体验,JavaScript 需要观察键盘事件和焦点 事件。我在 Google Cloud 上创建了一个小型开源库 npm 轻松实现。下面展示了如何将其用于 3 个滚动条:

import {rovingIndex} from 'roving-ux';

rovingIndex({
  element: someElement
});

此演示在文档中查询滚动条,并为每个滚动条调用 rovingIndex() 函数。向 rovingIndex() 传递元素以获取流动 例如列表容器和目标查询选择器, 焦点目标不是直接的后代。

document.querySelectorAll('.horizontal-media-scroller')
  .forEach(scroller =>
    rovingIndex({
      element: scroller,
      target: 'a',
}))

如需详细了解此效果,请参阅开源库 roving-ux

宽高比

截至撰写本博文时, aspect-ratio落后于 标记,但适用于 Chromium 浏览器或机顶盒。由于 媒体滚动条网格布局仅指定方向和间距,但调整尺寸 在该功能检查是否支持宽高比的媒体查询内进行更改。 通过渐进增强的方式让媒体滚动条更加动态化。

答
宽高比为 4:4 的方框显示在所使用的其他设计宽高比(16:9)的旁边
和 4:3

@supports (aspect-ratio: 1) {
  .horizontal-media-scroller figure > picture {
    inline-size: auto; /* for a block-size driven ratio */
    aspect-ratio: 1; /* boxes by default */

    @nest section:nth-child(2) & {
      aspect-ratio: 16/9;
    }

    @nest section:nth-child(3) & {
      /* double the size of the others */
      block-size: calc(var(--size) * 2);
      aspect-ratio: 4/3;

      /* adjust size to fit more items into the viewport */
      @media (width <= 480px) {
        block-size: calc(var(--size) * 1.5);
      }
    }
  }
}

如果浏览器支持 aspect-ratio 语法,则媒体滚动条图片为 已升级为 aspect-ratio 大小。使用草稿嵌套语法, 更改其宽高比,具体取决于它是第一行、第二行还是第三行。通过 nest 语法还允许设置一些较小的 调整视口大小,并采用其他大小调整逻辑。

有了 CSS,随着更多浏览器引擎支持此功能, 但会呈现更具视觉吸引力的布局

希望减少数据流量

下一种分析法仅适用于 在下列情况下,位于某个标志后面Canary 版、 我想和您分享一下如何节省大量网页加载时间, 使用几行 CSS 来降低数据使用效率。prefers-reduced-data 媒体查询来自 级别 5:允许询问设备是否处于 减少数据流量状态(例如流量节省程序模式)。如果是,我可以修改 在本示例中,是隐藏图片。

ALT_TEXT_HERE

figure {
  @media (prefers-reduced-data: reduce) {
    & {
      min-inline-size: var(--size);

      & > picture {
        display: none;
      }
    }
  }
}

内容仍然可导航,但无需消耗大量图片 已下载。以下是添加 prefers-reduced-data CSS 之前的网站:

(7 个请求,100kb 资源,131 毫秒)

ALT_TEXT_HERE

以下是添加 prefers-reduced-data CSS 后的网站性能:

ALT_TEXT_HERE

(71 个请求,1.07 秒内存储 1.2MB 资源)

减少 64 个请求,即视口内大约 60 张图片(已进行的测试) 将页面加载速度提升约 80%,并且 10% 的数据通过网络传输。非常强大的 CSS。

总结

现在你知道我怎么做到的了,你会怎么做?!🙂

让我们一起采用多样化的方法,学习所有在 Web 上构建应用的方法。 创建一个 Codepen 或托管自己的演示,将它发到 Twitter 微博中,然后我会将其添加到 下方的“社区混剪作品”部分。

来源

社区混剪作品

此处尚无任何可显示的内容!