如何使用jQuery更改css类规则?

52

请问有人可以帮忙吗?我有两个问题:

  1. 我想使用jQuery动态更改CSS类规则。

    .classname{color:red; font-size:14px;}

    如上例所示,我有一个名为.classname的类,现在我想只更改.classname内的字体大小而不是颜色,不通过添加CSS内联来实现。

  2. 我想创建并保存对.classname的更改到文件中,记住可能会保存完整的样式表或保存在文件中的类名数量。

有什么最简单和更好的方法可以做到这一点吗?

谢谢!


如果你想添加:hover和:active规则,这一点尤为重要,因为这是无法通过$.css()实现的。 - thugsb
14个回答

54
据我所知,没有jQuery的方法可以实现这个功能。可能有一些jQuery插件可以做到,但我不了解。
基本上,你在第一个问题中尝试实现的目标可以使用文档对象的styleSheets属性来实现。虽然需要遍历一个比较深的对象链,但在所有主流浏览器中都可以正常工作,包括Internet Explorer 6。下面是一个概念验证。CSS在STYLE标记内部,但外部CSS同样适用。我会让你自己进行抽象。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>
<head>
<title></title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta http-equiv="imagetoolbar" content="false">
<meta http-equiv="imagetoolbar" content="no">
<style type="text/css">
.classname {
 color: red;
 font-size: 14px;
}
</style>
<script type="text/javascript">
window.onload = function() {
    document.getElementById("button").onclick = function() {
        var ss = document.styleSheets;

        for (var i=0; i<ss.length; i++) {
            var rules = ss[i].cssRules || ss[i].rules;

            for (var j=0; j<rules.length; j++) {
                if (rules[j].selectorText === ".classname") {
                    rules[j].style.color = "green";
                }
            }
        }
    };
}
</script>
</head>
<body>

<h1 class="classname">Some red text</h1>

<button id="button">Make text green</button>

</body>
</html>
对于你的第二个问题,我没有时间编写一个解决方案,但是它需要像上面那样读取CSS声明,并使用CssRule对象的cssText属性构建一个字符串,最终通过Ajax POST请求发送到服务器。服务器端由你处理。
参考文献: 希望有所帮助。

感谢lonut G.Stan,你真厉害,我从未使用过document.styleSheets,甚至不知道它们存在 :S。实际上我想做这种工作http://www.coolchaser.com/layout/create或http://www.realeditor.com/editor/,你能告诉我他们是如何实现的吗?请告诉我概念。 - Yasir
1
@alpav,哦,这是一个bug :) 我不记得它是怎么从我的眼睛中溜走的了。 - Ionuț G. Stan
2
我的上面的例子是我从我链接到的文档页面中构思出来的,我想我记得为什么要这样做。我不仅仅是添加一个新规则,而是向现有声明添加一个新规则。因此,我必须查找每个样式表以找到该声明。现在,我能想到的最好的优化方法是按相反的顺序读取styleSheets,并在第一次遇到该selectorText后中断循环。这样,您只修改一个样式表,即具有最高优先级的样式表。 - Ionuț G. Stan
1
我不知道为什么,但这个解决方案在Google Chrome中不起作用(但在Safari中却可以,很奇怪)。有什么帮助吗? - Jesufer Vn
1
@JesuferVn 对我来说可行。我已经使用答案中的确切代码进行了测试。 - Ionuț G. Stan
显示剩余3条评论

17

最近,我需要修复Autocomplete小部件的一些jquery主题问题。我想改变自动完成小部件的背景颜色。

因此,我查找了CSS,并发现autocomplete类像这样定义

.ui-autocomplete { position: absolute; cursor: default; }   

因此,在我的程序中,我使用以下语句通过添加背景属性来更改类。请注意,我保留其他属性不变,否则它将破坏现有功能。

$("<style type='text/css'> .ui-autocomplete { position: absolute; cursor: default; background:black; color:white} </style>").appendTo("head");

5
这个技巧让我很开心。它可以减少大量代码,比这里获得最高票的答案还要好用。我会使用它。 - emackey

13

只有在以下情况下才应采用此方法:

  • 您需要将值设置为无法使用类名枚举的内容(例如像素中的变化宽度)
  • 并且您希望将此样式应用于将来插入DOM中的元素

有一个jQuery插件可以实现这一点:http://plugins.jquery.com/project/jquerycssrule

对于我所做的一个小项目,我提取了必要的要点并创建了以下函数:

function addCSSRule(sel, prop, val) {
    for(var i = 0; i < document.styleSheets.length; i++){
        var ss    = document.styleSheets[i];
        var rules = (ss.cssRules || ss.rules);
        var lsel  = sel.toLowerCase();

        for(var i2 = 0, len = rules.length; i2 < len; i2++){
            if(rules[i2].selectorText && (rules[i2].selectorText.toLowerCase() == lsel)){
                if(val != null){
                    rules[i2].style[prop] = val;
                    return;
                }
                else{
                    if(ss.deleteRule){
                        ss.deleteRule(i2);
                    }
                    else if(ss.removeRule){
                        ss.removeRule(i2);
                    }
                    else{
                        rules[i2].style.cssText = '';
                    }
                }
            }
        }
    }

    var ss = document.styleSheets[0] || {};
    if(ss.insertRule) {
        var rules = (ss.cssRules || ss.rules);
        ss.insertRule(sel + '{ ' + prop + ':' + val + '; }', rules.length);
    }
    else if(ss.addRule){
        ss.addRule(sel, prop + ':' + val + ';', 0);
    }
}

1
看起来现在已经消失了...唉。 - jedierikb
在GitHub上搜索jqurycssrule:https://github.com/search?q=jquerycssrule - Blago

