【问题标题】:How to dynamically create CSS class in JavaScript and apply?如何在 JavaScript 中动态创建 CSS 类并应用?
【发布时间】:2010-12-15 18:34:00
【问题描述】:

我需要在 JavaScript 中动态创建一个 CSS 样式表类,并将其分配给一些 HTML 元素,如 div、table、span、tr 等,以及一些控件,如 asp:Textbox、Dropdownlist 和 datalist。

有可能吗?

如果有样品就好了。

【问题讨论】:

标签: javascript css stylesheet


【解决方案1】:

这是一个选项:

var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = '.cssClass { color: #F00; }';
document.getElementsByTagName('head')[0].appendChild(style);

document.getElementById('someElementId').className = 'cssClass';

【讨论】:

  • 我的用例是一个小书签,它为 QA 目的突出显示某些元素。
  • 很确定这会在 IE 8 及更低版本中导致未知的运行时错误。
  • 我的用例是加载一个随机的谷歌网络字体,然后给 randomFont 类赋予 font-family :-)
  • 另一个用例是您想要一个不依赖 CSS 文件的单个 JS 库。就我而言,我想要开箱即用的轻量级咆哮式警报弹出窗口。
  • 我曾经需要同时高亮和取消高亮页面中的许多元素,对应于用户的选择。对所有元素应用和删除类是很慢的。因此,在我的 ajax 请求返回数据后的浏览器中,我为每个可能的选择创建了一个 css 类并将其应用于每个元素,为所有没有属性的类定义规则。一旦做出选择,重写规则本身就会以惊人的闪电速度更新页面上的所有元素。所以是的,有一个用例。
【解决方案2】:

找到了一个更好的解决方案,它适用于所有浏览器。
使用 document.styleSheet 添加或替换规则。接受的答案简短而方便,但这适用于 IE8 和更少。

function createCSSSelector (selector, style) {
  if (!document.styleSheets) return;
  if (document.getElementsByTagName('head').length == 0) return;

  var styleSheet,mediaType;

  if (document.styleSheets.length > 0) {
    for (var i = 0, l = document.styleSheets.length; i < l; i++) {
      if (document.styleSheets[i].disabled) 
        continue;
      var media = document.styleSheets[i].media;
      mediaType = typeof media;

      if (mediaType === 'string') {
        if (media === '' || (media.indexOf('screen') !== -1)) {
          styleSheet = document.styleSheets[i];
        }
      }
      else if (mediaType=='object') {
        if (media.mediaText === '' || (media.mediaText.indexOf('screen') !== -1)) {
          styleSheet = document.styleSheets[i];
        }
      }

      if (typeof styleSheet !== 'undefined') 
        break;
    }
  }

  if (typeof styleSheet === 'undefined') {
    var styleSheetElement = document.createElement('style');
    styleSheetElement.type = 'text/css';
    document.getElementsByTagName('head')[0].appendChild(styleSheetElement);

    for (i = 0; i < document.styleSheets.length; i++) {
      if (document.styleSheets[i].disabled) {
        continue;
      }
      styleSheet = document.styleSheets[i];
    }

    mediaType = typeof styleSheet.media;
  }

  if (mediaType === 'string') {
    for (var i = 0, l = styleSheet.rules.length; i < l; i++) {
      if(styleSheet.rules[i].selectorText && styleSheet.rules[i].selectorText.toLowerCase()==selector.toLowerCase()) {
        styleSheet.rules[i].style.cssText = style;
        return;
      }
    }
    styleSheet.addRule(selector,style);
  }
  else if (mediaType === 'object') {
    var styleSheetLength = (styleSheet.cssRules) ? styleSheet.cssRules.length : 0;
    for (var i = 0; i < styleSheetLength; i++) {
      if (styleSheet.cssRules[i].selectorText && styleSheet.cssRules[i].selectorText.toLowerCase() == selector.toLowerCase()) {
        styleSheet.cssRules[i].style.cssText = style;
        return;
      }
    }
    styleSheet.insertRule(selector + '{' + style + '}', styleSheetLength);
  }
}

