使用javascript获取数组中的所有css根变量并更改值

Posted

技术标签:

【中文标题】使用javascript获取数组中的所有css根变量并更改值【英文标题】:Get all css root variables in array using javascript and change the values 【发布时间】:2018-07-23 10:30:05 【问题描述】:

我在我的项目中使用 css 根变量来随时动态更改所有元素的颜色。

我的 CSS 看起来像

:root
  --primaryColor:aliceblue;
  --secondaryColor:blue;
  --errorColor:#cc2511;

在css中使用

.contentCss 
  background-color: var(--primaryColor);
 

我可以如下访问javascript中的变量以动态更改值

document.documentElement.style.setProperty('--primaryColor', 'green');

它工作正常。我想获取数组中的所有变量,并据此动态更改每个变量的值。

【问题讨论】:

【参考方案1】:

这是另一个打字稿,我继续 RLoniello 提到的工作。它还将其输出为 JS 对象,即将 --font-family: "Verdana" 转换为 fontFamily: "Verdana"。

const CssKeyToJsKey = (key: string) =>
    key.replace('--', '').replace(/-./g, (x) => x.toUpperCase()[1]);

const getAllCSSVariableNames = (styleSheets: StyleSheetList = document.styleSheets) => 
    const cssVars = [];

    Array.from(styleSheets).forEach((styleSheet) => 
        Array.from(styleSheet.cssRules).forEach((rule) => 
            if (!rule || !rule['style']) 
                return;
            

            Array.from(rule['style']).forEach((style: string) => 
                if (style.startsWith('--') && cssVars.indexOf(style) == -1) 
                    cssVars.push(style);
                
            );
        );
    );

    return cssVars;
;

const getElementCSSVariables = (
    allCSSVars: Array<string>,
    element: htmlElement = document.body,
    pseudo: string | undefined = ''
) => 
    const elStyles = window.getComputedStyle(element, pseudo);
    const cssVars = ;

    allCSSVars.forEach((key) => 
        const value = elStyles.getPropertyValue(key);

        if (value) 
            cssVars[CssKeyToJsKey(key)] = value;
        
    );

    return cssVars;
;

export const getAllCSSVariables = (): Record<string, string> => 
    const cssVars = getAllCSSVariableNames();

    return getElementCSSVariables(cssVars, document.documentElement);
;

【讨论】:

【参考方案2】:

此脚本将返回所有样式表中的根变量数组,由域提供。由于 CORS 策略,无法访问域外样式表。

Array.from(document.styleSheets)
  .filter(
    sheet =>
      sheet.href === null || sheet.href.startsWith(window.location.origin)
  )
  .reduce(
    (acc, sheet) =>
      (acc = [
        ...acc,
        ...Array.from(sheet.cssRules).reduce(
          (def, rule) =>
            (def =
              rule.selectorText === ":root"
                ? [
                    ...def,
                    ...Array.from(rule.style).filter(name =>
                      name.startsWith("--")
                    )
                  ]
                : def),
          []
        )
      ]),
    []
  );

注意:较低顺序样式表中的root: 规则将覆盖父root 规则。

【讨论】:

【参考方案3】:

我今天需要一个类似的解决方案。这是quick one on codepen。

// could pass in an array of specific stylesheets for optimization
function getAllCSSVariableNames(styleSheets = document.styleSheets)
   var cssVars = [];
   // loop each stylesheet
   for(var i = 0; i < styleSheets.length; i++)
      // loop stylesheet's cssRules
      try // try/catch used because 'hasOwnProperty' doesn't work
         for( var j = 0; j < styleSheets[i].cssRules.length; j++)
            try
               // loop stylesheet's cssRules' style (property names)
               for(var k = 0; k < styleSheets[i].cssRules[j].style.length; k++)
                  let name = styleSheets[i].cssRules[j].style[k];
                  // test name for css variable signiture and uniqueness
                  if(name.startsWith('--') && cssVars.indexOf(name) == -1)
                     cssVars.push(name);
                  
               
             catch (error) 
         
       catch (error) 
   
   return cssVars;


function getElementCSSVariables (allCSSVars, element = document.body, pseudo)
   var elStyles = window.getComputedStyle(element, pseudo);
   var cssVars = ;
   for(var i = 0; i < allCSSVars.length; i++)
      let key = allCSSVars[i];
      let value = elStyles.getPropertyValue(key)
      if(value)cssVars[key] = value;
   
   return cssVars;


var cssVars = getAllCSSVariableNames();
console.log(':root variables', getElementCSSVariables(cssVars, document.documentElement));

【讨论】:

【参考方案4】:

如果您知道您的所有变量都将放在 :root 中,并且这是您的第一个 CSS 文件中的第一个声明,您可以尝试这样的操作,您将在 Object 中获取所有变量:

var declaration = document.styleSheets[0].cssRules[0];
var allVar = declaration.style.cssText.split(";");

var result = 
for (var i = 0; i < allVar.length; i++) 
  var a = allVar[i].split(':');
  if (a[0] !== "")
    result[a[0].trim()] = a[1].trim();


