CSS 的 position 屬性可以設定不同的值,代表元素的定位方式,如果沒有設定,大多數元素預設是 static,元素依序繪製在文件的流動版面。還可以設定的值有 relative、absolute、fixed 與 inherit。
元素的 top 表示距原點的垂直距離,正值為往下,left 表示距原點的水平距離,正值為往右。bottom 表示距原點的垂直距離,正值為往上,right 表示距原點的水平距離,正值為往左。
absolute 表示絕對定位,可以藉由設置元素 top、left 或 bottom、right 來定位,雖說名為 absolute,然而定位方式實際上是相對於元素的首個(最接近的)非 static 定位(非流動)父元素(absolute 的意義應該是指,元素不參與流動配置,瀏覽器就算改變大小,元素位置看起來都像是絕對位置,也就是不會隨著瀏覽器大小改變而流動變化)。
在絕對定位時,元素可以堆疊,此時可利用 z-index 來設定重疊順序,數值越大,表示可以堆壘在越上面,z-index 預設是頁面中標籤定義的順序,越後定義的標籤 z-index 越大。
下面這個範例運用了絕對定位、top、left 與 z-index 屬性,可以使用滑鼠點選改變 id 為 message1 的 <div> 的位置,可以按下某個 <div>,使之 z-index 提高,就範例的 HTML 本身來說,<div> 元素的第一個非流動父元素就是 <html>,因此絕對位置都是指相對於 <html> 文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<style type="text/css">
#message1 {
color: #ffffff;
background-color: #ff0000;
border-width: 10px;
border-color: black;
border-style: solid;
width: 100px;
height: 50px;
padding: 50px;
margin: 10px;
position: absolute;
top: 50px;
left: 50px;
z-index: 0;
}
#message2 {
color: #ffffff;
background-color: #ff0000;
border-width: 10px;
border-color: black;
border-style: solid;
width: 100px;
height: 50px;
padding: 50px;
margin: 10px;
position: absolute;
top: 150px;
left: 150px;
z-index: 0;
}
</style>
</head>
<body>
<div id="message1">這是訊息一</div>
<div id="message2">這是訊息二</div>
<script type="text/javascript">
let message1 = document.getElementById('message1');
let message2 = document.getElementById('message2');
document.onclick = function(evt) {
message1.style.left = `${evt.clientX}px`;
message1.style.top = `${evt.clientY}px`;
};
message1.onclick = function(evt) {
message1.style.zIndex = 1;
message2.style.zIndex = 0;
evt.stopPropagation();
};
message2.onclick = function(evt) {
message2.style.zIndex = 1;
message1.style.zIndex = 0;
evt.stopPropagation();
};
</script>
</body>
</html>
relative 是指元素基本上仍是流動方式,然而最後會依指定的相對值偏移,相對值是使用 top、left 或 bottom、right 設定。例如,若某元素本來流動方式擺放的位置為 100x50,若設定該元素的 position 為 relative,而 top、left 分別設為 20、30 的話,則元素最後的位置就是在 (100+20)x(50+30)= 120x80 的位置。
fixed 則是以瀏覽器視埠(view-port)為基準點。例如,想要讓某個元素在捲動後,依舊可以在可視畫面中的 100x50 的位置,則可以將 position 設為 fixed,此時 top、left 與 bottom、right 就是相對於可視畫面。
想使用 JavaScript 來取得元素的確實位置,必須知道 offsetParent 為何,offsetParent 並非元素的直接父節點,而是在元素的所有父階層中,第一個可用來作為位置參考的節點。
每個元素都可以取得 offsetTop、offsetLeft,分別代表距 offsetParent 外邊框左上角的距離,所以,在簡單的排版下,想要知道元素在版面中的確實位置,基本上可以如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<style type="text/css">
#container {
color: #ffffff;
background-color: #ff0000;
border-width: 10px;
border-color: black;
border-style: solid;
width: 100px;
height: 50px;
padding: 50px;
position: absolute;
top: 50px;
left: 50px;
}
#message {
position: static;
top: 20px;
left: 20px;
}
</style>
</head>
<body>
<div id="container"><span id="message">這是一段訊息<span></div>
<span id="console"></span>
<script type="text/javascript">
function offset(elem) {
let x = 0;
let y = 0;
while(elem) {
x += elem.offsetLeft;
y += elem.offsetTop;
elem = elem.offsetParent;
}
return {
x,
y,
toString() {
return `(${this.x}, ${this.y})`;
}
};
}
document.onclick = function(evt) {
let container = document.getElementById('container');
container.style.left = `${evt.clientX}px`
container.style.top = `${evt.clientY}px`;
let message = document.getElementById('message');
let console = document.getElementById('console');
console.innerHTML = offset(message);
};
</script>
</body>
</html>
一個需要元素確實位置的例子,就是像搜尋框中出現的提示,你需要知道搜尋框的位置,將傳回的關鍵字建議顯示在搜尋框下方。下面這個例子是個簡單示範:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<style type="text/css">
#container {
color: #ffffff;
background-color: #ff0000;
height: 50px;
position: absolute;
top: -100px;
left:-100px;
}
</style>
</head>
<body>
<div id="container">這是一段訊息</div>
<hr>
搜尋:<input id="search" type="text">
<script type="text/javascript">
function offset(elem) {
let x = 0;
let y = 0;
while(elem) {
x += elem.offsetLeft;
y += elem.offsetTop;
elem = elem.offsetParent;
}
return {
x,
y,
toString() {
return `(${this.x}, ${this.y})`;
}
};
}
let input = document.getElementById('search');
let search = offset(input);
let container = document.getElementById('container');
container.style.left = `${search.x}px`;
container.style.top = `${search.y + input.offsetHeight}px`;
container.style.width = `${input.offsetWidth}px`;
</script>
</body>
</html>
(如果想做搜尋框的自動提示清單,如果能使用 HTML5,透過 <datalist> 會更方便。)
在更複雜的排版下,取得元素精確位置所要考慮的事情會更複雜,例如,CSS 的 overflow 設定可建立捲軸,偏移量不會考慮捲軸位置,如果使用了 overflow 設定,必須再考慮捲軸值。例如:
function offset(elem) {
let x = 0;
let y = 0;
for(let e = elem; e; e = e.offsetParent) {
x += e.offsetLeft;
y += e.offsetTop;
}
// 修正捲軸區域的量
for(let e = elem.parentNode; e && e != document.body; e = e.parentNode) {
if(e.scrollLeft) {
x -= e.scrollLeft;
}
if(e.scrollTop) {
y -= e.scrollTop;
}
}
return {
x,
y,
toString() {
return `(${this.x}, ${this.y})`;
}
};
}

