针对新 HTML <permission> 元素的源试用

有多种命令式方法可用于请求在 Web 应用中使用位置信息访问权限等强大功能的权限。这些方法存在许多挑战,因此 Chrome 权限团队正在尝试一种新的声明式方法:专用的 HTML <permission> 元素。此元素自 Chrome 126 起处于源试用阶段,我们最终希望将其标准化。

请求权限的命令式方法

当 Web 应用需要访问强大的功能时,需要请求权限。例如,当 Google 地图需要使用地理定位 API 获取用户的位置信息时,浏览器会提示用户,通常还会提供存储该决定的选项。这是权限规范中明确定义的概念

首次使用时隐式询问与预先明确请求

Geolocation API 是一种强大的 API,它依赖于首次使用时隐式请求的方法。例如,当应用调用 navigator.geolocation.getCurrentPosition() 方法时,权限提示会在首次调用时自动弹出。再比如 navigator.mediaDevices.getUserMedia()

其他 API(例如 Notification APIDevice Orientation and Motion API)通常具有通过静态方法(例如 Notification.requestPermission()DeviceMotionEvent.requestPermission())显式请求权限的方式。

使用命令式方法请求权限时遇到的挑战

权限垃圾内容

过去,网站不仅可以在加载时立即调用 navigator.mediaDevices.getUserMedia()Notification.requestPermission() 等方法,还可以调用 navigator.geolocation.getCurrentPosition()。在用户与网站互动之前,系统会弹出权限提示。这种情况有时被称为权限垃圾信息,会影响这两种方法:在首次使用时隐式请求权限,以及预先明确请求权限。

加载网站时显示的麦克风权限提示。

浏览器缓解措施和用户手势要求

权限垃圾内容导致浏览器供应商要求用户在显示权限提示之前执行用户手势(例如点击按钮)或触发 keydown 事件。这种方法的缺点在于,浏览器很难(甚至不可能)确定给定的用户手势是否应导致显示权限提示。也许用户只是因为网页加载时间过长而随意点击网页上的任何位置,也许他们确实点击了定位我按钮。某些网站还非常擅长诱骗用户点击内容来触发提示。

另一种缓解措施是添加提示滥用缓解措施,例如完全屏蔽功能,或者以非模态、侵入性较低的方式显示权限提示。

Chrome 浏览器显示了

权限情境化

另一个挑战(尤其是在大屏设备上)是权限提示的常见显示方式:位于死亡线上方,也就是说,位于应用可以绘制的浏览器窗口区域之外。用户在点击浏览器窗口底部的按钮后,可能会错过浏览器窗口顶部的提示。如果浏览器中启用了垃圾内容缓解措施,此问题通常会更加严重。

Google 地图打开,并显示位置信息权限提示。触发提示的位置信息访问权限按钮距离较远。

无法轻松撤消

最后,用户很容易自行进入死胡同。例如,用户一旦阻止访问某项功能,就必须知道网站信息下拉菜单,以便在其中重置权限或重新启用被阻止的权限。在最糟糕的情况下,这两种选项都需要完全重新加载网页,直到更新后的设置生效为止。网站无法为用户提供简单的快捷方式来更改现有权限状态,必须费尽心思地向用户说明如何更改其设置,如下面的 Google 地图屏幕截图底部所示。

Google 地图中的 Chrome 网站控制功能,用于撤消权限。

如果权限对体验至关重要,例如视频会议应用的麦克风访问权限,那么 Google Meet 等应用会显示侵入式对话框,指导用户如何解除权限限制。

Google Meet 说明:如何打开 Chrome 网站控件。

声明式 <permission> 元素

为了应对本文中所述的挑战,Chrome 权限团队针对新的 HTML 元素 <permission> 发起了来源试用。借助此元素,开发者可以声明性地请求使用目前可供网站使用的一小部分强大功能。在最简单的形式中,您可以使用它,如以下示例所示:

<permission type="camera" />

<permission> 是否应为空元素,目前仍在热烈讨论中。空元素是 HTML 中无法包含任何子节点的自闭合元素,在 HTML 中,这意味着它可能没有结束标记。

type 属性

type 属性包含以空格分隔的您请求的权限列表。在撰写本文时,允许的值包括 'camera''microphone'camera microphone(以空格分隔)。默认情况下,此元素的渲染效果类似于具有基本用户代理样式的按钮。

各种权限元素按钮,分别具有摄像头、麦克风和摄像头加麦克风权限。

type-ext 属性

对于允许使用其他参数的某些权限,type-ext 属性接受以空格分隔的键值对,例如,对于地理定位权限,该属性接受 precise:true

lang 属性

