在做页面交互的时候,获取元素位置是一个高频需求。比如点击某个按钮后要弹出一个浮层,这个浮层该放在哪里?怎么保证它紧挨着触发元素?这时候就得用到坐标定位。jQuery 里有一个专门干这事的方法——offset()。
我自己早期写定位逻辑时总搞混 offset() 和 position(),结果浮层位置飘来飘去。后来才搞清楚,offset() 参照的是整个文档(document),而 position() 参照的是最近的定位祖先元素。场景不同,用错就出 bug。
offset() 的核心用途
offset() 方法只做两件事,但很专精:
-
读取偏移坐标 — 获取匹配元素中第一个元素相对于 document 的当前坐标。
-
设置偏移坐标 — 为所有匹配元素统一设置相对于 document 的新坐标。
返回或设置的坐标是一个对象,包含两个属性:
-
top:元素顶部距离文档顶部的像素值 -
left:元素左侧距离文档左侧的像素值
这两个属性值是纯数字,不带单位。做计算时直接加减就行,不用 parseInt() 转换。
三种语法形式
1. 读取偏移坐标
$(selector).offset()
调用后返回一个对象 {top: number, left: number}。如果选中了多个元素,只返回第一个元素的坐标,后面的元素不管。这个规则和 prop()、val() 等取值方法一致。
2. 直接设置偏移坐标
$(selector).offset({top: value, left: value})
{top: value, left: value} 是必填参数,两个值都以像素为单位。这会改变元素在页面上的位置,本质上是修改了 CSS 的 top 和 left 属性。CSS 的 position 必须是 relative、absolute 或 fixed 才有效,否则 offset() 设置不生效。这点很多教程不提,但项目开发里经常踩坑。
3. 用回调函数设置偏移坐标
$(selector).offset(function(index, currentOffset) {
return {top: newTop, left: newLeft};
})
回调接收两个参数:
-
index:元素在 jQuery 中的索引位置 -
currentOffset:该元素当前的坐标对象,含有top和left属性
可以根据每个元素的当前位置动态计算新坐标,适合批量微调偏移量的场景。
参数说明一览
| 参数 | 说明 |
|---|---|
| {top: value, left: value} | 设置偏移时的必填对象,以像素指定目标坐标 |
| function(index, currentOffset) | 可选的回调函数,返回一个包含 top 和 left 属性的坐标对象 |
| index | 当前元素在选中中的索引,从 0 开始计数 |
| currentOffset | 该元素当前的 {top, left} 坐标对象 |
实战示例:点击段落读取坐标
这是一个基础用法示例,点击按钮弹出所选段落在文档中的坐标:
<p id="target-p">这是一段用来测试 offset 的文本</p>
<button id="get-offset">获取段落偏移坐标</button>
$(document).ready(function(){
$("#get-offset").click(function(){
var offsetData = $("#target-p").offset();
alert("Top 坐标: " + offsetData.top + "px\nLeft 坐标: " + offsetData.left + "px");
});
});
点击按钮后,你会看到段落相对于页面左上角的精确像素值。做弹窗定位、拖拽计算时,这个数据就是基础。
实战示例:点击色块获取各自坐标
下面这个例子更贴近项目开发——页面上有多个元素,点击哪个就显示哪个的坐标。配合 $(this) 使用:
<p>点击任意色块获取其偏移坐标:</p>
<span id="left-result"></span>
<span id="top-result"></span>
<div class="color-box" style="background-color:#7fffd4; width:60px; height:60px; margin:5px; float:left;"></div>
<div class="color-box" style="background-color:#a52a2a; width:60px; height:60px; margin:5px; float:left;"></div>
<div class="color-box" style="background-color:#7fff00; width:60px; height:60px; margin:5px; float:left;"></div>
<div class="color-box" style="background-color:#ff1493; width:60px; height:60px; margin:5px; float:left;"></div>
$(document).ready(function() {
$(".color-box").click(function () {
var offset = $(this).offset();
$("#left-result").html("left 偏移: <span>" + offset.left + "px</span>");
$("#top-result").html("top 偏移: <span>" + offset.top + "px</span>");
});
});
每个色块被点击时,用 $(this).offset() 获取被点击的那个色块的坐标。这里要注意,坐标是相对整个文档计算的,你滚动页面后再点击,数值会发生变化——因为元素在文档中的绝对位置变了。
设置偏移坐标的注意事项
用 offset() 设置位置时,有几个点值得提前知道:
-
元素必须可定位:CSS 的
position属性如果是默认的static,设置offset()不会生效。需要在 CSS 里给元素加上position: relative、absolute或fixed。 -
会覆盖原有定位:设置的新坐标直接替换原有的
top和left样式值。如果想保留一个维度不变,可以结合回调函数,返回{top: currentOffset.top, left: 新值}这样只改一边。 -
所有匹配元素都生效:和取值只返回第一个不同,设置坐标会影响选中里的每一个元素。
本节课程知识要点:在用 offset() 设置位置前,一定确认目标元素的 position 不是 static,这是新手最容易犯的低级错误。我的习惯是在 CSS 里提前给这些动态定位的元素统一加上 position: absolute;,避免运行时失效。
offset() 和 position() 的区别
虽然题目没要求展开讲 position(),但既然前面提了我自己踩过的坑,这里简单说透两者的核心差异:
-
offset()获取的是元素相对于 document 的坐标,即元素在整个页面里的绝对位置。 -
position()获取的是元素相对于最近的定位祖先元素(设置了position: relative/absolute/fixed的父级)的坐标。
做弹出菜单、工具提示这类跟随元素出现的效果时,如果父容器有定位,应该用 position() 计算相对位置,而不是 offset()。搞反了就会出现浮层跑到意料之外的地方。
个人经验
项目开发中我很少用 offset() 去“设置”坐标,更多的是用它“读取”坐标,然后配合其他方法做定位计算。真正设置位置时,往往直接操作 CSS,因为那样粒度更细,比如只想改 left 不影响 top。offset() 设置必须 top 和 left 一起给,灵活性上稍差一点。
如果页面有滚动,记得 offset() 返回的是文档坐标,想换算成视口坐标(viewport)得减去 $(window).scrollTop() 或 $(window).scrollLeft()。做固定定位的效果时这个换算很常用。