在我們深入探討 JavaScript 處理樣式和類別的方法之前,有一個重要的規則。希望這已經很明顯,但我們還是必須提到。
一般來說,有兩種方式可以設定元素樣式
- 在 CSS 中建立一個類別並新增它:
<div class="...">
- 直接在
style
中撰寫屬性:<div style="...">
。
JavaScript 可以修改類別和 style
屬性。
我們應該永遠優先使用 CSS 類別,而不是 style
。後者只應在類別「無法處理」的情況下使用。
例如,如果我們動態計算元素的座標並希望從 JavaScript 設定它們,則 style
是可以接受的,如下所示
let top = /* complex calculations */;
let left = /* complex calculations */;
elem.style.left = left; // e.g '123px', calculated at run-time
elem.style.top = top; // e.g '456px'
對於其他情況,例如將文字設為紅色、新增背景圖示,請在 CSS 中描述,然後新增類別(JavaScript 可以做到)。這樣更靈活且更容易支援。
className 和 classList
變更類別是腳本中最常使用的動作之一。
在遠古時代,JavaScript 有個限制:保留字例如 "class"
無法作為物件屬性。現在這個限制已經不存在了,但當時無法擁有 "class"
屬性,例如 elem.class
。
因此,對於 class 而言,引入了外觀相似的屬性 "className"
:elem.className
對應於 "class"
屬性。
例如
<body class="main page">
<script>
alert(document.body.className); // main page
</script>
</body>
如果我們將某個東西指定給 elem.className
,它會取代整個 class 字串。有時我們需要這樣做,但通常我們只想新增/移除單一 class。
針對這個需求,還有另一個屬性:elem.classList
。
elem.classList
是個特殊物件,具有方法來 新增/移除/切換
單一 class。
例如
<body class="main page">
<script>
// add a class
document.body.classList.add('article');
alert(document.body.className); // main page article
</script>
</body>
因此,我們可以使用 className
操作完整的 class 字串,或使用 classList
操作個別 class。我們的選擇取決於需求。
classList
的方法
elem.classList.add/remove("class")
– 新增/移除 class。elem.classList.toggle("class")
– 如果 class 不存在,則新增;否則移除。elem.classList.contains("class")
– 檢查指定的 class 是否存在,傳回true/false
。
此外,classList
是可迭代的,因此我們可以使用 for..of
列出所有 class,如下所示
<body class="main page">
<script>
for (let name of document.body.classList) {
alert(name); // main, and then page
}
</script>
</body>
元素樣式
elem.style
屬性是一個物件,對應於 "style"
屬性中所寫的內容。設定 elem.style.width="100px"
的作用與在 style
屬性中使用字串 width:100px
相同。
對於多字元屬性,使用駝峰式大小寫
background-color => elem.style.backgroundColor
z-index => elem.style.zIndex
border-left-width => elem.style.borderLeftWidth
例如
document.body.style.backgroundColor = prompt('background color?', 'green');
瀏覽器前綴屬性,例如 -moz-border-radius
、-webkit-border-radius
也遵循相同的規則:連字號表示大寫。
例如
button.style.MozBorderRadius = '5px';
button.style.WebkitBorderRadius = '5px';
重設樣式屬性
有時我們想要指定樣式屬性,然後稍後移除它。
例如,要隱藏元素,我們可以設定 elem.style.display = "none"
。
然後,我們可能想要移除 style.display
,就像它未設定一樣。我們不應該使用 delete elem.style.display
,而應該指定一個空字串給它:elem.style.display = ""
。
// if we run this code, the <body> will blink
document.body.style.display = "none"; // hide
setTimeout(() => document.body.style.display = "", 1000); // back to normal
如果我們將 style.display
設定為空字串,瀏覽器會套用 CSS class 和其內建樣式,就像根本沒有 style.display
屬性一樣。
另外,有一個特殊方法可以做到這一點,elem.style.removeProperty('style property')
。因此,我們可以像這樣移除屬性
document.body.style.background = 'red'; //set background to red
setTimeout(() => document.body.style.removeProperty('background'), 1000); // remove background after 1 second
style.cssText
完整重寫通常,我們使用 style.*
來指定個別樣式屬性。我們無法設定完整樣式,例如 div.style="color: red; width: 100px"
,因為 div.style
是物件,而且是唯讀的。
若要將完整樣式設定為字串,有一個特殊屬性 style.cssText
<div id="div">Button</div>
<script>
// we can set special style flags like "important" here
div.style.cssText=`color: red !important;
background-color: yellow;
width: 100px;
text-align: center;
`;
alert(div.style.cssText);
</script>
此屬性很少使用,因為此類指定會移除所有現有樣式:它不會新增,而是取代樣式。偶爾可能會刪除某些必要的內容。但是,當我們知道不會刪除現有樣式時,可以安全地將其用於新元素。
也可以透過設定屬性來達成相同效果:div.setAttribute('style', 'color: red...')
。
注意單位
別忘了在數值中加入 CSS 單位。
例如,我們不應將 elem.style.top
設定為 10
,而應設定為 10px
。否則它將無法運作
<body>
<script>
// doesn't work!
document.body.style.margin = 20;
alert(document.body.style.margin); // '' (empty string, the assignment is ignored)
// now add the CSS unit (px) - and it works
document.body.style.margin = '20px';
alert(document.body.style.margin); // 20px
alert(document.body.style.marginTop); // 20px
alert(document.body.style.marginLeft); // 20px
</script>
</body>
請注意:瀏覽器會在最後幾行「解開」屬性 style.margin
,並從中推斷出 style.marginLeft
和 style.marginTop
。
計算樣式:getComputedStyle
因此,修改樣式很簡單。但是如何讀取樣式?
例如,我們想要知道元素的大小、外框和顏色。如何執行此操作?
style
屬性僅作用於 "style"
屬性的值,不包含任何 CSS 層疊。
因此,我們無法使用 elem.style
讀取來自 CSS 類別的任何內容。
例如,這裡的 style
沒有看到外框
<head>
<style> body { color: red; margin: 5px } </style>
</head>
<body>
The red text
<script>
alert(document.body.style.color); // empty
alert(document.body.style.marginTop); // empty
</script>
</body>
…但是如果我們需要,例如將外框增加 20px
,該怎麼辦?我們需要它的目前值。
有一個方法可以做到這一點:getComputedStyle
。
語法為
getComputedStyle(element, [pseudo])
- 元素
- 要讀取其值的元素。
- 偽元素
- 如果需要,請使用偽元素,例如
::before
。空字串或沒有參數表示元素本身。
結果是一個包含樣式的物件,例如 elem.style
,但現在包含所有 CSS 類別。
例如
<head>
<style> body { color: red; margin: 5px } </style>
</head>
<body>
<script>
let computedStyle = getComputedStyle(document.body);
// now we can read the margin and the color from it
alert( computedStyle.marginTop ); // 5px
alert( computedStyle.color ); // rgb(255, 0, 0)
</script>
</body>
在 CSS 中有兩個概念
- 計算的樣式值是在套用所有 CSS 規則和 CSS 繼承後的值,也就是 CSS 層疊的結果。它可能看起來像
height:1em
或font-size:125%
。 - 解析的樣式值是最終套用於元素的值。
1em
或125%
等值是相對的。瀏覽器會取得計算值,並將所有單位設定為固定值和絕對值,例如:height:20px
或font-size:16px
。對於幾何屬性,解析值可能有浮點數,例如width:50.5px
。
很久以前,getComputedStyle
是用來取得計算值的,但後來發現解析值更方便,因此標準就變更了。
因此,現在 getComputedStyle
實際上會傳回屬性的已解析值,通常以幾何 px
為單位。
getComputedStyle
需要完整的屬性名稱我們應始終要求我們想要的確切屬性,例如 paddingLeft
、marginTop
或 borderTopWidth
。否則,無法保證正確的結果。
例如,如果存在屬性 paddingLeft/paddingTop
,那麼我們應該如何取得 getComputedStyle(elem).padding
?什麼都沒有,或者可能從已知的內距取得「已產生的」值?這裡沒有標準規則。
:visited
連結的樣式已隱藏!已造訪的連結可以使用 :visited
CSS 偽類別進行著色。
但是 getComputedStyle
無法存取該顏色,因為否則任意頁面都可以透過在頁面上建立連結並檢查樣式,找出使用者是否造訪過連結。
JavaScript 可能無法看到 :visited
套用的樣式。此外,CSS 中有一個限制,禁止在 :visited
中套用會變更幾何的樣式。這是為了保證邪惡頁面沒有任何側門方式可以測試連結是否已造訪,進而破壞隱私。
摘要
若要管理類別,有兩個 DOM 屬性
className
– 字串值,適合管理整組類別。classList
– 物件,具有方法add/remove/toggle/contains
,適合個別類別。
若要變更樣式
-
style
屬性是一個具有駝峰式大小寫樣式的物件。讀取和寫入它與修改"style"
屬性中的個別屬性具有相同的意義。若要查看如何套用important
和其他罕見項目,請參閱 MDN 上的方法清單。 -
style.cssText
屬性對應於整個"style"
屬性,也就是完整的樣式字串。
若要讀取已解析的樣式(相對於所有類別,在套用所有 CSS 並計算最終值之後)
getComputedStyle(elem, [pseudo])
會傳回具有這些樣式的樣式類似物件。唯讀。
留言
<code>
標籤,若要插入多行,請將其包覆在<pre>
標籤中,若要插入 10 行以上,請使用沙盒 (plnkr、jsbin、codepen…)