如何通过JavaScript获取prefers-contrast等matchMedia查询的当前值?
嗨,这个问题问得太到位了!确实,挨个枚举prefers-contrast的所有已知值不仅显得笨拙,而且完全没法应对未来标准的更新——就像你说的,custom就是后来才加入的取值,谁知道以后还会冒出什么新选项呢?而且这个需求其实适用于一大类媒体查询,比如prefers-color-scheme、prefers-reduced-motion这些,确实需要一个更通用、更靠谱的方案。
咱先直接说现状:遗憾的是,目前JavaScript里还没有一个原生API能直接返回任意媒体查询的当前值——比如没法直接调用window.getMediaQueryValue('prefers-contrast')就拿到结果。不过咱可以用两个聪明的办法来实现,其中一个还能完美兼顾未来兼容的需求。
方法一:CSS变量+JavaScript读取(最推荐,未来兼容拉满)
这个思路的核心是让CSS帮我们做媒体查询的匹配,然后用JS读取对应的结果。不管未来标准给媒体查询加了什么新取值,只要CSS支持,我们就能轻松拿到结果,完全不用改JS代码。
步骤1:在CSS中定义对应变量
我们可以在页面的根元素:root上,为每个关心的媒体查询设置默认变量,然后通过@media规则在对应的条件生效时更新变量值:
:root { /* 定义默认值 */ --prefers-contrast: no-preference; --prefers-color-scheme: light; --prefers-reduced-motion: no-preference; --orientation: portrait; } /* 为prefers-contrast的所有可能条件更新变量 */ @media (prefers-contrast: more) { :root { --prefers-contrast: more; } } @media (prefers-contrast: less) { :root { --prefers-contrast: less; } } @media (prefers-contrast: custom) { :root { --prefers-contrast: custom; } } /* 为prefers-color-scheme更新变量 */ @media (prefers-color-scheme: dark) { :root { --prefers-color-scheme: dark; } } /* 为prefers-reduced-motion更新变量 */ @media (prefers-reduced-motion: reduce) { :root { --prefers-reduced-motion: reduce; } } /* 为orientation更新变量 */ @media (orientation: landscape) { :root { --orientation: landscape; } }
步骤2:用JS读取变量值
写一个简单的工具函数,就能轻松拿到任意媒体查询的当前值:
function getMediaQueryValue(varName) { // 读取根元素的计算样式,拿到对应变量值并去除空格 return getComputedStyle(document.documentElement).getPropertyValue(varName).trim(); } // 调用示例 const currentContrast = getMediaQueryValue('--prefers-contrast'); const currentColorScheme = getMediaQueryValue('--prefers-color-scheme'); const currentOrientation = getMediaQueryValue('--orientation'); console.log('当前对比度偏好:', currentContrast);
这个方法的优势
- 未来兼容:如果以后
prefers-contrast新增了比如high-contrast这样的取值,你只需要在CSS里加一段对应的@media规则更新变量,JS代码完全不用改。 - 性能优秀:只需要读取一次计算样式,不用反复调用
matchMedia做暴力匹配。 - 通用性强:适用于所有“单一条件生效”的媒体查询,包括你提到的
hover、prefers-reduced-data等场景。
方法二:优化版纯JS检测(适合不想改CSS的场景)
如果不想依赖CSS,我们可以写一个纯JS的工具函数,但这个方法的局限性是没法自动识别未来新增的媒体查询取值,只能处理已知的旧值。不过比起挨个硬编码所有可能值,这个写法更优雅:
function getPrefersValue(mediaType, defaultValue = 'no-preference') { // 先检查默认值是否匹配 if (window.matchMedia(`(${mediaType}: ${defaultValue})`).matches) { return defaultValue; } // 定义已知的非默认取值,可根据需求扩展 const knownValues = { 'prefers-contrast': ['more', 'less', 'custom'], 'prefers-color-scheme': ['dark'], 'prefers-reduced-motion': ['reduce'], 'orientation': ['landscape'] }; // 检查已知的非默认取值 if (knownValues[mediaType]) { for (const value of knownValues[mediaType]) { if (window.matchMedia(`(${mediaType}: ${value})`).matches) { return value; } } } // 如果都没匹配到,说明是未知的新取值,返回null return null; } // 调用示例 const currentContrast = getPrefersValue('prefers-contrast'); console.log('当前对比度偏好:', currentContrast);
额外技巧:监听媒体查询变化
不管用哪种方法,如果你需要在用户的偏好设置变化时(比如系统切换了深色模式)实时更新结果,都可以监听MediaQueryList的change事件:
// 以prefers-contrast为例 const contrastQuery = window.matchMedia('(prefers-contrast)'); // 定义变化后的处理逻辑 function handleContrastChange() { const newContrast = getMediaQueryValue('--prefers-contrast'); console.log('对比度偏好已变更为:', newContrast); } // 初始调用一次 handleContrastChange(); // 监听变化 contrastQuery.addEventListener('change', handleContrastChange);
内容来源于stack exchange

