fix(template-07): 移动端顶部菜单展开后无法滚动
菜单面板留在 sticky 的 <header> 内,踩了两个叠加的 CSS 陷阱: 1) <header> 带 sticky(position:sticky + z-50)会自建层叠上下文, 面板在其中 z 写多大都只能在 header 内部排序,整体仍被 DOM 靠后的 <main>(Hero 为 relative,同样自建上下文)盖住。 2) sticky 的 header 会成为后代 fixed 的包含块——fixed 定位基准从视口 退化成 header 的盒子并被其高度裁剪。原实现面板是普通流式元素,高度 由内容撑开(汇吉采 6 个带子菜单的栏目约 1000px)直接溢出屏幕,而 header 内没有可滚动容器,于是「展开即滚不动」,底部栏目够不着。 修复:面板 Teleport 到 body 脱离 header 的层叠上下文;面板改 fixed 并 四边锚定(inset-x-0 top-16 bottom-0 + overflow-y-auto + overscroll-contain), top/bottom 同时钉住后高度才由视口决定,长菜单在面板内滚动。 实测(390x844 设备模拟):面板可滚到底,header 固定、背景页不动; 桌面 1440x900 无回归。约束与「只写 top-16 不够」的警告已写进组件注释。 Refs: .scratch/hjc-web-mobile-menu-scroll/issues/01-fix-mobile-menu-scroll.md
This commit is contained in:
@@ -88,9 +88,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 移动端菜单 -->
|
<!-- 移动端菜单 -->
|
||||||
|
<Teleport to="body">
|
||||||
<div
|
<div
|
||||||
v-if="mobileMenuOpen"
|
v-if="mobileMenuOpen"
|
||||||
class="lg:hidden bg-white border-t border-gray-100"
|
class="fixed inset-x-0 top-16 bottom-0 z-[60] overflow-y-auto overscroll-contain lg:hidden bg-white border-t border-gray-100"
|
||||||
>
|
>
|
||||||
<div class="container mx-auto px-4 py-4 space-y-1">
|
<div class="container mx-auto px-4 py-4 space-y-1">
|
||||||
<template v-for="item in navItems" :key="item.navigationId || item.path">
|
<template v-for="item in navItems" :key="item.navigationId || item.path">
|
||||||
@@ -130,6 +131,7 @@
|
|||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</Teleport>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -143,6 +145,23 @@ import type { CmsNavigation } from '~/types'
|
|||||||
const { siteInfo, siteName, siteLogo, siteIcon, navigations, showHeaderSearch, fetchSiteInfo } = useSite()
|
const { siteInfo, siteName, siteLogo, siteIcon, navigations, showHeaderSearch, fetchSiteInfo } = useSite()
|
||||||
const mobileMenuOpen = ref(false)
|
const mobileMenuOpen = ref(false)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 移动端菜单(模板里 `v-if="mobileMenuOpen"` 那块)为什么长这样——两个坑都踩过,别改回去:
|
||||||
|
*
|
||||||
|
* 1) 必须 <Teleport to="body">,不能留在 <header> 内。
|
||||||
|
* <header> 带 `sticky`(position:sticky + z-50),这会让它**自建层叠上下文**;
|
||||||
|
* 面板留在里面时,z 写多大都只在 header 内部排序,整体仍被 DOM 靠后的
|
||||||
|
* <main>(Hero 是 relative,同样自建上下文)盖住 → 菜单"展开了却看不见"。
|
||||||
|
*
|
||||||
|
* 2) 面板必须是 `fixed` 且四边锚定(inset-x-0 top-16 bottom-0 + overflow-y-auto)。
|
||||||
|
* <header> 是 sticky 时会成为后代 fixed 的**包含块**,fixed 的定位基准从视口
|
||||||
|
* 退化成 header 的盒子并被其高度裁剪。菜单项多起来时(汇吉采 6 个带子菜单的栏目,
|
||||||
|
* 展开约 1000px)面板会撑出屏幕,而 header 里没有可滚动容器 →
|
||||||
|
* 「展开即滚不动」,底部栏目在任何机型上都够不着(原缺陷)。
|
||||||
|
* top/bottom 同时钉住后高度才由视口决定,长菜单才能在面板内滚动。
|
||||||
|
* ⚠️ 只写 `top-16` 不够:高度仍锁在 header 的 h-16 内,症状原样复现。
|
||||||
|
*/
|
||||||
|
|
||||||
/** 子导航链接统一走 app/utils 的 getNavLink(自动避免 /page/4598?navId=4598 冗余拼接) */
|
/** 子导航链接统一走 app/utils 的 getNavLink(自动避免 /page/4598?navId=4598 冗余拼接) */
|
||||||
function getChildPath(child: CmsNavigation): string {
|
function getChildPath(child: CmsNavigation): string {
|
||||||
return getNavLink(child)
|
return getNavLink(child)
|
||||||
|
|||||||
Reference in New Issue
Block a user