鼠标位置检测器:实时 X/Y 坐标追踪
这个检测器做了一件多数坐标工具不做的事:同时显示四套坐标系 -- screen、client、page、offset -- 让你实时看到它们之间的差异。把鼠标移到下方网格区域内,点击可以记录坐标点。如果你一直搞不明白 e.clientX 和 e.screenX 为什么返回不同的数字,答案就在眼前。
为什么有四套坐标系
如果你在做任何 Web 交互 -- 拖拽、Canvas 绘画、游戏 -- 你会遇到至少四对不同的鼠标坐标。它们不是多余的,每一对回答的是不同的问题。
| 属性 | 测量起点 | 滚动时变化? | 窗口移动时变化? |
|---|---|---|---|
screenX / screenY | 物理显示器左上角 | 否 | 是(窗口移动时) |
clientX / clientY | 浏览器视口左上角 | 否 | 否 |
pageX / pageY | 整个文档左上角 | 是 | 否 |
offsetX / offsetY | 光标下方元素左上角 | 视情况 | 否 |
大部分在线工具只显示 screenX/screenY 或 clientX/clientY 中的一个。快速读数够用,但调试布局问题或写拖拽代码时隐藏了真正需要的信息。本检测器同时显示四套坐标,让你实时看到差异。
试一试:把页面滚到顶部,记下 page 和 client 的值。然后向下滚动半页。client 值不变,page 值增加了滚动的距离。这个差值就是滚动偏移量。
Screen 与 Client 的核心区别
关于鼠标坐标最常见的问题是:"为什么 screenX 和 clientX 对同一个鼠标位置给出不同的数字?" 看一眼就明白了,但几乎每个人第一次都会被绊住。
screenX 从物理显示器的左上角算起。如果你的浏览器窗口不在屏幕左上角 -- 比如离左边缘 200 像素 -- 那么 screenX 总是比 clientX 大约高 200。移动浏览器窗口,即使鼠标相对于页面没动,screenX 也会变。
clientX 从浏览器视口的左上角算起 -- 即网页显示区域。不管浏览器窗口在显示器哪个位置都无关。浏览器的标签栏、地址栏、书签栏不计入视口。
注意:screenX 和 clientX 的差异不只是浏览器窗口位置。在 Windows 上 DPI 缩放高于 100% 时,还可能有缩放因子不匹配。150% 缩放意味着 screenX 可能是 clientX 的 1.5 倍。详见我们的 DPI 缩放指南。
Page 坐标与页面滚动
当页面滚到顶部时,pageX/pageY 和 clientX/clientY 是完全一样的。一旦向下滚动,它们就分开了:pageY 增加你滚动的像素数,clientY 不变。
这只在一个场景下重要:存储鼠标位置以便稍后回放。如果你用 clientX/clientY 记录了点击位置,用户在回放前滚动了页面,位置就错了。你需要 pageX/pageY,因为它们考虑了滚动偏移,不管视口在哪里都指向文档中的同一个点。
Offset 坐标与元素交互
offsetX/offsetY 比较特殊。它们从鼠标正下方那个元素的左上角算起,不是从页面或视口算。如果你的鼠标在一个距页面左边缘 300 像素的按钮上,光标在按钮内移动了 10 像素,offsetX 就是 10 而不是 310。
这对容器内拖拽、Canvas 绘画以及任何关心相对于特定元素的位置的交互非常有用。但它有个怪癖:当鼠标移到子元素上时,offsetX/offsetY 会跳变,因为"偏移父元素"变了。
修复方法:用 e.currentTarget.getBoundingClientRect() 手动计算 e.clientX - rect.left。这样不管有没有子元素都能得到相对于容器的稳定偏移。本页顶部的演示工具正是用这种方法定位十字准星的。
坐标记录功能用法
上方网格有一个多数坐标工具没有的功能:点击捕获。每次在网格内点击都会记录当前鼠标位置 -- 三种坐标系全部记录 -- 到下方日志中。你可以捕获任意多个点,然后一次性复制为制表符分隔格式,直接粘贴到 Excel、Google Sheets 或脚本中。
工作流:1) 依次点击每个目标位置。2) 点"复制坐标"。3) 粘贴到脚本或表格。PyAutoGUI 用户需要的是 screenX/screenY 列,传入 pyautogui.click(x, y)。详见 PyAutoGUI 指南。
DPI 缩放如何影响数值
如果你用的是高 DPI 笔记本屏幕(Retina Mac 或 Windows 超极本),你可能注意到 screenX 值和原生系统工具的不匹配。这是因为浏览器报告的是 CSS 像素,不是物理像素,而原生工具如 PowerShell GetCursorPos 报告物理像素。
在 150% 缩放的显示器上,一个 CSS 像素等于 1.5 个物理像素。所以浏览器中的坐标 1000 对应原生坐标的 1500。这是"我的自动化脚本点错位置"的第一大原因。在控制台查看 window.devicePixelRatio -- 那就是你的缩放因子。
详见我们的 DPI 缩放指南和物理像素与逻辑像素指南。
触屏设备与移动端
触屏上没有 mousemove 事件 -- 但有 touchmove。上方的检测器在手机上也能用:在网格内触摸拖动,坐标读数会像鼠标一样更新。值来自 touches[0].clientX 和 touches[0].clientY,映射到同样的坐标系。
一个区别:手机上 screenX/screenY 通常和 clientX/clientY 一样,因为移动浏览器通常把视口当作全屏。而 offsetX/offsetY 在触摸事件上不总是可用 -- 可能需要用 getBoundingClientRect 手动计算。
与其他工具的对比
| 功能 | 典型在线工具 | 本检测器 |
|---|---|---|
| 显示坐标系数量 | 1-2 个(通常只有 screen 或 client) | 同时 4 个 |
| 点击捕获坐标点 | 罕见 | 支持,可复制/导出 |
| 十字准星辅助线 | 有时有 | 双轴都有 |
| 触屏/移动端支持 | 通常不可用 | 通过 touchmove 支持 |
| 教学性内容 | 无或极少 | 完整指南含真实用例 |
| 广告/弹窗 | 通常很多 | 无 |
常见问题
为什么移动浏览器窗口后 screenX 就变了?
screenX 从物理显示器边缘算起。移动浏览器窗口时,页面上每个点到显示器边缘的距离都变了,所以 screenX 就变了。clientX 不变,因为它从浏览器视口算起,视口跟着窗口走。
自动化脚本应该用哪对坐标?
用 PyAutoGUI、AutoHotkey 等系统级自动化工具,用 screenX/screenY。这些工具在物理屏幕坐标系中操作。如果用 Puppeteer 或 Playwright 在浏览器内自动化,clientX/clientY 或 pageX/pageY 更合适。上方的坐标记录同时捕获两种,你可以根据工具选择。
能获取光标位置的像素颜色吗?
浏览器安全限制阻止 JavaScript 读取任意屏幕像素。getImageData API 只能用于 canvas 元素。全屏取色需要原生工具如 macOS 的 Digital Color Meter 或有提权权限的浏览器扩展。原生取色方法见我们的像素坐标指南。
为什么鼠标经过子元素时 offsetX 会跳变?
offsetX/offsetY 是相对于光标正下方的元素的。当光标从父容器移到子元素上,参考点就变成了子元素的左上角。要得到相对于特定容器的稳定偏移,用 e.clientX - container.getBoundingClientRect().left 代替。
在 iframe 里能用吗?
能用,但 screenX/screenY 会相对于 iframe 在父页面中的位置报告坐标,可能令人困惑。本页的检测器在主文档中运行,所以显示的是本页的正确值。