在前两章中,我们学习了如何获取样式表,以及如何操作样式表中的规则。那是从“样式源头”入手——改变的是规则本身,影响的是所有匹配该选择器的元素。

但实际开发中,我们更常见的是另一种需求:只改变某一个特定元素的样式,而不是整个页面所有同类元素。比如,用户点击了某个按钮,我们只想让这个按钮变色,而不是让页面上所有按钮都变色。

这时候,element.style 就登场了。

element.style 是 HTMLElement 接口的一个属性,它返回一个 CSSStyleDeclaration 对象,代表了元素 内联样式 属性中的声明。通过它,我们可以用 JavaScript 直接读写元素标签上的 style 属性——也就是我们写在 HTML 里的 style="..."。

这可能是你最熟悉的一种 CSSOM 操作方式,甚至你平时写 JavaScript 时无意识就在使用它。但熟悉不等于真正理解,本章将带你彻底掌握 element.style 的用法、注意事项和最佳实践。

一、element.style 的基本用法

每个 DOM 元素都有一个 style 属性,它返回一个 CSSStyleDeclaration 对象。

<div id="box" style="width: 200px; height: 200px; background: red;"></div>

<script>
    const box = document.getElementById('box');
    
    // 读取样式
    console.log(box.style.width);      // "200px"
    console.log(box.style.height);     // "200px"
    console.log(box.style.background); // "red"
    
    // 修改样式
    box.style.background = 'blue';
    box.style.borderRadius = '50%';
</script>

修改 element.style 的属性,会 直接写入到元素标签的 style 属性中。上面的代码执行后,<div> 会变成:

<div id="box" style="width: 200px; height: 200px; background: blue; border-radius: 50%;"></div>
一个重要但不常见的用法:清空所有内联样式

如果你想把元素上的所有内联样式一次性清空,有两种方式:

// 方法一:将 style 属性设置为空字符串
element.style = '';

// 方法二:使用 removeAttribute
element.removeAttribute('style');

两种方式效果相同,都会清空元素标签上的 style 属性,让元素恢复到仅由样式表控制的样式状态。

二、内联样式与样式表规则的优先级关系

这是理解 element.style 最关键的环节之一。内联样式的优先级非常高——它在 CSS 层叠规则中仅次于 !important 声明。

优先级规则速记
!important 声明 > 内联样式(style 属性)> ID 选择器 > 类选择器 > 标签选择器

这意味着,如果你通过 element.style 给一个元素设置了样式,它的优先级会高于样式表中任何非 !important 的规则。

<style>
    .box { color: red; }        /* 类选择器,优先级较低 */
    #box { color: green; }      /* ID 选择器,优先级较高 */
</style>

<div id="box" class="box" style="color: blue;">文本</div>

在这个例子中,文本最终显示为 蓝色,因为内联样式的优先级高于 ID 选择器。

!important 是唯一的例外

如果样式表中使用了 !important,内联样式也会被覆盖:

<style>
    .box { color: red !important; }
</style>

<div class="box" style="color: blue;">文本</div>

文本最终显示为 红色,因为 !important 的优先级高于内联样式。

开发者工具中的表现

在浏览器的开发者工具(DevTools)中,你可以清晰地看到这种优先级关系。打开 Elements 面板,在 Styles 标签页中,内联样式会被单独列在一个名为 element.style 的区块中,并位于其他规则之上。

这个布局直观地反映了优先级:越靠上的规则优先级越高。

三、驼峰命名与 CSS 属性名的转换

操作 element.style 时,最常遇到的“坑”就是 属性名的写法问题

CSS 属性名 vs JavaScript 属性名

CSS 中的属性名使用 连字符命名(kebab-case),例如 background-color、font-size、border-radius。但 JavaScript 的标识符中不允许使用连字符(-),所以 style 对象将 CSS 属性名转换为 驼峰命名(camelCase)。

CSS 属性名

JavaScript 中的 style 属性名

background-color

backgroundColor

font-size

fontSize

border-radius

borderRadius

margin-top

marginTop

z-index

zIndex

flex-direction

flexDirection

