读取CSS自定义属性必须用getComputedStyle,因element.style仅读内联样式,无法获取:root或CSS文件中定义的变量;全局变量须查document.documentElement,返回值恒为字符串,未定义时为空字符串。

读取 CSS 自定义属性必须用 getComputedStyle,不能用 element.style
因为 element.style 只读内联样式(即 HTML 的 style 属性或 JS 直接赋的值),它完全忽略 CSS 文件、<style> 块和 :root 定义的变量。哪怕你在 :root 里写了 --theme: dark,someDiv.style.getPropertyValue('--theme') 也永远返回空字符串。
正确做法是:目标明确传入计算后能生效该变量的元素节点。常见场景有:
- 读全局变量 → 用
getComputedStyle(document.documentElement).getPropertyValue('--theme') - 读某子元素实际生效值(比如它自己或某个父元素设置了该变量)→ 用
getComputedStyle(someDiv).getPropertyValue('--theme') - 漏掉双短横(如写成
'theme')或前后多空格(如'--theme ')都会静默失败,返回空字符串 - 返回值恒为
string:哪怕 CSS 里是--size: 16,拿到的也是"16";未定义时是"",不是null或undefined,判空得用!val.trim()
setProperty 是唯一可靠写法,el.style.--var = value 会报错
修改只能通过 element.style.setProperty(),语法严格:
- 必须带双短横前缀:
el.style.setProperty('--color', 'red')✅;el.style.color = 'red'❌(改的是原生color) - 值必须是字符串:
el.style.setProperty('--opacity', '0.7')比0.7更可控,避免隐式转换歧义 - 作用域只限当前元素:设在
document.documentElement.style才算全局生效;设在按钮上,只影响该按钮及其后代中显式引用var(--color)的规则 - IE 完全不支持,现代浏览器都 OK;但 JSDOM(Node.js 测试环境)可能返回空或抛错,需兜底
为什么子元素 getComputedStyle(child) 读不到 :root 的变量?
这不是 JS 问题,是 CSS 规则本身:自定义属性默认不继承。子元素能“用” var(--theme),不代表它“拥有”这个变量值。
立即学习“前端免费学习笔记(深入)”;
getComputedStyle(child).getPropertyValue('--theme') 只返回 child 元素自身计算后的结果 —— 它不会向上查找祖先或 :root。只有满足以下任一条件,才能读到非空值:
- child 元素自己设置了
style="--theme: dark" - child 的某个父元素(含
document.documentElement)显式设置了该变量 - 你直接查
document.documentElement节点
别指望靠遍历 DOM 来“探测”全局变量值,必须明确目标节点是否参与了该变量的层叠计算。
频繁读取 getComputedStyle 会卡动画和滚动
每次调用 getComputedStyle 都可能触发强制同步布局(forced layout),尤其在 requestAnimationFrame 或 scroll 事件里反复调用,会导致明显卡顿。
实用建议:
- 读取结果尽量缓存,比如存到模块级变量或 WeakMap 中,避免重复计算
- 真需要响应尺寸/可见性变化时,优先用
ResizeObserver或IntersectionObserver替代轮询getComputedStyle - 移动端 Safari 13.4+ 才稳定支持
setProperty修改后立即重绘;旧版可能需要触发重排(如读el.offsetHeight)来刷新,但这是权宜之计,别滥用
最易被忽略的一点:CSS 自定义属性的“读”和“写”完全不对称——读要找对节点并处理字符串,写要管住作用域且注意兼容性。没想清楚变量作用范围就动手改,大概率出现“改了但没生效”或“局部改了却以为全局变了”的情况。


















