EN
Shopify 知识库 · 指南

Dawn 商品媒体:图库、变体联动与放大浏览

基于 Dawn v15.3.0 源码,追踪商品页媒体图库、缩略图、变体切换时的媒体联动、放大 Modal,以及视频与 3D 模型的按需加载和无障碍实现,并对照通用图库要求列出差距。
历史资料
请结合文中的适用版本和来源阅读。

本文基于 Dawn v15.3.0,源码固定到 ecb06c3(核验于 2026-09-29)。结论限于此提交,不表示其他版本行为相同;本篇为静态源码分析,未完成店铺运行验证。Dawn 上游已发布 v16.0.0(2026-08-10,GitHub Releases 核对),本库 Dawn 正文统一以 v15.3.0 为基线,升级前需重新核对。

对应哪些通用模式

覆盖 Media Gallery、Modal 与变体媒体模块在 Dawn 商品页上的实现。商品页整体结构见 Dawn 架构,本篇只展开媒体这一条链。

入口与文件

文件职责与输出条件
sections/main-product.liquid计算 variant_images,渲染图库与 Modal,声明图库设置;product.media.size > 0 才加载 product-modal.js、media-gallery.js
snippets/product-media-gallery.liquid、snippets/product-thumbnail.liquidmedia-gallery 外壳、幻灯列表、翻页按钮、缩略图;单个媒体的放大触发器与视频 / 3D 海报
snippets/product-media-modal.liquid、snippets/product-media.liquid放大浏览的 product-modal 及其中的大图 / 视频 / 3D,始终渲染
assets/media-gallery.js、assets/product-modal.js、assets/product-model.js缩略图与播报;Modal 定位;3D 与 AR(有 3D 才加载)
assets/global.jsModalDialog、ModalOpener、DeferredMedia、SliderComponent、trapFocus、pauseAllMedia
assets/product-info.js、assets/magnify.js变体切换后的 updateMedia;image_zoom == 'hover' 时的悬停放大

数据从哪来

  • 媒体来自 product.media(同一列表含 image、video、external_video、model),用到 media_type、alt、preview_image、aspect_ratio,外部视频另用 host、external_id。
  • 变体与媒体的唯一关联是 selected_or_first_available_variant.featured_media:图库先输出它,再输出其余媒体。此版本没有「变体专属媒体集合」的数据结构。
  • variant_images 取 product.images | where: 'attached_to_variant?', true | map: 'src'。设置 hide_variants 开启时,循环跳过这些图片(当前变体的 featured 除外),顾客看到「当前变体图 + 未关联任何变体的图」。schema 默认 false,templates/product.json 设为 true。
  • 图库设置:gallery_layout(stacked / columns / thumbnail / thumbnail_slider)、media_size、media_position、constrain_to_viewport、media_fit、mobile_thumbnails(columns / show / hide)、image_zoom(lightbox / hover / none)、hide_variants、enable_video_looping。
  • 变体切换的数据是同一商品 URL 的 Section Rendering 响应:<商品 URL>?section_id=…&option_values=…。

交互怎样运行

图库。 条目是 li.slider__slide,slider-component 用 scroll-snap 横向滚动,按钮调用 scrollTo。缩略图点击进入 MediaGallery.setActiveMedia:切换 is-active、滚动到该媒体、pauseAllMedia() 后对 .deferred-media 调 loadContent(false)、更新缩略图 aria-current。滚动触发的 slideChanged(防抖 500ms)反向同步缩略图。

变体联动。 product-info 先 abort() 上一个请求再拉取新分区 HTML,晚返回的旧请求不会覆盖新选择。updateMedia 仅在 variant.featured_media.id 存在时执行:插入响应中新增的 li、删除响应里没有的、按响应顺序重排,再 setActiveMedia(id, true) 把该媒体及其缩略图移到第一位。缩略图列表不按响应重建,靠 CSS 规则 .thumbnail-list_item--variant:not(:first-child)(display: none)隐藏其余变体缩略图;Modal 内容整体用响应的 innerHTML 替换。变体没有 featured 媒体时图库保持原状。

