在我们了解 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
。
因此,对于类,引入了类似的属性"className"
:elem.className
对应于"class"
属性。
例如
<body class="main page">
<script>
alert(document.body.className); // main page
</script>
</body>
如果我们将某些内容分配给elem.className
,它将替换整个类字符串。有时这就是我们需要的,但通常我们希望添加/删除单个类。
为此,还有另一个属性:elem.classList
。
elem.classList
是一个特殊对象,具有add/remove/toggle
单个类的的方法。
例如
<body class="main page">
<script>
// add a class
document.body.classList.add('article');
alert(document.body.className); // main page article
</script>
</body>
因此,我们可以使用className
对完整的类字符串进行操作,也可以使用classList
对各个类进行操作。我们选择什么取决于我们的需求。
classList
的方法
elem.classList.add/remove("class")
——添加/删除该类。elem.classList.toggle("class")
——如果该类不存在,则添加该类,否则将其删除。elem.classList.contains("class")
——检查给定的类,返回true/false
。
此外,classList
是可迭代的,因此我们可以使用for..of
列出所有类,如下所示
<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 类及其内置样式,就像根本没有 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])
- 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…)