// 正确:使用驼峰命名
element.style.backgroundColor = '#fff';
element.style.fontSize = '16px';
element.style.borderRadius = '50%';

// 错误:使用连字符会报语法错误
// element.style.background-color = '#fff'; // 报错!被解析为减法运算
特殊情况:保留字

少数 CSS 属性名恰好是 JavaScript 的保留字,需要特殊处理。最典型的例子是 float:

// 错误:float 是 JavaScript 保留字
// element.style.float = 'left';

// 正确:使用 cssFloat
element.style.cssFloat = 'left';

类似的还有:

  • for → htmlFor(用于 <label> 元素)。

  • class → className(但这是 DOM 属性,不通过 style 操作)。

通用解决方案:使用 setProperty()

如果你不想记忆驼峰命名规则,可以使用 setProperty() 方法,它允许你传入原始的 CSS 属性名(字符串):

// 三种等价写法
element.style.backgroundColor = '#fff';
element.style.setProperty('background-color', '#fff');
element.style.setProperty('background-color', '#fff', 'important'); // 可以指定优先级

setProperty() 的完整语法是:

element.style.setProperty(propertyName, value, priority);
  • propertyName:CSS 属性名(用连字符格式)。

  • value:属性值。

  • priority:可选,'important' 表示添加 !important。

读取时的注意事项

element.style 只能读取 内联样式 中的属性值。如果一个属性没有在 style 属性中显式设置,即使样式表中有定义,element.style 读取到的也是空字符串。

<style>
    .box { width: 200px; }
</style>

<div class="box" style="height: 100px;"></div>

<script>
    const box = document.querySelector('.box');
    console.log(box.style.width);  // "" (样式表中定义的,不在内联样式中)
    console.log(box.style.height); // "100px" (内联样式中显式设置了的)
</script>

如果需要获取元素的计算样式(即经过层叠计算后的最终值),需要使用 getComputedStyle()(我们会在第五章中详细讲解)。

四、最佳实践:优先使用 className 切换类

掌握了 element.style 的用法后,你需要知道一个重要的原则:

能用 class 切换解决的问题,就不要用 style 直接操作。

为什么要优先使用 className?

1. 关注点分离

将样式放在 CSS 文件中,逻辑放在 JavaScript 中,是前端工程化的基本准则。直接操作 style 将样式逻辑混入 JavaScript,不利于维护和复用。

2. 性能更好

通过 className 切换类,浏览器只需要在渲染树中更新样式——这通常比逐个修改 style 属性更高效。更重要的是,类切换可以触发浏览器的样式重计算优化。

3. 样式更易于复用

定义在 CSS 文件中的样式可以在多个元素间共享,而内联样式只能作用于单个元素。

4. 更容易维护

当需要调整样式时,只需要修改 CSS 文件,而不需要到 JavaScript 代码中去查找和修改。

对比示例

不推荐的做法:直接操作 style

// 每次都要写具体的样式值
function highlight(element) {
    element.style.background = 'yellow';
    element.style.color = 'black';
    element.style.border = '2px solid orange';
    element.style.borderRadius = '4px';
}

function unhighlight(element) {
    element.style.background = '';
    element.style.color = '';
    element.style.border = '';
    element.style.borderRadius = '';
}

推荐的做法:切换 class

/* 所有样式集中在 CSS 中定义 */
.highlight {
    background: yellow;
    color: black;
    border: 2px solid orange;
    border-radius: 4px;
}

// JavaScript 只负责切换类
function highlight(element) {
    element.classList.add('highlight');
}

function unhighlight(element) {
    element.classList.remove('highlight');
}

代码量更少,逻辑更清晰,样式更易于维护。

什么时候适合用 style?

当然,element.style 并非一无是处。在以下场景中,直接操作 style 是更合适的选择:

1. 动态计算的值

样式值依赖于 JavaScript 运行时计算,例如根据鼠标位置设置偏移量:

element.style.left = mouseX + 'px';
element.style.top = mouseY + 'px';

2. 需要动画过程中的实时变化

在动画循环中逐步修改样式值:

