很多初学者对于JavaScript中的offset、scroll、client一直弄不明白,虽然网上到处都可以看一张图(图1),但这张图太多太杂,并且由于浏览器差异性,图示也不完全正确。

图一

  不知道大家看到这张图的第一感觉如何,反正我的感觉就是“这次第,怎一个乱字了得”。

  既然我认为上图太多太乱,那么我就把offset、scroll、client分开说,希望能让大家彻底弄清楚,今天只说offset。

一、关于offset,我们要弄明白什么

  w3中offset相关页面是:http://www.w3.org/TR/cssom-view/#extensions-to-the-htmlelement-interface

  在这里我们可以看到,关于offset共有5个东西需要弄清楚:

  1、offsetParent

  2、offsetTop

  3、offsetLeft

  4、offsetWidth

  5、offsetHeight

  我们根据难易程度把以上5点分为三类来讲解。

  在分析之前,先来看段测试代码:

<body>
<style type="text/css">
body {
border:20px solid #CCC;
margin:10px;
padding:40px;
background:#EEE;
}
#test {
width:400px;
height:200px;
padding:20px;
background:#F60;
border:5px solid #888;
}
</style>
<div id="test"></div>
<script>
var test = document.getElementById("test");
test.innerHTML = "<p>Browser:" + navigator.userAgent + "</p>" +
"<p>offsetWidth:" + test.offsetWidth + "</p>" +
"<p>offsetHeight:"+test.offsetHeight+"</p>"+
"<p>offsetLeft:"+test.offsetLeft+"</p>"+
"<p>offsetTop:"+test.offsetTop+"</p>";
</script>
</body>

  这段代码在各个浏览器中的效果如图:

图二(IE6/7)

图三(IE8/9/10)

图四(Firefox)

图五(Chrome)

二、offsetWidth与offsetHeight

  大家可以看到,上面图二~图五中的共同点是 offsetWidth与offsetHeight是一致的,因此这里放到地起讲。

  MDN中对offsetWidth的概述和描述是:

Returns the layout width of an element.

Typically, an element's offsetWidth is a measurement which includes the element borders, the element horizontal padding, the element vertical scrollbar (if present, if rendered) and the element CSS width.

  也就是元素的可视宽度,这个宽度包括元素的边框(border),水平padding,垂直滚动条宽度,元素本身宽度等。

  offsetHeight跟offsetWidth类似,只是方向改为垂直方向上的。

  只是我们的示例中没有水平和垂直滚动条。另外经过测试可以发现,即使元素加上水平或垂直滚动条,offsetWidth跟offsetHeight的值是不会更改的,因为浏览器渲染时把滚动条的宽度(或高度)算在了元素本身的宽度(或高度)中了。

  通过代码及图中数值,我们不难看出:

  offsetWidth=(border-width)*2+(padding-left)+(width)+(padding-right)

  offsetHeight=(border-width)*2+(padding-top)+(height)+(padding-bottom)

  对这两个概念就总结到这里,大家现在弄明白了吗?

三、offsetLeft与offsetTop

  offsetWidth与offsetHeight有个特点,就是这两个属性的值只与该元素有关,与周围元素(父级和子级元素无关)。

  然而,offsetLeft与offsetTop却不是这样,这两个属性与offsetParent有关,但在我们讲到offsetParent之前,我们先不管offsetParent是什么及怎么判断,我们只要知道offsetLeft和offsetTop与offsetParent有关就行了,上面的示例中offsetParent就是body。

  MSDN上对offsetLeft的定义是:

Retrieves the calculated left position of the object relative to the layout or coordinate parent, as specified by the offsetParent property

  也就是返回对象元素边界的左上角顶点相对于offsetParent的左上角顶点的水平偏移量。从这个定义中我们可以明确地知道offsetLeft与当前元素的margin-left和offsetParent的padding-left有关。也就是说应该是:

  offsetLeft=(offsetParent的padding-left)+(中间元素的offsetWidth)+(当前元素的margin-left)。

  offsetTop=(offsetParent的padding-top)+(中间元素的offsetHeight)+(当前元素的margin-top)。

  但通过上面的例子我们可以看到,当offsetParent为body时,对于offsetLeft与offsetTop的值有三种,分别是:IE6/7中的40,IE8/9/10 和 Chrome中的70,以及FireFox中的50。

  通过这些数值我们可以知道,当offsetParent为body时情况比较特殊:

  在IE8/9/10及Chrome中,offsetLeft = (body的margin-left)+(body的border-width)+(body的padding-left)+(当前元素的margin-left)。

  在FireFox中,offsetLeft = (body的margin-left)+(body的padding-left)+(当前元素的margin-left)。

