news 2026/9/19 21:44:03

Yeti Scroller 布局:用不换行的横向滚动轨道组织照片条、卡片组与步骤胶片

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Yeti Scroller 布局:用不换行的横向滚动轨道组织照片条、卡片组与步骤胶片

Yeti Scroller 布局:用不换行的横向滚动轨道组织照片条、卡片组与步骤胶片

【免费下载链接】yetiA CSS-first, native, zero-build layout and styling framework for web designers.项目地址: https://gitcode.com/gh_mirrors/fo/yeti

导读

Scroller 是 Yeti 中专门负责"横向滚动单行"的布局:当一组同质内容必须保持在同一行、不能换行时,它让容器自身横向滚动,而不是挤压或折断子项。本文从 src/layouts/scroller/docs.md 出发,结合 scroller.css、manifest.json 与浏览器测试,完整讲解它的适用场景、实现原理、data-snap/data-width/data-gap三个数据属性、无障碍要求(tabindex+ 可访问名称),并给出可直接复制的示例与测试验证。读完你可以独立在 Yeti 项目中落地一个可键盘访问、可吸附对齐的横向滚动条。


何时使用 Scroller:一行必须是"一行"的内容

Scroller 解决的是一类特定的布局需求:一行内容应该始终是一行。典型场景包括:

  • 一溜照片(photo strip);
  • 一组相关的卡片(related cards);
  • 一组步骤的"胶片条"(filmstrip of steps);
  • 横向溢出的大元素,例如一张宽表格或一张超宽图片。

关键判断标准是与 cluster 的对比:cluster 是可换行的 flex 行,空间不足时子项会折行;而 scroller 恰恰相反——空间不足时子项保持原宽,容器开启横向滚动,让访客沿着这一行移动查看。因此,凡是"内容多到塞不下也不许换行"的横向条带,就是 scroller 的领地。

从 docs/guides/layouts.md 的 Foundation 6 对照表还能看到它的历史定位:Foundation 6 时代的 Orbit 轮播组件,在 Yeti 中就由scroller承担——一个不依赖 JavaScript 的原生横向滚动布局。


工作原理:不换行的 flex 行 + overflow-x

Scroller 的全部实现只有一份零依赖的 CSS,位于 src/layouts/scroller/scroller.css:

@layer yeti.layouts { .scroller { display: flex; gap: var(--_yeti-gap); overflow-x: auto; overscroll-behavior-x: contain; } .scroller:not([data-gap]) { --_yeti-gap: var(--yeti-space-md); } .scroller > * { margin: 0; flex: 0 0 auto; } .scroller[data-width] > * { inline-size: var(--_yeti-width); } .scroller[data-snap] { scroll-snap-type: x mandatory; } .scroller[data-snap] > * { scroll-snap-align: start; } }

逐行拆解其机制:

  1. display: flex+ 不换行:flex 容器默认不换行,这是"保持一行"的基础。
  2. 子项flex: 0 0 auto:这是核心——子项既不收缩也不伸展,保留自然宽度。当整行宽度超过容器时,行溢出,容器因此可以滚动。这正是文档中"Children are told not to shrink, so the row overflows and the container scrolls"的源码对应。
  3. overflow-x: auto:只在横向溢出时出现滚动条,纵向不干预。
  4. overscroll-behavior-x: contain:当滚动到轨道尽头时,把滚动"关在"轨道内部,避免连锁滚动触发外层页面(或相邻滚动区)的滚动,这是横向嵌套滚动场景中容易被忽略的细节。
  5. 子项margin: 0:间距完全交给gap决定,子项不携带任何外边距——这符合 Yeti 的总体原则:间距由持有子项的布局负责,测试中也有expectNoChildMargins专门校验这一点。

浏览器测试 test/browser/layouts/scroller.spec.js 精确验证了这套机制:在 400px 视口下断言scrollWidth > clientWidth(即确实溢出并可滚动),同时断言相邻子项top对齐、水平间距等于--yeti-space-md