函数使用如下。

createCSSSelector('.mycssclass', 'display:none');

【讨论】:

  • 确认使用 IE8。我确实必须在 mediaType for-loop ifs 中添加“styleSheet.cssRules[i].selectorText &&”和“styleSheet.rules[i].selectorText &&”,因为它在 Chrome 中不起作用,显然有时 selectorText 是'未定义。
  • @w00t 您能否粘贴或编辑代码以使其正常工作?
  • 我刚刚打开 Chrome(版本 34.0.1847.132)粘贴函数并执行它,但它不起作用:“TypeError:无法读取 null 的属性 'length'”。是不是从开发者控制台创建它不起作用?
  • 事实证明,某些版本的 chrome(或 chromium)不允许在索引 0 上插入规则。这里是修复:styleSheet.insertRule(selector + "{" + style + "}", styleSheet.cssRules.length);
  • @dnuske 我遇到了同样的问题。事实证明 styleSheet.cssRules 的计算结果为 null。我使用的修复方法是创建一个新变量 var styleSheetLength = styleSheet.cssRules ? styleSheet.cssRules.length : 0 并将其用法替换为函数的实现。
【解决方案3】:

简短的回答,这是“在所有浏览器上”兼容的(特别是 IE8/7):

function createClass(name,rules){
    var style = document.createElement('style');
    style.type = 'text/css';
    document.getElementsByTagName('head')[0].appendChild(style);
    if(!(style.sheet||{}).insertRule) 
        (style.styleSheet || style.sheet).addRule(name, rules);
    else
        style.sheet.insertRule(name+"{"+rules+"}",0);
}
createClass('.whatever',"background-color: green;");

最后一点将类应用于元素:

function applyClass(name,element,doRemove){
    if(typeof element.valueOf() == "string"){
        element = document.getElementById(element);
    }
    if(!element) return;
    if(doRemove){
        element.className = element.className.replace(new RegExp("\\b" + name + "\\b","g"));
    }else{      
        element.className = element.className + " " + name;
    }
}

这里还有一个小测试页:https://gist.github.com/shadybones/9816763

关键一点是样式元素有一个“styleSheet”/“sheet”属性,您可以使用它来添加/删除规则。

【讨论】:

  • 所以这会在每次创建类时创建一个新的“样式”元素?因此,如果我要在基于数据的 for 循环中创建 1000 多个类,这将需要应用 document.head.appendChild 1000 次?
  • 对我来说 chrome style.sheet 和 style.styleSheet 不存在
  • 它至少在 2022 年 1 月不再在 Chrome 中工作
【解决方案4】:

有一个轻量级的 jQuery 插件可以生成 CSS 声明:jQuery-injectCSS

事实上,它使用JSS(由 JSON 描述的 CSS),但它很容易处理以生成动态 css 样式表。

$.injectCSS({
    "#test": {
        height: 123
    }
});

【讨论】:

【解决方案5】:

YUI 拥有迄今为止我见过的最好的stylesheet utility。我鼓励你去看看,但这里有一个味道:

// style element or locally sourced link element
var sheet = YAHOO.util.StyleSheet(YAHOO.util.Selector.query('style',null,true));

sheet = YAHOO.util.StyleSheet(YAHOO.util.Dom.get('local'));


// OR the id of a style element or locally sourced link element
sheet = YAHOO.util.StyleSheet('local');


// OR string of css text
var css = ".moduleX .alert { background: #fcc; font-weight: bold; } " +
          ".moduleX .warn  { background: #eec; } " +
          ".hide_messages .moduleX .alert, " +
          ".hide_messages .moduleX .warn { display: none; }";

sheet = new YAHOO.util.StyleSheet(css);

