偏移量(offset dimension)

偏移量:包括元素在屏幕上占用的所有可见空间,元素的可见大小由其高度,宽度决定,包括所有内边距,滚动条和边框大小(注意,不包括外边距)。

以下4个属性可以获取元素的偏移量

  1. offsetHeight:元素在垂直方向上占用的空间大小,以像素计。包括元素的高度(可见的),水平滚动条的高度,上边框高度和下边框高度。

  2. offsetWidth:元素在水平方向上占用的空间大小,以像素计。包括元素的宽度(可见的),垂直滚动条的宽度,左边框宽度和右边框宽度。

3: offsetLeft:元素的左外边框至包含元素的左内边框之间的像素距离。

4: offsetTop:元素的上外边框至包含元素的上内边框之间的像素距离。

其中offsetLeft,offsetTop属性与包含元素有关,包含元素的引用保存在offsetParent中,请注意offsetParent与parentNode的值不一定相等。

有了理论基础,那我们就要动手看看,看看事实是不是真的是那样:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {margin: 0;padding: 0;}.parent {width: 500px;height: 500px;margin: 100px auto;background-color: red;border: 10px solid #000;overflow: hidden;}.child {width: 300px;height: 300px;border: 1px solid #000;padding: 10px;margin: 50px 90px;background-color: green;}</style>
</head><body><div class="parent"><div class="child"></div></div><script>var child = document.querySelector('.child');var html = '';html += "offsetWidth=" + child.offsetWidth + "<br>";html += "offsetHeight=" + child.offsetHeight + "<br>";html += "offsetTop=" + child.offsetTop + "<br>";html += "offsetLeft=" + child.offsetLeft;child.innerHTML = html;</script>
</body></html>

在查看结果之前我们按照自己对理论的理解,先猜测以下会出现什么结果。

class名称为child的相关偏移量猜测结果如下:(猜测前提,child是包含在parent中的)
offsetWidth = 102(左右内边距) + 12(左右边框)+ 300(元素的宽度)+ 0(垂直滚动条的高度)= 322;

offsetHeight = 102(上下内边距)+12(上下边框)+300 (元素的高度)+ 0(水平滚动条的高度)= 322;

offsetLeft = 90 (元素的上外边框至包含元素的上内边框之间的像素距离,在此为左外边的距离);

offsetTop = 50 (元素的上外边框至包含元素的上内边框之间的像素距离,在此为上外边的距离);

在看看下实际的结果:

不难发现offsetWidth和offsetHeight与我们猜测的一致,但是其他两个属性出现较大偏差,原因如下:

offsetParent:是指元素最近的定位(relative,absolute)祖先元素,如果没有祖先元素是定位的话,会指向body元素。

现修改parent样式如下:

.parent {width: 500px;height: 500px;margin: 100px auto;background-color: red;border: 10px solid #000;overflow: hidden;position: relative;}

再次查看结果:

现在结果和我们的猜测一致。所以在使用offsetLeft和offsetTop的时候,一定要注意offsetParent的指向。

接下来我们做如下几个测试:(为了测试方便,指定child的offsetParent为parent)

1. 元素的盒模型对以上四个属性有什么影响?

修改child的css代码如下:

.child {width: 300px;height: 300px;border: 1px solid #000;padding: 10px;margin: 50px 90px;background-color: green;box-sizing: border-box;}

查看结果:

发现改变盒模型会对元素的offsetWidth盒offsetHeight产生影响.

2. 元素定位对上面四个属性的影响?

修改css代码如下:

.parent {width: 500px;height: 500px;margin: 100px auto;background-color: red;border: 10px solid #000;overflow: hidden;position: relative;}.child {position: absolute;top: 30px;left: 50px;width: 300px;height: 300px;border: 1px solid #000;padding: 10px;margin: 50px 90px;background-color: green;box-sizing: border-box;;}

查看结果:

发现offsetTop多了30(这30就是child相对于parent绝对定位top方向上的方位值),offsetLeft多了50(这50就是child相对于parent绝对定位left方向上的方位值)。

可以的出元素的偏移量中的offsetTop,offsetLeft与在offsetParent中的外边距和定位的方位值有关系。

现给出计算元素在页面上的offsetLeft和offsetTop(注意,不仅仅是在包含元素中的值)

var getOffset = {left: function (element) {var actualLeft = element.offsetLeft;var current = element.offsetParent;while (current) {actualLeft += current.offsetLeft;current = current.offsetParent;}return actualLeft;},top: function (element) {var actualTop = element.offsetTop;var current = element.offsetParent;while (current) {actualTop += current.offsetTop;current = current.offsetParent;}return actualTop;}}

在这里我们递归寻找元素的offsetParent,然后在一直加上offsetParent中的offsetTop或者offsetLeft,最终得到元素在页面中的offsetLeft和offsetTop。乍一看很完美是吧,但是两个函数只能得到一个基本准确的值,为什么这么说了,通过下面几个案例就可以得到答案。

测试案例1代码如下:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {margin: 0;padding: 0;}.parent {width: 500px;height: 500px;margin: 100px auto;background-color: red;border: 10px solid #000;overflow: hidden;}.child {width: 300px;height: 300px;border: 10px solid #000;padding: 10px;margin: 50px 90px;background-color: green;}</style>
</head><body><div class="parent"><div class="child"></div></div><script>var child = document.querySelector('.child');var html = '';html += "offsetWidth=" + child.offsetWidth + "<br>";html += "offsetHeight=" + child.offsetHeight + "<br>";html += "offsetTop=" + child.offsetTop + "<br>";html += "offsetLeft=" + child.offsetLeft;child.innerHTML = html;</script>
</body></html>

在这里child的offsetParent为body元素,就以此结果为元素在页面上的偏移量的准确结果。

查看结果:

请记住这个结果,下面我们用定义的方法来获取child的offsetTop和offsetLeft。

测试案例2代码如下:

<script>var child = document.querySelector('.child');var html = '';var getOffset = {left: function(element){var actualLeft = element.offsetLeft;var current = element.offsetParent;while(current) {actualLeft += current.offsetLeft;current = current.offsetParent;}return actualLeft;},top: function(element){var actualTop = element.offsetTop;var current = element.offsetParent;while(current) {actualTop += current.offsetTop;current = current.offsetParent;}return actualTop;}}html += "offsetWidth=" + child.offsetWidth + "<br>";html += "offsetHeight=" + child.offsetHeight + "<br>";html += "offsetTop=" + getOffset.top(child) + "<br>";html += "offsetLeft=" + getOffset.left(child);child.innerHTML = html;</script>
</body>

在这里没有直接使用child元素的offsetLeft和offsetTop,而是通过所定义的函数计算出来的。

结果如下:

结果一样,是不是说明那个函数计算出来的就是准确的结果了?,继续往下看。

测试案例3代码如下:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {margin: 0;padding: 0;}.parent {width: 500px;height: 500px;margin: 100px auto;background-color: red;border: 10px solid #000;overflow: hidden;/*注意这里 相当于把child的offsetParent设置为了parent*/position: relative;}.child {width: 300px;height: 300px;border: 10px solid #000;padding: 10px;margin: 50px 90px;background-color: green;}</style>
</head><body><div class="parent"><div class="child"></div></div><script>var child = document.querySelector('.child');var html = '';var getOffset = {left: function (element) {var actualLeft = element.offsetLeft;var current = element.offsetParent;while (current) {actualLeft += current.offsetLeft;current = current.offsetParent;}return actualLeft;},top: function (element) {var actualTop = element.offsetTop;var current = element.offsetParent;while (current) {actualTop += current.offsetTop;current = current.offsetParent;}return actualTop;}}html += "offsetWidth=" + child.offsetWidth + "<br>";html += "offsetHeight=" + child.offsetHeight + "<br>";html += "offsetTop=" + getOffset.top(child) + "<br>";html += "offsetLeft=" + getOffset.left(child);child.innerHTML = html;</script>
</body></html>

请注意parent样式注释的部分,现在看看结果:

发现是不是在页面上的offsetLeft和offsetTop相对于精确结果来说都少了10,为什么会出现这个现象?其中从offsetLeft和offsetTop的定义中就可以得到答案

offsetLeft:元素的左外边框至包含元素的左内边框之间的像素距离。

offsetTop:元素的上外边框至包含元素的上内边框之间的像素距离。

在这例子中我们把parent设置了child的offsetParent,根据定义我们可以得出child在parent中的offsetTop为50而parent在body中的offsetTop为100(offsetTop:元素的上外边框至包含元素的上内边框之间的像素距离)所以在计算中我们忽略了parent的边框高度(为10px)所以就出现了10px的误差,offsetLeft的10误差解释也是一样。

在来看一个案例:

测试案例4代码如下:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {margin: 0;padding: 0;}.parent {width: 500px;height: 500px;margin: 100px auto;background-color: red;border: 10px solid #000;overflow: hidden;/*注意这里*/box-sizing: border-box;}.child {width: 300px;height: 300px;border: 10px solid #000;padding: 10px;margin: 50px 90px;background-color: green;}</style>
</head><body><div class="parent"><div class="child"></div></div><script>var child = document.querySelector('.child');var html = '';var getOffset = {left: function (element) {var actualLeft = element.offsetLeft;var current = element.offsetParent;while (current) {actualLeft += current.offsetLeft;current = current.offsetParent;}return actualLeft;},top: function (element) {var actualTop = element.offsetTop;var current = element.offsetParent;while (current) {actualTop += current.offsetTop;current = current.offsetParent;}return actualTop;}}html += "offsetWidth=" + child.offsetWidth + "<br>";html += "offsetHeight=" + child.offsetHeight + "<br>";html += "offsetTop=" + getOffset.top(child) + "<br>";html += "offsetLeft=" + getOffset.left(child);child.innerHTML = html;</script>
</body></html>

注意看parent样式注释的地方。

结果如下:

发现child在页面上的offsetLeft比标准结果多了10,因为改变了parent的盒模型,导致parent原先向外扩充的边框变成向内填充,其边框长度为10,所以导致offsetLeft的结果多了10。

到这里可以发现上面计算元素在页面的offsetLeft和offsetTop确实是存在一定误差的,相关因素如下:

  1. 修改元素的offsetParent
  2. 修改offetParent的盒模型(如果offsetParent设置了边框和内边距的话)

注意:元素的偏移量都是只读的,每次访问他们都需要重新计算,如果要重复用到这些属性值,请保存在局部变量中,以提高性能

所以我们在实际开发中,怎样写代码才能将误差降到最小是我们值得思考的。当然对于偏移量的其他测试没有全部进行,如果有错,请告知一声,我会及时修改。

一文看懂js中元素偏移量(offsetLeft,offsetTop,offsetWidth,offsetHeight)相关推荐

  1. 一文看懂js中元素的客户区大小(clientWidth,clientHeight)

    元素的客户区 元素的客户区大小,指的是元素内容及其内边距(padding)所占据的空间大小. 相关属性如下: clientWidth:元素内容区宽度+元素左右内边距 clientHeight:元素内容 ...

  2. 一文看懂js中的clientX,clientY,pageX,pageY,screenX,screenY

    一. 客户区坐标位置(clientX,clientY) 鼠标事件都是在浏览器视口中的特定位置发生的.这个位置信息保存在事件对象的clientX和clientY属性中,所有浏览器都支持这两个属性. 我们 ...

  3. ​【Python基础】一文看懂 Pandas 中的透视表

    作者:来源于读者投稿 出品:Python数据之道 一文看懂 Pandas 中的透视表 透视表在一种功能很强大的图表,用户可以从中读取到很多的信息.利用excel可以生成简单的透视表.本文中讲解的是如何 ...

  4. 一文搞懂JS中的赋值·浅拷贝·深拷贝

    前言 为什么写拷贝这篇文章?同事有一天提到了拷贝,他说赋值就是一种浅拷贝方式,另一个同事说赋值和浅拷贝并不相同.我也有些疑惑,于是我去MDN搜一下拷贝相关内容,发现并没有关于拷贝的实质概念,没有办法只 ...

  5. 一文看懂JS里隐式转换、toString() 和 valueOf()

    js-看懂隐式转换toString 和 valueOf js隐式类型转换 数值类型和布尔类型的相加 字符串和数字相加 隐式类型转换隐藏一些错误 isNaN() 对象的隐式转换 强制类型转换 - &qu ...

  6. 一文看懂CV中的注意力机制

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 作者丨AdamLau@知乎 来源丨https://zhuanlan.zhihu.com/p/28875 ...

  7. 一文看懂机器学习中的常用损失函数

    作者丨stephenDC 编辑丨zandy 来源 | 大数据与人工智能(ID: ai-big-data) 导语:损失函数虽然简单,却相当基础,可以看做是机器学习的一个组件.机器学习的其他组件,还包括激 ...

  8. 一文看懂 NLP 中的情感分析任务

    目前,情感分析在中文自然语言处理(Natural Language Processing)中比较火热,很多场景下,我们都需要用到情感分析.比如,做金融产品量化交易,需要根据爬取的舆论数据来分析政策和舆 ...

  9. 一文看懂神经网络中的梯度下降原理 图像说明

    本文是一篇关于深度学习优化方法--梯度下降的介绍性文章.作者通过长长的博文,简单介绍了梯度下降的概念.优势以及两大挑战.文中还配有大量生动形象的三维图像,有兴趣的亲了解一下? 从很大程度上来说,深度学 ...

最新文章

  1. 有监督、无监督与半监督学习【总结】
  2. Ciel and Robot CodeForces - 322C
  3. 【CF1179 A,B,C】Valeriy and Deque / Tolik and His Uncle / Serge and Dining Room
  4. Python编程从入门到实践~字典
  5. 学位论文是根,学术论文是叶
  6. ios 支付宝支付 回调数据_iOS逆向支付宝
  7. SQL的注入式攻击方式和避免方法
  8. java ——线程与并行
  9. Java 基础常见面试题大全
  10. PDF旋转保存居然还能如此高效的办法
  11. 达人评测 联想小新Pad Pro/Pad Plus怎么样
  12. AI开发者大会,李彦宏成“宏颜获水”?
  13. vue的provide的使用
  14. 28岁程序员:我要转行能行么?网友:除了写代码你还能干啥?
  15. win7局域网自建ftp服务器,win7系统搭建FTp服务器局域网内传输文件的解决教程
  16. mye连接mysql数据库_myeclipse连接数据库
  17. Spring boot(web 组件,ORM 操作 MySQL,接口架构风格—RESTful,集成 Redis,集成 Dubbo,打包)
  18. 竞品分析:小宇宙APP——如何在播客领域站住脚?
  19. centos卸载nvidia驱动_在Ubuntu系统中NVIDIA显卡驱动卸载与安装
  20. 风景照片的PS后期处理(3)

热门文章

  1. 计算机应用在学科整合中的课题研究,多媒体计算机技术与学科教学的整合(课题研究阶段总结)...
  2. GML与KML的区别
  3. 评绿色数据中心建筑评价标准
  4. decode解码 geohash_Geohash 原理及 Python 实现
  5. 项目管理专业人员能力评价(CSPM)相关问题汇总,看这篇就够了!
  6. java.lang.NullPointerException出现的几种原因及解决方案
  7. 每天给你推荐一本好书的经典段落,增长你的文学素养。
  8. iOS CALayer anchorPoint 的应用场景
  9. http range 用法与说明
  10. java main方法的快捷方式