应将弹窗逻辑置于 DOM 就绪后执行,推荐用 DOMContentLoaded 事件或脚本置于 前;HTML 需含 aria-hidden、role="dialog" 和 tabindex="-1" 保障可访问性;localStorage 需带版本号与时间戳防过期;关闭需支持点击、Esc 键、遮罩层点击,并同步清理焦点、滚动锁及状态。

用 window.onload 触发弹窗,但别在 head 里直接写 JS
页面还没加载完就执行弹窗逻辑,容易导致 document.getElementById 找不到元素、样式未生效或遮罩层错位。必须等 DOM 就绪后操作。
实操建议:
- 把 JS 代码放在
底部,紧挨着;或者 - 用
window.addEventListener('DOMContentLoaded', ...)替代window.onload(后者等资源如图片加载完才触发,延迟更明显); - 避免在
中使用内联<script></script>调用弹窗函数。
公告弹窗 HTML 结构要带 aria-hidden 和 tabindex
否则键盘用户无法聚焦关闭按钮,屏幕阅读器可能跳过弹窗内容,不符合基础可访问性要求。
最小可用结构示例:
立即学习“前端免费学习笔记(深入)”;
<div id="notice-modal" aria-hidden="true" class="modal">
<div class="modal-content" role="dialog" aria-labelledby="notice-title">
<h3 id="notice-title">网站公告</h3>
<p>即日起启用新版备案系统,请及时更新信息。</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill9263" title="Html2md"><img
src="https://img.php.cn/upload/skill/000/000/081/179249945220127.jpg" alt="Html2md" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill9263" title="Html2md">Html2md</a>
<p>使用 Readability + Turndown 将 HTML 页面转换为干净的、Agent 友好的 Markdown。去除导航栏、广告、页脚、Cookie 横幅、社交按钮等干扰元素。支持 URL...</p>
</div>
<a href="/xiazai/skill9263" title="Html2md" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div>
<button id="close-notice">我知道了</button>
</div>
</div>
关键点:
-
aria-hidden="true"初始隐藏,JS 显示时需同步设为false; -
role="dialog"告诉辅助技术这是模态框; -
tabindex="-1"加到.modal-content上,让focus()可控定位。
用 localStorage 控制“今日不再提示”,但别只依赖它
用户点了“我知道了”,下次打开页面就不该再弹。但 localStorage 是按域名隔离的,且不跨设备、不处理过期时间。
实操建议:
- 存键名用带版本号的命名,比如
notice_v2_shown,避免升级公告后旧逻辑误判; - 加时间戳判断是否过期:
localStorage.getItem('notice_v2_ts')与当前时间比对,超 24 小时就重置; - 服务端下发公告时带
expires_at字段,前端只做兜底,真正时效控制在后端; - 别用
cookie替代 —— 它会随每个请求发送,纯属浪费带宽。
关闭按钮必须同时处理 Escape 键和点击遮罩层
只绑点击事件,键盘用户按 Esc 关不掉,或点弹窗外区域没反应,会被当成 bug 报给前端。
必须覆盖的交互路径:
-
document.getElementById('close-notice').addEventListener('click', hideModal); -
document.addEventListener('keydown', e => e.key === 'Escape' && hideModal()); -
document.getElementById('notice-modal').addEventListener('click', e => e.target === e.currentTarget && hideModal()); - 关闭时记得恢复
body的overflow: auto(如果之前设了hidden防滚动穿透)。
localStorage 更新、滚动锁释放、辅助技术感知同步——漏一项,就有人卡在那儿出不来。

















