如何在 JavaScript 中动态创建 CSS 类并应用?

IT技术 javascript css stylesheet
2021-01-30 16:36:12

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

是否可以?

有样品就好了。

6个回答

虽然我不确定您为什么要使用 JavaScript 创建 CSS 类,但这里有一个选项:

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 目的突出显示某些元素。
2021-03-15 16:36:12
另一个用例是您想要一个不依赖于 CSS 文件的单个 JS 库。就我而言,我想要开箱即用的轻量级咆哮式警报弹出窗口。
2021-03-20 16:36:12
我的用例是加载一个随机的谷歌网络字体,然后给 randomFont 类提供字体系列:-)
2021-03-21 16:36:12
我曾经需要一次突出显示和取消突出显示页面中的许多元素,对应于用户的选择。对所有元素应用和删除类是 slooooow。因此,在我的 ajax 请求返回数据后的浏览器中,我为每个可能的选择创建了一个 css 类并将其应用于每个元素,为所有没有属性的类定义规则。一旦做出选择,重写规则本身就会以惊人的闪电般的速度更新页面上的所有元素。所以是的,有一个用例。
2021-03-23 16:36:12
很确定这会导致 IE 8 及更低版本中出现未知的运行时错误。
2021-04-08 16:36:12

找到了一个更好的解决方案,它适用于所有浏览器。
使用 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 是没有定义。
2021-03-10 16:36:12
事实证明,某些版本的铬(或铬)不允许在索引 0 上插入规则。这是修复:styleSheet.insertRule(selector + "{" + style + "}", styleSheet.cssRules.length);
2021-03-10 16:36:12
@w00t 您能否粘贴或编辑代码以使其正常工作?
2021-03-27 16:36:12
@dnuske 我遇到了同样的问题。结果是 styleSheet.cssRules 的计算结果为 null。我使用的修复方法是创建一个新变量var styleSheetLength = styleSheet.cssRules ? styleSheet.cssRules.length : 0并将其用法替换为函数的实现。
2021-04-01 16:36:12
我刚刚打开 Chrome(版本 34.0.1847.132)粘贴函数并执行它,但它不起作用:“TypeError:无法读取 null 的属性‘长度’”。从开发人员控制台创建它可能不起作用吗?
2021-04-05 16:36:12

简短的回答,这是“在所有浏览器上”兼容的(特别是 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”属性,您可以使用它来添加/删除规则。

对我来说,chrome style.sheet 和 style.styleSheet 不存在
2021-03-10 16:36:12
所以这会在每个类创建时创建一个新的“样式”元素?因此,如果我要基于数据在 for 循环中创建 1000 多个类,这需要应用 document.head.appendChild 1000 次吗?
2021-03-31 16:36:12

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

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

$.injectCSS({
    "#test": {
        height: 123
    }
});
2021-04-03 16:36:12

YUI 拥有迄今为止我见过的最好的样式表实用程序我鼓励你检查一下,但这里有一个味道:

// 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 属性。这并不总是想要的效果。