深度指南:把目标元素滚入视口并返回可见边界)
BrowserSkill 滚动定位原语scroll-to深度指南把目标元素滚入视口并返回可见边界【免费下载链接】BrowserSkillLet AI agents use your real, logged-in browser without interrupting your work. CLI extension for browser automation across any shell-capable AI agent.项目地址: https://gitcode.com/GitHub_Trending/br/BrowserSkillscroll-to是 BrowserSkill一个让任意支持 Shell 的 AI Agent 复用真实浏览器、通过bskCLI 与浏览器扩展自动化操作已登录浏览器的开源项目提供的元素级滚动原语它接收一个元素目标快照 ref 或 CSS 选择器把该元素及其所在的所有嵌套 frame 滚入视野然后返回其在顶层视口坐标系下可见部分的边界矩形。读完本文你将掌握bsk scroll-to的完整命令行用法、wire protocol 与 DeepSeek Harness 插件两种调用方式、结果矩形与错误码的精确语义以及从 Rust CLI 到 TypeScript 扩展处理器的底层实现原理。1. 为什么需要 scroll-to元素驱动而非像素驱动传统的滚动工具通常接受滚动 N 像素或向下滚动这类方向性指令Agent 需要自行估算滚动量并反复确认。scroll-to与之不同它接受元素目标而非像素距离或方向它把目标元素含其所在 iframe滚入视口让元素在视觉上可被看到它返回目标元素可见部分的边界矩形upper-left 坐标 宽高供后续截图、检查页面或进一步交互使用真正的原生方向性滚轮输入请使用 wheel 原语。适合在检查页面或截图前先把目标区域显示出来的场景先通过一次 observation 拿到元素 ref再scroll-to将其揭示最后截图或继续操作。入口名称CLIbsk scroll-toWire protocoltool.scroll_toDeepSeek Harnessbrowser_interactwithaction: scroll-to在 skill/SKILL.md 的能力清单中它被描述为 Reveal an elementbsk scroll-to e3 --session id并在同文件的行 103 注明关键语义scroll-toreturns ancestor-clipped bounds in top-level viewport CSS pixels——即返回的是经祖先容器裁剪后的、顶层视口 CSS 像素坐标下的边界。2. CLI 用法与参数详解2.1 基本命令使用你启动的会话session以及来自最近一次 observation 的新鲜 ref。下面命令中的 id 仅为示例请替换为实际调用返回的 session、tab 与 refbsk scroll-to e3 --session abcd --tab-id 42 --timeout 5s --json bsk scroll-to --selector #details --session abcd2.2 目标约束三者取一必须提供恰好一个目标位置参数 ref 或 selector、--ref、或--selector。三者冲突时命令会直接报错。ref接受e3与e3两种写法指向最近一次 observation 分配的快照引用selectorCSS 选择器只在主文档中搜索位于 iframe包括 out-of-process iframe / OOPIF或 shadow root 中的元素必须使用 ref因为选择器搜索范围仅限主文档ref 归属于某一个 session 和 tab页面变化后可能失效stale需要重新 observation。CLI 侧的解析逻辑位于 crates/bsk-cli/src/cli/scroll.rssplit_target负责把位置参数拆分为 ref 或 selector测试用例split_target_detects_refs_and_selectors验证了e3与#target两种形态的识别随后ScrollToArgs结构通过 clap 声明--ref、--selector、--session、--tab-id与--timeout参数。2.3 会话、标签与超时--session必填--tab-id可省略默认使用 Agent Window 的当前活动标签页--timeout默认30s必须为正数接受5000ms、5s等时长写法由parse_timeout_ms解析默认值30s直接写在 clap 的default_value中命令操作的是 Agent Window 内的标签页包括被显式借用到该窗口的用户标签页。2.4 JSON 输出示例{ tab_id: 42, used_ref: e3, x: 10, y: 20, width: 100, height: 80 }used_ref或used_selector标明实际解析用的目标二者只出现其一可选字段dialogs数组会报告调用期间处理过的 JavaScript 对话框alert/confirm/prompt/beforeunload四类包含handled: accepted | dismissed的处理方式扩展侧由attachDialogs附加到结果上非 JSON 的人类可读输出形如scroll-to ok tab42 targete3 bounds(10, 20, 100, 80)并打印对话框摘要。3. 结果契约边界矩形的精确语义返回的四个数值遵循以下精确约定x、y为可见部分的左上角width、height为可见 border-box 部分的边界矩形尺寸四个值均为顶层视口 CSS 像素坐标且已经过滚动、祖先容器裁剪与 frame 视口裁剪——它们不是文档坐标也不是截图像素坐标部分可见即视为成功例如一个 400px 高的元素被 80px 高的滚动容器裁掉只要露出 80pxheight: 80即可成功返回完全隐藏或完全被裁剪的目标会失败返回element_not_visible该矩形不是遮挡检测或命中测试其他元素可能盖住目标矩形中心不保证是可点击点布局在结果返回后仍可能变化后续交互应使用新鲜的 ref。这一语义在 crates/bsk-protocol/schema/tool_scroll_to_result.json 的x字段描述中被原样固化Bounding rectangle of the elements visible border-box portion, in top-level viewport CSS pixels, after ancestor and viewport clipping. Partial visibility is sufficient. This is not an occlusion or hit test.4. Wire Protocol 调用与参数校验CLI 通过 daemon 向扩展发送一次普通请求{ id: scroll-1, method: tool.scroll_to, params: { session_id: abcd, ref: e3, tab_id: 42, timeout_ms: 5000 } }协议调用方必须提供恰好一个非空的ref或selectortab_id可选缺省用 Agent Window 活动标签页timeout_ms为正整数默认 30000这些目标约束由扩展侧 handler 强制校验。参数类型定义在 crates/bsk-protocol/src/tools/scroll.rsScrollToParams中ref字段通过serde(rename ref)序列化为ref键单元测试params_serialise_ref_field_name验证了这一序列化行为timeout_ms为Optionu32且 schema 限定minimum: 1。生成的参数/结果 schema 见 tool_scroll_to_params.json 与 tool_scroll_to_result.json其中 params 仅session_id为必填。wire 响应把上述结果包装在{ id: scroll-1, result: ... }中。4.1 插件DeepSeek Harness调用插件以惯用的 camelCase 参数暴露同一动作{ action: scroll-to, session: abcd, target: e3, tabId: 42, timeoutMs: 5000 }通过browser_interact使用插件自有会话调用其返回结果包含session、tabId、x、y、width、height边界语义与 CLI 完全一致。省略session时使用插件当前会话。5. 错误码与中断语义wire 响应使用标准的error.code、error.message以及可选的error.data.reason字段。常见错误如下Codedata.reason含义invalid_params—目标缺失/冲突或 timeout/tab id 非法not_foundref_not_foundref 未知、已过期或属于其他标签页not_foundselector_not_found主文档中选择器未匹配到元素permission_deniedagent_window_scope目标标签页未被借用到 Agent Windowpermission_deniedelement_not_visible滚动后仍无任何可见区域cancelled—调用被取消timeout—动作截止时间到期cdp_failedvaries浏览器命令、frame 几何或可见性测量失败协议把 scroll-to 归类为浏览器变更browser mutation因此它复用现有的按会话排队per-session queue与用户中断门user-interruption gate机制扩展在派发前会释放任何保留的 hover 状态。取消与截止检查包裹着每一步 CDP 操作——包括 frame 查找、滚动与测量——一旦检测到即停止进一步滚动并拒绝成功响应但远程对象清理仍会执行。已完成的滚动不会回滚因此重试被中断的调用前应先检查当前页面状态。5.1 取消保护与对象清理源码级在扩展实现 apps/extension/src/tools/scroll.ts 的handleScrollTo中可以看到这套机制的落地每个调用分配独立的bsk-scroll-${crypto.randomUUID()}object groupDOM.resolveNode分配的对象在finally中通过Runtime.releaseObjectGroup统一释放且清理过程绕过取消守卫不会因中断而泄漏对象注释明确说明 Cleanup bypasses the cancellation guard and cannot replace the result每个 CDP 调用前后都会调用checkActive()在signal.aborted时抛AbortError、超过deadline时抛TimeoutErrorresolveTargetTab之后立即调用enforceAgentWindow实现agent_window_scope权限检查返回路径上attachDialogs追加调用期间处理的对话框信息。6. 实现原理frame 滚动复用 独立的可见性测量scroll-to的实现是作用域内复用的它复用了共享的 frame 滚动与坐标投影逻辑同时为可见性单独实现了一套考虑祖先裁剪与隐藏 frame 持有者的测量。共享的 click / hover / screenshot 几何逻辑保持不变。完整调用链为handleScrollTo ├─ lookupSession → resolveTargetTab → enforceAgentWindow ├─ resolveBackendNode解析 ref / selector 为后端节点跨 iframe / shadow root ├─ scrollElementAndFramesIntoView滚动元素及其 frame 祖先 ├─ scrollVisibleBoundsIntersectionObserver 测量可见矩形 投影/裁剪 └─ attachDialogs → 返回 { tab_id, used_ref/used_selector, x, y, width, height, dialogs }6.1 滚动阶段连带 frame 祖先一起滚动apps/extension/src/tools/frame-geometry.ts 中的scrollElementAndFramesIntoView负责把元素和它的所有容器 frame 滚入视野scrollFrameOwners沿 frame 祖先链从顶层向下逐个调用scrollNodeIntoView确保承载该元素的每一个 iframe 持有者先被滚动到可见若节点地址属于 OOPIF 却缺少frameId直接返回cdp_failedan OOPIF node address requires frameId杜绝跨 target 地址歧义目标节点的 target 必须与tabId一致否则拒绝。6.2 测量阶段渲染进程内裁剪而非把布局四边形当可见像素apps/extension/src/tools/scroll-visibility.ts 中的scrollVisibleBounds是 scroll-to 特有逻辑的核心渲染进程内可见性判断把一段VISIBLE_RECT函数注入元素所在文档先调用element.checkVisibility({ checkOpacity: true, checkVisibilityCSS: true, contentVisibilityAuto: true })含 shadow DOM 的 containing-block 裁剪再通过IntersectionObserverroot 为元素所属 document取entry.intersectionRect要求isIntersecting且宽高均 0。观测带超时钳制在 11000ms保证即使后台文档停止渲染observer 也总是 disconnect不会留下存活 observer投影到顶层视口projectRect通过GeometryContext把文档局部矩形沿 frame 投影链映射到顶层 tab 视口坐标若目标在同一 CDP target 的同源 iframe 内会先跨一次 owner 边界再走 target 级投影祖先裁剪对存在frameId的目标遍历 frame 祖先链对每一层 iframe 持有者再做一次visibleRect测量子文档可见但 iframe 可能被隐藏或裁剪然后用clipPolygon对目标区域做多边形逐层裁剪最后regionBounds汇总出最终边界。这一设计与resolveNodeGeometryclick/hover 共享复用同一套GeometryContext与clipPolygon几何工具但测量入口完全独立因此不会影响既有交互几何。7. 实战要点与限制小结目标选型同文档元素用 selector 最省事iframe / shadow root / OOPIF 内元素务必用 observation 分配的 refref 会随页面导航失效交互前重新 observation部分可见即成功不要假设返回矩形等于元素完整尺寸若需要完整元素先确保其未被小容器裁剪矩形不是命中点返回的x,y是可见区域左上角居中点不保证可点击遮挡由其他元素造成时需另行判断中断不可回滚cancelled/timeout后页面可能已滚动到新位置重试前先bsk observe确认当前状态超时与队列调用会排队执行per-session queuetimeout_ms必须为正整数CLI 侧 IPC 超时会在请求超时基础上额外放宽 15 秒见 crates/bsk-cli/src/cli/scroll.rs 的ipc_timeout给 daemon 转发留出余量。在 BrowserSkill 中滚动到元素是一项跨 CLI、协议与插件三层一致暴露的能力无论你通过bsk scroll-to、原始tool.scroll_to请求还是 DeepSeek Harness 的browser_interact插件动作调用最终都会汇入扩展侧同一条解析节点 → 滚动 frame 祖先 → 渲染进程裁剪测量 → 顶层视口投影的实现路径这也是它能在多 frame 页面中稳定返回真实可见边界的原因。【免费下载链接】BrowserSkillLet AI agents use your real, logged-in browser without interrupting your work. CLI extension for browser automation across any shell-capable AI agent.项目地址: https://gitcode.com/GitHub_Trending/br/BrowserSkill创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考