有许多命令式方法可用于请求在 Web 应用中使用位置信息访问权限等强大功能的权限。这些方法存在诸多挑战,因此 Chrome 权限团队正在尝试一种新的声明式方法:专用 HTML <permission>
元素。此元素从 Chrome 126 开始处于源试用阶段,我们最终希望将其标准化。
请求权限的命令式方法
当 Web 应用需要访问强大的功能时,需要请求权限。例如,当 Google 地图使用 Geolocation API 请求用户的位置信息时,浏览器会向用户发出提示,通常会提供存储该决定的选项。这是权限规范中定义明确的概念。
在首次使用时隐式询问,而不是预先明确请求
Geolocation API 是一款强大的 API,采用“首次使用时隐式询问”方法。例如,当应用调用 navigator.geolocation.getCurrentPosition()
方法时,权限提示会在首次调用时自动弹出。再比如 navigator.mediaDevices.getUserMedia()
。
其他 API(如 Notification API 或 Device Orientation and Motion API)通常具有通过 Notification.requestPermission()
或 DeviceMotionEvent.requestPermission()
等静态方法明确请求权限的方式。
使用命令式方法请求权限时遇到的问题
权限垃圾内容
过去,网站可以调用 navigator.mediaDevices.getUserMedia()
或 Notification.requestPermission()
等方法,但在加载网站时也可以立即调用 navigator.geolocation.getCurrentPosition()
。在用户与网站互动之前,系统会弹出权限提示。这有时被称为“权限垃圾流量”,会影响两种方式,即在首次使用时隐式请求以及预先明确请求。
浏览器缓解措施和用户手势要求
垃圾权限导致浏览器供应商要求用户手势(例如按钮点击或 keydown 事件)才会显示权限提示。这种方法存在的问题是,浏览器很难(如果不是不可能)确定给定的用户手势是否应导致显示权限提示。也许用户只是因为网页加载时间太长而感到沮丧,随便点击了网页上的某个位置;也许他们确实点击了定位我按钮。一些网站还非常擅长诱骗用户点击内容以触发提示。
另一种缓解措施是添加提示滥用缓解措施,例如一开始就完全屏蔽功能,或者以非模态且不太侵扰的方式显示权限提示。
权限情境化
另一个挑战(尤其是在大屏设备上)是权限提示的常见显示方式:位于死亡线上方,即位于应用可以绘制到浏览器窗口的区域之外。用户只点击浏览器窗口底部的按钮,而错过浏览器窗口顶部的提示,这种情况并不少见。在浏览器实施垃圾内容防范措施后,此问题通常会加剧。
无法轻松撤消
最后,用户很容易迷失在导航界面中。例如,如果用户屏蔽了某项功能的访问权限,则需要他们知道网站信息下拉菜单,在其中重置权限或重新开启已屏蔽的权限。在最糟糕的情况下,这两种方法都需要完全重新加载网页,更新后的设置才能生效。网站无法为用户提供更改现有权限状态的简便快捷方式,而必须费心向用户说明如何更改其设置,如下方 Google 地图屏幕截图底部所示。
如果权限对体验至关重要(例如,视频会议应用的麦克风访问权限),Google Meet 等应用会显示侵扰性对话框,指引用户如何取消屏蔽权限。
声明式 <permission>
元素
为了解决本文中所述的问题,Chrome 权限团队已针对新的 HTML 元素 <permission>
启动了源代码试用。借助此元素,开发者可以声明式地请求使用网站提供的强大功能(目前仅限部分功能)。在最简单的形式下,您可以按以下示例使用它:
<permission type="camera" />
对于 <permission>
是否应为 void 元素,目前仍处于积极讨论。空元素是 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 捕获。错误消息将包含有关检测到的违规行为的更多详细信息。
属性 | 规则 |
---|---|
|
分别用于设置文本和背景颜色。两种颜色之间的对比度需要足够,以便文本清晰可辨(对比度至少为 3)。Alpha 渠道必须为 1。 |
|
必须设置为 small 和 xxxlarge 的等效值。否则,该元素将被停用。计算 font-size 时,系统会考虑缩放。 |
|
负值将更正为 0 。 |
margin (所有) |
负值将更正为 0 。 |
|
“200 ”下的值将更正为“200 ”。 |
|
normal 和 italic 以外的值将更正为 normal 。 |
|
超过 0.5em 的值将更正为 0.5em 。0 下的值将更正为 0 。 |
|
inline-block 和 none 以外的值将更正为 inline-block 。 |
|
超过 0.2em 的值将更正为 0.2em 。-0.05em 下的值将更正为 -0.05em 。 |
|
默认值为 1em 。如果提供,系统会考虑默认值和所提供值之间的最大计算值。 |
|
默认值为 3em 。如果提供,系统会考虑默认值和所提供值之间的最小计算值。 |
|
默认值为 fit-content 。如果提供,将考虑默认值和所提供的值之间的最大计算值。 |
|
默认值为 fit-content 的三倍。如果提供,系统会考虑默认值和所提供值之间计算的最小值。 |
|
仅当 height 设置为 auto 时才会生效。在这种情况下,大于 1em 的值将更正为 1em ,并且 padding-bottom 将设置为 padding-top 的值。 |
|
只有在 width 设置为 auto 时才会生效。在这种情况下,大于 5em 的值将更正为 5em ,并且 padding-right 将设置为 padding-left. 的值 |
|
不允许使用扭曲视觉效果。目前,我们仅接受 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
::invalid
伪类允许在元素处于无效状态(例如,在跨源 iframe 中传送)时设置特殊样式。
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"
;否则(例如,当该元素被其他 HTML 内容部分遮挡时),则被视为"invalid"
。
您可以直接在 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>
元素的公开信号。
常见问题解答
- 这与与 Permissions API 搭配使用的常规
<button>
相比有何优势?点击<button>
是一种用户手势,但浏览器无法验证它是否与请求权限相关联。如果用户点击了<permission>
,浏览器可以确定该点击与权限请求相关。这样一来,浏览器便能简化原本风险更高的流程。例如,允许用户轻松撤消对某项权限的屏蔽。 - 如果其他浏览器不支持
<permission>
元素,该怎么办?<permission>
元素可用作渐进增强功能。在不受支持的浏览器中,可以使用传统权限流程。例如,基于常规<button>
的点击。权限团队也在开发 polyfill。为 GitHub 代码库加注星标,以便在其就绪时收到通知。 - 是否与其他浏览器供应商讨论过此问题?2023 年,W3C TPAC 在一个分组讨论会中积极讨论了
<permission>
元素。您可以阅读公开会话记录。Chrome 团队还要求这两家供应商提供正式的标准立场,请参阅相关链接部分。<permission>
元素是我们与其他浏览器持续讨论的话题,我们希望对其进行标准化。 - 这实际上应该是一个空元素吗?对于
<permission>
是否应为 void 元素,我们仍然有争议。如果您有反馈意见,请就相应问题进行说明。
相关链接
致谢
本文档由 Balázs Engedy、Thomas Nguyen、Penelope McLachlan、Marian Harbach、David Warren 和 Rachel Andrew 审核。