按钮文字由浏览器提供,旨在保持一致,因此无法直接自定义。浏览器会根据文档或父元素链的继承语言或可选的 lang 属性来更改文本的语言。这意味着开发者无需自行本地化 <permission> 元素。如果 <permission> 元素超出初始源试用阶段,则每种权限类型可能支持多个字符串或图标,以提高灵活性。如果您有兴趣使用 <permission> 元素,并且需要特定的字符串或图标,请与我们联系

行为

当用户与 <permission> 元素互动时,可以循环浏览各个阶段:

  • 如果他们之前未允许某项功能,则可以选择每次访问时都允许,也可以选择仅在当前访问期间允许。

    权限提示,用于允许本次或每次访问时使用某项功能。

  • 如果用户之前允许使用该功能,则可以继续允许或停止允许。

    权限提示,用于继续允许或停止允许。

  • 如果之前不允许使用某项功能,他们可以继续不允许使用该功能,也可以允许使用该功能。

    权限提示,让用户选择继续不允许或允许本次。

<permission> 元素的文本会根据状态自动更新。例如,如果已授予使用某项功能的权限,相应文字会更改为表示允许使用该功能。如果需要先授予权限,则文字会发生变化,邀请用户使用该功能。将之前的屏幕截图与下面的屏幕截图进行比较,即可看到这两种状态。

带有文字的权限按钮

CSS 设计

为确保用户能够轻松识别出该按钮是用于访问强大功能的界面,系统对 <permission> 元素的样式进行了限制。如果样式限制不适合您的使用情形,我们很乐意了解具体情况和原因!虽然我们无法满足所有样式需求,但我们希望在源试用结束后,找到安全的方法来允许对 <permission> 元素进行更多样式设置。下表详细列出了一些受到限制或应用了特殊规则的属性。如果违反了任何规则,<permission> 元素将被停用,无法与之互动。任何与之互动的尝试都会导致可通过 JavaScript 捕获的异常。错误消息中将包含有关检测到的违规行为的更多详细信息。

属性 规则

colorbackground-color

可分别用于设置文字颜色和背景颜色。这两种颜色之间的对比度需要足够高,才能让文字清晰可辨(对比度至少为 3)。Alpha 渠道必须为 1。

font-sizezoom

必须设置在相当于 smallxxxlarge 的范围内。否则,该元素将被停用。计算 font-size 时会考虑缩放比例。

outline-offset

负值将更正为 0
margin(全部) 负值将更正为 0

font-weight

200 下的值将更正为 200

font-style

normalitalic 以外的值将被更正为 normal

word-spacing

超过 0.5em 的值将更正为 0.5em0 以下的值将更正为 0

display

inline-blocknone 以外的值将被更正为 inline-block

letter-spacing

超过 0.2em 的值将更正为 0.2em。低于 -0.05em 的值将更正为 -0.05em

min-height

默认值为 1em。如果提供,系统将考虑默认值和提供的值之间的最大计算值。

max-height

默认值为 3em。如果提供,则会考虑默认值和提供的值之间的最小计算值。

min-width

默认值为 fit-content。如果提供,系统将考虑默认值和提供的值之间的最大计算值。

max-width

默认值为 fit-content 的三倍。如果提供,则会考虑默认值和提供的值之间的最小计算值。

padding-top

仅当 height 设置为 auto 时才会生效。在这种情况下,大于 1em 的值将更正为 1em,而 padding-bottom 将设置为 padding-top 的值。

padding-left

仅当 width 设置为 auto 时才会生效。在这种情况下,超过 5em 的值将被更正为 5em,而 padding-right 将设置为 padding-left. 的值

transform

不允许使用扭曲视觉效果。目前,我们仅接受 2D 平移和按比例放大。

以下 CSS 属性可正常使用:

  • font-kerning
  • font-optical-sizing
  • font-stretch
  • font-synthesis-weight
  • font-synthesis-style
  • font-synthesis-small-caps
  • font-feature-settings
  • forced-color-adjust
  • text-rendering
  • align-self
  • anchor-name aspect-ratio
  • border(以及所有 border-* 媒体资源)
  • clear
  • color-scheme
  • contain
  • contain-intrinsic-width
  • contain-intrinsic-height
  • container-name
  • container-type
  • counter-*
  • flex-*
  • float
  • height
  • isolation
  • justify-self
  • left
  • order
  • orphans
  • outline-*outline-offset 的例外情况除外,如前所述)
  • overflow-anchor
  • overscroll-behavior-*
  • page
  • position
  • position-anchor
  • content-visibility
  • right
  • scroll-margin-*
  • scroll-padding-*
  • text-spacing-trim
  • top
  • visibility
  • x
  • y
  • ruby-position
  • user-select
  • width
  • will-change
  • z-index