console.log(result);
var keys = Object.keys(result);
console.log(keys);

//we change the first variable
document.documentElement.style.setProperty(keys[0], 'green');

//we change the variable  --secondary-color
document.documentElement.style.setProperty(keys[keys.indexOf("--secondary-color")], 'red');
:root 
  --primary-color: aliceblue;
  --secondary-color: blue;
  --error-color: #cc2511


p 
  font-size: 25px;
  color: var(--primary-color);
  border:1px solid var(--secondary-color)
&lt;p&gt;Some text&lt;/p&gt;

【讨论】:

有趣的解决方案,很干净,我考虑过使用.cssRules[0],但我发现只读取了第一个:root元素。如果您有多个来自不同来源的文件,比如本地和 CDN,则只会读取第一个。 @RLoniello 是的,您可能会注意到我使用了0 索引,如果您按照它们进行操作,您会看到我采用了第一个 CSS 文件和该 CSS 文件中的第一条规则......所以你可以对另一个做同样的事情,你唯一需要知道的是顺序和索引......这是一个小缺点:)但是如果你知道你的 CSS 文件就不会成为问题;) @RLoniello 使用console.log 和document.styleSheets 看看里面有什么,你就会明白;) 是的,我明白了 :) 请注意 CDN 样式表的加载顺序。 :P @RLoniello 是的,如果你很容易得到订单......但如果不是你可以使代码更复杂,你可以循环遍历所有样式以获取变量..所以几乎相同的事情我已经完成了,但是所有的样式.. 你只需要添加一个if else 来检查样式是否是一个变量(它应该以-- 开头)【参考方案5】:

您可以声明一个带有键的关联数组作为节点属性及其值,然后使用函数来设置您的主题:

var primaryColor = document.documentElement.style.getPropertyValue('--primaryColor');
var secondaryColor = document.documentElement.style.getPropertyValue('--secondaryColor');
var errorColor = document.documentElement.style.getPropertyValue('--errorColor');

var themeColors = 
themeColors["--primaryColor"] = primaryColor;
themeColors["--secondaryColor"] = secondaryColor;
themeColors["--errorColor"] = errorColor;

function setTheme(theme) 
     for (key in theme) 
        let color = theme[key];
        document.documentElement.style.setProperty(key, color);
   
 

我使用 Atom 和 Bootstrap 的一个工作示例:

        var backgroundColor = document.documentElement.style.getPropertyValue('--blue');
        backgroundColor = "#dc3545";

        function setTheme(theme) 
          for (key in theme) 
            let color = theme[key];
            document.documentElement.style.setProperty(key, color);
          
        

        var theme = 
        theme["--blue"] = backgroundColor;

        setTheme(theme);

>>编辑

Nadeem 在下面的评论中更好地澄清了这个问题,但不幸的是,我了解到 :root 可以使用 get Window.getComputedStyle() 访问,但这不会返回 CSS 变量声明。

解决这个问题的方法是读取 css 文件,解析变量并将它们填充到关联数组中,但即使这样也假设您知道从哪里获取 css 文件...

        //an associative array that will hold our values
        var cssVars = ;

        var request = new XMLHttpRequest();
        request.open('GET', './css/style.css', true);

        request.onload = function() 
          if (request.status >= 200 && request.status < 400) 
              //Get all CSS Variables in the document
              var matches = request.responseText.match(/(--)\w.+;/gi);

              //Get all CSS Variables in the document
              for(let match in matches) 
                  var property = matches[match];
                  //split the Variable name from its value
                  let splitprop = property.split(":")

                  //turn the value into a string
                  let value = splitprop[1].toString()

                  cssVars[splitprop[0]] = value.slice(0, -1); //remove ;
              

              // console.log(cssVars);
              // > Object --primaryColor: "aliceblue", --secondaryColor: "blue", --errorColor: "#cc2511"

              // console.log(Object.keys(cssVars));
              // > ["--primaryColor", "--secondaryColor", "--errorColor" ]

              setTheme(cssVars)

             else 
              // We reached our target server, but it returned an error
            
          ;

          request.onerror = function() 
            console.log("There was a connection error");
          ;

          request.send();



          function setTheme(theme) 
            var keys = Object.keys(theme)

            for (key in keys) 
              let prop = keys[key]
              let color = theme[keys[key]];

              console.log(prop, color);
              // --primaryColor aliceblue etc...
            
          

【讨论】:

假设我在 css 中有 200 个变量,所以我必须写这一行 var primaryColor = document.documentElement.style.getPropertyValue('--primaryColor'); 200 次。我想要动态的。

以上是关于使用javascript获取数组中的所有css根变量并更改值的主要内容,如果未能解决你的问题,请参考以下文章

光纤从1根变40根,在光纤扩容问题上不再烦恼!!!

使用 JavaScript 将两个数组的所有可能组合作为数组数组获取

纤亿通光纤1根变40,光纤扩容您不再烦恼!!!

如何从 JavaScript 中的对象数组中获取不同的值?

JavaScript-简单的贪吃蛇小游戏

Java 之 JavaScript