登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  前端

CSS ::scroll-button 怎样给横向滚动列表添加原生箭头

来源:17golang原创

时间:2026-11-07 00:30:31 277浏览 收藏

热门推荐
漫画APP
动画内容聚合,热门资源快捷查看
立即下载

如果横向卡片列表已经可以滚动,但还想给用户一个清晰的“向前/向后”入口,可以把滚动容器交给 CSS 的 ::scroll-button() 伪元素。它会在滚动容器内部生成按钮,方向由 left、right 等参数决定,不需要为箭头再写一组 JavaScript 点击逻辑。

最小做法是:让列表成为横向滚动容器,再分别给 ::scroll-button(left) 和 ::scroll-button(right) 设置非 none 的 content。按钮会随着可滚动范围自动进入可用或 disabled 状态;同时要保留原生滚动和键盘焦点作为降级入口。

官方地址:https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Overflow/Carousels

下面只讨论横向列表、前后按钮、可访问名称和状态样式,不把 ::scroll-marker 导航或 JavaScript 轮播控制混进来。

先确定 scroll container 与生成条件

::scroll-button() 的前提不是“页面上有一排卡片”,而是目标元素本身要形成滚动容器。横向列表通常需要 display:flex、不换行和 overflow-x:auto;当内容宽度超过容器时,按钮才有实际的滚动空间。

第二个关键点是生成条件:伪元素的 content 不能是 none。只写选择器而不提供内容,浏览器不会创建可交互按钮。这个判断也解释了为什么示例同时设置箭头符号和文本替代。

横向滚动容器、溢出内容、content 非 none 与左右 scroll-button 之间的静态关系说明图
图1:结构说明图,展示滚动容器与按钮生成条件的边界;这不是浏览器截图或运行证据。

分别生成 left 与 right 按钮

方向参数表达的是滚动方向,而不是按钮摆放位置。对常见的横向列表,可以把起点方向交给 left,把终点方向交给 right。按钮图标只是视觉提示,真正的滚动语义由伪元素参数决定。

.card-list {
  display: flex;
  flex-wrap: nowrap;
  gap: 1rem;
  overflow-x: auto;
  scroll-behavior: smooth;
  /* 保留原生横向滚动,兼容时仍然可以拖动或使用键盘。 */
  scrollbar-width: thin;
}

.card-list::scroll-button(left) {
  content: "‹" / "向左滚动";
}

.card-list::scroll-button(right) {
  content: "›" / "向右滚动";
}

.card-list::scroll-button(*) {
  inline-size: 2.25rem;
  block-size: 2.25rem;
  border: 1px solid #b8c8dc;
  border-radius: 999px;
  background: #ffffff;
  color: #17324d;
  cursor: pointer;
  /* 让按钮和卡片列表之间保留明确的视觉层次。 */
  box-shadow: 0 0.25rem 0.75rem rgb(23 50 77 / 14%);
}

这里用 ::scroll-button(*) 统一设置两个按钮的外观,再用具体方向选择器提供不同图标。content 右侧的字符串是可访问名称的文本替代,避免只给辅助技术暴露一个不明确的符号。

补齐可访问性与状态样式

生成出来的按钮仍然是交互入口,不能只依赖颜色或箭头形状。键盘用户需要明确的焦点轮廓;当列表已经到达某一侧边界时,浏览器会把对应方向的按钮设置为 :disabled,此时视觉上应降低强调,并取消指针手势。

.card-list::scroll-button(*):focus-visible {
  outline: 3px solid #f0a33a;
  outline-offset: 3px;
  /* 高对比焦点轮廓不改变按钮的滚动职责。 */
}

.card-list::scroll-button(*):hover {
  background: #eef6ff;
}

.card-list::scroll-button(*):disabled {
  opacity: 0.32;
  cursor: default;
  /* 到达滚动边界后,按钮保留位置但表达不可继续滚动。 */
}

@media (prefers-reduced-motion: reduce) {
  .card-list {
    /* 用户要求减少动画时,切回即时滚动。 */
    scroll-behavior: auto;
  }
}
前后 scroll-button、可访问名称、焦点轮廓、disabled 状态与可继续滚动范围的静态依赖关系图
图2:状态说明图,展示按钮名称、焦点和 disabled 状态各自承担的职责;这不是运行截图。

:disabled 是状态反馈,不是业务代码主动维护的布尔变量。不要再用 JavaScript 监听滚动位置去重复计算同一件事;如果还需要显示页码、当前卡片或滚动标记,那是另一个交互需求,应单独设计。

兼容与降级边界

::scroll-button() 属于较新的 CSS 轮播能力,不应当成为唯一的可用路径。基础列表要先保证在没有伪元素支持时仍可横向滚动;箭头只是增强入口,不能通过隐藏滚动条、禁止触摸滑动或依赖唯一的点击事件来替代基础体验。

可以把增强样式放进能力查询,并保留容器本身的 overflow-x:auto:

@supports selector(.card-list::scroll-button(right)) {
  .card-list::scroll-button(left),
  .card-list::scroll-button(right) {
    /* 只有支持该选择器时,才启用增强按钮的布局和外观。 */
    display: inline-grid;
    place-items: center;
  }
}

@supports not selector(.card-list::scroll-button(right)) {
  .card-list {
    /* 不支持时继续提供可滚动区域,不伪造一个失效箭头。 */
    overflow-x: auto;
    scrollbar-width: auto;
  }
}

降级时最重要的结果不是“看起来仍有两个箭头”,而是用户仍然能发现列表可以横向移动。真实项目还应结合目标浏览器版本做兼容性决策,但不需要为了使用这个新伪元素重写整个轮播组件。

几个容易混淆的边界

问题应当怎样判断
按钮没有出现先确认选择器挂在滚动容器上,再确认对应 content 不是 none。
按钮出现但不能继续滚动检查内容是否真的超出容器,以及当前方向是否已经到达边界。
只显示箭头没有名称给 content 提供文本替代,并保留清晰的焦点轮廓。
不支持新特性怎么办保留 overflow-x:auto、触摸滚动和键盘路径,把按钮作为可选增强。

总结

给横向滚动列表添加原生箭头的关键是把职责分开:滚动容器负责产生可移动的内容范围,::scroll-button(left/right) 负责提供方向入口,content 负责触发生成并补充名称,:focus-visible 和 :disabled 负责让交互状态可感知。先保留基础滚动,再叠加这层 CSS 增强,兼容和可访问性会更稳。

相关问题

为什么只写 ::scroll-button(right) 没有按钮?因为生成伪元素还需要对应选择器的 content 为非 none,仅声明选择器不会自动创建控件。

::scroll-button() 和 ::scroll-marker 是一回事吗?不是。前者是滚动方向按钮,后者用于把子项或分页位置组织成滚动标记,两者解决的导航层级不同。

能不能完全隐藏横向滚动条?可以有视觉设计上的处理,但不应因此丢失触摸、键盘或其他可发现的滚动入口;新伪元素不支持时尤其要保留原生滚动。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>