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})`;
}
};
}