matchMedia 是浏览器原生 API,用于主动监听 CSS 媒体查询状态变化,适合深色模式适配、响应式逻辑切换等场景;需用 addEventListener 绑定 change 事件并及时清理,避免 SSR 报错和内存泄漏。

matchMedia 是什么,什么时候该用它
matchMedia 是浏览器原生 API,用于在 JavaScript 中主动监听 CSS 媒体查询状态(比如 (prefers-color-scheme: dark) 或 (max-width: 768px))。它不是一次性判断,而是支持持续监听变化——这点和 window.innerWidth 手动比对或 getComputedStyle 查伪元素完全不同。
适合场景包括:动态适配深色模式、响应式组件逻辑切换、根据视口宽度懒加载不同资源、第三方库需要实时感知断点等。别在页面初始化后只调用一次就完事,那等于浪费了它的核心能力。
如何创建并监听一个 matchMedia 查询
调用 matchMedia 传入媒体查询字符串,返回一个 MediaQueryList 对象。关键操作是绑定 change 事件,而不是轮询或反复调用 .matches。
- 必须用
addEventListener('change', handler),旧版的.addListener()已废弃(Chrome 99+ 不再支持) - 回调中直接读取
event.matches或mediaQueryList.matches,值为布尔型,无需解析字符串 - 记得在不需要时调用
removeEventListener,避免内存泄漏(尤其在 React 组件卸载、单页路由跳转时)
const media = window.matchMedia('(prefers-color-scheme: dark)');
const handleChange = (event) => {
if (event.matches) {
document.body.classList.add('dark');
} else {
document.body.classList.remove('dark');
}
};
media.addEventListener('change', handleChange);
// 卸载前清理
// media.removeEventListener('change', handleChange);
常见错误:为什么 .matches 总是 false 或不触发
典型问题不是 API 写错,而是媒体查询本身无效或上下文不对:
立即学习“Java免费学习笔记(深入)”;
-
matchMedia不支持 CSS 自定义属性(@media (width > var(--breakpoint))),只接受标准媒体特性语法 - 传入字符串必须是完整、合法的媒体查询,比如
'(min-width: 768px)'可以,但'min-width: 768px'(缺括号)会静默失败,返回matches: false - 在 SSR 环境(如 Next.js、Nuxt)中,服务端没有
window,直接调用会报ReferenceError: window is not defined,需加判断:if (typeof window !== 'undefined') { ... } - 某些低版本 Safari((orientation: portrait) and (max-width: 480px))支持不稳定,建议拆成单条件或降级处理
matchMedia 和 window.matchMedia 的兼容性与性能注意点
matchMedia 在所有现代浏览器中都可用(Chrome 9+、Firefox 6+、Safari 5.1+、Edge 12+),IE 完全不支持——如果还要兼容 IE,只能靠 resize 事件 + 手动比对 window.innerWidth,但无法监听系统级偏好(如深色模式)。
性能方面,它本身无渲染开销,但频繁触发 change 回调可能影响主线程。如果回调里有重排重绘操作(比如批量修改 DOM 样式),建议用 requestAnimationFrame 节流;另外,不要为同一查询反复新建 matchMedia 实例——浏览器内部已做缓存,复用同一个实例更稳妥。
最易被忽略的是:媒体查询状态可能在脚本执行前就已确定(比如用户打开页面时已是深色模式),所以首次判断不能只依赖 change 事件,得立刻检查 media.matches 并同步初始化状态。



















