Horizon 跑马灯、幻灯片与滚动动画:自动播放、控制与减少动态
本文基于 Horizon 4.2.0,源码固定到 5acd1b6(核验于 2026-10-07)。结论限于此提交,不表示其他版本行为相同;本篇为静态源码分析,未完成店铺运行验证。Dawn 上游已发布 v16.0.0(2026-08-10,GitHub Releases 核对),本库 Dawn 正文统一以 v15.3.0 为基线,升级前需重新核对;本库 Horizon 正文统一以 4.2.0 为基线(固定提交中 config/settings_schema.json 的 theme_version 为 4.2.0)。
对应哪些通用模式
覆盖 Marquee、Carousel、Hero 与 Scroll Reveal。公告栏是另一份独立的自动播放实现,见头部与导航;Hero 的媒体选择见内容模块。本篇补运动、控制与减少动态处理。
入口与文件
| 文件 | 职责 / 何时输出 |
|---|---|
| marquee.liquid、_marquee.liquid、marquee.js | 跑马灯,作 Section 或 Hero 的块 |
| snippets/slideshow.liquid、slideshow.js、slideshow-controls.liquid | 共用滑动组件,商品画廊、卡片轮播与整屏幻灯片都用它 |
| sections/slideshow.liquid、_slide.liquid | 整屏幻灯片,自动播放只出现在这里 |
| carousel.liquid、_carousel-content.liquid | 卡片轮播,只有箭头 |
| layered-slideshow.liquid、_layered-slide.liquid、layered-slideshow.js | 分层幻灯片(tab 模式) |
| hero.liquid | Hero,无脚本 |
| jumbo-text.js、jumbo-text.liquid | 进入视口的文字动效 |
数据从哪来
全部来自 Section 与块设置,不读 metafield。幻灯片:display_mode(full_frame、with_hints)、slideshow_controls_style(none、dots、counter)、autoplay(默认关,仅 full_frame 且块数大于 1)、autoplay_speed(3–7 秒,默认 4)。跑马灯:movement_direction、gap_between_elements,无速度设置,data-speed-factor="25",时长为副本数平方根乘 25 秒。卡片轮播:columns(1–8)、mobile_columns、icons_style。文字动效:jumbo-text 块的 text_effect(none、blur、reveal)与 animation_repeat。全局“动画”分组只有 page_transition_enabled、transition_to_main_product、add_to_cart_animation、card_hover_effect。
交互怎样运行
- slideshow:
slideshow-slides是 scroll-snap 横向滚动容器。自动播放是setInterval,悬停或页面隐藏时该次跳过;mouseenter暂停、mouseleave恢复。鼠标拖拽调用pause(),而resume()遇到paused直接返回,所以拖过之后不再自动播放,直到用户点播放钮。aria-hidden由 IntersectionObserver(阈值 0.7)维护;slideshow.js没有 focus 或 keydown 处理。prefers-reduced-motion只让select()变为即时、CSS 改scroll-behavior: auto,不影响自动播放。 - 跑马灯:CSS
animation: marquee-motion无限循环,只在prefers-reduced-motion: no-preference内声明;marquee.js按容器宽度复制条目,再克隆整份content并设aria-hidden="true";pointerenter 500ms 后开始用 500ms 把playbackRate缓动到 0,离开再恢复。 - 分层幻灯片:
tablist、tab、tabpanel,rovingtabindex,非当前面板inert;桌面 ← →(RTL 下随阅读方向对调)、移动 ↑ ↓、Home、End 切换,:focus-visible焦点即选中;无自动播放;切换时对面板内视频play()或pause()。 - Hero:纯服务端输出,视频为
autoplay、loop、muted、无控件。 - 滚动触发:
jumbo-text.js用 IntersectionObserver(阈值 0.3)加ready、jumbo-text-visible类;_slide内容用 CSSanimation-timeline随 slide 横向进入视口而显现;页面转场用 View Transition(view-transition-opt-in.liquid)。
与通用契约的一致与差距
Marquee
- 一致:减少动态下不声明动画;整份克隆的
content有aria-hidden;块类型限text、icon、logo、_divider,无按钮。 - 无暂停、停止或隐藏控件,仅有指针悬停缓停,键盘焦点无效,与 Marquee 页及 WCAG 2.2.2 要求的可操作暂停不符。
#addRepeatedItems把首组条目克隆进原content且不设aria-hidden,副本数大于 1 时重复内容仍在可访问树中,与页面“副本不应再次进入可访问树”不符;logo块的链接是否被复制未核验。- 减少动态下不是变为静态 Grid 或 List,而是
overflow: hidden截断,只见前一屏宽内容(推断)。[data-disabled]选择器存在,但仓库内没有代码设置该属性。
Carousel 与 Slideshow
- 一致:上一张、下一张与圆点是带
aria-label的button,圆点有aria-selected;非infinite的卡片轮播在端点disabled;自动播放默认关,开启后有暂停与播放钮,用户暂停或拖拽后不会自行恢复;箭头默认透明,悬停或focus-within时显现;触摸滑动不是唯一控制;整屏幻灯片有视觉隐藏的 “Slideshow” 标题。 - 键盘焦点不暂停自动播放;暂停钮在 DOM 中位于 slides 之后,不在 Tab 首位。
- 自动播放时
slideshow-component带aria-live="polite",暂停后不移除,页面要求自动轮播期间关闭实时播报。 - 暂停与播放两个按钮同时输出,靠 CSS 按
[paused]切换图标,无aria-pressed,隐藏图标的那个是否仍在 Tab 顺序中未核验。 - 自动播放不读取减少动态偏好;
_slide里的背景视频autoplay、loop、muted且无暂停。 - slide 没有
role="group"、aria-roledescription或名称;inert只用于分层幻灯片,非活动 slide 靠aria-hidden与content-visibility: hidden,其中可聚焦元素是否仍可 Tab 未核验。 - 无 JavaScript:
in-viewport由脚本添加,缺失时滚动容器overflow: hidden,非首项初始aria-hidden="true",只显示第一项,满足“至少一个完整项目”,其余不可达。
分层幻灯片:有完整的 tab 键盘模型与非活动面板 inert;差距是 tab 名称只有 “Slide N of M”,不含标题,面板视频无暂停控制、不判断减少动态。
Hero:整块链接 hero__link 是无文本、无 aria-label 的空 a,hero.liquid 全文没有 aria-*;视频无控件与暂停,不受减少动态影响,而经 background-media 输出的分组与卡片背景视频在 prefers-reduced-motion: reduce 下会 display: none;标题由 text 块内容决定,Hero 自身不输出标题标签。
Scroll Reveal
- 在固定提交的全仓库搜索中未找到通用的滚动显现、视差或粘性叙事机制(搜索词:
parallax、scroll-reveal、animate-on、data-animate、scroll_animation)。IntersectionObserver 的其余用途是 slide 可见性、悬浮购买条、无限滚动等,不是显现动画。 - 最接近的三处:
jumbo-text的 blur 与 reveal(animation_repeat默认关,即一次性;JS 与 CSS 都判断减少动态);_slide内容的animation-timeline(@supports包裹,减少动态下opacity: 1; animation: none);页面转场(默认开,CSS 与 JS 双判断)。 - 差距:
jumbo-text基础样式opacity: 0; visibility: hidden,直到脚本加ready,即使text_effect为none;无 JavaScript 时文字不可见,仓库中无noscript,不满足“默认可见”。
定制入口与风险
商家可改 autoplay 与 autoplay_speed、movement_direction、text_effect、全局“动画”分组。slideshow.js 同时服务商品画廊、卡片轮播与整屏幻灯片,改它要三处一起验;公告栏另有 announcement-bar.js。_slide.liquid 比较 slide_height == 'adapt_image',而该设置只有 auto、small、medium、large,按 schema 该分支不可达。
建议的验证范围
本篇未执行。开启自动播放后分别测悬停、键盘聚焦、点暂停、拖拽后是否恢复;开启系统“减少动态效果”后测自动播放、跑马灯、Hero 视频与文字动效;读屏软件检查跑马灯重复朗读;关闭 JavaScript 检查 jumbo-text 与非首项 slide;用键盘操作分层幻灯片并核对焦点顺序。