在运行时使用jQuery创建CSS规则/类

205
通常我有一个CSS文件,其中包含以下规则:
#my-window {
    position: fixed;
    z-index: 102;
    display:none;
    top:50%;
    left:50%;
}

我如何避免创建静态的CSS文件,通过在运行时将CSS信息添加到body或类似的东西中?(仅使用jQuery)

我想要用jQuery定义一次并在后续多次使用它;这就是为什么我不想每次将它添加到特定的DOM元素中。

我知道简单的功能(css("attr1", "value");),但我如何创建一个完整可重用的CSS规则?

22个回答

286

你可以创建样式元素并将其插入到DOM中

$("<style type='text/css'> .redbold{ color:#f00; font-weight:bold;} </style>").appendTo("head");
$("<div/>").addClass("redbold").text("SOME NEW TEXT").appendTo("body");

在 Opera10、FF3.5、IE8 和 IE6 上测试过。


要点是自给自足的。您可以在本地创建它,它将正常工作。下载链接的直接链接:https://gist.github.com/gists/714352/download - Daniel Ribeiro
1
在IE8中,对于我来说会抛出一个“意外调用方法或属性访问”的错误。我不得不遵循这篇文章才能使其正常工作。 - Brandon Boone
6
IE9中网页样式表最多只能有31个样式。详见:http://blogs.msdn.com/b/ieinternals/archive/2011/05/14/internet-explorer-stylesheet-rule-selector-import-sheet-limit-maximum.aspx - IvanH
1
如果它不起作用,请尝试将样式附加到 body。例如:$("<style>...</style>").appendTo("body"); - inDream
1
@Andrew 你不能只是用一个ID定义样式标签,然后通过匹配该ID来删除它吗? - Koert van Kleef
显示剩余3条评论

134

简单地

$("<style>")
    .prop("type", "text/css")
    .html("\
    #my-window {\
        position: fixed;\
        z-index: 102;\
        display:none;\
        top:50%;\
        left:50%;\
    }")
    .appendTo("head");

注意到反斜杠了吗?它们用于连接位于新行上的字符串。如果没有它们,就会生成错误。


6
这应该是被接受的答案。它实际上回答了这个问题。 - Johannes Pille
2
我同意@JohannesPille的观点,这才是真正的答案! - bayu
在 Cordova iOS 上无法工作。你能否提供建议? - RamGrg
2
非常高效和直接。一旦新规则被注入到头部,您可以从页面的任何位置检索它,包括从PHP中。 - Brice Coustillas
https://dev59.com/v3I-5IYBdhLWcg3wsKv9#1720483 - user1742529

19

你可以将CSS应用于对象。因此,你可以在JavaScript中定义你的对象,如下所示:

var my_css_class = { backgroundColor : 'blue', color : '#fff' };

然后只需将其应用于您想要的所有元素即可

$("#myelement").css(my_css_class);

所以它是可重复使用的。不过你会出于什么目的而这样做呢?


22
我认为这是一条 CSS 规则,而不是 CSS 类。 - hippietrail
18
这个答案是误导性的。提问者想在运行时创建一个CSS规则,而不是将特定元素的样式设置为恒定(可重用)的CSS声明。 - Dan Dascalescu
4
虽然不完全符合他们的要求,但这确实是正确的解决方案 :) 在DOM中添加额外的<style>元素会导致一些糟糕的代码气味。 - Kevin
3
您需要移除这些已应用的规则,这可以通过其他解决方案来实现。 - Vishwanath
@Kevin - 可能是这样,但有时候这正是你所需要的。例如 - 当某个元素正在被一些ajax脚本重新创建,并且您需要保留新的样式规则时。 - But those new buttons though..
这也无法修改或创建伪元素样式规则。 - ksoo

13

根据 dottoro,如果您不需要支持IE < 9,可以使用insertRule。那里还有一些跨浏览器的代码。

document.styleSheets[0].insertRule('#my-window {\
    position: fixed;\
    z-index: 102;\
    display:none;\
    top:50%;\
    left:50%;\
}', 0)

11

这里有一个jQuery插件,可以让您注入CSS:

https://github.com/kajic/jquery-injectCSS

示例:

$.injectCSS({
    "#my-window": {
        "position": "fixed",
        "z-index": 102,
        "display": "none",
        "top": "50%",
        "left": "50%"
    }
});

9

相对于其他答案,这并不是什么新的东西,因为它使用了在这里这里描述的概念,但我想利用JSON风格的声明:

function addCssRule(rule, css) {
  css = JSON.stringify(css).replace(/"/g, "").replace(/,/g, ";");
  $("<style>").prop("type", "text/css").html(rule + css).appendTo("head");
}

使用方法:

addCssRule(".friend a, .parent a", {
  color: "green",
  "font-size": "20px"
});

我不确定它是否涵盖了CSS的所有功能,但目前对我来说有效。如果不行,请将其视为满足您自己需求的起点。 :)


为了清晰起见,我建议将参数命名为“selector”和“body”。替换逗号会在指定字体或使用rgb()等时造成问题,但总体而言这个想法很好。 - Palec

8

如果您不想将CSS硬编码到CSS块/文件中,您可以使用jQuery动态地向HTML元素、ID和类添加CSS。

$(document).ready(function() {
  //Build your CSS.
  var body_tag_css = {
    "background-color": "#ddd",
    "font-weight": "",
    "color": "#000"
  }
  //Apply your CSS to the body tag.  You can enter any tag here, as
  //well as ID's and Classes.
  $("body").css(body_tag_css);
});

