你以为摄像头权限只能靠一堆JS回调?今天一行HTML把这件事彻底原生化了

写过前端的人都踩过这个坑——每次要用摄像头或麦克风,navigator.mediaDevices.getUserMedia() 要写一套权限判断、错误处理、stream 赋值的样板。更难受的是:JavaScript 触发的权限请求特别容易被用户拒绝,Cisco 的数据说原来只有 10% 的「拒绝后重试」用户最终给了权限。

Chrome 153 今天把这个彻底原生化了——<camera><microphone> 两个声明式 HTML 元素,分别只请求视频和音频单一能力。

从 usermedia 到单一能力的梯度

Chrome 151 引入了 <usermedia>(同时请求视频+音频),Chrome 153 则补全了单一能力的梯度:

  • <usermedia> → 视频 + 音频同时请求(Chrome 151)
  • <camera> → 仅视频捕获(Chrome 153)
  • <microphone> → 仅音频捕获(Chrome 153)

三个元素共享同一套安全模型,用法几乎一样,只是按需选择粒度更细的那个。

工作原理:浏览器接管权限 UI

<camera id="my-cam"></camera>
<video id="preview" autoplay></video>

<script>
  const cam = document.getElementById(my-cam);

  // 可选:设置约束
  cam.setConstraints({ video: { width: 1280, height: 720 } });

  // 成功:拿到 MediaStreamTrack
  cam.ontrack = (e) => {
    document.getElementById(preview).srcObject = e.track;
  };

  // 失败
  cam.onerror = (e) => {
    console.error(摄像头错误:, cam.error);
  };

  // 用户取消
  cam.oncancel = () => {
    console.log(用户拒绝了权限请求);
  };
</script>

对比传统 getUserMedia() 的样板:

// 传统方式:各种错误类型要分别处理,样板代码多
navigator.mediaDevices.getUserMedia({ video: true })
  .then(stream => {
    const videoTrack = stream.getVideoTracks()[0];
    document.getElementById(preview).srcObject = stream;
  })
  .catch(err => {
    if (err.name === NotAllowedError) { /* ... */ }
    if (err.name === NotFoundError) { /* ... */ }
    if (err.name === OverconstrainedError) { /* ... */ }
  });

<camera> 的核心区别在于:浏览器自己渲染控件、自己强制执行样式规则(不能伪装、不能隐藏),而且必须用户真实点击控件,权限请求才会发出。

数据说明一切

这不是炫技,是真的管用:

  • Cisco:原来拒绝过的用户给权限率从 10% 提升到 65%
  • Google Meet:权限恢复成功率提升 131%
  • Zoom:摄像头/麦克风捕获错误下降 46.9%,「麦克风不工作」投诉下降 17%

本质原因是:浏览器原生渲染的按钮是用户熟悉的 UI,真实点击是可信的操作信号,权限提示的通过率自然就上去了。

W3C 规范定义

<camera><microphone> 属于 W3C Media Capture Extensions 规范,接口如下:

interface HTMLCameraElement : HTMLElement {
  readonly attribute MediaStreamTrack? track;  // 直接拿到 track
  readonly attribute DOMException? error;
  undefined setConstraints(optional MediaTrackConstraintSet constraints = {});
  attribute EventHandler ontrack;
  attribute EventHandler onerror;
  attribute EventHandler oncancel;
}

getUserMedia() 一样,必须在 HTTPS 环境(或者 localhost)下才能工作。

什么时候用、什么时候不用

适合用 <camera> / <microphone>

  • 用户主动点击「打开摄像头」「开启麦克风」按钮的场景
  • 视频会议、在线教育、直播等标准媒体交互
  • 想提升权限获取成功率

仍需要 getUserMedia()

  • 需要同时请求视频+音频(用 <usermedia> 也可以)
  • 复杂设备选择(前/后摄像头、多个麦克风)
  • 需要动态切换媒体约束

下一步

如果你的项目现在还在用 getUserMedia() 做摄像头/麦克风权限,可以:

  1. 先检查目标用户是否在 Chrome 153+(caniuse.com 查 <camera> 支持)
  2. 不支持的浏览器写 <camera> + fallback content 渐进增强
  3. 把「打开摄像头」按钮从 JS 触发改成声明式 HTML 标签

下一个值得关注的 capability element 是 <speaker>——覆盖音频输出控制,Web Audio API 一直没解决的声明式方案。

评论区

0 条评论

登录后可评论。

阿柯·前端架构 85 阅读