☰
Styling DOM Elements in JavaScript: className, classList, style, and getComputedStyle
2026/10/7 15:13:07 网站建设 项目流程
  • 文档/教程
  • 前端

【免费下载链接】en.javascript.info

Modern JavaScript Tutorial

项目地址:https://gitcode.com/gh_mirrors/en/en.javascript.info
点击查看免费下载

在 Modern JavaScript Tutorial(本仓库的2-ui/1-document章节)中,Styles and classes一课系统讲解了 JavaScript 操作元素样式与 CSS 类的全部手段。读完本文,你将掌握四条核心能力:用className整体替换类名、用classList精确增删切换单个类、通过style对象与style.cssText写入内联样式,以及用getComputedStyle读取 CSS 级联之后的最终计算值。本文还会结合仓库中随章节附带的"创建通知(Create a notification)"实战任务(任务说明)给出完整可运行的代码示例。

样式操作的第一原则:优先用 CSS 类,而不是 style

在深入 JavaScript 的样式 API 之前,先记住一条贯穿始终的重要规则:Web 中有两种给元素加样式的方式——

  1. 在 CSS 中定义一个类,然后把类加到元素上:<div class="...">;
  2. 直接把样式属性写进style属性:<div style="...">。

JavaScript 可以同时修改类与style属性,但我们应当始终优先使用 CSS 类,style只应在"类搞不定"的场景下使用。

最典型的合理场景是动态计算坐标:例如运行时算出了元素的位置,需要从 JavaScript 直接写入:

let top = /* 复杂计算 */; let left = /* 复杂计算 */; elem.style.left = left; // 例如 '123px',运行时计算得出 elem.style.top = top; // 例如 '456px'

而像"把文字变红""加一个背景图标"这类静态外观需求,应当写进 CSS,再通过 JavaScript 添加对应的类。这样更灵活、更易于维护——样式与逻辑分离,改外观时不需要动 JS 代码。

className:操作完整的类名字符串

改类是脚本中最常见的操作之一。这里有一段历史背景:早期 JavaScript 中存在一个限制,保留字(如"class")不能作为对象属性名。虽然这个限制如今已不存在,但在当时无法使用elem.class这样的写法。于是引入了外观相近的className:elem.className与 HTML 的"class"属性一一对应。

<body class="main page"> <script> alert(document.body.className); // main page </script> </body>

注意:给elem.className赋值会整体替换整个类名字符串。有些场景这正是我们想要的,但更多时候我们只想增删某一个类。此时应该使用另一个属性classList。

classList:精确操作单个类

elem.classList是一个特殊对象,提供add/remove/toggle等操作单个类的方法:

<body class="main page"> <script> // 添加一个类 document.body.classList.add('article'); alert(document.body.className); // main page article </script> </body>

classList的方法清单:

  • elem.classList.add("class")/elem.classList.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,再弹出 page } </script> </body>

因此实践中的选择标准很清晰:需要整体管理类的集合时用className,需要增删单个类时用classList。

elem.style:对应 style 属性的内联样式对象

elem.style是一个对象,与"style"属性中写入的内容一一对应。elem.style.width = "100px"等价于在style属性里写上width:100px。

对于多词属性名,JavaScript 中使用驼峰命名(camelCase):

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';

重置样式属性:赋空字符串或 removeProperty

有时我们设置了一个样式属性,稍后又想把它移除。例如要隐藏元素可以设置elem.style.display = "none",之后想恢复原状,不能写delete elem.style.display,而应赋空字符串:

// 如果运行这段代码,<body> 会闪烁一下 document.body.style.display = "none"; // 隐藏 setTimeout(() => document.body.style.display = "", 1000); // 恢复正常

把style.display设为空字符串后,浏览器会像从未设置过该属性一样,正常应用 CSS 类与内置样式。

还有一个专门的方法elem.style.removeProperty('style property'):

document.body.style.background = 'red'; // 把背景设为红色 setTimeout(() => document.body.style.removeProperty('background'), 1000); // 1 秒后移除背景

整体重写:style.cssText

通常我们用style.*逐个赋值属性。我们不能直接写div.style = "color: red; width: 100px",因为div.style是对象且只读。要整体写入一串样式字符串,需要使用特殊属性style.cssText:

<div id="div">Button</div> <script> // 这里甚至可以设置 !important 这样的特殊标记 div.style.cssText=`color: red !important; background-color: yellow; width: 100px; text-align: center; `; alert(div.style.cssText); </script>

需要注意:cssText的赋值是整体替换而非追加,会清除所有已有内联样式,偶尔会误删我们需要保留的属性。所以它只适合用于"确定不会破坏现有样式"的场景,例如给新建元素一次性初始化全部样式。同样的效果也可以通过设置属性实现:div.setAttribute('style', 'color: red...')。

别忘加单位

给样式属性赋值时,不要忘记添加 CSS 单位。例如不能把elem.style.top设为10,而应设为10px,否则赋值会被忽略:

<body> <script> // 不生效! document.body.style.margin = 20; alert(document.body.style.margin); // '' (空字符串,赋值被忽略) // 加上 CSS 单位 px 之后才生效 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 级联(cascade)。

