JavaScript與CSS — 元素的位置和各種座標系
使用位置、尺寸和可見性基本就可以在現代瀏覽器中模擬絕大多數常見的使用者效果了。元素的位置是實現互動效果的基礎。在CSS中,元素使用偏移量來定位,它是通過元素到它父元素的左上角的偏移量來計算。CSS的座標系如下圖
<html>
<head>
<style>
p {
border: 3px solid red;
padding: 10px;
width: 400px;
background: #FFF;
}
p.odd {
/* 定位資訊 */
position: static;
top: 0px;
left: 0px;
}
</style>
</head>
<body>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Etiam ...</p>
<p class='odd'>Phasellus dictum dignissim justo. Duis nec risus id nunc ...</p>
<p>Sed vel leo. Nulla iaculis, tortor non laoreet dictum, turpis diam ...</p>
</body>
</html>
通過對第二個段落的定位,分析一下CSS的定位方式。
□ 靜態定位:這是預設方式。它遵循文件的普通流動(flow)。當靜態定位中,top和left屬性無效。下圖的定位程式碼是 position:static; top:0px; left:0px; 的效果:
□ 相對定位:和靜態定位類似,同樣遵循文件的普通流動。如果設定了top和left屬性則會產生相應的偏移。下圖的定位程式碼是:position:relative; top:-50px; left:50px;
□ 絕對定位:絕對定位會使元素完全跳出頁面佈局的普通流動,會相對於它的第一個非靜態定位的祖先元素而定位。如果沒有這樣的祖先元素,則相對於整個文件。下圖的定位程式碼是:position:absolute; top:20px; left:0px;
□ 固定定位:固定定位相對於瀏覽器視窗而定位。設定top和left為0會使它在瀏覽器的左上角顯示,而且不受滾動條的影響。下圖的定位程式碼是:position:fixed; top:20px; right:0px;
元素的位置取決於CSS設定,同時又受其它因素的影響。所以單純的訪問CSS屬性並不能獲取元素的精確位置。為了獲取元素相對於頁面的位置,有一些CSS屬性可以利用,在現代瀏覽器中都支援以下3個屬性:
□ offsetParent : 理論上,這是元素的父元素,元素相對於它定位
□ offsetLeft 和 offfsetTop : 在 offsetParent 環境中的水平和垂直偏移量
為了獲取元素相對於頁面的精確位置,可以遍歷DOM,使用offsetParent屬性並累加它們的偏移量來計算元素的位置。下面是連個確定元素相對於整個文件的x和y位置的輔助函式:
// 獲取元素的水平位置
function pageX(elem) {
var p = 0;
// 累加每一個父元素的偏移量
while ( elem.offsetParent ) {
// 增加偏移量
p += elem.offsetLeft;
// 遍歷下一個父元素
elem = elem.offsetParent;
}
return p;
}
// 獲取元素的垂直位置
function pageY(elem) {
var p = 0;
// 累加每一個父元素的偏移量
while ( elem.offsetParent ) {
// 增加偏移量
p += elem.offsetTop;
// 遍歷下一個父元素
elem = elem.offsetParent;
}
return p;
}
接下來是獲取元素相對於它的父元素的水品和垂直位置。簡單地使用 style.left 或 style.top 並不夠,因為需要處理的元素可能尚未經過JavaScript或CSS的格式化。要找到元素相對於它的父元素的位置,可以利用offsetParent屬性,但該屬性並不保證能夠反追指定元素的真實父元素,所以還需要使用前面的pageX和pageY函式來計算父元素和子元素之間的差。在下面的函式中,如果是當前元素的父元素,則使用offsetParent;否則繼續遍歷DOM,使用pageX和pageY函式來確定它的真實位置。
// 獲取相對於父元素的水平位置
function parentX(elem) {
// 如果 offsetParent 是元素的父元素,則返回
return elem.parentNode == elem.offsetParent ?
elem.offsetLeft :
// 否則計算元素和其父元素的水平差值
pageX( elem ) - pageX( elem.parentNode );
}
// 獲取相對於父元素的垂直位置
function parentY(elem) {
// 如果 offsetParent 是元素的父元素,則返回
return elem.parentNode == elem.offsetParent ?
elem.offsetTop :
// 否則計算元素和其父元素的水平差值
pageY( elem ) - pageY( elem.parentNode );
}
最後是獲取元素相對於它的CSS容器的位置。在CSS定位方式的討論中我麼知道,即使元素包含在另一個元素內,它也可以相對於其他的父元素定位(使用相對和絕對定位)。這種情形可以使用getStyle函式得到CSS偏移的最終值,這等於元素的位置值。
// 左側位置
function posX(elem) {
// 獲取樣式並得到數值
return parseInt( getStyle( elem, "left" ) );
}
// 頂端位置
function posY(elem) {
// 獲取樣式並得到數值
return parseInt( getStyle( elem, "top" ) );
}
設定位置
調整元素位置的唯一方法就是修改它的CSS屬性,僅需要修改left和top屬性即可(儘管還有right和bottom屬性)。這樣就可以設定元素的位置,不管元素的當前位置在哪兒裡。
// 設定元素的水平位置
function setX(elem, pos) {
// 設定CSS的 'left' 屬性
elem.style.left = pos + "px";
}
// 設定元素的垂直位置
function setY(elem, pos) {
// 設定CSS的 'top' 屬性
elem.style.top = pos + "px";
}
最後,實現一對函式用來增加相對於當前位置的偏移量。利用這個函式可以調整元素的位置向上偏移5畫素,從而實現各種動畫效果。
// 增加水平偏移量
function addX(elem,pos) {
setX( posX(elem) + pos );
}
// 增加垂直偏移量
function addY(elem,pos) {
setY( posY(elem) + pos );
}
===============================================座標系文一=================================
在JavaScript中有三種不同的座標系:螢幕座標,視窗(viewport)座標和文件(document)座標。其中要注意的是文件座標和視窗座標的關係。視窗座標的原點是其視口的作上角,由於視窗具有滾動條,文件的座標原點可能會滾動到視窗以外,這時要注意兩者的關係。在程式碼的書寫過程中要注意的是JavaScript的AIP返回的值是基於什麼座標系的。在利用javaScript來操縱css
style的時候中的時候absolute的座標是相對於document座標系的。
以下是一些常見的座標問題
1.document中elemenet的位置和大小
每個element都有四個屬性:offsetleft,offsetTop,OffsetHeight,offsetWidth,這四個屬性分別代表的是element的左上角和高寬。
最初是由IE4引入的,後來也得到了其他瀏覽器的支援。但是這些屬性值相對於該element的offsetParent的座標.在<html>檔案中中<body>的offsetParent為null,因此要得到一個elment的座標的正確方法是
getElementX(e)
{
var x=0;
while(e)
{
x+=e.offsetLeft;
e=e.offsetParent;
}
return x;
}
這個方法的返回值是相對於document的座標的,它不會受到視窗是否滾動的影響。
但是這種方法還有一個小問題,那就是一個element通過設定它的css屬性overflow可以擁有自身的滾動條,這時以這種方法得到的只是不正確的。這時正確的方法如下
function getY(element)
{
// Iterate the offsetParents
// Add up offsetTop values
var y = 0;
for(var e = element; e; e = e.offsetParent)
y += e.offsetTop;
// any that have scrollTop set. Subtract these scrolling values from
// the total offset. However, we must be sure to stop the loop before
// we reach document.body, or we'll take document scrolling into account
// and end up converting our offset to window coordinates. for(e = element.parentNode; e && e != document.body; e = e.parentNode)
// subtract scrollbar values
if (e.scrollTop) y -= e.scrollTop; // This is the Y coordinate with document-internal scrolling accounted for.
return y;
} 2.滑鼠事件中的座標問題
在DOM2的時間模型中的MouseEvent物件和IE的時間模型中的Event物件都有一對屬性clinetX和clientY屬性,它們表明的是滑鼠事件發生時滑鼠在viewport座標中的位置,他們都沒有考慮doucument的滾動。如果要得到docuemnt做座標系下的位置,則應加上windows.pageOffsetX和windows.pageOffsetY的值.
====================================座標系文二========================================
Window Geometry
視窗幾何關係
Screen座標系是描述瀏覽器視窗和桌面之間的幾何關係的,其座標是相對於桌面左上角的。
引用 Window coordinates describe a position within the web browser's viewport; they are measured relative to the upper-left corner of the viewport.
Window座標系描述了瀏覽器頁面可視區域的幾何關係,其座標是相對於可視區域的左上角。
引用 Document coordinates describe a position within an HTML document; they are measured relative to the upper-left corner of the document. When the document is longer or wider than the viewport (as web pages often are), document coordinates and window coordinates are not the same, and you'll need to take the position of the scrollbars into account when converting between these two coordinate systems.
Document座標系描述了HTML元素與document文件的幾何關係,其座標是相對於document物件的左上角的。
當document足夠長而產生滾動條,document座標系和window座標系就會產生差異,兩個座標系之間就要考慮轉換的方法。
引用 For some reason, IE places these window geometry properties on the <body> of the HTML document. And, further confusing matters, IE 6, when displaying a document with a <!DOCTYPE> declaration, places the properties on the document.documentElement element instead of document.body.
IE在預設狀態下將這些相關屬性放在document.body下,但如果有<!DOCTYPE>宣告,那麼就會放在document.documentElement下。
瀏覽器 | window物件座標大小 | 可視區域大小 | 滾動條 | document物件座標大小 |
FF | screenX/Y | innerWidth/Height | pageXOffset/YOffset | documentElement.scrollLeft/Top |
IE with doctype | screenLeft/Top | documentElement.clientWidth | documentElement.scrollLeft/Top/Height | documentElement.scrollLeft/Top |
以下是一個獲取幾何引數的函式
Js程式碼
- /**
- * Geometry.js: portable functions for querying window and document geometry
- *
- * This module defines functions for querying window and document geometry.
- *
- * getWindowX/Y( ): return the position of the window on the screen
- * getViewportWidth/Height( ): return the size of the browser viewport area
- * getDocumentWidth/Height( ): return the size of the document
- * getHorizontalScroll( ): return the position of the horizontal scrollbar
- * getVerticalScroll( ): return the position of the vertical scrollbar
- *
- * Note that there is no portable way to query the overall size of the
- * browser window, so there are no getWindowWidth/Height( ) functions.
- *
- * IMPORTANT: This module must be included in the <body> of a document
- * instead of the <head> of the document.
- */
- var Geometry = {};
- if (window.screenLeft) { // IE and others
- Geometry.getWindowX = function( ) { return window.screenLeft; };
- Geometry.getWindowY = function( ) { return window.screenTop; };
- }
- else if (window.screenX) { // Firefox and others
- Geometry.getWindowX = function( ) { return window.screenX; };
- Geometry.getWindowY = function( ) { return window.screenY; };
- }
- if (window.innerWidth) { // All browsers but IE
- Geometry.getViewportWidth = function( ) { return window.innerWidth; };
- Geometry.getViewportHeight = function( ) { return window.innerHeight; };
- Geometry.getHorizontalScroll = function( ) { return window.pageXOffset; };
- Geometry.getVerticalScroll = function( ) { return window.pageYOffset; };
- }
- else if (document.documentElement && document.documentElement.clientWidth) {
- // These functions are for IE 6 when there is a DOCTYPE
- Geometry.getViewportWidth =
- function( ) { return document.documentElement.clientWidth; };
- Geometry.getViewportHeight =