2022 年 9 月 29 日

样式和类

在我们了解 JavaScript 处理样式和类的方式之前,这里有一个重要的规则。希望它足够明显,但我们仍然必须提及它。

通常有两种方法可以设置元素的样式

  1. 在 CSS 中创建一个类并添加它:<div class="...">
  2. 直接将属性写入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.marginLeftstyle.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 中有两个概念

  1. 计算样式值是在应用所有 CSS 规则和 CSS 继承后,作为 CSS 级联结果的值。它可能看起来像 height:1emfont-size:125%
  2. 已解决样式值是最终应用于元素的值。1em125% 等值是相对的。浏览器获取计算值并将所有单位固定为绝对值,例如:height:20pxfont-size:16px。对于几何属性,已解决值可能带有浮点数,例如 width:50.5px

很久以前,getComputedStyle 被创建来获取计算值,但事实证明已解决值更方便,因此标准发生了改变。

所以现在 getComputedStyle 实际上返回属性的已解决值,通常以 px 为几何单位。

getComputedStyle 需要完整的属性名称

我们应该始终询问我们想要的准确属性,例如 paddingLeftmarginTopborderTopWidth。否则无法保证正确的结果。

例如,如果存在属性 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]) 返回具有它们的样式对象。只读。

任务

重要性:5

编写一个函数 showNotification(options),该函数创建一个通知:<div class="notification">,其中包含给定的内容。通知应在 1.5 秒后自动消失。

选项为

// shows an element with the text "Hello" near the right-top of the window
showNotification({
  top: 10, // 10px from the top of the window (by default 0px)
  right: 10, // 10px from the right edge of the window (by default 0px)
  html: "Hello!", // the HTML of notification
  className: "welcome" // an additional class for the div (optional)
});

在新窗口中演示

使用 CSS 定位在给定的顶部/右侧坐标处显示元素。源文档具有必要的样式。

为任务打开沙箱。

教程地图

评论

在评论之前先阅读此内容…
  • 如果您有改进建议,请 提交 GitHub 问题 或提交拉取请求,而不是发表评论。
  • 如果您无法理解文章中的某些内容,请详细说明。
  • 要插入几行代码,请使用 <code> 标记,对于多行,请将其包装在 <pre> 标记中,对于 10 行以上的代码,请使用沙箱(plnkrjsbincodepen…)