navigator.onLine 仅能判断在线/离线,无法识别弱网;需通过 fetch 探测(超时1500ms、响应>800ms且连续两次失败)动态触发降级提示,并用 aria-live 安全插入 DOM,禁用复杂动画,结合真机与中间件模拟验证。

怎么用 navigator.onLine 检测弱网并触发提示
navigator.onLine 只能区分“在线/离线”,不能识别“弱网”。它返回 true 时,可能是 2G、高延迟、丢包严重的网络——这时候用户实际体验已接近降级。直接靠它显示“简化模式已启用”会误判,比如 WiFi 信号格数少但带宽足够,或 5G 但服务器远导致 RTT 高。
真正可行的做法是:用 fetch 发起轻量探测(如 GET /ping?_t=xxx),结合超时 + 响应时间 + 状态码综合判断:
- 超时设为
1500ms(比常规 HTTP 超时更激进,贴近用户可感知卡顿) - 响应时间 >
800ms 且连续两次失败 → 触发降级提示 - 避免在页面加载初期就发请求,等 DOM ready 后再启动,否则干扰首屏
- 不要轮询,用节流控制探测频率(例如每 30 秒最多一次)
HTML 中如何安全插入“简化模式已启用”提示而不破坏 SSR 或 SEO
这个提示必须是 JS 动态插入的 DOM,不能写死在 HTML 源码里。否则服务端渲染(SSR)会把提示一起吐给爬虫和首屏,造成语义污染,也违背“按需降级”的逻辑。
正确做法是:只预留一个空容器,JS 根据网络状态决定是否往里面塞内容:
立即学习“前端免费学习笔记(深入)”;
<div id="network-status" aria-live="polite" aria-atomic="true"></div>
关键点:
- 用
aria-live="polite"让屏幕阅读器能读出变化,但不打断当前操作 - 插入时用
textContent而非innerHTML,防 XSS(提示文案固定,不拼接用户输入) - 不要用
display: none隐藏提示再 show,而是完全不创建节点,需要时才appendChild - 如果项目用了微前端或 Web Component,注意 shadow DOM 边界,
querySelector可能查不到
为什么 CSS 动画在弱网下容易卡顿甚至失效
不是网络慢导致动画卡,而是弱网常伴随低性能设备(低端安卓机、旧 iPad)或后台标签页被浏览器节流。此时 requestAnimationFrame 调度变慢,CSS 动画帧率掉到 10fps 以下,视觉上就像“卡住”或“跳变”。
降级提示本身不该依赖复杂动效:
- 禁用所有
transition和@keyframes,改用opacity: 1+transform: translateY(0)硬切 - 避免对
height做动画(触发布局重排),改用max-height+overflow: hidden - 用
will-change: opacity提前声明,但仅在提示出现瞬间加,不用就立刻移除 - 检查是否启用了
prefers-reduced-motion,若用户开启,直接跳过所有动效
本地开发时怎么模拟弱网验证提示逻辑
Chrome DevTools 的 Network 面板里选 “Slow 3G” 不够准:它只限速,不模拟高丢包、DNS 延迟、TCP 建连失败。真实弱网下,fetch 更可能卡在 pending 状态或直接抛 TypeError: Failed to fetch。
推荐组合手段:
- DevTools 中手动勾选 “Offline”,验证离线路径是否走通
- 用
chrome://dino页面观察浏览器原生离线行为,对比自己提示的时机和文案是否一致 - 本地起个 Express 中间件,在特定路由(如
/ping)里随机res.status(503).delay(2000)模拟抖动 - 真机测试别省:iOS 上
navigator.onLine在飞行模式关闭后仍有缓存,需杀进程重开
最麻烦的其实是“半连通”状态——DNS 可解析、TCP 能建连、但 TLS 握手卡住或首字节延迟极高。这种场景没法靠简单超时兜住,得靠 Service Worker 拦截请求并记录连接阶段耗时,普通项目往往没这层基建。











