window.matchmedia("(display-mode: standalone)") 是最标准可靠的 pwa 运行模式检测方式,基于 manifest.json 中 display: "standalone" 声明和浏览器实时渲染状态匹配,需在 dom 就绪后执行,不适用于服务端判断。

matchMedia("(display-mode: standalone)") 是什么
它是一个 CSS 媒体查询接口,用于在 JavaScript 中检测当前网页是否以 PWA 的 standalone 模式运行——也就是用户已“添加到主屏幕”并点击图标启动,此时浏览器 UI(地址栏、标签页等)被隐藏,应用像原生 App 一样独立运行。
这个值不是靠 UA 或历史行为推测的,而是由浏览器根据 manifest.json 中声明的 display 字段 + 实际安装/启动状态实时匹配出来的,所以它是目前最标准、最可靠的检测依据。
为什么 window.navigator.standalone 不够用
window.navigator.standalone 是 iOS Safari 早期私有属性,仅在旧版 Safari(iOS 11.3 之前)有效;iOS 11.3+ 已废弃,返回 undefined 或始终为 false;Chrome、Firefox、Edge 完全不支持。依赖它会导致安卓 PWA 和新版 iOS 全部误判。
常见错误现象:if (navigator.standalone) { ... } 在 iPhone 15(iOS 17.5)上永远进不去分支,哪怕应用已添加到主屏幕。
实操建议:
- 必须把
window.matchMedia("(display-mode: standalone)").matches作为主判断条件 - 可将
navigator.standalone作为兼容 iOS 老版本的兜底项,但不能单独使用 - 不要用
document.referrer.includes("android-app://")判断 TWA,它只适用于特定封装场景,且 referrer 可被清空或伪造
检测时机和 DOM 就绪问题
这个媒体查询状态在页面加载过程中就可读取,但必须确保 DOM 已就绪,否则可能拿到过早的 false(尤其在 SSR 或 hydration 过程中)。
错误写法:console.log(matchMedia("(display-mode: standalone)").matches) 放在 <script></script> 标签顶部,未等 HTML 解析完就执行。
正确做法:
- 监听
DOMContentLoaded事件后再检查 - 或轮询
document.readyState === "complete"确保资源加载完毕 - 避免在服务端渲染(SSR)阶段做判断——该状态纯客户端决定,服务端永远拿不到
示例:
document.addEventListener('DOMContentLoaded', () => {
const isStandalone = window.matchMedia('(display-mode: standalone)').matches;
if (isStandalone) {
console.log('PWA 已安装并以独立模式运行');
}
});
display-mode 还有哪些合法值?要不要监听变化
除了 standalone,display-mode 还支持 fullscreen、minimal-ui、browser。其中 fullscreen 在 iOS Safari 16.4+ 才完整支持,且需 manifest 中明确设为 "display": "fullscreen";minimal-ui 已被现代浏览器弃用。
是否需要监听变化?一般不需要。用户从浏览器标签页切换到 PWA 图标启动是离散操作,不会在运行中动态切换 display-mode。但如果你做了「强制跳转回浏览器」或「引导用户重新安装」的逻辑,可以监听:
const mql = window.matchMedia('(display-mode: standalone)');
mql.addEventListener('change', (e) => {
if (e.matches) {
// 刚进入 standalone 模式(比如用户点了桌面图标)
}
});
注意:不要在每次页面加载都重复 addListener,避免内存泄漏;若需多次使用,先 mql.removeEventListener 清理旧监听器。
manifest.json 是否真的生效。如果 display 字段拼错、start_url 路径不匹配 scope、或 service worker 注册失败,matchMedia 就永远返回 false——它不撒谎,只是你没让它有机会为真。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