支持性方面,manifest.json 的support字段标注了三个"无降级风险"的依赖:flexbox gapscroll snapoverscroll-behavior,并且js: null——整个布局不需要任何脚本。


三个数据属性:data-gap />[data-gap="xs"] { --_yeti-gap: var(--yeti-space-xs); } [data-gap="lg"] { --_yeti-gap: var(--yeti-space-lg); }

值得注意的两点:

  • 默认值用:not([data-gap])选择器提供.scroller:not([data-gap]) { --_yeti-gap: var(--yeti-space-md); })。这是 Yeti 的既定惯例:只有属性缺席时布局才提供默认,因此嵌套布局永远不会继承父级的间距值。
  • 支持流体间距对data-gap="sm-lg"不会在smlg之间跳变,而是从窄视口下的sm端点平滑流动到宽视口下的lg端点,与字体尺度本身的流式逻辑一致(见 src/tokens/scale.css 的插值机制)。

data-snap:滚动吸附

data-snap开启两条规则:

.scroller[data-snap] { scroll-snap-type: x mandatory; } .scroller[data-snap] > * { scroll-snap-align: start; }

scroll-snap-type: x mandatory让横向滚动强制吸附,scroll-snap-align: start让每个子项的起始边缘成为吸附点,滚动停下时子项会"干净地"对齐到轨道起始边,不会卡在两张卡片中间。对应测试断言:未加data-snap的轨道scroll-snap-typenone,加了之后以x开头(scroll-snap-type: x mandatory)。

data-width:等宽子项

data-width让轨道从"自然宽度各异"变为"每格等宽"的胶片感序列:

.scroller[data-width] > * { inline-size: var(--_yeti-width); }

取值同样是令牌后缀:data-width="xs"读取--yeti-width-xs(16rem),sm为 24rem、md为 32rem、lg为 48rem、xl为 64rem、2xl为 80rem(见 space.css 的宽度令牌定义)。测试对此的断言是:加了data-width="xs"后,子项宽度精确等于--yeti-width-xs的令牌值。

直接可用的最小示例

来自组件自带示例 src/layouts/scroller/example.html:

<div class="scroller"><div class="scroller" contenteditable="false">【免费下载链接】yetiA CSS-first, native, zero-build layout and styling framework for web designers.项目地址: https://gitcode.com/gh_mirrors/fo/yeti

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 21:43:27

Noi 批量提问完整指南:一个问题,同时发给 3 个 AI 平台

Noi 批量提问完整指南&#xff1a;一个问题&#xff0c;同时发给 3 个 AI 平台 【免费下载链接】Noi &#x1f680; Less chaos. More flow. 项目地址: https://gitcode.com/GitHub_Trending/no/Noi 早上 9 点&#xff0c;你为对比回答质量&#xff0c;在 ChatGPT、Clau…

作者头像 李华
网站建设 2026/9/19 21:39:39

前端AI应用开发:流式渲染与状态管理工程实践

1. 这个系列到底在写什么&#xff0c;为什么第四篇才是真正的分水岭“前端手摸手跑路之 AI 应用开发”这个系列&#xff0c;我从第一篇追到第四篇&#xff0c;越看越觉得它踩中了一个很真实的痛点&#xff1a;前端开发者想往 AI 应用方向靠&#xff0c;但市面上要么是纯算法视角…

作者头像 李华
网站建设 2026/9/19 21:37:57

Cursor 跑 MCP Host 接 Server,Base URL 改走 TaoToken 兼容通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 21:36:38

AI代理异常终止分析与解决方案

1. 异常现象解析&#xff1a;Agent terminated due to error最近在调试自动化流程时遇到一个典型报错&#xff1a;"Antigravity提示Agent terminated due to error You can prompt the model to try again or start a"。这个错误通常发生在AI代理执行过程中遇到不可恢…

作者头像 李华