四、offsetParent

  终于到offsetParent了。

  offsetParent属性返回一个对象的引用,这个对象是距离调用offsetParent的元素最近的(在包含层次中最靠近的),并且是已进行过CSS定位的容器元素。 如果这个容器元素未进行CSS定位, 则offsetParent属性的取值为根元素的引用。

  总的来说两条规则:

  1、如果当前元素的父级元素没有进行CSS定位(position为absolute或relative),offsetParent为body。

  2、如果当前元素的父级元素中有CSS定位(position为absolute或relative),offsetParent取最近的那个父级元素。

  上面的示例就是第1条说的情况,我们来验证一下:

  我们把JS改为(添加了一行代码:红色部分):

var test = document.getElementById("test");
test.innerHTML = "<p>Browser:" + navigator.userAgent + "</p>" +
"<p>offsetParent:" + test.offsetParent.tagName + "</p>" +
"<p>offsetWidth:" + test.offsetWidth + "</p>" +
"<p>offsetHeight:"+test.offsetHeight+"</p>"+
"<p>offsetLeft:"+test.offsetLeft+"</p>"+
"<p>offsetTop:"+test.offsetTop+"</p>";

  FireFox下的效果为:

图六

  在其他浏览器中效果相同,都是body。

  我们再来验证一下第2条,测试HTML如下:

<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
</head>
<body>
<style type="text/css">
body {
margin:0;
padding:0;
background:#EEE;
}
div,ul,li {
margin:0;
}
li {
height:20px;
line-height:20px;
}
#test {
width:400px;
height:250px;
padding:20px;
background:#F60;
border:10px solid #888;
}
#divtest {
margin:30px;
position:relative;
left:50px;
top:70px;
padding:20px;
}
</style>
<div id="divtest">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
<div id="test">
</div>
</div>
<script>
var test = document.getElementById("test");
test.innerHTML = "<p>Browser:" + navigator.userAgent + "</p>" +
"<p>offsetParent:" + test.offsetParent.tagName + "</p>" +
"<p>offsetWidth:" + test.offsetWidth + "</p>" +
"<p>offsetHeight:"+test.offsetHeight+"</p>"+
"<p>offsetLeft:"+test.offsetLeft+"</p>"+
"<p>offsetTop:"+test.offsetTop+"</p>";
</script>
</body>
</html>

  在FireFox中效果为:

图七

  在其他浏览器中offsetParent也是一致的。

  在这里我们也可以看到,第三点中给出的offsetLeft的计算公式是适用的。

小结

  以上的总结希望能对大家有所帮助,在看完本文内容后再回过头来看文章开头部分的那张图(只看offset)部分,是不是清楚了很多?

  最后,对于offsetParent为body的情况,现在的主流浏览器IE8/9/10和Chrome及Firefox都跟定义

      offsetLeft=(offsetParent的padding-left)+(中间元素的offsetWidth)+(当前元素的margin-left)。

  offsetTop=(offsetParent的padding-top)+(中间元素的offsetHeight)+(当前元素的margin-top)。

  的不一样,对于这一点我也没有弄明白,如果有朋友知道请不吝赐教。

