HTML元素坐标定位

 文档坐标和视口坐标

  视口坐标是相对于窗口的坐标,而文档坐标是相对于整个文档而言。例如,在文档坐标中如果一个元素的相对于文档的Y坐标是200px,并且用户已经把浏览器向下滚动了75px,那么视口坐标中元素的Y坐标为200px – 75px = 125px。

  如何获取浏览器滚动条的位置?Window对象的pageXOffset和pageYOffset属性在所有浏览器中提供这些值,除IE8以及更早的版本。IE和所有现代浏览器也可以通过scrollLeft和scrollTop属性获取滚动条位置。

  下面代码的getScrollOffsets方法获取滚动条位置:

01 //以一个对象的x和y属性放回滚动条的位置
02 function getScrollOffsets(w){
03     w = w || window;
04     //除了IE 8以及更早的版本以外,其他浏览器都支持
05     if(w.pageXOffset != null) return {x: w.pageXOffset, y: w.pageYOffset};
06     //对标准模式下的IE
07     var d = w.document;
08     if(document.compatMode == "CSS1Compat")
09         return {x: d.documentElement.scrollLeft, y: d.documentElement.scrollTop};
10     //对怪异模式下的浏览器
11     return { x: d.body.scrollLeft, y: d.body.scrollTop};
12 }

  有时候能够判定视口的尺寸也是非常有用的,下面的代码简便地查询视口尺寸:

01 //作为一个对象的w和h属性返回视口的尺寸
02 function getViewportSize(w){
03     //使用指定的窗口, 如果不带参数则使用当前窗口
04     w = w || window;
05  
06     //除了IE8及更早的版本以外,其他浏览器都能用
07     if(w.innerWidth != null)
08         return {w: w.innerWidth, h: w.innerHeight};
09  
10     //对标准模式下的IE(或任意浏览器)
11     var d = w.document;
12     if(document.compatMode == "CSS1Compat")
13         return {w: d.documentElement.clientWidth, h: d.documentElement.clientHeight};
14  
15     //对怪异模式下的浏览器
16     return {w: d.body.clientWidth, h: d.body.clientHeight};
17 }

  上面的两个例子已经使用到scrollLeft、scrollTop、clientWidth、clientHeight。 scrollLeft和scrollTop获取滚动条位置,而clientWidth和clientHeight获取对象的尺寸。


  查询元素的几何尺寸


  判定一个元素的尺寸和位置最简单的方法是调用它的getBoundingClientRect()方法。该方法是在IE5中引入的,而现在当前的所有浏览器都实现了。它不需要参数,返回left、right、top、bottom属性的对象。

  这个方法返回元素在视口坐标中的位置。为了转换为甚至用户滚动浏览器窗口以后任然有效的文档坐标,需要加上滚动偏移量:

1 //元素相对于文档的坐标位置
2 function getElementRect(e){
3     var box = e.getBoundingClientRect();
4     var offsets = getScrollOffsets();
5     var x = box.left + offsets.x;
6     var y = box.top + offsets.y;
7  
8     return {x:x, y: y};
9 }

  在很多浏览器中,getBoundingClientRect()返回的对象还包括width和height属性。但在原始的IE中未实现。可以这样计算元素的width和height:

1 //元素尺寸
2 function getElementSize(e){
3     var box = getElementRect(e);
4     var w = box.width || box.right - box.left;
5     var h = box.height || box.bottom - box.top;
6  
7     return {w: w, h: h};
8 }

  滚动元素


  之前的getScrollOffsets方法可以查询滚动条的位置。该例子的scrollLeft和scrollTop属性可以用来设置让浏览器滚动,但有一种更简单的方法从Javascript最早时期开始支持的。Window对象的scrollTop()方法接口一个点的X和Y坐标(文档坐标),并作为滚动条的偏移量设置它们。下面代码滚动浏览器到文档最下面的页面可见:

1 //滚动到浏览器最底部
2 function scrollToBottom(){
3     //获取文档和视口的高度
4     var documentHeight = document.documentElement.offsetHeight;
5     var viewportHeight = window.innerHeight; //或使用上面的getViewPortSize()方法
6  
7     //然后,滚动让最后一页在视口中可见
8     window.scrollTo(0, documentHeight - viewportHeight);
9 }

  Window的scrollBy方法和scroll()和scrollTo()类似,但是它的参数是相对的,并在当前滚动条的偏移量上增加。例如,快速阅读者可能会喜欢这样:

1 javascript:void setInterval(function(){scrollBy(0, 10)}, 200);

  如果想让某个元素在文档中可见,可以利用getBoundingClientRect()计算元素的位置,并转换为文档坐标,然后使用scrollTo()方法达到目的。但在需要显示Html元素上调用scrollIntoView()方法更方便。

  scrollIntoView()的行为与设置window.location.hash为一个命名锚点的名字后浏览器产生的行为类似。


  元素尺寸、位置和溢出


  任何HTML元素的只读属性offsetWidth和offsetHeight以CSS像素返回它的屏幕尺寸。返回的尺寸包含元素的边框和内边距,除去了外边距。

  所有HTML元素拥有offsetLeft和offsetTop属性来返回元素的X和Y坐标。这些值是文档坐标,并直接指定元素的位置。当对于已定位元素的后代元素和一些其他元素,这些属性返回的坐标是相对于祖先元素的而非文档。

  offsetParent属性指定这些属性所相对的父元素。如果offsetParent为null,这些属性都是文档坐标,因此,一般来说,用offsetLeft和offsetTop来计算元素e的位置需要一个循环:

01 //计算元素位置
02 function getElementPosition(e){
03     var x = 0, y = 0;
04     while(e != null){
05         x += e.offsetLeft;
06         y += e.offsetTop;
07         e = e.offsetParent;
08     }
09  
10     return {x: x, y: y };
11 }

  getElementPosition函数也不总是计算正确的值,下面看如何修复它。除了这些名字以offset开头的属性以外,所有的文档元素定义了其他两组属性,名字一组以client开头,另一组以scroll开头。即每个元素都有以下这些属性:

offsetWidth

