Horizon 页眉导航:Mega Menu、移动抽屉、吸顶与公告栏
本文基于 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)。
对应哪些通用模式
覆盖 Navigation Menu(桌面主导航与 Mega Menu)、Drawer(移动菜单抽屉)、Sticky Bar(吸顶页眉)和 Banner(公告栏)。页面外壳、分区组与首屏高度测量见布局与导航,购物车抽屉走另一套 theme-drawer,见购物车,本篇不重复。面包屑在此版本未内置,见文末搜索口径。
入口与文件
| 文件 | 职责 |
|---|---|
| sections/header-group.json | 页眉分区组:公告栏在前、页眉在后;默认 enable_sticky_header: "always"、菜单 main-menu、menu_style: "featured_products" |
| sections/header.liquid | 用 content_for 'block' 静态取 logo 与 _header-menu(桌面、mobile、navigation_bar 三种变体),写出 sticky / transparent 属性 |
| blocks/_header-menu.liquid、mega-menu-list | 桌面菜单:顶层链接、展开按钮、Mega Menu 分栏与精选内容 |
| snippets/header-drawer.liquid | 移动抽屉,details / summary 结构(mobile 变体) |
| assets/header-menu.js、header-drawer.js、header.js | 子菜单开合、抽屉开合、吸顶状态与高度变量 |
| sections/header-announcements.liquid、_announcement、announcement-bar.js | 公告栏与轮播,仅 header 分组可用 |
数据从哪来
- 菜单:
_header-menu的menu(link_list,默认main-menu)。link.links生成子级;link.current输出aria-current="page",桌面菜单中link.active只加样式类;抽屉按linklist.levels < 3与 3 层两条分支渲染。 - Mega Menu 内容:
menu_style取text、collection_images、featured_products、featured_collections。前者在子链接没有集合类目标时、后者在顶层链接不是集合或全部商品入口时退回text。 - 精选内容延迟加载:
section.index == blank(Section Rendering 场景)才算eager_loading,桌面精选商品、抽屉的精选商品与集合只在该场景输出。非设计模式下header.liquid的模块脚本用requestIdleCallback调hydrate(),section-hydration.js 只 morph 带data-hydration-key的节点,因此首屏 HTML 不含精选商品。 - 公告栏:
_announcement的text、link,分区设置speed(2–10 秒,默认 5)。空文本块不输出,但自动播放与箭头按section.blocks.size > 1判断,可能与实际幻灯片数不一致。
交互怎样运行
- 桌面菜单:
on:pointerenter激活,on:pointerleave与on:blur停用(on:由component.js在 document 上委托)。激活时把展开按钮的aria-expanded置true并移除子菜单inert;指针追踪用data-safety-box留出斜向移动的安全区;header-menu元素自身也被写入aria-expanded(供 CSS 用,无角色,读屏含义未核验)。overflow-list放不下时收进 More 按钮,可见项少于minimum-items(2)时页眉改用抽屉;触屏设备(ontouchstart且maxTouchPoints > 0)由theme.liquid内联脚本直接设为data-menu-style="drawer"。 - 移动抽屉:
<details scroll-lock>加summary,aria-expanded由open()/#close()写;dialog.js 监听details的toggle事件锁滚动。动画结束后trapFocus(details)(focus.js:Tab 首尾循环,focusin把外部焦点拉回);Escape 由抽屉元素上的keyup处理,遮罩点击调用close。 - 吸顶:
enable_sticky_header(always/scroll-up/never)写成<header-component sticky>,与透明页眉同开时透明值降为not-sticky。always用.header-section { position: sticky; top: -1px }加IntersectionObserver写data-sticky-state;scroll-up由header.js的 rAF 节流滚动回调比较scrollTop,上滚为active(此时才 sticky),下滚为idle(opacity: 0)。≥990px 时滚动容器是.page-wrapper,跨断点会重绑监听。公告栏所在 section 无 sticky 规则,随页滚走。--header-height由ResizeObserver维护,购物车摘要与商品详情的 sticky 偏移读取它。 - 公告栏:多块时
announcement-bar-component带autoplay与aria-live="polite",setInterval切换各幻灯片的aria-hidden;鼠标进入暂停、离开恢复,箭头复用slideshow-arrows。
与通用契约的一致与差距
一致
- 桌面菜单是
nav(aria-label取accessibility.header_navigation_label,英文Primary)加列表;全仓库没有role="menu"/menuitem角色(ref="menuitem"只是脚本引用名),与 Navigation Menu 的「不必用 role=menu」一致。 - 有子级的顶层项是「链接 + 独立展开按钮」,按钮带
aria-controls、aria-expanded与show_submenu文案,平时opacity: 0,:focus-visible才显示;链接聚焦不自动展开(菜单中没有on:focus)。 - Escape 关闭并把焦点交还展开按钮(溢出面板交还 More 按钮);折叠子菜单带
inert,不进 Tab 顺序;悬停内容可移入(.menu-list__submenu:hover)、可用 Escape 关闭,与 1.4.13 在代码层面对应,未实测。
差距
- 无 JS:桌面菜单默认
display: none,仅data-menu-style='menu'才显示,该属性只由脚本写;抽屉.menu-drawer默认visibility: hidden,需脚本加.menu-open。按静态阅读,无 JavaScript 时顶层链接不可达,与契约「顶层链接仍可跳转」有差距(未做禁用脚本实验)。 - 抽屉不是模态对话框:无
role="dialog"/aria-modal,背景不设inert,仅靠trapFocus;未见关闭后把焦点交还summary的调用;trapFocus的container.focus()作用于无tabindex的details,初始焦点未核验;summary的服务端输出没有aria-expanded。 - 当前页:只有顶层与抽屉链接输出
aria-current,mega-menu-list子链接没有;navigation_bar变体(窄屏横向滚动)是div加ul,没有nav与名称。面包屑与「当前位置」不存在。 - 公告栏:无关闭按钮、有效期字段与暂停控件(仅悬停暂停,键盘聚焦不暂停);无
prefers-reduced-motion分支;aside无名称。页面隐藏时pause()写入paused,回到可见时resume()遇paused直接返回,按静态阅读自动播放此后不再恢复,需浏览器验证。 - 吸顶遮挡焦点:
scroll-padding/scroll-margin只在与页眉无关的片段出现,未见为 sticky 页眉预留滚动偏移(2.4.11 需实测);header.liquid、header.js无prefers-reduced-motion降级。
定制入口与风险
编辑器可改(schema 设置名):_header-menu 的 menu、menu_style、navigation_bar、drawer_accordion、drawer_accordion_expand_first、drawer_dividers;页眉的 menu_row、show_search、enable_sticky_header、enable_transparent_header_home 等三项、section_height;公告栏的 speed。耦合点:theme.liquid 内联脚本重复了页眉高度、--top-row-height 与 data-menu-style 的计算,注释要求与 utilities.js 同步;header.js 声明 requiredRefs(headerDrawerContainer、headerMenu、headerRowTop),移除菜单块的后果未核验;自定义菜单标记须保留 data-hydration-key。
建议的验证范围
均未执行:禁用 JS 后首页导航是否可达;仅用键盘走完顶层项、展开按钮与子链接,检查 Escape 与焦点回位;触屏与 ≥750px 非触屏各测展开方式;抽屉三层前进与返回;always 与 scroll-up 下锚点跳转、Tab 聚焦是否被页眉遮住;切换标签页后公告是否继续轮播;开启减少动态偏好观察公告与页眉过渡。
搜索口径:对固定提交整个检出(含 sections、snippets、blocks、assets、templates、locales、config,含隐藏文件)用 rg -uui 搜索 breadcrumb,无命中;scroll-padding|scroll-margin 有 5 个文件命中,均与页眉无关。