浮窗导航必须用 position: fixed;避免父容器 transform 导致 absolute 偏移;居中用 top: 50% + translateY(-50%);固定像素 right;z-index ≥ 1000;body 预留 padding;键盘弹起时监听 focusin 临时隐藏;球与菜单 DOM 分离;菜单用 visibility: hidden + opacity: 0;菜单项用 标签;位置动态计算;收起需覆盖点击菜单、点击外部、按 Esc 三种路径;移动端用 touchstart 替代 click;删除父级 z-index 防层叠上下文限制。

浮窗导航必须用 position: fixed,别碰 absolute
用 absolute 做悬浮菜单,90% 的问题是父容器加了 transform 或 perspective,导致菜单“突然偏移”或“跟着滚动”。fixed 才是唯一靠谱的方案——它锚定视口,不依赖任何父级定位上下文。
常见错误:top: 50vh 看似居中,但用户缩放页面、横屏、或 zoom 变化时,vh 值会跳变,菜单立刻错位。正确做法是 top: 50%; transform: translateY(-50%),配合 right: 20px(固定像素值,不用 rem 或 %)。
- 所有悬浮元素(球、菜单、公告层)都必须设
z-index≥ 1000,否则微信内置浏览器、广告 SDK、弹窗组件一盖一个准 -
body要预留空间:右浮窗 → 给body加padding-right: 80px;底浮窗 → 加padding-bottom: 80px,否则正文被遮挡 - 移动端键盘弹起时,
fixed元素常卡在输入框正上方。监听focusin事件,对input和textarea触发时临时隐藏浮窗
菜单容器和触发按钮必须分离 DOM 结构
把菜单项写进悬浮球内部(比如 <div class="ball"><div class="item">首页</div></div>)是典型反模式:圆形球体被撑变形、overflow: hidden 挡不住 absolute 子项、鼠标移入菜单瞬间触发球体 mouseleave 导致闪退。
正确结构只有两个独立节点:
立即学习“前端免费学习笔记(深入)”;
<div id="floatBall" class="floating-ball"></div> <div id="floatMenu" class="floating-menu"> <a href="#home">首页</a> <a href="#contact">联系</a> </div>
- 悬浮球只负责触发和定位,不能含任何子交互节点,推荐用
<button></button>而非<div>,语义清晰且天然支持键盘聚焦<li>菜单容器初始状态用 <code>visibility: hidden; opacity: 0;,别用display: none——后者会让getBoundingClientRect()返回全 0,后续定位失效 - 菜单项必须用
<a></a>标签,不是<button></button>:支持原生锚点跳转、SEO 可读、无需额外tabindex适配 - 点击球体时,执行
const rect = ball.getBoundingClientRect() - 菜单
top设为rect.bottom + 8(留出 8px 间距,避免紧贴难点击) - 菜单
right设为window.innerWidth - rect.right(比用left+width推算更稳,避开移动端 viewport 宽度含滚动条的偏差) - 计算前加校验:
if (!rect.width || !rect.height) return,防止球体被display: none后还强行定位 - 菜单项点击:每个
<a></a>绑click,执行业务后调closeMenu() - 外部点击:给
document绑click,用event.target.closest('.floating-ball, .floating-menu')判断是否在范围内,不在就收起 - 键盘退出:监听
keydown,event.key === 'Escape'时关闭,并event.preventDefault()防止页面意外滚动 - 移动端注意:
click有 300ms 延迟,改用touchstart替代;同时加touch-action: none在球体上,防 iOS 把拖拽识别成缩放
展开时位置必须动态计算,不能写死 top/right
写死 top: 80px; right: 24px 在 PC 浏览器里可能刚好,但一上 iOS Safari、横屏 iPad、或用户开了系统缩放,就彻底跑偏。唯一可靠的方式是 JS 实时读取触发球位置再算菜单位置。
关键步骤:
收起逻辑要覆盖三种退出路径,漏一个就卡住
只监听悬浮球点击,等于默认用户“只会点球”,现实里用户会点菜单项、点空白处、按 Esc 键——三者缺一,浮窗就永远关不掉。
最易被忽略的是层叠上下文:如果悬浮球父容器写了 position: relative; z-index: 1,整个浮窗就被锁死在那个局部层级里,外面弹窗再高也盖不住——删掉父级 z-index,让浮窗直接挂到根层叠上下文上。



