此外,还可以使用所有逻辑上等效的属性(例如,inline-size 等效于 width),但需遵循与其等效属性相同的规则。

伪类

有两个特殊的伪类可用于根据状态设置 <permission> 元素的样式:

  • :granted:granted 伪类允许在授予权限时进行特殊样式设置。
  • :invalid:当元素处于无效状态时(例如,当元素在跨源 iframe 中提供时),:invalid 伪类允许进行特殊样式设置。
permission {
  background-color: green;
}

permission:granted {
  background-color: light-green;
}

/* Not supported during the origin trial. */
permission:invalid {
  background-color: gray;
}

JavaScript 事件

<permission> 元素应与 Permissions API 搭配使用。您可以监听多种事件:

  • onpromptdismiss:当用户关闭元素触发的权限提示时(例如,通过点击关闭按钮或点击提示外部),系统会触发此事件。

  • onpromptaction:当用户对元素触发的权限提示采取某种操作,从而解决该提示时,系统会触发此事件。这并不一定意味着权限状态已更改,用户可能采取了维持现状的操作(例如继续允许某项权限)。

  • onvalidationstatuschange:当元素从 "valid" 切换到 "invalid" 时,系统会触发此事件。如果浏览器信任信号的完整性(在用户点击信号的情况下),则该元素被视为 "valid";否则,该元素被视为 "invalid",例如当该元素部分被其他 HTML 内容遮挡时。

您可以直接在 HTML 代码 (<permission type="…" onpromptdismiss="alert('The prompt was dismissed');" />) 中内嵌注册这些事件的事件监听器,也可以在 <permission> 元素上使用 addEventListener(),如以下示例所示。

<permission type="camera" />
<script>
  const permission = document.querySelector('permission');
  permission.addEventListener('promptdismiss', showCameraWarning);

  function showCameraWarning() {
    // Show warning that the app isn't fully usable
    // unless the camera permission is granted.
  }

  const permissionStatus = await navigator.permissions.query({name: "camera"});
  
  permissionStatus.addEventListener('change', () => {
    // Run the check when the status changes.
    if (permissionStatus.state === "granted") {
      useCamera();
    }
  });

  // Run the initial check.
  if (permissionStatus.state === "granted") {
    useCamera();
  }
</script>

功能检测

如果浏览器不支持某个 HTML 元素,则不会显示该元素。这意味着,如果您的 HTML 代码中包含 <permission> 元素,但浏览器不知道该元素,则不会发生任何情况。您可能仍想使用 JavaScript 检测支持情况,例如,创建通过点击常规 <button> 触发的权限提示。

if ('HTMLPermissionElement' in window) {
  // The `<permission>` element is supported.
}

源试用

如需在您的网站上向真实用户试用 <permission> 元素,请注册源试用。 如需了解如何准备网站以使用源试用,请参阅源试用使用入门。源试用将从 Chrome 126 开始,到 Chrome 131 结束(2025 年 2 月 19 日)。

演示

浏览演示,并在 GitHub 上查看源代码。以下是在支持的浏览器中的体验的屏幕截图。

权限元素演示,显示了三个权限按钮。

反馈

我们非常希望了解 <permission> 在您的使用情形中发挥的作用。您可以随意回复代码库中的问题,也可以提交新问题。<permission> 元素的 repo 中的公开信号会让我们和其他浏览器知道您对此感兴趣。

常见问题解答

  • 与常规 <button> 搭配 Permissions API 相比,这种方式有何优势?点击 <button> 是一种用户手势,但浏览器无法验证该手势是否与请求权限相关联。如果用户点击了 <permission>,浏览器可以确定该点击与权限请求相关。这样一来,浏览器便能促成原本风险大得多的流程。例如,允许用户轻松撤消对权限的屏蔽。
  • 如果其他浏览器不支持 <permission> 元素,该怎么办?<permission> 元素可用作渐进式增强功能。在不支持的浏览器上,可以使用经典权限授予流程。例如,基于常规 <button> 的点击。权限团队也在开发填充区。为 GitHub 代码库加星标,以便在准备就绪时收到通知。
  • 是否与其他浏览器供应商讨论过此问题?在 2023 年 W3C TPAC 的分组会议上,人们积极讨论了 <permission> 元素。您可以阅读公开会议记录。 Chrome 团队还向这两家供应商索取了正式的标准立场,请参阅相关链接部分。<permission> 元素是与其他浏览器持续讨论的主题,我们希望对其进行标准化。
  • 这是否应为 void 元素?<permission> 是否应为空元素仍处于热烈讨论阶段。如果您有反馈,请在问题中发表意见。

致谢

本文档由以下人员审核:Balázs EngedyThomas NguyenPenelope McLachlanMarian HarbachDavid WarrenRachel Andrew