EN
Shopify 知识库 · 指南

Horizon 跑马灯、幻灯片与滚动动画:自动播放、控制与减少动态

基于 Horizon 4.2.0 源码,拆解跑马灯、幻灯片、卡片轮播、分层幻灯片与 Hero 的自动播放、暂停控制、键盘与 aria 处理,并核查主题是否内置滚动显现,对照通用页面列出减少动态差距。
历史资料
请结合文中的适用版本和来源阅读。

本文基于 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.liquidHero,无脚本
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,roving tabindex,非当前面板 inert;桌面 ← →(RTL 下随阅读方向对调)、移动 ↑ ↓、Home、End 切换,:focus-visible 焦点即选中;无自动播放;切换时对面板内视频 play() 或 pause()。
  • Hero:纯服务端输出,视频为 autoplay、loop、muted、无控件。
  • 滚动触发:jumbo-text.js 用 IntersectionObserver(阈值 0.3)加 ready、jumbo-text-visible 类;_slide 内容用 CSS animation-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;用键盘操作分层幻灯片并核对焦点顺序。

源码基线