【分享】深入挖掘 offsetParant 元素的判定

WebAdvocate 2010-08-06 08:26:17
加精
在处理某些JS程序的时候,往往会用到一个元素的坐标值,如果,把页面的左上角当作是原点,那么,如何正确的取到一个元素的坐标值呢?一般来说,会采用元素的 offsetLeft 值取得横轴的坐标, offsetTop 值取得纵轴的坐标。某元素 offsetLeft 和 offsetTop 属性值是偏移量没错,关键在于,它针对哪个元素的偏移值?是它的直接父元素吗?…… 其实应该是它的 offsetParent。而且,要求它的确切坐标,也需要递归计算它所有的 offsetParent 的相对坐标值,直到 offsetParent 是null为止。看来,offsetParent 是关键。

对于元素A的offsetParent,W3C标准的 CSSOM 规范,对此作了规定。我们现在就跟据标准挖掘一下,各浏览器到底是不是一致,是不是遵守标准。

如何元素 A 的 offsetParant 元素 B

A是根元素或 BODY 则 offsetParent 元素为null
<html id="_html">
<script>
function op(id) {
var off = document.getElementById(id);
return id + " offsetParent : " + (!!off.offsetParent ? off.offsetParent : "null");
}
window.onload = function() {
document.getElementById("info").innerHTML =
op("_body") + "</br>" + op("_html");
}
</script>
<body id="_body">
<div id="info"></div>
</body>
</html>
可见,html和body的offsetParent 都不存在。这时,不存在兼容性问题。


A的 position特性计算后的值是 fixed 则 offsetParent元素为null
<html id="_html">
<script>
function op(id) {
var off = document.getElementById(id);
return id + " offsetParent : " + (!!off.offsetParent ? off.offsetParent.id : "null");
}
window.onload = function() {
document.getElementById("info").innerHTML =
op("_fixed");
}
</script>
<body id="_body">
<div id="_fixed" style="position:fixed;">fixed</div>
<div id="info"></div>
</body>
</html>
此时,存在兼容性问题。
Opera/Chrome/Safari中输出的是:_fixed offsetParent : null
Firefox/IE中会输出:_fixed offsetParent : _body
可见,在Firefox和IE中,固定定位的元素的offsetParent是 BODY 元素,明显是不符合W3C标准的。注意,在IE中 BODY 是默认拥有布局的,BODY是默认触发hasLayout的。

position 特性计算后的值是非 ‘static’ 的祖先元素B
<html id="_html">
<script>
function op(id) {
var off = document.getElementById(id);
return id + " offsetParent : " + (!!off.offsetParent ? off.offsetParent.id : "null");
}
window.onload = function() {
document.getElementById("info").innerHTML = op("_normaldiv");
}
</script>
<body id="_body">
<div id="_positioned" style="position:relative;">
<div id="second">
<div id="_normaldiv"></div>
</div>
</div>
<div id="info"></div>
</body>
</html>
所有浏览器中的输出都是:_normaldiv offsetParent : _positioned
此时无兼容性问题。

修改一下代码,<div id="second">外面再套一个 DIV,并且此 DIV 在IE中触发了hasLayout(设置了 ‘width:100px;’):
<html id="_html">
<script>
function op(id) {
var off = document.getElementById(id);
return id + " offsetParent : " + (!!off.offsetParent ? off.offsetParent.id : "null");
}
window.onload = function() {
document.getElementById("info").innerHTML = op("_normaldiv");
}
</script>
<body id="_body">
<div id="_positioned" style="position:relative;">
<div id="first" style="width:100px;">
<div id="second">
<div id="_normaldiv"></div>
</div>
</div>
</div>
<div id="info"></div>
</body>
</html>
这时,情况发生变化了,IE6/IE7/IE8(Q) 中的输出变成了:_normaldiv offsetParent : first
其他浏览器中还是:_normaldiv offsetParent : _positioned
看来,在IE中,元素的offsetParent 是离它最近的触发hasLayout的元素。

