唯一可靠方式是@supports (color: color(display-p3 0 0 0)),因@media (color-gamut: p3)仅检测硬件能力,不验证浏览器是否支持color(display-p3)语法解析,Safari 16.3及更早、Chrome ≤116等版本会匹配媒体查询却忽略该函数。

@supports (color: color(display-p3 0 0 0)) 检测,这是目前唯一可靠的方式。仅靠 @media (color-gamut: p3) 或 window.matchMedia("(color-gamut: p3)").matches 不足以确认浏览器能真正渲染 P3 颜色。
为什么不能只用 @media (color-gamut: p3)
这个媒体查询只反映设备硬件是否上报支持 P3 色域,不保证浏览器实现了 color(display-p3) 解析能力:
• Safari 16.3 及更早版本匹配 @media (color-gamut: p3),但完全忽略 color(display-p3) 声明
• 某些 Android 设备(如 Pixel 8)系统报告 color-gamut: p3,但 Chrome 根本不解析该函数,静默降级为 transparent
• macOS 上部分旧版 Safari 会匹配媒体查询,却因缺少 @supports 包裹而跳过整条 CSS 规则
@supports (color: color(display-p3 0 0 0)) 才是真检测
它测试的是 CSS 引擎能否识别并接受该语法,而非设备能力:
• Safari 16.4+、Chrome 117+(macOS)、Edge 116+(macOS)返回 true
• Safari ≤16.3、Chrome ≤116、Firefox 全版本、所有安卓 WebView 返回 false
• 必须写成 @supports (color: color(display-p3 0 0 0)),漏掉 color: 前缀(如 @supports (color(display-p3 0 0 0)))会被视为无效语法,整个块被忽略
• 参数必须是三元组小数,@supports (color: color(display-p3 #FF0000)) 或 @supports (color: color(display-p3 255 0 0)) 都不合法,直接失败
搭配 window.matchMedia 用于运行时逻辑
当需要 JS 动态响应时,不能只依赖 matchMedia 结果:
• 先检查 @supports 是否成立(通过 CSS.supports("color", "color(display-p3 0 0 0)"))
• 再调用 window.matchMedia("(color-gamut: p3)").matches 确认设备能力
• 两者同时为 true,才可安全注入 P3 颜色或切换资源
• 注意:iOS Safari 在页面加载后首次调用 matchMedia 可能返回 false,需在 DOMContentLoaded 后延迟 10ms 再查
最容易被忽略的兼容性陷阱
即使 @supports 和 matchMedia 都通过,仍可能渲染失败:
• HTML 缺少 <meta name="color-scheme" content="light dark"> —— 某些 iOS Safari 版本拒绝启用 P3 渲染上下文
• 父元素存在 opacity、filter 或 transform —— 整个层叠上下文强制回退到 sRGB
• 使用了 background-color —— 该属性在多数环境下最易降级,建议改用 background-image: linear-gradient(...)
• 颜色值不是真实 P3 坐标 —— 从设计稿直接抄 #FF6B6B 并填进 color(display-p3) 会导致严重偏色,必须用 Photoshop Display P3 校样模式取值


















