鼠标事件坐标全面解析:pageX、clientX、screenX、offsetX、movementX 等
🖱️
目的:系统梳理鼠标事件中的各类坐标属性,厘清它们的坐标系基准、与滚动/缩放/变换的关系、兼容性与最佳实践,帮助在不同场景下正确取值。
一览对照表
| 属性 | 基准坐标系 | 受页面滚动影响 | 受浏览器缩放影响 | 受 CSS 变换影响 | 典型用途 |
| pageX/pageY | 文档(document)左上角 | 是(包含滚动偏移) | 是(CSS 像素) | 否 | 整页定位、文档级拖拽 |
| clientX/clientY | 视口(viewport)左上角 | 否 | 是(CSS 像素) | 否 | 浮层定位、命中检测、fixed 布局 |
| screenX/screenY | 物理屏幕左上角 | 否 | 实现相关 | 否 | 系统级工具、扩展场景 |
| offsetX/offsetY | 事件 target 内容盒左上角 | 间接(随元素位置变) | 是(CSS 像素) | 实现差异,谨慎依赖 | 组件内相对坐标、画布 |
| movementX/movementY | 上一事件到当前事件的增量 | 否 | 是(CSS 像素) | 否 | 拖拽速度、画笔轨迹 |
| x/y | 等同 clientX/clientY | 否 | 是(CSS 像素) | 否 | 简写;更推荐使用 clientX/clientY |
注:本文以 MouseEvent 为主。PointerEvent 与 TouchEvent 的坐标属性大体一致,但命名与细节略有差异,后文给出迁移建议。
概念与坐标系
- 文档坐标系(document):以整页左上角为原点,包含滚动出去的部分。pageX/pageY 基于此。
- 视口坐标系(viewport):以当前可视区域左上角为原点,不随滚动累加偏移。clientX/clientY 基于此。
- 屏幕坐标系(screen):以系统屏幕左上角为原点,和浏览器窗口位置相关。screenX/screenY 基于此。
- 元素本地坐标系(local/box):以目标元素内容区左上角为原点。offsetX/offsetY 近似于此。
- 增量坐标(delta):两次事件之间的位移,movementX/movementY。
各属性详解
1) pageX / pageY
- 定义:相对整个文档左上角,包含页面滚动偏移。
- 公式:pageX = clientX + window.scrollX;pageY = clientY + window.scrollY。
- 用法:
- 注意:在嵌套滚动容器中,若你要容器内的相对位置,还需加上容器的 scrollLeft/Top。
2) clientX / clientY
- 定义:相对视口左上角,不随页面滚动变化。
- 用法:
- 搭配命中检测:
3) screenX / screenY
- 定义:相对物理屏幕左上角。
- 场景:浏览器扩展、系统级工具。普通 Web 布局应避免使用。
4) offsetX / offsetY
- 定义:相对事件 target 元素内容盒左上角。
- 用法(画布内绘制):
- 注意:
- 基准是 event.target 而非 currentTarget;若事件在子元素触发,坐标相对子元素。
- 建议统一用 currentTarget + getBoundingClientRect 计算,避免 target 漂移带来的不一致。
- layerX/layerY 非标准,不建议使用。
5) movementX / movementY
- 定义:与上一事件的位移差,单位 CSS 像素。
- 用法:
- 注意:窗口切换、Pointer Lock 会影响增量表现;Pointer Lock 下 movement 不受屏幕边界限制。
6) x / y
- 多数现代浏览器等同 clientX/clientY。建议显式使用 clientX/clientY。
坐标换算常用片段
- client -> page:
- 任意点 -> 元素局部坐标(推荐):
- page -> 可滚动容器局部:
- 考虑 CSS transform 的局部坐标(示意):
滚动、缩放、CSS 变换的影响
- 滚动:只影响 pageX/pageY;clientX/clientY 不变。
- 浏览器缩放:所有值以 CSS 像素计。物理像素 = CSS 像素 × window.devicePixelRatio。
- CSS 变换:原始读数不自动反变换。若元素旋转/缩放,需用矩阵求逆映射到局部坐标。
实战选择建议
- 浮层与命中检测:clientX/clientY。
- 整页对齐与文档级拖拽:pageX/pageY。
- 组件内部绘制与局部拖拽:client + rect 换算,少用 offsetX/offsetY。
- 连续位移与速度估计:movementX/movementY。
- 跨端统一:优先 PointerEvent 的 clientX/clientY 与 pointerType。
常见坑排查清单
监听在父层但事件在子元素触发导致 offsetX/offsetY 基准漂移。
页面缩放后绘制发虚,未按 dpr 处理物理像素。
有滚动容器时用 pageX 直接减元素 rect 产生偏移。
transform: scale/rotate 后命中不准,未做坐标反变换。
多屏环境使用 screenX/screenY 做布局定位。
PointerEvent 与移动端补充
- PointerEvent 兼容性较好,属性含义与 MouseEvent 基本一致,推荐统一使用 pointerdown/pointermove/pointerup。
- 触摸屏同样使用 clientX/clientY 表示视口坐标。多指需遍历 changedPointers(或 TouchEvent 的 touches)。
参考实现:可复用坐标工具
小结
- 记忆法:page 看“页”、client 看“窗”、offset 看“target”、movement 看“增量”。
- 优先策略:布局与交互定位用 client + rect,整页对齐用 page,增量跟踪用 movement,谨慎使用 offsetX/offsetY 与 screenX/screenY。