放大 Modal。 主媒体包在 modal-opener 里,真实触发元素是 button.product__media-toggle(aria-haspopup="dialog")。ProductModal.show 继承 ModalDialog.show:body 加 overflow-hidden、设置 open、trapFocus 到 [role="dialog"]、暂停所有媒体,再滚动到被点击媒体。关闭:关闭按钮、keyup Escape、鼠标 pointerup 落在视频 / 3D 之外;焦点还给触发按钮。image_zoom 为 hover 时加载 magnify.js,在支持悬停的设备上隐藏 Modal 触发器(视口 ≤749px 仍显示),点击图片生成背景图覆盖层;none 用 CSS 隐藏图片的触发器。

视频与 3D。 非图片媒体先输出海报 button 与 <template>,模板里才是 media_tag / external_video_tag 产出的元素(视频 preload: 'none')。点击海报由 DeferredMedia.loadContent 克隆模板内容、追加 video / model-viewer / iframe 并聚焦。3D 由 ProductModel 通过 Shopify.loadFeatures 加载 [email protected](该函数在固定提交的主题文件中只有调用点,定义来自 Shopify 平台脚本),AR 按钮走 shopify-xr;有 3D 时才输出 model-viewer-ui.css 的 CDN 链接。

与通用契约的一致与差距

通用要求Dawn 现状
缩略图与控制可用键盘、选中态非仅颜色缩略图与翻页是原生 button,选中态写 aria-current 并有聚焦样式;图库无方向键处理(media-gallery.js 无键盘事件),靠 Tab
替代文本按用途缩略图传 alt: media.alt,Modal 大图用 media.alt;主图 image_tag 未显式传 alt,是否自动带出未核验;视频 / iframe 名称由 media_tag 生成,未核验
切换后对辅助技术可理解role="status" 的 GalleryStatus 在图片 onload 后播报「Image N is now available」,仅限图片;视频与 3D 切换无播报
视频不强制自动播放首次需点海报,但点缩略图或变体切换到视频时,playActiveMedia 调 loadContent(false),模板含 autoplay: true,会加载并按参数尝试自动播放(不移动焦点;浏览器自动播放策略未核验)。图库与 DeferredMedia 的 JS 中无 prefers-reduced-motion 判断
Modal:焦点进入、循环、Escape、返还自定义元素加 role="dialog" aria-modal="true",trapFocus 与返还焦点已实现;全仓库未使用原生 <dialog> 或 inert(搜索词 inert、showModal、<dialog,范围 assets、layout、sections、snippets),背景靠遮罩与 overflow-hidden;Escape 监听 keyup
单项与零项退化media_count == 1 或 limit == 1 时隐藏移动端翻页按钮;product.media.size == 0 时布局类为 product--no-media 且不加载图库脚本
加载优先级与占位首项 lazy_load: false,其余 loading="lazy";--ratio 变量预留比例
无 JS图片仍在列表中可滚动;视频与 3D 在 <template> 内,无 JS 不显示。未在浏览器验证
变体切换失败请求异常仅 console.error,未见用户可见提示;AbortError 被忽略

两处细节:product-media.liquid 的 AR 按钮 data-shopify-title 是字面量 "title"(product-thumbnail.liquid 用 product.title | escape);featured-product 复用同一图库但传 limit: 1:不渲染缩略图,移动端隐藏翻页按钮。

定制入口与风险

商家可调整上文的图库设置;hide_variants 与 gallery_layout 组合会改变可见条目,需同时检查缩略图与 Modal。耦合点:li[data-media-id] 与缩略图 data-target 被 updateMedia、setActiveMedia、ProductModal 共同依赖;Modal 会被 ModalDialog 移到 body 下,样式不能假设它在分区内;Quick Add 弹窗会移除 product-modal 并把图库改成 role="presentation"(assets/quick-add.js),改结构后需连带回归。

建议的验证范围

本篇均未执行:

  1. 选择 featured 图不同的变体并快速连点,核对主图、缩略图、Modal、URL 的 variant,再加购确认行项目。
  2. hide_variants 开 / 关下检查缩略图与计数总数。
  3. 键盘走完「Tab 到缩略图 → 打开 Modal → Escape → 焦点回触发按钮」,并用屏幕阅读器听 GalleryStatus。
  4. 含视频、外部视频、3D 的商品:点海报、切缩略图、切变体,观察自动播放、暂停与 3D 不支持时的表现。
  5. 开启系统减少动态、关闭 JavaScript、放慢网络,核对上述行为与首屏比例。

源码基线