显然还有其他更简单的方法可以即时更改样式,例如此处建议的方法。如果它们对您的问题有意义,那么它们可能是最好的,但是修改 CSS 是一个更好的解决方案肯定是有原因的。最明显的情况是当您需要修改大量元素时。另一个主要情况是如果您需要更改样式以涉及级联。使用 DOM 修改元素将始终具有更高的优先级。这是大锤方法,相当于直接在 HTML 元素上使用 style 属性。这并不总是理想的效果。

【讨论】:

    【解决方案6】:

    从 IE 9 开始。您现在可以加载文本文件并设置 style.innerHTML 属性。所以基本上你现在可以通过 ajax 加载一个 css 文件(并获取回调),然后像这样在样式标签中设置文本。

    这适用于其他浏览器,不知道多远。但只要你不需要支持 IE8 就可以了。

    // RESULT: doesn't work in IE8 and below. Works in IE9 and other browsers.
    $(document).ready(function() {
        // we want to load the css as a text file and append it with a style.
        $.ajax({
            url:'myCss.css',
            success: function(result) {
                var s = document.createElement('style');
                s.setAttribute('type', 'text/css');
                s.innerHTML = result;
                document.getElementsByTagName("head")[0].appendChild(s);
            },
            fail: function() {
                alert('fail');
            }
        })
    });
    

    然后你可以让它拉一个像 myCss.css 这样的外部文件

    .myClass { background:#F00; }
    

    【讨论】:

      【解决方案7】:

      这是 Vishwanath 用 cmets 稍微改写的解决方案:

      function setStyle(cssRules, aSelector, aStyle){
          for(var i = 0; i < cssRules.length; i++) {
              if(cssRules[i].selectorText && cssRules[i].selectorText.toLowerCase() == aSelector.toLowerCase()) {
                  cssRules[i].style.cssText = aStyle;
                  return true;
              }
          }
          return false;
      }
      
      function createCSSSelector(selector, style) {
          var doc = document;
          var allSS = doc.styleSheets;
          if(!allSS) return;
      
          var headElts = doc.getElementsByTagName("head");
          if(!headElts.length) return;
      
          var styleSheet, media, iSS = allSS.length; // scope is global in a function
          /* 1. search for media == "screen" */
          while(iSS){ --iSS;
              if(allSS[iSS].disabled) continue; /* dont take into account the disabled stylesheets */
              media = allSS[iSS].media;
              if(typeof media == "object")
                  media = media.mediaText;
              if(media == "" || media=='all' || media.indexOf("screen") != -1){
                  styleSheet = allSS[iSS];
                  iSS = -1;   // indication that media=="screen" was found (if not, then iSS==0)
                  break;
              }
          }
      
          /* 2. if not found, create one */
          if(iSS != -1) {
              var styleSheetElement = doc.createElement("style");
              styleSheetElement.type = "text/css";
              headElts[0].appendChild(styleSheetElement);
              styleSheet = doc.styleSheets[allSS.length]; /* take the new stylesheet to add the selector and the style */
          }
      
          /* 3. add the selector and style */
          switch (typeof styleSheet.media) {
          case "string":
              if(!setStyle(styleSheet.rules, selector, style));
                  styleSheet.addRule(selector, style);
              break;
          case "object":
              if(!setStyle(styleSheet.cssRules, selector, style));
                  styleSheet.insertRule(selector + "{" + style + "}", styleSheet.cssRules.length);
              break;
          }
      

      【讨论】:

        【解决方案8】:

        https://jsfiddle.net/xk6Ut/256/

        在 JavaScript 中动态创建和更新 CSS 类的一个选项:

        • 使用样式元素创建 CSS 部分
        • 为样式元素使用 ID,以便我们可以更新 CSS

        .....

        function writeStyles(styleName, cssText) {
            var styleElement = document.getElementById(styleName);
            if (styleElement) 
                     document.getElementsByTagName('head')[0].removeChild(
                styleElement);
            styleElement = document.createElement('style');
            styleElement.type = 'text/css';
            styleElement.id = styleName;
            styleElement.innerHTML = cssText;
            document.getElementsByTagName('head')[0].appendChild(styleElement);
        }
        

        ...

            var cssText = '.testDIV{ height:' + height + 'px !important; }';
            writeStyles('styles_js', cssText)
        

        【讨论】:

          【解决方案9】:

          JSS 是一个可以帮助您完成任务的有趣项目。

          JSS 是一个 CSS 创作工具,它允许您使用 JavaScript 以声明性、无冲突和可重用的方式描述样式。它可以在浏览器、服务器端或在 Node 中构建时编译。

          JSS 库允许您使用 .attach() 函数注入 DOM/head 部分。

          Repl online version 用于评估。

          进一步information on JSS

          一个例子:

          // Use plugins.
          jss.use(camelCase())
          
          // Create your style.
          const style = {
            myButton: {
              color: 'green'
            }
          }
          
          // Compile styles, apply plugins.
          const sheet = jss.createStyleSheet(style)
          
          // If you want to render on the client, insert it into DOM.
          sheet.attach()
          

          【讨论】:

            【解决方案10】:

            使用谷歌闭包:

            你可以只使用 ccsom 模块:

            goog.require('goog.cssom');
            var css_node = goog.cssom.addCssText('.cssClass { color: #F00; }');
            

            将css节点放入文档头部时,javascript代码尝试跨浏览器。

            【讨论】:

              【解决方案11】:

              一个衬里,将一个或多个新的级联规则附加到文档。

              此示例将cursor:pointer 附加到每个buttoninputselect

              document.body.appendChild(Object.assign(document.createElement("style"), {textContent: "select, button, input {cursor:pointer}"}))
              

              【讨论】:

                【解决方案12】:

                我在这里查看了一些答案,如果没有,我找不到任何自动添加新样式表的东西,如果不是简单地修改已经包含所需样式的现有样式表,所以我做了一个新功能(应该适用于所有浏览器,虽然未经测试,但使用 addRule,除此之外只有基本的原生 JavaScript,如果它有效,请告诉我):

                function myCSS(data) {
                    var head = document.head || document.getElementsByTagName("head")[0];
                    if(head) {
                        if(data && data.constructor == Object) {
                            for(var k in data) {
                                var selector = k;
                                var rules = data[k];
                
                                var allSheets = document.styleSheets;
                                var cur = null;
                
                                var indexOfPossibleRule = null,
                                    indexOfSheet = null;
                                for(var i = 0; i < allSheets.length; i++) {
                                    indexOfPossibleRule = findIndexOfObjPropInArray("selectorText",selector,allSheets[i].cssRules);
                                    if(indexOfPossibleRule != null) {
                                        indexOfSheet = i;
                                        break;
                                    }
                                }
                
                                var ruleToEdit = null;
                                if(indexOfSheet != null) {
                
                                    ruleToEdit = allSheets[indexOfSheet].cssRules[indexOfPossibleRule];
                
                                } else {
                                    cur = document.createElement("style");
                                    cur.type =  "text/css";
                                    head.appendChild(cur);
                                    cur.sheet.addRule(selector,"");
                                    ruleToEdit = cur.sheet.cssRules[0];
                                    console.log("NOPE, but here's a new one:", cur);
                                }
                                applyCustomCSSruleListToExistingCSSruleList(rules, ruleToEdit, (err) => {
                                    if(err) {
                                        console.log(err);
                                    } else {
                                        console.log("successfully added ", rules, " to ", ruleToEdit);
                                    }
                                });
                            }
                        } else {
                            console.log("provide one paramter as an object containing the cssStyles, like: {\"#myID\":{position:\"absolute\"}, \".myClass\":{background:\"red\"}}, etc...");
                        }
                    } else {
                        console.log("run this after the page loads");
                    }
                
                };  
                

                然后只需在上述函数内或其他任何地方添加这 2 个辅助函数:

                function applyCustomCSSruleListToExistingCSSruleList(customRuleList, existingRuleList, cb) {
                    var err = null;
                    console.log("trying to apply ", customRuleList, " to ", existingRuleList);
                    if(customRuleList && customRuleList.constructor == Object && existingRuleList && existingRuleList.constructor == CSSStyleRule) {
                        for(var k in customRuleList) {
                            existingRuleList["style"][k] = customRuleList[k];
                        }
                
                    } else {
                        err = ("provide first argument as an object containing the selectors for the keys, and the second argument is the CSSRuleList to modify");
                    }
                    if(cb) {
                        cb(err);
                    }
                }
                
                function findIndexOfObjPropInArray(objPropKey, objPropValue, arr) {
                    var index = null;
                    for(var i = 0; i < arr.length; i++) {
                        if(arr[i][objPropKey] == objPropValue) {
                            index = i;
                            break;
                        }
                    }
                    return index;
                }
                

                (请注意,我在这两个中都使用了 for 循环而不是 .filter,因为 CSS 样式/规则列表类只有一个长度属性,而没有 .filter 方法。)

                然后调用它:

                myCSS({
                    "#coby": {
                        position:"absolute",
                        color:"blue"
                    },
                    ".myError": {
                        padding:"4px",
                        background:"salmon"
                    }
                })
                

                让我知道它是否适用于您的浏览器或出现错误。

                【讨论】:

                • 由于某种原因,添加 !important 会使声明为空。知道如何使用“重要”吗?
                【解决方案13】:

                浏览了答案,但最明显和最直接的答案不见了:使用document.write() 写出您需要的一大段 CSS。

                这是一个示例(在 codepen 上查看:http://codepen.io/ssh33/pen/zGjWga):

                <style>
                   @import url(http://fonts.googleapis.com/css?family=Open+Sans:800);
                   .d, body{ font: 3vw 'Open Sans'; padding-top: 1em; }
                   .d {
                       text-align: center; background: #aaf;
                       margin: auto; color: #fff; overflow: hidden; 
                       width: 12em; height: 5em;
                   }
                </style>
                
                <script>
                   function w(s){document.write(s)}
                   w("<style>.long-shadow { text-shadow: ");
                   for(var i=0; i<449; i++) {
                      if(i!= 0) w(","); w(i+"px "+i+"px #444");
                   }
                   w(";}</style>");
                </script> 
                
                <div class="d">
                    <div class="long-shadow">Long Shadow<br> Short Code</div>
                </div>
                

                【讨论】:

                • 这很好,除非您需要在页面加载后创建 CSS 规则或使用 XHTML。
                【解决方案14】:

                为了搜索者的利益;如果您使用的是 jQuery,您可以执行以下操作:

                var currentOverride = $('#customoverridestyles');
                
                if (currentOverride) {
                 currentOverride.remove();
                }
                
                $('body').append("<style id=\"customoverridestyles\">body{background-color:pink;}</style>");
                

                显然,您可以将内部 css 更改为您想要的任何内容。

                感谢一些人更喜欢纯 JavaScript,但它可以工作并且对于动态编写/覆盖样式非常强大。

                【讨论】:

                  【解决方案15】:
                  function createCSSClass(selector, style, hoverstyle) 
                  {
                      if (!document.styleSheets) 
                      {
                          return;
                      }
                  
                      if (document.getElementsByTagName("head").length == 0) 
                      {
                  
                          return;
                      }
                      var stylesheet;
                      var mediaType;
                      if (document.styleSheets.length > 0) 
                      {
                          for (i = 0; i < document.styleSheets.length; i++) 
                          {
                              if (document.styleSheets[i].disabled) 
                              {
                                  continue;
                              }
                              var media = document.styleSheets[i].media;
                              mediaType = typeof media;
                  
                              if (mediaType == "string") 
                              {
                                  if (media == "" || (media.indexOf("screen") != -1)) 
                                  {
                                      styleSheet = document.styleSheets[i];
                                  }
                              } 
                              else if (mediaType == "object") 
                              {
                                  if (media.mediaText == "" || (media.mediaText.indexOf("screen") != -1)) 
                                  {
                                      styleSheet = document.styleSheets[i];
                                  }
                              }
                  
                              if (typeof styleSheet != "undefined") 
                              {
                                  break;
                              }
                          }
                      }
                  
                      if (typeof styleSheet == "undefined") {
                          var styleSheetElement = document.createElement("style");
                          styleSheetElement.type = "text/css";
                          document.getElementsByTagName("head")[0].appendChild(styleSheetElement);
                          for (i = 0; i < document.styleSheets.length; i++) {
                              if (document.styleSheets[i].disabled) {
                                  continue;
                              }
                              styleSheet = document.styleSheets[i];
                          }
                  
                          var media = styleSheet.media;
                          mediaType = typeof media;
                      }
                  
                      if (mediaType == "string") {
                          for (i = 0; i < styleSheet.rules.length; i++) 
                          {
                              if (styleSheet.rules[i].selectorText.toLowerCase() == selector.toLowerCase()) 
                              {
                                  styleSheet.rules[i].style.cssText = style;
                                  return;
                              }
                          }
                  
                          styleSheet.addRule(selector, style);
                      }
                      else if (mediaType == "object") 
                      {
                          for (i = 0; i < styleSheet.cssRules.length; i++) 
                          {
                              if (styleSheet.cssRules[i].selectorText.toLowerCase() == selector.toLowerCase()) 
                              {
                                  styleSheet.cssRules[i].style.cssText = style;
                                  return;
                              }
                          }
                  
                          if (hoverstyle != null) 
                          {
                              styleSheet.insertRule(selector + "{" + style + "}", 0);
                              styleSheet.insertRule(selector + ":hover{" + hoverstyle + "}", 1);
                          }
                          else 
                          {
                              styleSheet.insertRule(selector + "{" + style + "}", 0);
                          }
                      }
                  }
                  
                  
                  
                  
                  
                  createCSSClass(".modalPopup  .header",
                                                   " background-color: " + lightest + ";" +
                                                    "height: 10%;" +
                                                    "color: White;" +
                                                    "line-height: 30px;" +
                                                    "text-align: center;" +
                                                    " width: 100%;" +
                                                    "font-weight: bold; ", null);
                  

                  【讨论】:

                  • 如果文档上没有当前样式表怎么办
                  【解决方案16】:

                  这是我的模块化解决方案:

                  var final_style = document.createElement('style');
                  final_style.type = 'text/css';
                  
                  function addNewStyle(selector, style){
                    final_style.innerHTML += selector + '{ ' + style + ' } \n';
                  };
                  
                  function submitNewStyle(){
                    document.getElementsByTagName('head')[0].appendChild(final_style);
                  
                    final_style = document.createElement('style');
                    final_style.type = 'text/css';
                  };
                  
                  function submitNewStyleWithMedia(mediaSelector){
                    final_style.innerHTML = '@media(' + mediaSelector + '){\n' + final_style.innerHTML + '\n};';
                      submitNewStyle();
                  };
                  

                  您基本上在代码中的任何地方都可以:
                  addNewStyle('body', 'color: ' + color1); ,其中 color1 是定义变量。

                  当您想“发布”当前 CSS 文件时,您只需执行 submitNewStyle(),
                  然后您仍然可以稍后添加更多 CSS。

                  如果您想通过“媒体查询”添加它,您可以选择。
                  在“addingNewStyles”之后,您只需使用submitNewStyleWithMedia('min-width: 1280px');


                  这对我的用例非常有用,因为我正在根据当前时间更改公共(不是我的)网站的 CSS。我在使用“活动”脚本之前提交了一个 CSS 文件,然后提交了其余文件(使网站看起来有点像在通过 querySelector 访问元素之前应该有的样子)。

                  【讨论】:

                  • 我今天要试试这个。会让你知道这在我的用例中是如何工作的。手指交叉!!!!
                  猜你喜欢
                  • 2021-04-14
                  • 2012-09-26
                  • 2015-07-17
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-02-17
                  • 1970-01-01
                  相关资源
                  最近更新 更多