学习笔记(一):offset的更多相关文章

  1. MySQL 学习笔记 (limit offset)

    select * from table limit (10000,10);这样是很慢的,因为要定位 比较快的写法是 select * from table where id >=(select ...

  2. redis 学习笔记(6)-cluster集群搭建

    上次写redis的学习笔记还是2014年,一转眼已经快2年过去了,在段时间里,redis最大的变化之一就是cluster功能的正式发布,以前要搞redis集群,得借助一致性hash来自己搞shardi ...

  3. linux驱动开发之块设备学习笔记

    我的博客主要用来存放我的学习笔记,如有侵权,请与我练习,我会立刻删除.学习参考:http://www.cnblogs.com/yuanfang/archive/2010/12/24/1916231.h ...

  4. jQuery 学习笔记

    jQuery 学习笔记   一.jQuery概述    宗旨: Write Less, Do More.    基础知识:        1.符号$代替document.getElementById( ...

  5. 两千行PHP学习笔记

    亲们,如约而至的PHP笔记来啦~绝对干货! 以下为我以前学PHP时做的笔记,时不时的也会添加一些基础知识点进去,有时还翻出来查查. MySQL笔记:一千行MySQL学习笔记http://www.cnb ...

  6. spark学习笔记总结-spark入门资料精化

    Spark学习笔记 Spark简介 spark 可以很容易和yarn结合,直接调用HDFS.Hbase上面的数据,和hadoop结合.配置很容易. spark发展迅猛,框架比hadoop更加灵活实用. ...

  7. jQuery学习笔记 - 基础知识扫盲入门篇

    jQuery学习笔记 - 基础知识扫盲入门篇 2013-06-16 18:42 by 全新时代, 11 阅读, 0 评论, 收藏, 编辑 1.为什么要使用jQuery? 提供了强大的功能函数解决浏览器 ...

  8. cocos2dx游戏开发——别踩白块学习笔记(二)——经典模式的实现

    一.创建GameScene以及GameLayer 就是简单创建一个Scene而已,在此就不多说啦~,可以参照我的打飞机的学习笔记(2). 二.添加一个开始栏 很简单,就是调用Block中的create ...

  9. zepto源码--核心方法10(位置)--学习笔记

    今天基本上就是zepto学习笔记的最后一篇了,介绍一下有关位置的函数,position, offset, scrollLeft, scrollTop scrollLeft 如果所选取的包装集不存在,则 ...

  10. 学习笔记:The Log(我所读过的最好的一篇分布式技术文章)

    前言 这是一篇学习笔记. 学习的材料来自Jay Kreps的一篇讲Log的博文. 原文很长,但是我坚持看完了,收获颇多,也深深为Jay哥的技术能力.架构能力和对于分布式系统的理解之深刻所折服.同时也因 ...

随机推荐

  1. [工具] UltraEdit使用技巧汇总

    ltraEdit是一套功能强大的文本编辑器,可以编辑文本.十六进制.ASCII码,可以取代记事本,内建英文单字检查.C++及VB指令突显,可同时编辑多个文件,而且即使开启很大的文件速度也不会慢.说到编 ...

  2. Coderfroces 862 C. Mahmoud and Ehab and the xor

    C. Mahmoud and Ehab and the xor Mahmoud and Ehab are on the third stage of their adventures now. As ...

  3. Felx之HTTPService

    获取并显示数据 为了向我们的程序提供数据,Adobe Flex包含特别为与HTTP服务器,网络服务或者是远程对象服务(Java对象)进行交互的而设计的组件.这些组件被称之为远程过程调用(RPC)服务组 ...

  4. 利用反射实现Servlet公共类的抽取

    一次请求的执行过程: 请求:发送请求地址-->到达web.xml中,找到地址对应的servlet类-->通过反射调用该类的构造函数,创建该servlet类的对象-->通过当前对象调用 ...

  5. Java main方法中的String[] args

    -- Java 命令行参数 -- 关于其中的args以及public static / static public Java 命令行参数 前面已经看到多个使用Java数组的示例,每一个Java应用程序 ...

  6. 分享《Python 游戏编程快速上手(第3版)》高清中文版PDF+高清英文版PDF+源代码

    通过编写一个个小巧.有趣的游戏来学习Python,通过实例来解释编程的原理的方式.14个游戏程序和示例,介绍了Python基础知识.数据类型.函数.流程控制.程序调试.流程图设计.字符串操作.列表和字 ...

  7. CSUOJ 1525 Algebraic Teamwork

    Problem A Algebraic Teamwork The great pioneers of group theory and linear algebra want to cooperate ...

  8. 从零開始的Android新项目7 - Data Binding入门篇

    Data Binding自从去年的Google I/O公布到至今,也有近一年的时间了.这一年来,从Beta到如今比較完好的版本号.从Android Studio 1.3到如今2.1.2的支持,能够说D ...

  9. 在XEN上启动guest时loopback设备不足

    现象: 通常出现在用户挂载了多个img到guest上,会发现无法再创建guest或者无法启动guest的现象. /var/log/xen/xen-hot-plug.log中错误如下: xenstore ...

  10. OpenCASCADE 麻花钻头造型实例分析

    OpenCASCADE 麻花钻头造型实例分析 eryar@163.com Abstract. OpenCASCADE provides a simple twist drill bit modelin ...