背景

window.matchMedia:在 JavaScript 里读写媒体查询

发表于 2026/05/07 09:32
🌺 摘要
用与 CSS 相同的媒体查询字符串在脚本中判断布局与系统偏好,并用 change 事件替代粗糙的 resize;附深色模式与减少动效示例及卸载监听要点。

window.matchMedia 是浏览器提供的标准 API,用来在脚本里判断当前环境是否满足某条 CSS 媒体查询,并在条件变化时收到通知。它和写在样式表里的 @media 使用同一套查询语法,因此可以把断点、深色模式、用户动效偏好等从「纯 CSS」延伸到组件逻辑或初始化策略中。


1. 基本用法

const mq = window.matchMedia("(min-width: 768px)");

// 当前是否匹配
console.log(mq.matches); // boolean

返回值是 MediaQueryList 实例,常用属性包括:

  • matches:此刻该查询是否为真。
  • media:规范化后的查询字符串(便于调试时打印)。

查询写法与 CSS 一致,例如:

  • (min-width: 768px)(max-width: 1023.98px)
  • (prefers-color-scheme: dark)
  • (prefers-reduced-motion: reduce)
  • printscreen and (orientation: landscape)

权威文档可参考 MDN:Window.matchMedia


2. 监听变化:比 window.resize 更贴切

若只为「是否超过某宽度」分支逻辑,用 resize 再手动算像素容易与 CSS 断点漂移,且触发频繁。matchMediachange 事件只在该条查询的真假翻转时触发,语义与性能都更合适。

推荐(现代浏览器):

const mq = window.matchMedia("(min-width: 768px)");

function onChange(e) {
  if (e.matches) {
    // 满足 min-width: 768px
  } else {
    // 不满足
  }
}

mq.addEventListener("change", onChange);
// 组件销毁或页面卸载时务必移除:
// mq.removeEventListener("change", onChange);

旧版 WebKit 等环境仍可能只实现 MediaQueryList.addListener(已标记为 legacy),可封装一层:优先 addEventListener("change"),不存在则回退 addListener


3. 典型场景

3.1 与 CSS 断点对齐的组件逻辑

例如仅在「桌面」宽度初始化复杂图表,窄屏降级为列表:

const desktop = window.matchMedia("(min-width: 1024px)");

function applyLayout() {
  if (desktop.matches) {
    // initChart();
  } else {
    // destroyChart?.();
  }
}

applyLayout();
desktop.addEventListener("change", applyLayout);

脚本里的 1024px 建议与样式里 @media (min-width: 1024px) 刻意共用同一常量或注释约定,避免两套断点慢慢不一致。

3.2 系统深色 / 浅色模式

const dark = window.matchMedia("(prefers-color-scheme: dark)");

function syncTheme(e) {
  document.documentElement.dataset.theme = e.matches ? "dark" : "light";
}

syncTheme(dark);
dark.addEventListener("change", syncTheme);

若站点同时提供「用户手动选主题」,通常要在业务层约定优先级(例如用户选择优先于系统),matchMedia 只反映系统偏好,不会替你合并策略。

3.3 尊重「减少动效」

const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)");

function shouldAnimate() {
  return !reduceMotion.matches;
}

可与 CSS 中的 prefers-reduced-motion 搭配:样式侧关掉过渡与动画,脚本侧关闭轮播、视差等。

3.4 打印、横竖屏等

window.matchMedia("print").matches;
window.matchMedia("(orientation: portrait)").matches;

4. 服务端渲染与首屏

SSR(如 Astro、Next 等)中,构建或请求阶段没有 window,需要:

  • 仅在浏览器环境调用(例如 typeof window !== "undefined"),或在框架的 onMount / useEffect 中调用;
  • 避免首屏 HTML 强依赖 matches 的同步结果而导致闪烁,可与 CSS 变量、<meta name="color-scheme"> 或内联关键样式配合。

5. 常见误区

  1. 用轮询代替监听:不需要;应使用 change(或 legacy 的 addListener)。
  2. resize 混用:同一套逻辑尽量单一数据源,宽度类需求优先媒体查询。
  3. 忘记注销监听:SPA 路由切换、组件卸载时移除监听,避免泄漏与重复绑定。
  4. 查询字符串写错:非法查询可能导致行为异常,开发时打印 mq.media 并用开发者工具设备模拟验证。

6. 小结

能力作用
matchMedia(query).matches同步读取当前是否满足查询
addEventListener("change", …)查询结果变化时回调(推荐)
@media 同语法断点、主题、无障碍偏好与样式层一致

matchMedia 用在「需要在 JS 里做决定」的场景(是否挂载重组件、是否启用动画、是否按打印样式采集 DOM 等),而把纯视觉仍交给 CSS,通常是最干净的分工方式。

文章发表于 2026/05/07 09:32
上一篇 window.dispatchEvent:在浏览器里派发与消费自定义事件
下一篇 用 ECharts GL 做「3D 环图」:参数曲面与引导线实战