首屏广告必须用 fixed 全屏 div 实现,因 dialog.showModal() 需用户事件触发且 iOS 旧版不支持;主内容需 display: none 隐藏;倒计时用 setInterval + Date.now() 精准控制;移动端须禁滚动、用 inset: 0 居中、加 touch-action: manipulation。

首屏广告不是“一打开就弹”,而是“一进入就占满整个可视区”,且必须绕过浏览器对自动弹窗的拦截。用 dialog 做不了,用 alert() 会被直接屏蔽,真正能落地的只有手动构造全屏 div + 精确控制触发时机。
为什么不能用 dialog.showModal() 做首屏广告
因为现代浏览器(Chrome 97+、Firefox 94+、Safari 16.4+)强制要求 showModal() 必须由用户激活事件(如 click、keydown)同步触发。页面加载完成时调用会直接抛错:Failed to execute 'showModal' on 'HTMLDialogElement': The element is not in a Document. —— 即使 DOM 已就绪,只要没用户点过任何东西,它就拒绝工作。iOS 15.x 及更早版本连 show() 都不支持模态行为,背景仍可点击滚动。
首屏广告 DOM 结构怎么写才不被拦截
核心是:用一个 position: fixed 全屏遮罩包裹所有广告内容,主页面区域初始设为 display: none,而不是靠 z-index 叠加隐藏。否则用户仍能滚动、点击底层按钮,广告形同虚设。
<div id="splash" style="position:fixed;top:0;left:0;width:100vw;height:100vh;background:#000;z-index:1000;>- 内部必须包含:
<img src=" ad.jpg>、<code><span id="countdown">5</span>、<button id="skip">跳过</button> - 主内容区包在
<main id="main-content" style="display:none"></main>里,不要用visibility: hidden或opacity: 0—— 它们不阻断交互 - 启动前先检查
document.getElementById('splash').offsetParent !== null,确保广告 DOM 已渲染完毕 - 图片加载慢?监听
document.getElementById('ad-img').onload = startCountdown,避免白屏计时 - 归零瞬间必须调用
clearInterval(timer),否则可能因异步执行导致多次切换main-content的display属性 - 用户点“跳过”时,要统一调用同一个关闭函数,避免和倒计时逻辑各自操作 DOM 导致状态错乱
- 禁用页面滚动不能只写
document.body.style.overflow = 'hidden',还要保存当前scrollY,关闭后执行window.scrollTo(0, savedY),否则用户回到顶部 - 居中别用
top: 50%; left: 50%; transform: translate(-50%, -50%)—— iOS Safari 在双指缩放后会严重偏移;改用inset: 0; margin: auto;(需检查兼容性)或 JS 动态计算top/left - 给广告容器加
touch-action: manipulation,否则 300ms 点击延迟会让“点一下关”变成“点两下才关”
倒计时逻辑怎么写才准、不丢秒、不重复触发
别用 setTimeout(() => { hideSplash() }, 5000)。它不显示数字,也不响应跳过,且 JS 执行延迟可能导致少计 1 秒。正确做法是用 setInterval 每秒更新,并以 Date.now() 为起点计算剩余时间。
立即学习“前端免费学习笔记(深入)”;
移动端适配最容易忽略的三个细节
iOS Safari 和 Android WebView 对固定定位、滚动锁定、点击响应有特殊行为,漏掉任意一个都会导致广告偏移、关不掉、或点两下才响应。
最复杂的不是代码怎么写,而是判断“用户到底有没有激活”。比如 SPA 页面路由切换后首次进入某页,这个“首次”是否算用户激活?答案是否定的——必须等用户真实点击过某个按钮,或者提交过表单,才能安全调用广告展示逻辑。这点常被忽略,结果上线后广告在 Chrome 上全灭,在 Safari 上半残。



















