pin_drop当前位置:知识文库 ❯ 图文

JS集成:HTML DOM修改样式 - 详细教程与实战指南

教程简介

DOM样式操作是前端开发中实现动态交互效果的核心手段。通过JavaScript修改元素的样式,可以实现动画效果、主题切换、响应式布局调整、用户界面反馈等功能。浏览器提供了多种样式操作方式,包括style属性、cssTextgetComputedStyleclassList和CSS变量操作等。本教程将全面讲解这些样式操作方法的使用、区别、性能考虑以及样式优先级规则。


核心概念

样式来源与优先级

CSS样式有多个来源,它们的优先级从低到高为:

  1. 浏览器默认样式:浏览器内置的默认样式

  2. 外部样式表:通过<link>引入的CSS文件

  3. 内部样式表<style>标签中的样式

  4. 内联样式:元素的style属性

  5. !important声明:最高优先级(应尽量避免使用)

行内样式vs计算样式

  • 行内样式(Inline Style):通过element.style访问,只包含style属性中设置的样式

  • 计算样式(Computed Style):通过getComputedStyle()获取,包含所有来源的最终计算结果


语法与用法

1. style属性

style 属性用于读取和设置元素的内联样式。

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>style属性示例</title>
  <style>
    .box { width: 200px; height: 200px; background: #f0f0f0; }
  </style>
</head>
<body>
  <div id="demo" class="box" style="color: red;">示例元素</div>

  <script>
    var demo = document.getElementById('demo');

    // 读取内联样式(只能读取style属性中设置的样式)
    console.log(demo.style.color);     // "red"
    console.log(demo.style.width);     // ""(空字符串,因为width在CSS类中设置,不在style属性中)

    // 设置内联样式
    demo.style.color = 'blue';
    demo.style.backgroundColor = '#ffcc00';
    demo.style.fontSize = '20px';
    demo.style.marginTop = '10px';
    demo.style.borderRadius = '8px';

    // CSS属性名到JavaScript属性名的转换规则:
    // CSS: background-color -> JS: backgroundColor
    // CSS: font-size -> JS: fontSize
    // CSS: border-radius -> JS: borderRadius
    // CSS: margin-top -> JS: marginTop
    // 规则:去掉连字符,连字符后的首字母大写(驼峰命名)

    // 特殊属性名:
    // CSS: float -> JS: cssFloat(因为float是JS保留字)
    demo.style.cssFloat = 'left';

    // 读取时注意:style属性只能读取内联样式
    // CSS类中设置的样式无法通过style属性读取
    console.log(demo.style.background);  // ""(空,因为在CSS类中设置)
  </script>
</body>
</html>

2. cssText

cssText 属性用于一次性设置或读取元素的整个内联样式字符串。

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>cssText示例</title>
</head>
<body>
  <div id="demo">示例元素</div>

  <script>
    var demo = document.getElementById('demo');

    // 设置cssText(会覆盖所有已有的内联样式)
    demo.style.cssText = 'color: white; background: #333; padding: 20px; border-radius: 8px;';

    // 读取cssText
    console.log(demo.style.cssText);
    // "color: white; background: #333; padding: 20px; border-radius: 8px;"

    // 追加样式(注意:直接赋值会覆盖)
    demo.style.cssText += ' font-size: 18px;';

    // 清除所有内联样式
    demo.style.cssText = '';

    // cssText vs 逐个设置style属性
    // cssText优点:一次性设置多个样式,只触发一次重排
    // cssText缺点:会覆盖已有内联样式

    // 逐个设置
    demo.style.color = 'white';
    demo.style.background = '#333';
    demo.style.padding = '20px';
    // 每次设置都可能触发重排(浏览器会优化批量设置)
  </script>
</body>
</html>

3. getComputedStyle

getComputedStyle 方法获取元素的所有最终计算样式,包括来自CSS类、继承和内联样式的所有样式。

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>getComputedStyle示例</title>
  <style>
    .container {
      width: 300px;
      padding: 20px;
      background: #f5f5f5;
      font-size: 16px;
      line-height: 1.5;
      color: #333;
    }
  </style>
</head>
<body>
  <div id="demo" class="container" style="color: red;">示例元素</div>

  <script>
    var demo = document.getElementById('demo');

    // 获取计算样式
    var computedStyle = window.getComputedStyle(demo);

    // 读取各种样式属性
    console.log(computedStyle.color);           // "rgb(255, 0, 0)"(内联样式优先)
    console.log(computedStyle.width);           // "300px"
    console.log(computedStyle.padding);         // "20px"
    console.log(computedStyle.fontSize);        // "16px"
    console.log(computedStyle.lineHeight);      // "24px" 或 "1.5"(取决于浏览器)
    console.log(computedStyle.backgroundColor);  // "rgb(245, 245, 245)"
    console.log(computedStyle.display);         // "block"
    console.log(computedStyle.position);        // "static"

    // 获取特定属性值
    var width = window.getComputedStyle(demo).width;
    console.log('宽度:', width);

    // 获取伪元素样式
    var beforeStyle = window.getComputedStyle(demo, '::before');
    console.log('::before content:', beforeStyle.content);

    // 注意事项:
    // 1. 返回值是只读的,不能修改
    // 2. 返回的是计算后的绝对值(如颜色转为rgb,相对单位转为px)
    // 3. 某些属性返回值可能因浏览器而异
    // 4. 读取计算样式会触发重排

    // 获取数值(去掉单位)
    var widthValue = parseFloat(computedStyle.width);
    console.log('宽度数值:', widthValue);  // 300
  </script>
</body>
</html>

4. classList

classList 属性返回元素的类名列表,提供了方便的方法来操作类名。

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>classList示例</title>
  <style>
    .box { padding: 20px; border: 1px solid #ddd; border-radius: 8px; margin: 8px 0; }
    .active { background: #007bff; color: white; }
    .highlight { background: #fff3cd; border-color: #ffc107; }
    .hidden { display: none; }
    .large { font-size: 24px; }
    .bold { font-weight: bold; }
  </style>
</head>
<body>
  <div id="demo" class="box">示例元素</div>

  <script>
    var demo = document.getElementById('demo');

    // add:添加类名
    demo.classList.add('active');
    demo.classList.add('highlight', 'bold');  // 添加多个类名

    // remove:移除类名
    demo.classList.remove('highlight');
    demo.classList.remove('bold', 'large');   // 移除多个类名

    // toggle:切换类名(存在则移除,不存在则添加)
    demo.classList.toggle('active');   // 移除active
    demo.classList.toggle('active');   // 添加active

    // toggle带强制参数
    demo.classList.toggle('active', true);   // 强制添加(等同于add)
    demo.classList.toggle('active', false);  // 强制移除(等同于remove)

    // contains:检测是否包含类名
    console.log(demo.classList.contains('box'));     // true
    console.log(demo.classList.contains('active'));  // 取决于当前状态

    // replace:替换类名
    demo.classList.replace('active', 'highlight');

    // 遍历类名
    demo.classList.forEach(function(className) {
      console.log('类名:', className);
    });

    // 类名数量
    console.log('类名数量:', demo.classList.length);  // 2

    // 通过索引访问
    console.log('第一个类名:', demo.classList.item(0));  // "box"

    // 旧方式:使用className(字符串操作,不推荐)
    // 添加类名
    demo.className += ' new-class';
    // 移除类名(麻烦且容易出错)
    demo.className = demo.className.replace(/\bnew-class\b/, '').trim();
  </script>
</body>
</html>

5. className

className 属性获取或设置元素的class属性值(字符串形式)。

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>className示例</title>
</head>
<body>
  <div id="demo" class="box primary large">示例元素</div>

  <script>
    var demo = document.getElementById('demo');

    // 读取className
    console.log(demo.className);  // "box primary large"

    // 设置className(替换所有类名)
    demo.className = 'new-class';
    console.log(demo.className);  // "new-class"

    // 追加类名
    demo.className += ' another-class';
    console.log(demo.className);  // "new-class another-class"

    // className vs classList
    // className:字符串操作,适合需要整体替换类名的场景
    // classList:API操作,适合增删单个类名的场景

    // 推荐使用classList进行单个类名操作
    demo.classList.add('safe-add');
    demo.classList.remove('safe-add');
    demo.classList.toggle('safe-toggle');
  </script>
</body>
</html>

6. CSS变量操作

CSS自定义属性(CSS变量)可以通过JavaScript动态修改。

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>CSS变量操作示例</title>
  <style>
    :root {
      --primary-color: #007bff;
      --secondary-color: #6c757d;
      --font-size-base: 16px;
      --border-radius: 8px;
      --spacing: 16px;
    }

    .card {
      padding: var(--spacing);
      border: 1px solid #ddd;
      border-radius: var(--border-radius);
      margin: var(--spacing) 0;
      font-size: var(--font-size-base);
    }

    .card h3 {
      color: var(--primary-color);
      margin-top: 0;
    }

    .card .btn {
      background: var(--primary-color);
      color: white;
      border: none;
      padding: 8px 16px;
      border-radius: var(--border-radius);
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="card" id="theme-card">
    <h3>CSS变量操作演示</h3>
    <p>通过修改CSS变量实现主题切换</p>
    <button class="btn" onclick="switchTheme('blue')">蓝色主题</button>
    <button class="btn" onclick="switchTheme('green')">绿色主题</button>
    <button class="btn" onclick="switchTheme('purple')">紫色主题</button>
  </div>

  <script>
    // 读取CSS变量
    var root = document.documentElement;
    var computedStyle = getComputedStyle(root);
    console.log('主色:', computedStyle.getPropertyValue('--primary-color'));  // " #007bff"

    // 设置CSS变量(在根元素上)
    function switchTheme(theme) {
      var themes = {
        blue: {
          '--primary-color': '#007bff',
          '--secondary-color': '#6c757d'
        },
        green: {
          '--primary-color': '#28a745',
          '--secondary-color': '#20c997'
        },
        purple: {
          '--primary-color': '#6f42c1',
          '--secondary-color': '#e83e8c'
        }
      };

      var selectedTheme = themes[theme];
      Object.keys(selectedTheme).forEach(function(varName) {
        root.style.setProperty(varName, selectedTheme[varName]);
      });
    }

    // 在特定元素上设置CSS变量
    var card = document.getElementById('theme-card');
    card.style.setProperty('--spacing', '24px');  // 只影响此元素及其后代

    // 读取元素上的CSS变量
    var cardStyle = getComputedStyle(card);
    console.log('卡片间距:', cardStyle.getPropertyValue('--spacing'));

    // 移除CSS变量
    card.style.removeProperty('--spacing');
  </script>
</body>
</html>

代码示例

示例1:主题切换系统

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>主题切换系统</title>
  <style>
    :root {
      --bg-primary: #ffffff;
      --bg-secondary: #f5f5f5;
      --text-primary: #333333;
      --text-secondary: #666666;
      --border-color: #dddddd;
      --accent-color: #007bff;
      --accent-hover: #0056b3;
      --shadow: 0 2px 8px rgba(0,0,0,0.1);
      --transition-speed: 0.3s;
    }

    [data-theme="dark"] {
      --bg-primary: #1a1a2e;
      --bg-secondary: #16213e;
      --text-primary: #e0e0e0;
      --text-secondary: #a0a0a0;
      --border-color: #333355;
      --accent-color: #4fc3f7;
      --accent-hover: #29b6f6;
      --shadow: 0 2px 8px rgba(0,0,0,0.3);
    }

    * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
      font-family: -apple-system, sans-serif;
      background: var(--bg-primary);
      color: var(--text-primary);
      transition: background var(--transition-speed), color var(--transition-speed);
      padding: 20px;
      max-width: 800px;
      margin: 0 auto;
    }
    .card {
      background: var(--bg-secondary);
      border: 1px solid var(--border-color);
      border-radius: 8px;
      padding: 20px;
      margin: 16px 0;
      box-shadow: var(--shadow);
      transition: all var(--transition-speed);
    }
    .card h2 { color: var(--accent-color); margin-bottom: 12px; }
    .btn {
      padding: 8px 16px; border: none; border-radius: 6px; cursor: pointer;
      background: var(--accent-color); color: white; margin: 4px;
      transition: background var(--transition-speed);
    }
    .btn:hover { background: var(--accent-hover); }
    .theme-switch {
      position: fixed; top: 20px; right: 20px;
      width: 50px; height: 26px; border-radius: 13px;
      background: var(--border-color); cursor: pointer;
      transition: background var(--transition-speed);
    }
    .theme-switch::after {
      content: ''; position: absolute; top: 3px; left: 3px;
      width: 20px; height: 20px; border-radius: 50%;
      background: white; transition: transform var(--transition-speed);
    }
    [data-theme="dark"] .theme-switch { background: var(--accent-color); }
    [data-theme="dark"] .theme-switch::after { transform: translateX(24px); }
  </style>
</head>
<body>
  <div class="theme-switch" id="theme-toggle" role="button" tabindex="0" aria-label="切换主题"></div>

  <h1>主题切换系统</h1>

  <div class="card">
    <h2>关于主题</h2>
    <p>本页面使用CSS变量实现主题切换,点击右上角开关即可切换明暗主题。</p>
    <p>所有颜色和阴影都通过CSS变量定义,切换主题只需更改变量值。</p>
  </div>

  <div class="card">
    <h2>操作按钮</h2>
    <button class="btn">主要按钮</button>
    <button class="btn">次要按钮</button>
  </div>

  <script>
    var themeToggle = document.getElementById('theme-toggle');

    // 读取保存的主题
    var savedTheme = localStorage.getItem('theme') || 'light';
    document.documentElement.setAttribute('data-theme', savedTheme);

    themeToggle.addEventListener('click', function() {
      var currentTheme = document.documentElement.getAttribute('data-theme');
      var newTheme = currentTheme === 'dark' ? 'light' : 'dark';

      document.documentElement.setAttribute('data-theme', newTheme);
      localStorage.setItem('theme', newTheme);
    });

    // 键盘支持
    themeToggle.addEventListener('keydown', function(e) {
      if (e.key === 'Enter' || e.key === ' ') {
        e.preventDefault();
        themeToggle.click();
      }
    });
  </script>
</body>
</html>

示例2:classList实现手风琴组件

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>classList实现手风琴组件</title>
  <style>
    body { font-family: -apple-system, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; }
    .accordion { border: 1px solid #ddd; border-radius: 8px; overflow: hidden; }
    .accordion-item { border-bottom: 1px solid #ddd; }
    .accordion-item:last-child { border-bottom: none; }
    .accordion-header {
      padding: 16px 20px; cursor: pointer; display: flex;
      justify-content: space-between; align-items: center;
      background: #f8f9fa; transition: background 0.2s;
    }
    .accordion-header:hover { background: #e9ecef; }
    .accordion-header::after { content: '+'; font-size: 20px; font-weight: bold; transition: transform 0.3s; }
    .accordion-item.open .accordion-header::after { transform: rotate(45deg); }
    .accordion-body {
      max-height: 0; overflow: hidden; transition: max-height 0.3s ease-out;
      padding: 0 20px;
    }
    .accordion-item.open .accordion-body { max-height: 200px; padding: 16px 20px; }
  </style>
</head>
<body>
  <h1>手风琴组件</h1>

  <div class="accordion" id="faq-accordion">
    <div class="accordion-item" data-accordion="item">
      <div class="accordion-header">什么是DOM?</div>
      <div class="accordion-body">
        <p>DOM(文档对象模型)是HTML文档的编程接口,它将文档表示为节点树,使JavaScript能够访问和操作页面内容。</p>
      </div>
    </div>
    <div class="accordion-item" data-accordion="item">
      <div class="accordion-header">什么是classList?</div>
      <div class="accordion-body">
        <p>classList是元素类名列表的API,提供了add、remove、toggle、contains和replace等方法来方便地操作类名。</p>
      </div>
    </div>
    <div class="accordion-item" data-accordion="item">
      <div class="accordion-header">什么是CSS变量?</div>
      <div class="accordion-body">
        <p>CSS变量(自定义属性)允许定义可复用的值,通过var()函数引用。JavaScript可以通过style.setProperty动态修改CSS变量。</p>
      </div>
    </div>
    <div class="accordion-item" data-accordion="item">
      <div class="accordion-header">如何获取元素的计算样式?</div>
      <div class="accordion-body">
        <p>使用window.getComputedStyle(element)方法可以获取元素的所有最终计算样式,包括CSS类、继承和内联样式的综合结果。</p>
      </div>
    </div>
  </div>

  <script>
    var accordion = document.getElementById('faq-accordion');

    // 事件委托
    accordion.addEventListener('click', function(e) {
      var header = e.target.closest('.accordion-header');
      if (!header) return;

      var item = header.parentElement;
      var isOpen = item.classList.contains('open');

      // 关闭所有其他项
      accordion.querySelectorAll('.accordion-item').forEach(function(otherItem) {
        otherItem.classList.remove('open');
      });

      // 切换当前项
      if (!isOpen) {
        item.classList.add('open');
      }
    });
  </script>
</body>
</html>

示例3:样式操作性能对比

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>样式操作性能对比</title>
  <style>
    body { font-family: -apple-system, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
    .test-box { width: 100px; height: 100px; background: #007bff; margin: 4px; display: inline-block; }
    table { width: 100%; border-collapse: collapse; margin: 16px 0; }
    th, td { padding: 8px 12px; text-align: left; border: 1px solid #ddd; }
    th { background: #f5f5f5; }
    button { padding: 10px 20px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; margin: 4px; }
  </style>
</head>
<body>
  <h1>样式操作性能对比</h1>
  <p>对比不同样式修改方式的性能差异</p>

  <button onclick="runPerformanceTest()">运行性能测试</button>

  <div id="test-container" style="min-height:50px;"></div>

  <table>
    <thead>
      <tr><th>方式</th><th>操作次数</th><th>耗时(ms)</th><th>说明</th></tr>
    </thead>
    <tbody id="perf-results"></tbody>
  </table>

  <script>
    function runPerformanceTest() {
      var container = document.getElementById('test-container');
      var resultsBody = document.getElementById('perf-results');
      resultsBody.innerHTML = '';

      // 创建测试元素
      container.innerHTML = '';
      var elements = [];
      for (var i = 0; i < 100; i++) {
        var div = document.createElement('div');
        div.className = 'test-box';
        container.appendChild(div);
        elements.push(div);
      }

      var iterations = 1000;

      // 测试1:逐个设置style属性
      var start = performance.now();
      for (var iter = 0; iter < iterations; iter++) {
        for (var i = 0; i < elements.length; i++) {
          elements[i].style.backgroundColor = '#28a745';
          elements[i].style.margin = '8px';
          elements[i].style.borderRadius = '4px';
        }
      }
      var time1 = (performance.now() - start).toFixed(2);

      // 测试2:使用cssText
      start = performance.now();
      for (var iter = 0; iter < iterations; iter++) {
        for (var i = 0; i < elements.length; i++) {
          elements[i].style.cssText = 'background-color: #28a745; margin: 8px; border-radius: 4px;';
        }
      }
      var time2 = (performance.now() - start).toFixed(2);

      // 测试3:使用classList
      // 先定义CSS类
      var style = document.createElement('style');
      style.textContent = '.test-style { background-color: #28a745 !important; margin: 8px !important; border-radius: 4px !important; }';
      document.head.appendChild(style);

      start = performance.now();
      for (var iter = 0; iter < iterations; iter++) {
        for (var i = 0; i < elements.length; i++) {
          elements[i].classList.add('test-style');
          elements[i].classList.remove('test-style');
        }
      }
      var time3 = (performance.now() - start).toFixed(2);

      // 测试4:使用CSS变量
      start = performance.now();
      for (var iter = 0; iter < iterations; iter++) {
        for (var i = 0; i < elements.length; i++) {
          elements[i].style.setProperty('--test-bg', '#28a745');
          elements[i].style.removeProperty('--test-bg');
        }
      }
      var time4 = (performance.now() - start).toFixed(2);

      // 渲染结果
      var results = [
        { method: '逐个style属性', time: time1, desc: 'style.prop = value' },
        { method: 'cssText', time: time2, desc: 'style.cssText = "..."(覆盖式)' },
        { method: 'classList', time: time3, desc: 'classList.add/remove(切换类名)' },
        { method: 'CSS变量', time: time4, desc: 'style.setProperty/removeProperty' }
      ];

      results.forEach(function(r) {
        var tr = document.createElement('tr');
        tr.innerHTML = '<td>' + r.method + '</td><td>' + (iterations * 100) +
          '</td><td>' + r.time + '</td><td>' + r.desc + '</td>';
        resultsBody.appendChild(tr);
      });

      // 清理
      container.innerHTML = '';
    }
  </script>
</body>
</html>

浏览器兼容性

样式操作方法兼容性

方法/属性 Chrome Firefox Safari Edge IE
element.style 全部 全部 全部 全部 全部
style.cssText 全部 全部 全部 全部 全部
getComputedStyle 全部 全部 全部 全部 9+
classList 8+ 3.6+ 5.1+ 12+ 10+
classList.toggle(force) 24+ 24+ 7+ 12+ 不支持
classList.replace 61+ 49+ 10.1+ 17+ 不支持
style.setProperty 全部 全部 全部 全部 9+
style.getPropertyValue 全部 全部 全部 全部 9+
style.removeProperty 全部 全部 全部 全部 9+
CSS变量 49+ 31+ 9.1+ 15+ 不支持

classList兼容性写法

代码示例

// classList兼容性封装
function addClass(element, className) {
  if (element.classList) {
    element.classList.add(className);
  } else {
    if (!hasClass(element, className)) {
      element.className += ' ' + className;
    }
  }
}

function removeClass(element, className) {
  if (element.classList) {
    element.classList.remove(className);
  } else {
    element.className = element.className.replace(
      new RegExp('(^|\\s)' + className + '(\\s|$)'), ' '
    ).trim();
  }
}

function toggleClass(element, className) {
  if (element.classList) {
    element.classList.toggle(className);
  } else {
    if (hasClass(element, className)) {
      removeClass(element, className);
    } else {
      addClass(element, className);
    }
  }
}

function hasClass(element, className) {
  if (element.classList) {
    return element.classList.contains(className);
  }
  return new RegExp('(^|\\s)' + className + '(\\s|$)').test(element.className);
}

注意事项与最佳实践

1. 减少重排和重绘

代码示例

// 不推荐:多次修改样式,可能触发多次重排
element.style.width = '100px';
element.style.height = '100px';
element.style.margin = '10px';

// 推荐1:使用cssText一次性设置
element.style.cssText = 'width: 100px; height: 100px; margin: 10px;';

// 推荐2:使用CSS类
element.className = 'styled-box';

// 推荐3:批量修改时先隐藏元素
element.style.display = 'none';
// ... 大量样式修改
element.style.display = '';

// 推荐4:使用requestAnimationFrame
requestAnimationFrame(function() {
  element.style.transform = 'translateX(100px)';
});

2. 优先使用CSS类而非直接修改样式

代码示例

// 不推荐:直接修改样式
element.style.backgroundColor = 'red';
element.style.color = 'white';
element.style.padding = '10px';

// 推荐:使用CSS类
// CSS: .error { background-color: red; color: white; padding: 10px; }
element.classList.add('error');

// 优点:
// 1. 关注点分离:样式在CSS中,逻辑在JS中
// 2. 可维护性:修改样式只需改CSS
// 3. 性能:切换类名比修改多个样式属性更高效
// 4. 可复用:同一类名可在多处使用

3. 使用CSS变量实现动态主题

代码示例

// 推荐:使用CSS变量
document.documentElement.style.setProperty('--primary-color', '#ff6600');

// 不推荐:遍历所有元素修改样式
document.querySelectorAll('.btn').forEach(function(btn) {
  btn.style.backgroundColor = '#ff6600';
});

4. 获取元素尺寸的正确方式

代码示例

// 获取元素尺寸的几种方式

// 方式1:getComputedStyle(返回包含单位的字符串)
var width = getComputedStyle(element).width;  // "300px"

// 方式2:getBoundingClientRect(返回数值,包含边框)
var rect = element.getBoundingClientRect();
console.log(rect.width);   // 302(包含border)
console.log(rect.height);  // 202

// 方式3:offsetWidth/offsetHeight(包含边框和滚动条)
console.log(element.offsetWidth);   // 302
console.log(element.offsetHeight);  // 202

// 方式4:clientWidth/clientHeight(不包含边框,包含padding)
console.log(element.clientWidth);   // 300
console.log(element.clientHeight);  // 200

// 方式5:scrollWidth/scrollHeight(包含溢出内容)
console.log(element.scrollWidth);
console.log(element.scrollHeight);

代码规范示例

样式操作规范

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>样式操作规范</title>
  <style>
    /* 1. 使用CSS类定义样式状态 */
    .is-active { background: #007bff; color: white; }
    .is-hidden { display: none; }
    .is-loading { opacity: 0.6; pointer-events: none; }
    .is-disabled { opacity: 0.5; cursor: not-allowed; }
    .has-error { border-color: #dc3545; }
    .has-success { border-color: #28a745; }
  </style>
</head>
<body>
  <div id="app">
    <button id="submit-btn" class="btn">提交</button>
  </div>

  <script>
    (function() {
      'use strict';

      var btn = document.getElementById('submit-btn');

      // 1. 使用CSS类切换状态(推荐)
      btn.addEventListener('click', function() {
        btn.classList.add('is-loading');

        // 模拟异步操作
        setTimeout(function() {
          btn.classList.remove('is-loading');
          btn.classList.add('has-success');
        }, 2000);
      });

      // 2. 必须直接修改样式时,使用style属性
      function setElementPosition(element, x, y) {
        element.style.transform = 'translate(' + x + 'px, ' + y + 'px)';
      }

      // 3. 使用CSS变量实现动态值
      function setThemeColor(color) {
        document.documentElement.style.setProperty('--primary-color', color);
      }

      // 4. 批量修改时使用cssText
      function resetStyles(element) {
        element.style.cssText = '';
      }

      // 5. 读取计算样式
      function getActualWidth(element) {
        return element.getBoundingClientRect().width;
      }
    })();
  </script>
</body>
</html>

常见问题与解决方案

问题1:style属性读取不到CSS类中的样式

症状: element.style.width 返回空字符串,但元素确实有宽度。

解决方案:

代码示例

// style属性只能读取内联样式
// CSS类中的样式需要使用getComputedStyle

// 错误方式
var width = element.style.width;  // ""(空字符串)

// 正确方式
var width = getComputedStyle(element).width;  // "300px"

// 或者使用offsetWidth
var width = element.offsetWidth;  // 300(数值)

问题2:classList在IE9及以下不支持

解决方案:

代码示例

// 使用前面的兼容性封装函数
// 或者使用className操作

// 添加类名
function addClass(el, cls) {
  if (el.classList) {
    el.classList.add(cls);
  } else {
    var classes = el.className.split(' ');
    if (classes.indexOf(cls) === -1) {
      classes.push(cls);
      el.className = classes.join(' ');
    }
  }
}

问题3:getComputedStyle返回的值带有单位

症状: 需要数值进行计算,但返回的是"300px"这样的字符串。

解决方案:

代码示例

// 方案1:使用parseFloat
var width = parseFloat(getComputedStyle(element).width);  // 300

// 方案2:使用getBoundingClientRect
var rect = element.getBoundingClientRect();
var width = rect.width;   // 300(数值)
var height = rect.height; // 200(数值)

// 方案3:使用offsetWidth/clientWidth
var width = element.offsetWidth;   // 数值,包含border
var width = element.clientWidth;   // 数值,不包含border

问题4:CSS变量在IE中不支持

解决方案:

代码示例

// 方案1:直接修改元素样式
// 不使用CSS变量,直接设置样式
element.style.color = themeColor;

// 方案2:使用PostCSS插件将CSS变量编译为静态值
// 构建时处理,运行时无需CSS变量支持

// 方案3:使用polyfill
// 引入ie11-customproperties等polyfill库

总结

DOM样式操作是实现动态交互效果的核心能力,掌握各种样式操作方法及其适用场景至关重要:

  1. style属性:设置内联样式,CSS属性名需转为驼峰命名

  2. cssText:一次性设置多个样式,适合批量修改但会覆盖已有内联样式

  3. getComputedStyle:获取最终计算样式,包含所有来源的综合结果

  4. classList:操作类名的最佳方式,提供add/remove/toggle/contains/replace方法

  5. className:整体替换类名字符串,适合需要完全替换的场景

  6. CSS变量:通过setProperty/getPropertyValue操作,实现动态主题

  7. 性能优化:优先使用CSS类、减少重排重绘、使用CSS变量替代遍历修改

遵循"样式在CSS中,逻辑在JS中"的原则,优先使用CSS类切换状态,能够编写出更高效、更可维护的代码。

常见问题

问题1:style属性读取不到CSS类中的样式?

症状: element.style.width 返回空字符串,但元素确实有宽度。 解决方案:

问题2:classList在IE9及以下不支持?

解决方案:

问题3:getComputedStyle返回的值带有单位?

症状: 需要数值进行计算,但返回的是"300px"这样的字符串。 解决方案:

问题4:CSS变量在IE中不支持?

解决方案:

标签: Script标签 JavaScript JS DOM HTML CSS 样式操作

本文由小确幸生活整理发布,转载请注明出处

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: JS集成:HTML DOM修改属性 - 详细教程与实战指南 下一篇: JS集成:HTML DOM创建与删除节点 - 详细教程与实战指南

poll相关推荐