8
这个回答并不完全符合提问者的要求。提问者想要在运行时创建一个CSS规则,而不是将特定元素的样式设置为恒定的CSS声明。 - Dan Dascalescu
我理解,但这是一种替代方案,所以我提供了它。 - Mike Trpcic
3
@MikeTrpcic 问题在于还有其他人正在寻找这个解决方案——向页面添加CSS规则——而你的答案并没有解决这个问题。 - nate

6
在(不寻常的)情况下,您希望经常动态更改样式 - 例如主题构建器应用程序 - 添加<style>标签或调用CSSStyleSheet.insertRule()将导致日益增长的样式表,这可能会影响性能和设计调试。
我的方法仅允许每个选择器/属性组合一个规则,并在设置任何规则时清除任何现有规则。该API简单且灵活:
function addStyle(selector, rulename, value) {
    var stylesheet = getAppStylesheet();
    var cssRules = stylesheet.cssRules || stylesheet.rules;
    var rule = stylesheet.insertRule(selector + ' { ' + rulename + ':' + value + ';}', cssRules.length);
}

function clearStyle(selector, rulename) {
    var stylesheet = getAppStylesheet();
    var cssRules = stylesheet.cssRules || stylesheet.rules;
    for (var i=0; i<cssRules.length; i++) {
        var rule = cssRules[i];
        if (rule.selectorText == selector && rule.style[0] == rulename) {
            stylesheet.deleteRule(i);
            break;
        }
    }       
}

function addStyles(selector, rules) {
    var stylesheet = getAppStylesheet();
    var cssRules = stylesheet.cssRules || stylesheet.rules;
    for (var prop in rules) {
        addStyle(selector, prop, rules[prop]);
    }
}

function getAppStylesheet() {
    var stylesheet = document.getElementById('my-styles');
    if (!stylesheet) {
        stylesheet = $('<style id="my-styles">').appendTo('head')[0];
    }
    stylesheet = stylesheet.sheet;
    return stylesheet;
}

使用方法:

addStyles('body', {
    'background-color': 'black',
    color: 'green',
    margin: 'auto'
});

clearStyle('body', 'background-color');
addStyle('body', 'color', '#333')

6

如果您创建一个需要自定义CSS的jQuery小部件(例如为特定小部件扩展现有的jQueryUI CSS框架),则添加自定义规则非常有用。此解决方案基于Taras的答案(上面的第一个答案)。

假设您的HTML标记有一个id为“addrule”的按钮和一个包含一些文本的id为“target”的div:

jQuery代码:

$( "#addrule" ).click(function () { addcssrule($("#target")); });

function addcssrule(target) 
{ 
var cssrules =  $("<style type='text/css'> </style>").appendTo("head");

cssrules.append(".redbold{ color:#f00; font-weight:bold;}"); 
cssrules.append(".newfont {font-family: arial;}"); 
target.addClass("redbold newfont");     
}       

这种方法的优点在于您可以重复使用变量cssrules来随意添加或删除规则。如果cssrules嵌入到像jQuery小部件这样的持久对象中,您就有一个持久的局部变量可供使用。

多好的想法啊!我将它与这个页面上的片段http://www.ssdtutorials.com/tutorials/title/jquery-flashing-text.html结合使用,以允许切换颜色(原始版本仅切换类)。谢谢! - bgmCoder

6
请注意,jQuery().css()只会更改匹配元素的样式,而不会更改样式表规则。
这里是我编写的一个JavaScript函数,用于修改样式表规则本身。
    /**
     * Modify an existing stylesheet.
     * - sheetId - the id of the <link> or <style> element that defines the stylesheet to be changed
     * - selector - the id/class/element part of the rule.  e.g. "div", ".sectionTitle", "#chapter2"
     * - property - the CSS attribute to be changed.  e.g. "border", "font-size"
     * - value - the new value for the CSS attribute.  e.g. "2px solid blue", "14px"
     */
    function changeCSS(sheetId, selector, property, value){
        var s = document.getElementById(sheetId).sheet;
        var rules = s.cssRules || s.rules;
        for(var i = rules.length - 1, found = false; i >= 0 && !found; i--){
            var r = rules[i];
            if(r.selectorText == selector){
                r.style.setProperty(property, value);
                found = true;
            }
        }
        if(!found){
            s.insertRule(selector + '{' + property + ':' + value + ';}', rules.length);
        }
    }

优点:

  • 样式可以在<head>脚本中计算,而无需创建DOM元素,因此可以在文档第一次渲染之前避免一个令人烦恼的渲染、计算和重新渲染过程。使用jQuery,您需要等待DOM元素被创建后再重新设置样式并重新渲染它们。
  • 在重新设置样式后添加的动态元素将自动应用新样式,而无需额外调用jQuery(newElement).css()

注意事项:

  • 我已经在Chrome和IE10上使用过它。我认为它可能需要一些修改才能在旧版本的IE上运行良好。特别是,旧版本的IE可能没有定义s.cssRules,因此它们将退回到有些奇特的s.rules,例如与逗号分隔的选择器相关的奇怪/有缺陷的行为,如"body,p"。如果避免这些问题,则在较旧的IE版本中,您可能不需要进行修改,但我尚未测试过。
  • 当前选择器需要完全匹配:使用小写字母,并小心处理逗号分隔的列表;顺序需要匹配,它们应该是"first, second"格式,即分隔符是逗号后跟一个空格字符。
  • 可以花费一些额外的时间来检测和智能处理重叠的选择器,例如那些在逗号分隔的列表中的选择器。
  • 也可以在不太费力的情况下添加对媒体查询和!important修饰符的支持。

如果您想对此函数进行改进,您会发现这里有一些有用的API文档: https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet


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