<picture>标签无法根据环境光传感器切换图片,因其media属性仅支持CSS媒体查询,不支持light-level等非标准特性;必须用JavaScript读取LightSensor API等硬件数据并动态替换src。

<picture> 标签本身不感知环境光,它只是静态的响应式图片容器。想根据环境光传感器切换图片,必须靠 JavaScript 主动读取传感器数据,再动态替换 <source> 或 <img> 的 src 属性。
为什么不能只靠 <picture> 的 media 属性
media 属性只支持 CSS 媒体查询(如 (prefers-color-scheme: dark) 或 (max-width: 768px)),它无法监听硬件传感器实时值。Windows 8/10/11 的 LightSensor API、Android 的 SensorManager、或 Web Platform 的 GenericSensor(如 Accelerometer)都不被 <picture> 原生支持。
常见错误是写成这样,结果完全不生效:
<picture> <source media="(light-level: dim)" srcset="dark-bg.jpg"> <source media="(light-level: bright)" srcset="light-bg.jpg"> <img src="fallback.jpg" alt="bg"> </picture>
——因为 light-level 不是标准媒体特性,浏览器会直接忽略该 <source>。
立即学习“前端免费学习笔记(深入)”;
用 LightSensor API 动态切换图片(Windows / Chromium Edge)
目前唯一较成熟的 Web 环境光传感器 API 是 Chromium 系(Edge 105+、Chrome 114+)支持的 LightSensor,需用户授权且设备有硬件支持。
- 先检查兼容性:
if ('LightSensor' in window) - 创建传感器实例时传入采样间隔(单位 ms),太短易耗电,太长响应迟钝,建议
1000(1秒) - 在
reading事件中读取sensor.illuminance(单位:lux),典型阈值参考:
•< 10 lux:黑暗(如室内关灯)
•10–100 lux:弱光(台灯下)
•> 100 lux:明亮(窗边自然光) - 避免频繁 DOM 操作:用
img.src = newSrc替代重写整个<picture>结构,防止重排重绘
简短示例:
if ('LightSensor' in window) {
const sensor = new LightSensor({ frequency: 1000 });
const img = document.querySelector('main img');
sensor.addEventListener('reading', () => {
const lux = sensor.illuminance;
if (lux < 20) img.src = 'night-mode.jpg';
else if (lux > 80) img.src = 'day-mode.jpg';
else img.src = 'auto-mode.jpg';
});
sensor.start();
}
降级方案:用系统配色偏好 + 手动 fallback
当 LightSensor 不可用时,不要留白。可组合以下信号做合理推测:
-
matchMedia('(prefers-color-scheme: dark)').matches—— 用户系统设为深色模式,大概率处于低光环境 -
navigator.onLine && screen.availWidth < 768—— 移动设备离线小屏,可能在被窝/包里,光线受限 - 加一个手动开关按钮(
<button id="toggle-light-mode">),让用户强制覆盖自动判断
关键点:所有传感器读数都只是线索,不是事实。比如 illuminance = 5 lux 可能是深夜,也可能是手机被盖住了。永远提供手动干预入口,且默认图应是中性光照下的版本。
真正难的不是换图,而是判断“当前光是否稳定”。传感器原始值抖动大,需要简单滤波(如滑动平均 3–5 帧),否则图片会来回闪。这点在 ESP32 或 STM32 工程里常做,但在前端容易被忽略。



















