遮罩层必须用 position: fixed,而非 absolute;正确写法是 fixed + top:0 + left:0 + width:100vw + height:100vh + z-index:9999;背景用 rgba() 而非 opacity;显示/隐藏须匹配请求生命周期(finally 关闭);需拦截 touchstart 防穿透。

遮罩层必须用 position: fixed,不是 absolute
表格本身是相对定位或文档流内元素,如果给遮罩层设 position: absolute,它会相对于最近的已定位祖先(比如 table 或 div)定位——但表格通常没设 position: relative,结果遮罩层就按 body 定位,宽度/高度只覆盖视口可视区域,滚动后遮罩消失。用户一拉滚动条,底下表格还能点。
正确做法是:position: fixed + top: 0 + left: 0 + width: 100vw + height: 100vh。这样不管表格多长、是否在页面中间、是否嵌套在 iframe 里,遮罩始终盖满整个视口。
-
100vw和100vh比100%更可靠:后者依赖父容器高度,而vw/vh始终基于视口 - 别漏写
z-index: 9999—— 表格里如果有select、iframe或第三方组件(如某些富文本编辑器),它们的默认z-index可能意外高于你的遮罩 - 移动端 Safari 对
fixed在overflow: scroll容器里有兼容问题,此时可加will-change: transform强制触发合成层
遮罩不能用 opacity,要用 background: rgba()
常见错误是把整个 table 包进一个带 opacity: 0.5 的容器里。这会让表格文字、边框、表头全部变灰变淡,用户看不清内容,也分不清哪行正在加载——遮罩本意是“阻断交互”,不是“弱化视觉”。
真正要遮的是操作入口,不是信息本身。所以遮罩层应是独立 DOM 元素,背景用 background: rgba(0, 0, 0, 0.4),不透明度只作用于自身,不影响下层表格渲染。
立即学习“前端免费学习笔记(深入)”;
-
filter: alpha(opacity=40)是 IE 旧语法,现代项目不用;opacity会透出子元素,绝对不要套在表格外层 - 如果表格用了
border-collapse: collapse,遮罩层上叠加的 loading 动画(如loading.gif)建议用position: fixed单独居中,避免被表格overflow截断 - 动画资源优先用 GIF:比 CSS
@keyframes旋转更兼容,尤其在 Android 4.4–6.0 上,transform: rotate()可能卡顿或不触发硬件加速
显示/隐藏时机必须匹配数据加载生命周期
表格数据加载常走 AJAX 或 fetch,但很多人只在 success 回调里 hide 遮罩,一旦请求失败、超时或网络中断,遮罩就永远挂着——用户以为页面卡死,实际只是 JS 没收到响应。
关键不是“成功才关”,而是“请求结束就关”。jQuery 用 complete,原生 fetch 必须包在 finally 里:
fetch('/api/table-data')
.then(res => res.json())
.then(data => renderTable(data))
.catch(err => console.error(err))
.finally(() => document.getElementById('table-loading').style.display = 'none')
- 不要用
DOMContentLoaded或$(document).ready()控制遮罩显隐——那是 DOM 解析完成,和表格数据无关 - 如果表格支持分页或筛选,每次重新加载都要重置遮罩:先
display: block,再发请求,避免用户连点两次按钮导致遮罩失效 - 禁用表格内可交互元素(如排序箭头、操作按钮)比单靠遮罩更稳妥:可在遮罩显示时加
pointer-events: none到tbody,但注意tr上的onclick仍可能触发,需同步设disabled属性或移除事件监听
移动端 touch 点击穿透必须手动拦截
iOS Safari 和部分安卓浏览器中,即使遮罩层 z-index 很高,用户仍可能穿透点击到表格里的按钮或链接——这不是 bug,是浏览器对 pointer-events 的宽松实现。
仅设 pointer-events: auto 不够,得加一层防御:
document.getElementById('table-loading').addEventListener('touchstart', e => {
e.preventDefault()
})
- 这个
touchstart.preventDefault()要在遮罩display: block后立即绑定,隐藏时记得removeEventListener避免内存泄漏 - 不要用
pointer-events: none—— 这会让遮罩层完全不可捕获事件,也就拦不住点击了 - 如果表格用了
virtual scroll或复杂滚动容器(如overflow-y: auto的 div),遮罩层需额外加inset: 0替代top/left/width/height,防止因容器 transform 导致定位偏移



















