EyeDropper API:用户激活与颜色隐私
使用 EyeDropper 时明确用户激活、可见取消、安全上下文与隐私友好的 sRGB 处理。
BotBrowser Team
EyeDropper API 允许用户在明确操作后从浏览器窗口选择颜色。这种交互不会给页面提供后台像素流、屏幕校准配置或识别屏幕的方法。应用在用户完成选择后获得 sRGB 十六进制值,并且必须让取消、拒绝和不可用保持可见。BotBrowser 受控上下文可以运行获授权页面,从声明的用户操作调用 EyeDropper,并在 runtime 暴露 API 时记录可见结果;BotBrowser 不能制造瞬时用户激活、在没有交互时读取像素、校准显示器,也不能保证不同宿主有相同的原生选择器行为。相邻边界可参考 CSS 颜色管理与显示无障碍以及指针事件与输入方式无障碍。
TL;DR
- 在瞬时激活仍有效时,从用户操作直接调用
EyeDropper.open()。 - 检查安全上下文和构造函数,API 缺失时保留普通颜色输入。
- 把
sRGBHex当作应用值,不要当作物理屏幕测量。 - 使用
AbortController表示取消,并区分关闭选择器与完成选择。 - 不要超出产品决策所需时间保存截图、坐标、窗口历史或颜色样本。
目录
用用户激活保护选择器
EyeDropper API 提案描述用户有意调用后的颜色选择器。MDN EyeDropper API 参考记录 EyeDropper 构造函数和 open()。API 需要安全上下文和瞬时用户激活。点击或键盘命令应拥有整个请求。
不要在操作与 open() 之间等待无关 Promise;请求、渲染轮次或排队 callback 都可能消耗激活。先检测构造函数与安全上下文;缺失只代表能力不可用,不是读取其他表面的许可。worker 不能继承页面激活,因此由页面打开选择器,再向 worker 发送颜色或取消结果。
Chrome EyeDropper 指南展示常见流程,但不承诺每个浏览器或 webview 都相同。用小记录表达边界:
const pickerState = {
phase: 'idle',
outcome: 'unavailable',
sequence: 0,
};
phase 表示生命周期,outcome 表示可见结果,sequence 防止旧 Promise 覆盖新调色板。控件必须有可访问名称、键盘操作、焦点保持和可见替代路径。
建模选择、取消与回退
选择颜色后 open() 返回 sRGBHex。关闭、Escape、离开页面或 abort 都是正常取消;区分 cancelled 与 rejected。回退可以是 <input type="color">、可编辑的十六进制字段或文档化调色板。
| 结果 | 记录 | 可见动作 | 安全下一步 |
|---|---|---|---|
| API 缺失或上下文不安全 | unavailable、fallback | 显示原生输入 | 使用回退值继续 |
| 用户操作打开选择器 | open、pending | 显示状态和取消 | 等待终态 |
| 选择颜色 | selected、sRGBHex | 更新色块和文本 | 验证并提交一次 |
| 用户关闭或中止 | cancelled、保留旧值 | 说明颜色未变化 | 回到 idle,不静默重试 |
| runtime 拒绝调用 | rejected | 说明当前不可用 | 保留回退,不收集像素 |
async function chooseColor(button, fallback, signal) {
if (!window.isSecureContext || !('EyeDropper' in window)) return fallback('unavailable');
const picker = new EyeDropper();
try {
const result = await picker.open({ signal });
return { outcome: 'selected', value: result.sRGBHex.toLowerCase() };
} catch (error) {
if (error?.name === 'AbortError') return fallback('cancelled');
return fallback('rejected');
}
}
从按钮激活处理器调用函数,不要从 timer、页面加载或旧 continuation 调用。等待时保留旧值,解析失败时显示本地错误,不自动重开选择器。
把采样颜色留在隐私边界内
颜色可能来自私人文档或未发布项目。只为实际功能保留它。API 不会提供截图;不要请求屏幕捕获,不要用 canvas 替代任意屏幕像素,也不要从颜色序列推断屏幕布局。
sRGB 值适合主题、标记或注释,但不是亮度或校准测量。色彩管理、显示器配置、HDR 和缩放都会改变观感。页面拥有激活,worker 在选择后才接收值,iframe 只接收经过 origin 与 schema 校验的必要数据。BotBrowser 可以比较获授权的可见结果,但不能制造激活或校准显示器。
BotBrowser 支持复现获授权的 EyeDropper 流程并记录可见的选择或取消,但不能制造瞬时用户激活,也不能保证每个宿主都有相同的原生选择器。
用有界 fixture 验证生命周期
使用含按钮、原生颜色控件、文本和结果记录的合成页面。只在事件中打开,离开路由时清理 controller,不保存截图或坐标。
const record = { phase: 'idle', outcome: 'unavailable', value: null, sequence: 0 };
const controller = new AbortController();
const button = document.querySelector('[data-pick-color]');
button.addEventListener('click', async () => {
record.sequence += 1;
record.phase = 'pending';
try {
if (!window.isSecureContext || !('EyeDropper' in window)) {
record.outcome = 'unavailable';
return showNativeColorControl();
}
const { sRGBHex } = await new EyeDropper().open({ signal: controller.signal });
record.value = sRGBHex.toLowerCase();
record.outcome = 'selected';
} catch (error) {
record.outcome = error?.name === 'AbortError' ? 'cancelled' : 'rejected';
} finally {
record.phase = 'idle';
}
});
function disposePicker() {
controller.abort();
button.replaceWith(button.cloneNode(true));
}
| Fixture 情况 | 预期结果 | 能证明什么 | 不能证明什么 |
|---|---|---|---|
| 缺少构造函数或安全上下文 | unavailable、显示回退 | 能力检测与任务连续性 | 屏幕存在缺陷 |
| 用户激活打开选择器 | pending 直到终态 | 操作拥有调用权 | timer 或 worker 能打开 |
| 用户选择颜色 | selected、六位 sRGBHex | 应用验证和一次提交 | 物理显示校准 |
| 关闭或 abort | cancelled、保留旧值 | 可逆取消 | 应静默重试 |
| runtime 拒绝 | rejected、回退可用 | 区分拒绝 | 文档边界之外的原因 |
只记录合成且有界的 browserVersion、runtimePath、secureContext、outcome、valuePresent、fixtureId 和 sequence。浏览器、屏幕、策略或回退变化后重放,并比较第一个不同字段。
Public sources
- EyeDropper API proposal (WICG)
- MDN: EyeDropper API
- Chrome for Developers: EyeDropper API
- BotBrowser: Advanced features
实践结论
只从可见用户操作打开 EyeDropper,保留原生或文字回退,并区分选择、取消、拒绝和不可用。只为产品决策保留 sRGBHex,不把它当作屏幕或身份证据。变化后重放 fixture,从第一个可见变化状态开始排查。
本文属于指南: Web 平台能力面:一致性复核地图