HTML body类型的祖先元素B
<html id="_html">
<script>
function op(id) {
var off = document.getElementById(id);
return id + " offsetParent : " + (!!off.offsetParent ? off.offsetParent.id : "null");
}
window.onload = function() {
document.getElementById("info").innerHTML = op("_normaldiv");
}
</script>
<body id="_body">
<div id="_positioned">
<div id="first" style="width:100px;">
<div id="second">
<div id="_normaldiv"></div>
</div>
</div>
</div>
<div id="info"></div>
</body>
</html>
IE6/IE7/IE8(Q) 中输出:_normaldiv offsetParent : first
其他浏览器中:_normaldiv offsetParent : _body

将 first 的style属性去掉,在IE6/IE7/IE8(Q) 中输出:_normaldiv offsetParent : _body

A的 position 特性计算后的值是 static 并且其祖先元素B是 TD/TH/TABLE元素
<html id="_html">
<script>
function op(id) {
var off = document.getElementById(id);
return id + " offsetParent : " + (!!off.offsetParent ? off.offsetParent.id : "null");
}
window.onload = function() {
document.getElementById("info").innerHTML =
op("_th") + "<br/>" + op("_td") + "<br/>" +
op("_positoinedinth") + "<br/>" + op("_positoinedintd") + "<br/>" +
op("_inth") + "<br/>" + op("_intd") + "<br/>";
}
</script>
<body id="_body">
<table id="_table">
<tr id="_tr">
<th id="_th">
<div id="_inth">in th</div>
<div id="_positoinedinth" style="position:relative;">positoined in th</div>
</th>
<td id="_td">
<div id="_intd">in tr</div>
<div id="_positoinedintd" style="position:relative;">positoined in th</div>
</td>
</tr>
</table>
<div id="info"></div>
</body>
</html>
从上面测试代码中,可以看出:
● IE6(Q)/IE7(Q)/IE8/Firefox/Chrome/Safari/Opera中,非static元素的 offsetParent 都是 BODY
● IE6(S)/IE7(S)中很奇怪,非static元素的 offsetParent 竟然是 HTML。
● 所有浏览器中,TD 和 TH 的 offsetParent 是TABLE,这跟标准是符合的。
● static定位元素的 offsetParent 不是TD/TH/TABLE。应该根据上面已经说明的规则向上查找。注意,<table>, <tr>, <th>, <td> 都会自动触发hasLayout。

IE中的offsetParent究竟是什么
综合以上测试结果,可以得到一个结论,在IE中的offsetParent元素的取值算法,跟其他浏览器不同:
● 对于static定位的元素,其offsetParent是离它最近的触发hasLayout的元素。
● 对于非static定位的元素,则是离它最近的非static定位的元素。如果不存在,在IE6(S)/IE7(S)下取 HTML 元素,其他情况下取 BODY元素。

不知上述总结是否严密,还请大伙一起检查、讨论,欢迎拍砖……

扩展阅读:
hasLayout: http://msdn.microsoft.com/en-us/library/ms533776(VS.85).aspx

大伙儿还可以讨论一下,怎么样才能有效的避免这个问题???Thx。

现实意义何在
知道这些差异,可以让你取出的坐标更加准确,让你的定位更加准确,所以,绕开IE的hasLayout很有必要,但是很难。
还是多多注意吧!


资料:
W3C: http://www.w3.org/TR/cssom-view/#dom-htmlelement-offsetparent


更多兼容性问题:
【分享】浏览器兼容性问题目录
...全文
1559 73 打赏 收藏 举报
写回复
用AI写文章
73 条回复
切换为时间正序
请发表友善的回复…
发表回复
liangshangjunzi 2010-08-23
  • 打赏
  • 举报
回复
太难解决的问题
mycjzlove 2010-08-19
  • 打赏
  • 举报
回复
没看明白,收藏一起慢慢看,呵呵。。。。。。。。。。
hujun4561812 2010-08-13
  • 打赏
  • 举报