clientWidth scrollWidth
offsetHeight clientHeight crollHeight
offsetLeft clientLeft scrollLeft
offsetTop clientTop scrollTop
offsetParent    

  为了理解client和scroll属性,你需要知道元素的实际内容可能比分配用来容纳的盒子更大,因此单个元素可能有滚动条。内容区域是视口,就像浏览器窗口,当实际内容比视口大,需要把元素滚动套位置考虑进去。

  clientWidth和clientHeight类似offsetWidth和offsetHeight,区别在于它们不包含边框大小。只包含内容和内边距。同时,如果浏览器在内边距和边框之间添加了滚动条,clientWidth和clientHeight不包含滚动条尺寸。在文档的根元素上查询这些属性时,它们的返回值和窗口的innerWidth和innerHeight属性值相等。

  clientLeft和clientTop属性没什么用:它们返回元素的内边距的外边框和它的边框的外边缘之间的水平距离和垂直距离。

  scrollWidth和scrollHeight是元素的内容区域加上它的内边距再加上任何溢出内容的尺寸。当内容正好和内容区域匹配没溢出时,这些属性与clientWidth和clientHeight相等。有溢出时,包含了溢出的内容尺寸。

  scollLeft和scrollTop指定元素滚动条的位置。在getScrollOffsets()方法中查询过它们。注意,scrollLeft和scrollTop是可写的,通过设置它们来让元素中的内容滚动(HTML元素并没有类似Window对象的scrollTo()方法。


  DEMO


  下面代码介绍了前面几个函数的使用:

001 <!DOCTYPE html>
002 <html lang="en">
003     <head>
004         <meta charset="UTF-8">
005         <title>Title</title>
006         <script type="text/javascript">
007             //以一个对象的x和y属性放回滚动条的位置
008             function getScrollOffsets(w){
009                 w = w || window;
010                 //除了IE 8以及更早的版本以外,其他浏览器都支持
011                 if(w.pageXOffset != null) return {x: w.pageXOffset, y: w.pageYOffset};
012                 //对标准模式下的IE
013                 var d = w.document;
014                 if(document.compatMode == "CSS1Compat")
015                     return {x: d.documentElement.scrollLeft, y: d.documentElement.scrollTop};
016                 //对冠以模式下的浏览器
017                 return { x: d.body.scrollLeft, y: d.body.scrollTop};
018             }
019  
020             //作为一个对象的w和h属性返回视口的尺寸
021             function getViewportSize(w){
022                 //使用指定的窗口, 如果不带参数则使用当前窗口
023                 w = w || window;
024  
025                 //除了IE8及更早的版本以外,其他浏览器都能用
026                 if(w.innerWidth != null)
027                     return {w: w.innerWidth, h: w.innerHeight};
028  
029                 //对标准模式下的IE(或任意浏览器)
030                 var d = w.document;
031                 if(document.compatMode == "CSS1Compat")
032                     return {w: d.documentElement.clientWidth, h: d.documentElement.clientHeight};
033  
034                 //对怪异模式下的浏览器
035                 return {w: d.body.clientWidth, h: d.body.clientHeight};
036             }
037  
038             //元素相对于文档的坐标位置
039             function getElementRect(e){
040                 var box = e.getBoundingClientRect();
041                 var offsets = getScrollOffsets();
042                 var x = box.left + offsets.x;
043                 var y = box.top + offsets.y;
044  
045                 return {x:x, y: y};
046             }
047  
048             //元素尺寸
049             function getElementSize(e){
050                 var box = getElementRect(e);
051                 var w = box.width || box.right - box.left;
052                 var h = box.height || box.bottom - box.top;
053  
054                 return {w: w, h: h};
055             }
056  
057             //滚动到浏览器最底部
058             function scrollToBottom(){
059                 //获取文档和视口的高度
060                 var documentHeight = document.documentElement.offsetHeight;
061                 var viewportHeight = window.innerHeight; //或使用上面的getViewPortSize()方法
062  
063                 //然后,滚动让最后一页在视口中可见
064                 window.scrollTo(0, documentHeight - viewportHeight);
065             }
066  
067             //计算元素位置
068             function getElementPosition(e){
069                 var x = 0, y = 0;
070                 while(e != null){
071                     x += e.offsetLeft;
072                     y += e.offsetTop;
073                     e = e.offsetParent;
074                 }
075  
076             return {x: x, y: y };
077             }
078         </script>
079     </head>
080     <body>
081         <button id="scrolltoBottomBtn">滚动到浏览器</button>
082         <div style="height: 400px; background: red;">
083  
084         </div>
085         <button id="btn">获取滚动条位置</button>
086         <button id="viewportBtn">获取视口尺寸</button>
087         <button id="eleRectBtn">元素文档坐标</button>
088         <script type="text/javascript">
089             var btn = document.getElementById("btn");
090             btn.onclick = function(event){
091             console.log(getScrollOffsets());
092             }
093  
094             var viewportBtn = document.getElementById("viewportBtn");
095             viewportBtn.onclick = function(event){
096             console.log(getViewportSize());
097             }
098  
099             var eleRectBtn = document.getElementById("eleRectBtn");
100             eleRectBtn.onclick = function(eevent){
101             console.log(getElementRect(this));
102             }
103  
104             var scrolltoBottomBtn = document.getElementById("scrolltoBottomBtn");
105             scrolltoBottomBtn.onclick = function(){
106             scrollToBottom();
107             }
108         </script>
109     </body>
110 </html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花语者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值