12
如果我理解你的问题正确,你想要读取CSS文件,更改类别并通过保存文件来保留这些更改?
你无法使用客户端的JavaScript/jQuery来完成这个任务;但是你可以通过以下方式确实地更改匹配CSS类 .classname 的DOM元素的字体大小。
$('.classname').css('font-size','14px');

但是客户端JavaScript无法从Web浏览器访问文件系统,因此您需要其他方式(即服务器端代码)来对CSS文件本身进行更改。


19
在这里,你并没有改变 CSS 类本身的字体大小,而是向每个匹配该类名的 DOM 元素添加了一个单独的字体大小样式声明 - 这是一个重要的区别。如果在运行此 jQuery 语句后,构建一个新的 class 为 .classname 的 DOM 元素并将其附加到文档中,它将不具有字体大小属性。你需要重新运行 jQuery 命令来设置新元素的字体大小属性。 - Yetanotherjosh
@Yetanotherjosh,没错,我用词不当。已更新措辞以澄清。 - Russ Cam

6

你也可以尝试使用JSS,它对我非常有效:https://github.com/Box9/jss

Download and include jss.js in your HTML:

<script type="text/javascript" src="jss.js"></script>

Add new rule (or extend existing rule):

jss('.special', {
    color: 'red',
    fontSize: '2em',
    padding: '10px'
});

Retrieve existing rule:

jss('.special').get();

Returns:

{
    'color': 'red',
    'font-size': '2em',
    'padding-bottom': '10px',
    'padding-left': '10px',
    'padding-right': '10px',
    'padding-top': '10px'
}

Remove existing rule:

jss('.special').remove();

你说“添加”或“扩展”,但你是否也能“覆盖”一条规则呢?如果没有人回答,我将下载并尝试它,然后回来给出答案。 - Jeach
是的,@Jeach,“extend”确实意味着“override”。我正在为Google Chrome扩展程序的选项屏幕使用它。当用户定义其设置时,他们会覆盖样式表中的信息,因此任何动态添加的元素都会使用新样式。据我所知,使用jQuery没有简单的方法来做到这一点 - 您必须重新应用新元素的样式,而不能实际“更改”类。JSS只是使用其他答案中已建议的方法非常简洁地修改文档的CSS规则。 - Vlad Sabev
不行,这对我也不起作用(还试过'jQuery.Rules')。提醒任何人,我必须将'z-index'用引号括起来,否则在尝试更改时会出现错误。但我认为之所以'jss'和'jQuery.Rules'不起作用是因为实现网页的人将CSS在所有我加载的带有AJAX的页面中引用到body中注入。所以我不确定这是否是原因,但我的规则无论我尝试使用哪个库都不会改变。我需要进一步调查这个问题,看看我的理论是否是它不起作用的原因! - Jeach

2

DOM Level 2允许直接操作样式表的CSS规则。 例如:

var ss = document.styleSheets[1];  // ref to the first stylesheet
ss.cssRules[0].style.backgroundColor="blue";  // modification of the 1rst rule

有2个接口: 这使得激活/停用样式表、删除规则、添加规则等操作成为可能... 所有细节都在MDM中: 使用动态样式信息

1
你想做的是在服务器上有几个主题(theme1.css、theme2.css、theme3.css等),让用户选择他喜欢的主题。然后,你可以将用户选择的主题(theme2.css)保存在数据库中与用户配置文件一起保存。当用户显示页面时,你可以在页面顶部包含 theme2.css 而不是默认的 default.css 主题。
这在服务器端技术(如 PHP 或 ASP.NET)中非常有效。当然,你也可以使用 JavaScript 在用户计算机上保存 cookie 来记住用户的选择,并再次使用 JavaScript 通过 cookie 来 包含记忆的文件

如果你想让用户精确地管理设计的特定元素(如标题颜色,字体等),可以再次使用服务器端技术(在我看来更好)或 javascript 保存像头部=蓝色、字体=Arial这样的内容,并使用 jQuery 将存储的内容应用到你的页面上。

希望这能给你一个概述。


感谢ipfavreau,我已经得到了第一个点,即加载不同的CSS,但它将是预定义的。我想做这种类型的事情,或者改变我的MySpace主题。我必须在数据库中保存所有类名和属性吗?发送更改并检索然后更改界面? - Yasir
如果您不介意更改不会永久保存,您可以仅使用JavaScript将更改保存在Cookie中,但正如我所说,使用数据库可能会更好。您可以将所有属性保存在数据库中,然后使用AJAX在不重新加载的情况下将其显示回来。 - lpfavreau
太好了,谢谢老兄。我会将数据库表格与所有类名作为表和属性进行设置,这样我也可以更新类规则。我写得对吗? - Yasir
回答你的架构问题可能不在这个答案的范畴之内,你可能需要提出另一个更专注于具体实现的问题,但基本上是这样的:是的,你需要一个表格来将用户、属性和选择的值关联起来。 - lpfavreau

0

对于第一部分,我通常会指定一个样式块,并使用jQuery开启/关闭它。例如:

<style type="text/css" id="my-style" media="all">
    .classname{color:red; font-size:14px;}
</style>

然后您可以通过设置disabled属性来进行切换,例如:

$('#my-style').prop('disabled', true);
$('#my-style').prop('disabled', false);

0

由于应用于头部部分的样式会相互“重载”,它们最后使用的是针对所有相关元素的样式的append(),除非之前有!important

用于分配CSS内容的函数应该是text()而不是html(),以防止意外注入代码。

var dynamic_css = function(class_name){
  return '.' + class_name + ' {color:red; font-size:14px;}';
}
var styles = $('<style type="text/css">');
styles.text(dynamic_css('my_classname'));
$('html head').append(styles);

稍后:

styles.remove();

将一个类分配给样式元素以便稍后识别也可以很好地工作


0

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