function animate(element) {
    let progress = 0;
    function tick() {
        progress += 0.02;
        if (progress > 1) return;
        element.style.transform = `translateX(${progress * 100}px)`;
        requestAnimationFrame(tick);
    }
    tick();
}

3. 临时性的、一次性的样式调整

例如给某个输入框设置错误状态的边框颜色。

决策指南

场景

推荐方式

原因

预定义的视觉状态(如 hover、active、暗色模式)

classList 切换类

样式集中管理,性能更好

值依赖 JavaScript 计算(如鼠标位置、滚动百分比)

直接操作 style

值无法预先定义在 CSS 中

第三方组件或动态创建的元素的样式

直接操作 style

可能没有预定义的类可用

需要覆盖某个特定元素的样式

直接操作 style

利用内联样式的高优先级

五、一个综合示例

以下示例展示了 element.style 的各种用法,以及如何与 classList 配合使用:

<style>
    .card {
        width: 300px;
        padding: 20px;
        background: #f5f5f5;
        border-radius: 8px;
        transition: all 0.3s ease;
        font-family: Arial, sans-serif;
    }
    .card.active {
        background: #e3f2fd;
        border: 2px solid #1976d2;
        box-shadow: 0 4px 12px rgba(25, 118, 210, 0.3);
    }
    .card.highlight {
        background: #fff3e0;
        border-color: #ff9800;
    }
</style>

<div id="myCard" class="card">这是卡片内容</div>

<script>
    const card = document.getElementById('myCard');
    
    // 场景1:切换预定义状态——使用 classList(推荐)
    document.querySelector('.btn-toggle').addEventListener('click', () => {
        card.classList.toggle('active');
    });
    
    // 场景2:动态跟随鼠标位置——必须使用 style
    document.addEventListener('mousemove', (e) => {
        // 计算卡片相对于视口的偏移
        const x = e.clientX - card.offsetLeft - card.offsetWidth / 2;
        const y = e.clientY - card.offsetTop - card.offsetHeight / 2;
        card.style.transform = `translate(${x * 0.05}px, ${y * 0.05}px)`;
    });
    
    // 场景3:临时性反馈——使用 style(避免污染类名)
    card.addEventListener('click', () => {
        // 临时添加脉冲效果
        card.style.transition = 'transform 0.15s ease';
        card.style.transform = 'scale(0.95)';
        setTimeout(() => {
            card.style.transform = 'scale(1)';
            // 重置过渡,避免影响后续操作
            setTimeout(() => {
                card.style.transition = 'all 0.3s ease';
            }, 150);
        }, 150);
    });
    
    // 场景4:读取当前设置的值
    console.log('当前背景:', card.style.background || '(未设置内联背景)');
    // 注意:如果背景来自 CSS 类,element.style 读取不到
</script>

六、小结

本章我们完整学习了 element.style 的用法,这是前端开发中使用频率最高的一种动态样式操作方式:

  1. element.style 的基本用法:通过元素 style 属性获取 CSSStyleDeclaration 对象,读写元素的 内联样式。修改会直接写入标签的 style 属性。

 2. 优先级关系:内联样式的优先级高于样式表中的 ID 选择器和类选择器,仅次于 !important。这意味着操作 element.style 可以“强制”覆盖大部分样式表规则。

 3. 驼峰命名转换:CSS 属性名(background-color)在 JavaScript 中需要转换为驼峰形式(backgroundColor)。float 需要写作 cssFloat。如果不确定,可以使用 setProperty() 方法。

 4. 读取限制:element.style 只能读取内联样式中的值,无法读取来自样式表的样式。要获取计算后的完整样式,需要使用 getComputedStyle()(下一章会讲)。

 5. 最佳实践优先使用 classList 切换类 来管理样式,仅在值需要动态计算、动画过程中或临时性调整时使用 element.style。这一原则能让代码更清晰、更易维护、性能更好。

理解了 element.style 和样式表规则操作这两条不同的路径,你就掌握了 CSSOM 完整的使用图景。在下一章中,我们将学习如何突破 element.style 的局限——通过 getComputedStyle 获取元素在 CSS 层叠后的最终计算样式。