存取樣式資訊
September 26, 2022在 HTML 標籤上,可以設定 style
屬性,藉以改變元素的樣式。例如:
<div style="color: #ffffff; background-color: #ff0000; width: 500px; height: 200px; padding-left: 250px; padding-top: 150px;">這是一段訊息</div>
可以直接使用 JavaScript 設定 style
特性上的各個特性來達到相同效果。例如:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div id="message">這是一段訊息</div>
<script type="text/javascript">
let message = document.getElementById('message');
message.style.color = '#ffffff';
message.style.backgroundColor = '#ff0000';
message.style.width = '500px';
message.style.height = '200px';
message.style.paddingLeft = '250px';
message.style.paddingTop = '150px';
</script>
</body>
</html>
屬性/特性/樣式表
style
特性參考的是 CSSProperties
物件,注意特性名稱的大小寫,通常是沒有破折線、採駝峰式命名。一般不會或不建議使用標籤的 style
屬性來設定樣式,而是定義在樣式表中。例如:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<style type="text/css">
#message {
color: #ffffff;
background-color: #ff0000;
width: 500px;
height: 200px;
padding-left: 250px;
padding-top: 150px;
}
</style>
</head>
<body>
<div id="message">這是一段訊息</div>
</body>
</html>
然而在這種情況下,無法使用 style
特性來取得樣式表中定義的各個樣式資訊,因為元素的 style
特性是對應於標籤的 style
屬性,標籤若沒有定義 style
屬性,或程式中沒有設定 style
的特性,就無法使用 style
特性來取得樣式資訊。
標籤的 style
屬性或透過元素的 style
特性會覆蓋樣式表的設定,由於一般並不建議直接於標籤上設定 style
屬性,因此透過程式時,通常建議將 style
特性用於設定樣式,而不是取得樣式。
如果標籤沒有設定 style
屬性,而想要取得元素上套用的樣式資訊,則必須取得元素的計算樣式(Computed style),計算樣式是指所有樣式規則(包括樣式表、style
屬性)已套用至元素後的樣式結果。
若是在標準瀏覽器中,可以使用 window
的 getComputedStyle
函式(與 document.defaultView.getComputedStyle
是相同函式),取得的樣式物件是唯讀的 CSS2Properties
物件,可以直接如同使用 style
特性,直接於上指定特性來取得樣式資訊,或是使用 getPropertyValue
方法指定 CSS 屬性。
getComputedStyle
的第二個引數可指定虛擬類別(pseudo-class),如果不設定的話,也必須指定 null
,例如:
window.getComputedStyle(elem, null)[prop];
來使用程式取得上一個範例網頁的 CSS 樣式設定:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<style type="text/css">
#message {
color: #ffffff;
background-color: #ff0000;
width: 500px;
height: 200px;
padding-left: 250px;
padding-top: 150px;
}
</style>
</head>
<body>
<div id="message">這是一段訊息</div>
<span id="console"></span>
<script type="text/javascript">
function style(elem, prop) {
return window.getComputedStyle(elem, null)[prop];
}
let message = document.getElementById('message');
let color = style(message, 'backgroundColor');
document.getElementById('console').innerHTML = color;
</script>
</body>
</html>
元素寬高/大小
可以透過樣式的 width
與 height
來設定元素的寬高,但要注意所謂的寬高定義為何,一個元素的寬高如何定義,要看盒模式(Box model),也就是將元素當作一個盒子來看待,每個元素都會有四個部份可以設定。
內容(content)就是放置元素真正有內容的部份,像是一段文字、一個圖片或者是其它子元素。每個元素都可以有邊框(border)。內距(padding)是指內容區與邊框的距離。邊距(margin)則是指與另一元素的邊框距離。內容可以設定寬、高,內距的上、下、左、右可以分別設定距離,邊框可以設定寬度,而邊距的上、下、左、右可以分別設採定距離。
當指定元素的 width
與 height
時,在標準 CSS 盒模型,指定的 width
、height
僅指定內容區大小。
在遵守標準的瀏覽器中,就是採取這種盒模型。例如下面這個範例:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<style type="text/css">
img {
color: #ffffff;
background-color: #ff0000;
border-width: 10px;
border-color: black;
border-style: solid;
width: 100px;
height: 82px;
padding: 50px;
margin: 10px;
}
div {
color: #ffffff;
background-color: #ff0000;
border-width: 10px;
border-color: black;
border-style: solid;
text-align: center;
width: 100px;
height: 82px;
padding: 50px;
margin: 10px;
}
</style>
</head>
<body>
<img src="https://openhome.cc/Gossip/images/caterpillar_small.jpg">
<div>內容</div>
</body>
</html>
範例中的圖就是內容區,寬、高為 100x82,加上內距 50px 與邊框 10px,元素視覺上看得到的部份為 (100+502+102)x(82+502+102),也就是 220x202。下方了一個內容區寬、高,內距與邊框相同的 <div>
以資對照。
每個元素都會有 offsetWidth
與 offsetHeight
特性,這兩個特性是唯讀的,可分別取得元素的寬與高,在標準 CSS 盒模型下,所取得的是邊框、內距與內容區的加總大小:
元素位置
樣式的 position
屬性可以設定不同的值,代表元素的定位方式,如果沒有設定,大多數元素預設是 static
,元素依序、流動式地繪製版面上,其他常用的設定值有 relative
、absolute
與 fixed
。
元素的 top
特性表示元素上緣,與參考元素上緣的垂直距離,正值為往下,left
表示元素左緣與參考元素左緣的水平距離,正值為往右。bottom
表示下緣與參考元素的下緣垂直距離,正值為往上,right
表示元素右緣與參考元素的右緣水平距離,正值為往左;這些特性都包含含邊距,而設定後的效果,必須視 position
是哪個而定,例如,設為 static
時,top
、left
、right
、bottom
的設置沒有作用。
relative
是指元素相對於static應有的位置進行偏移,也就是依序、流動式地繪製版面之後,依 top
、left
或 bottom
、right
設定偏移。例如,若元素左上位置,在本來流動式地繪製後 100x50,若設定元素的 position
為 relative
,而 top
、left
分別為 20、30 的話,元素最後的左上角位置會是 (100+20)x(50+30)=120x80 的位置。
position
屬性設為 absolute
表示絕對定位,不過這個絕對,並不是以 body
左上角為絕對參考點,而是以最接近的非 static
父元素為絕對定位參考元素,也就是說,若有個 a
是 relative
定位,其中有個 span
是 absolute
定位,那麼 span
設定的 top
、left
,會是以 a
元素的上緣與左緣來進行絕對定位。
在絕對定位時,元素可以堆疊,此時可利用 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>
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
標籤會更方便。
在更複雜的排版下,取得元素精確位置所要考慮的事情會更複雜,例如,樣式表的 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})`;
}
};
}