列出CSS自定义属性(CSS变量)

11

我在样式表中设置了一些CSS自定义属性:

:root {
    --bc: #fff;
    --bc-primary: #eee;
    --bc-secondary: #ddd;
}

如果我已经知道CSS变量的名称,我可以单独检索它们,如下所示:

console.log(getComputedStyle(document.body).getPropertyValue('--bc'));

// #fff

但是如果我想要提取CSS变量及其值的列表,该如何操作呢?


你找到这些变量后,计划用它们做什么? - user663031
我正在开发一个“主题切换器”,可以在我的应用程序中切换暗色和亮色主题。只需更改与CSS变量相关联的颜色即可实现我想要的效果,而无需添加/删除类。我相信还有其他方法可以实现相同的目标,并具有更好的浏览器支持。 - MorganR
5个回答

15

更新:

  • 为了捕获 CORS 错误,我在第一个 if 语句中添加了!styleSheet.href &&

一个可能的解决方案是解析 document.styleSheets,然后将规则拆分为属性/值。

var allCSS = [].slice.call(document.styleSheets)
  .reduce(function(prev, styleSheet) {
    if (!styleSheet.href && styleSheet.cssRules) {
      return prev + [].slice.call(styleSheet.cssRules)
        .reduce(function(prev, cssRule) {        
          if (cssRule.selectorText == ':root') {
            var css = cssRule.cssText.split('{');
            css = css[1].replace('}','').split(';');
            for (var i = 0; i < css.length; i++) {
              var prop = css[i].split(':');
              if (prop.length == 2 && prop[0].indexOf('--') == 1) {
                console.log('Property name: ', prop[0]);
                console.log('Property value:', prop[1]);
              }              
            }
          }
        }, '');
    }
  }, '');
:root {
    --bc: #fff;
    --bc-primary: #eee;
    --bc-secondary: #ddd;
}


3
非常感激您所投入的努力,谢谢。 - MorganR
1
非常有用的解决方案!谢谢。 - johnpyp

6
根据LGSon这里的回答,下面是类似的代码,但使用了mapfilterflat,使其逐行阅读更加容易。基于Exo Flame这里的回答捕获CORS错误。

const variables = Array.from(document.styleSheets)
    .filter(styleSheet => {
        try { return styleSheet.cssRules; }
        catch(e) { console.warn(e); }
    })
    .map(styleSheet => Array.from(styleSheet.cssRules))
    .flat()
    .filter(cssRule => cssRule.selectorText === ':root')
    .map(cssRule => cssRule.cssText.split('{')[1].split('}')[0].trim().split(';'))
    .flat()
    .filter(text => text !== "")
    .map(text => text.split(':'))
    .map(parts => ({key: parts[0].trim(), value: parts[1].trim() }))
;

console.log(variables);
:root {
    --foo: #fff;
    --bar: #aaa
}


这是我制作的演示页面,用于为网页主题设置 https://mvndaai.com/css_variables/ - mvndaai

3

MDN网站上有一篇介绍如何使用实验性方法Element.computedStyleMap的页面:

for (const [prop, val] of document.documentElement.computedStyleMap()){ 
  console.log( prop, val); 
}

您可以在caniuse上查看当前的支持情况。截至最后编辑,除了Firefox浏览器外,所有主流浏览器都支持此API。

CSS Tricks教程明确回答了这个问题,并且使用清晰的代码还包括基本样式规则中的自定义属性。


1
在新版Chrome中,使用JavaScript读取外部样式表可能会因为CORS而出现错误。是否有人知道解决方法?如果没有,那么如果你使用CDN,请注意这个警告。

https://dev59.com/HlUL5IYBdhLWcg3wqpk7#49994161

这是有帮助的: https://betterprogramming.pub/how-to-fix-the-failed-to-read-the-cssrules-property-from-cssstylesheet-error-431d84e4a139 这是一个过滤远程样式表的版本,因此您仍然可以获取本地样式。我还使用了Array.from()来提高可读性。

    var allCSSVars = Array.from(document.styleSheets)
        .filter((styleSheet) => {
            let isLocal = !styleSheet.href || styleSheet.href.startsWith(window.location.origin)
            if (!isLocal) console.warn("Skipping remote style sheet due to cors: ", styleSheet.href);
            return isLocal;
        })
        .map((styleSheet) => Array.from(styleSheet.cssRules))
        .flat()
        .filter((cssRule) => cssRule.selectorText === ':root')
        .map((cssRule) => cssRule.cssText.split('{')[1].split('}')[0].trim().split(';'))
        .flat()
        .filter((text) => text !== '')
        .map((text) => text.split(':'))
        .map((parts) => {
            return {key: parts[0].trim(), value: parts[1].trim()}
        })
        
        
        
console.log("vars: ", allCSSVars)

//another way not sure whitch is best but the top way is looking promising

allCSSVars = [].slice.call(document.styleSheets)
        .reduce(function (prev, styleSheet) {
            try {
                if (styleSheet.cssRules) {

                    return prev + [].slice.call(styleSheet.cssRules)
                        .reduce(function (prev, cssRule) {

                            if (cssRule.selectorText == ':root') {
                                var css = cssRule.cssText.split('{');
                                css = css[1].replace('}', '').split(';');
                                for (var i = 0; i < css.length; i++) {
                                    var prop = css[i].split(':');
                                    if (prop.length == 2 && prop[0].indexOf('--') == 1) {
                                        console.log('Property name: ', prop[0]);
                                        console.log('Property value:', prop[1]);
                                    }
                                }
                            }
                        }, '');
                }
            } catch (e) {
                console.warn("Skiping: ", e)
                return [];
            }

        }, '');
:root {
    --bc: #fff;
    --bc-primary: #eee;
    --bc-secondary: #ddd;
}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/water.css@2/out/water.css">

这段话展示了没有使用 try 语句会发生什么,我无法快速转换这段密集的代码,因此使用了更传统的版本 :).

const variables = [].slice.call(document.styleSheets)
  .map((styleSheet) => [].slice.call(styleSheet.cssRules))
  .flat()
  .filter((cssRule) => cssRule.selectorText === ':root')
  .map((cssRule) => cssRule.cssText.split('{')[1].split('}')[0].trim().split(';'))
  .flat()
  .filter((text) => text !== '')
  .map((text) => text.split(':'))
  .map((parts) => parts[0].trim() + ':  ' + parts[1].trim())
;

console.log(variables.join('\n'));
:root {
    --foo: #fff;
    --bar: #aaa
}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/water.css@2/out/water.css">


这非常有趣。我可能会在 .filter 内部执行 try/catch。 - mvndaai
我更新了我的答案,包含了对此的异常处理。谢谢! - mvndaai

0

感谢 @Ason 和 @mvndaai。我个人喜欢这种格式:

const variables = [].slice.call(document.styleSheets)
  .map((styleSheet) => [].slice.call(styleSheet.cssRules))
  .flat()
  .filter((cssRule) => cssRule.selectorText === ':root')
  .map((cssRule) => cssRule.cssText.split('{')[1].split('}')[0].trim().split(';'))
  .flat()
  .filter((text) => text !== '')
  .map((text) => text.split(':'))
  .map((parts) => parts[0].trim() + ':  ' + parts[1].trim())
;

console.log(variables.join('\n'));
:root {
    --foo: #fff;
    --bar: #aaa
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接