回复
明天看看,先收藏
tizll521 2010-08-13
  • 打赏
  • 举报
回复
确保offsetParent的统一性 最好是触发父元素的position:relative属性
WebAdvocate 2010-08-10
  • 打赏
  • 举报
回复
IE 离开hasLayout就没法活了……
tangjin2006 2010-08-10
  • 打赏
  • 举报
回复
好好学习
尛傻囝 2010-08-10
  • 打赏
  • 举报
回复
收藏了....
lianxw123 2010-08-10
  • 打赏
  • 举报
回复
我只是路过
mela200800 2010-08-10
  • 打赏
  • 举报
回复
牛啊,不会。。
Jamy325 2010-08-09
  • 打赏
  • 举报
回复
不懂。。。。
asd612429 2010-08-09
  • 打赏
  • 举报
回复
没懂aaaa
qq295939260 2010-08-09
  • 打赏
  • 举报
回复
不懂 只能帮顶咯
linbt 2010-08-09
  • 打赏
  • 举报
回复
综合以上测试结果,可以得到一个结论,在IE中的offsetParent元素的取值算法,跟其他浏览器不同:
● 对于static定位的元素,其offsetParent是离它最近的触发hasLayout的元素。
● 对于非static定位的元素,则是离它最近的非static定位的元素。如果不存在,在IE6(S)/IE7(S)下取 HTML 元素,其他情况下去 BODY元素。
Abin-2008 2010-08-09
  • 打赏
  • 举报
回复
路過....
xiaoxiangqing 2010-08-09
  • 打赏
  • 举报
回复
说得太详细了。
六六木木 2010-08-09
  • 打赏
  • 举报
回复
牛啊,不会。。
linguangfei2007 2010-08-08
  • 打赏
  • 举报
回复
路过,路过,学习
hepburn2010 2010-08-08
  • 打赏
  • 举报
回复
有见解。。。
yarpee 2010-08-08
  • 打赏
  • 举报
回复
没太明白。
zhan750520 2010-08-08
  • 打赏
  • 举报
回复
学习。
加载更多回复(36)
详情可查看下方数据集可视化效果。 【数据集概况】 · 检测类别(中文):[自行车(bicycle), 汽车(car), 牛(cow), 鹅(goose), 马(horse), 人(human), 摩托车(motorbike), 羊(sheep), 危险标志(ss danger), 左转标志(ss left), 禁止鸣笛标志(ss no horn), 停车标志(ss parking), 右转标志(ss right), 停止标志(ss stop), 人行横道标志(ss xwalk), 绿灯(tl green), 关灯(tl off), 红灯(tl red), 黄灯(tl yellow)] · 训练集:1365 张 · 验证集:90 张 · 测试集:62 张 · 总计:1517 张 该数据集基于室内模拟交通场景构建,聚焦于交通标志、车辆及动物等目标的精准识别,为智能交通系统训练提供高质量样本,具有显著的行业应用价值与技术研究意义。训练集、验证集与测试集分别包含1365张、90张与62张图像,数据分布比例合理,训练集规模充足以保障模型学习充分,验证集与测试集用于模型性能评估,有效支撑模型迭代优化。所有目标均经过严格标注,边界框绘制精准,类别标注规范统一,无模糊或错误标注情况,确... 【训练曲线与评估图】 【模型训练配置】 参数 | 值 模型 | yolo26n 训练轮数 | 100 epochs 输入尺寸 | 640x640 批次大小 | 24 优化器 | auto 初始学习率 | 0.01 训练设备 【关键指标汇总】 训练了 41 个 epoch,最终轮指标: 指标 | 数值 mAP50 | **0.9644** mAP50-95 | 0.7193 Precision | 0.9278 Recall | 0.9049 train/box_loss | 0.8936 tra...

5,006

社区成员

发帖
与我相关
我的任务
社区描述
解读Web 标准、分析和讨论实际问题、推动网络标准化发展和跨浏览器开发进程,解决各种兼容性问题。
社区管理员
  • 跨浏览器开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