也就是说,用elem.style读不到任何来自 CSS 类的样式。下面的例子中,style就读不到 CSS 定义的 margin:

<head> <style> body { color: red; margin: 5px } </style> </head> <body> The red text <script> alert(document.body.style.color); // 空 alert(document.body.style.marginTop); // 空 </script> </body>

但假如我们需要"把 margin 增加 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); // 现在可以读到 margin 和 color 了 alert( computedStyle.marginTop ); // 5px alert( computedStyle.color ); // rgb(255, 0, 0) </script> </body>

计算值(computed)与解析值(resolved)的区别

CSSOM 中有两个相关概念:

  1. 计算值(computed value):所有 CSS 规则与继承应用之后、级联完成的取值,可能是height:1em、font-size:125%这类相对形式;
  2. 解析值(resolved value):最终实际应用到元素上的值。浏览器把1em、125%等相对单位换算为固定、绝对的单位,例如height:20px、font-size:16px。几何属性还可能带有浮点数,如width:50.5px。

早年getComputedStyle是为获取计算值而设计的,但实践中解析值方便得多,标准也随之演进。因此如今getComputedStyle实际返回的是属性的解析值,几何属性通常以px呈现。

必须使用完整的属性名

调用getComputedStyle时应始终指定想要的精确属性,如paddingLeft、marginTop或borderTopWidth,否则结果不保证正确。例如同时存在paddingLeft/paddingTop时,getComputedStyle(elem).padding到底返回什么?标准里没有统一规则,可能是空,也可能是"生成"的值。

:visited 链接的样式被隐藏

被访问过的链接可以用:visited伪类着色,但getComputedStyle读不到这个颜色——否则任意网页都能通过在页面中创建链接并检查样式,来探测用户是否访问过某个网址。JavaScript 无法看到:visited应用的样式;同时 CSS 也禁止在:visited中修改几何相关样式,从两端共同保证用户浏览历史的隐私不被恶意页面探测。

仓库实战:用 className、classList 与 style 实现通知组件

本仓库为该章节附带的练习题"Create a notification"(task.md)正好把本文的知识点串起来:要求实现showNotification(options)函数,创建一个<div class="notification">元素,1.5 秒后自动消失,并支持指定top、right坐标、HTML 内容与附加类名。

完整参考实现位于 solution.view/index.html,核心代码:

function showNotification({top = 0, right = 0, className, html}) { let notification = document.createElement('div'); notification.className = "notification"; // 整体设置基础类 if (className) { notification.classList.add(className); // 用 classList 追加可选类 } notification.style.top = top + 'px'; // 记得拼上单位! notification.style.right = right + 'px'; notification.innerHTML = html; document.body.append(notification); setTimeout(() => notification.remove(), 1500); }

对照本文的知识点,这段代码展示了几处关键实践:

  • className与classList配合:先用className一次性设定基础类notification,再用classList.add追加可选的welcome类——正是"整体管理"与"单个增删"两种工具的分工;
  • 动态坐标用style写入:top、right是运行时参数,属于第一节所说的"类搞不定"的场景,通过style.top = top + 'px'动态赋值;
  • 单位意识:top + 'px'严格拼接了 CSS 单位,避免了"没写单位导致赋值被忽略"的经典坑。

配套样式写在 solution.view/index.css,notification类用position: fixed把元素钉在窗口坐标系中,z-index: 1000保证置顶;welcome类则负责配色:

.notification { position: fixed; z-index: 1000; padding: 5px; border: 1px solid black; font-size: 20px; background: white; text-align: center; } .welcome { background: #b80000; color: yellow; }

测试代码每隔 2 秒调用一次showNotification,在页面右上角持续弹出 "Hello 1、Hello 2…" 的通知,直观验证了"类负责外观、内联样式负责动态坐标"的分工模式。

扩展阅读:与相邻章节的衔接

本章的样式 API 是后续 DOM 操作的基础:下一章 Element size and scrolling 继续讲解offsetWidth/offsetHeight、clientWidth、scrollWidth等几何属性,其中的关键前提正是本章强调的"几何属性只对已显示元素有效,display:none的元素所有几何值为 0"。而创建、插入元素所使用的document.createElement、append等 API 则在本教程的 Modifying the document 一章中详细展开。

小结

  • 管理类有两个 DOM 属性:className是字符串,适合整体管理类集合;classList是带有add/remove/toggle/contains方法的对象,适合操作单个类,且可迭代。
  • 修改样式:style是驼峰命名的样式对象,读写它等价于修改"style"属性中的单个属性;style.cssText对应整个"style"属性,可整体写入一串样式(会替换而非追加)。
  • 读取最终样式:getComputedStyle(elem, [pseudo])返回考虑全部 CSS 类、级联计算完成后的样式对象,且为只读;调用时应使用完整属性名,且无法读取:visited对链接施加的颜色。
  • 文档/教程
  • 前端

【免费下载链接】en.javascript.info

Modern JavaScript Tutorial

项目地址:https://gitcode.com/gh_mirrors/en/en.javascript.info
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询