从JavaScript设置CSS伪类规则

156

我正在寻找一种从 JavaScript 中更改伪类选择器的 CSS 规则的方法(例如:link、:hover等)。

因此,需要在 JS 中实现这样一个 CSS 代码的类比:a:hover { color: red }

我在其他地方都找不到答案;如果有人知道浏览器不支持这个功能,那么这也是一个有用的结果。

12个回答

215

您不能仅针对特定元素设置伪类样式,就像您无法在inline style="..."属性中使用伪类一样(因为没有选择器)。

您可以通过修改样式表来实现,例如添加以下规则:

#elid:hover { background: red; }

假设你想要操作的每个元素都有一个唯一的ID,以允许对其进行选择。

理论上,你需要的文档是http://www.w3.org/TR/DOM-Level-2-Style/Overview.html,这意味着你可以(在已存在嵌入或链接样式表的情况下)使用以下语法:

document.styleSheets[0].insertRule('#elid:hover { background-color: red; }', 0);
document.styleSheets[0].cssRules[0].style.backgroundColor= 'red';

当然,IE需要使用自己的语法:

document.styleSheets[0].addRule('#elid:hover', 'background-color: red', 0);
document.styleSheets[0].rules[0].style.backgroundColor= 'red';

老旧和较低版本的浏览器可能不支持这两种语法。动态样式表操作很少被使用,因为它很难正确实现,很少需要,并且在历史上存在问题。


36
为什么这个答案没有被选为最佳答案? - Shlomo Zalman Heigh
更具体的参考网址:
  • http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet
  • https://developer.mozilla.org/en/DOM/CSSStyleSheet/insertRule
  • http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/WebKitDOMRef/CSSStyleSheet_idl/Classes/CSSStyleSheet/index.html#//apple_ref/js/instm/CSSStyleSheet/insertRule/unsignedlong/%28inDOMString,inunsignedlong%29
- user166560
2
Firefox: "错误:操作不安全。" - 8128
@fluteflute,如果您尝试从不同域名操作CSS文件,则该操作被认为是不安全的(我猜这是一种同源策略)。可惜!检查符合同源策略的简单函数:`function sameOrigin(url) { var loc = window.location, a = document.createElement('a');a.href = url; return a.hostname === loc.hostname && a.port === loc.port && a.protocol === loc.protocol;}` - WickyNilliams
4
仅仅为了给特定的元素应用样式而操纵样式表并不推荐,因为每当样式表被改变时,它会导致浏览器重新排版整个文档。详情请参考:http://www.stubbornella.org/content/2009/03/27/reflows-repaints-css-performance-making-your-javascript-slow/ - Johannes Ewald
这个选项唯一的问题是如果存在一个样式表元素数组。一定要设置一个循环来查找你需要的特定元素,就像我所做的那样。 - Jester

30

我为此写了一个小型库,因为我认为在JS中操作样式表有有效的用例。原因如下:

  • 设置必须计算或检索的样式 - 例如从cookie中设置用户喜欢的字体大小。
  • 设置行为(不是美学)样式,特别是对于UI部件/插件开发人员。选项卡、旋转木马等通常需要一些基本CSS才能正常工作 - 不应该要求核心功能的样式表。
  • 比内联样式更好,因为CSS规则适用于所有当前和未来元素,并且在Firebug /Developer Tools中查看时不会混乱HTML。

20

只需将css放置在一个模板字符串中。

const cssTemplateString = `.foo:[psuedoSelector]{prop: value}`;

然后创建一个样式元素,将字符串放入样式标签中,并将其附加到文档中。

const styleTag = document.createElement("style");
styleTag.innerHTML = cssTemplateString;
document.head.insertAdjacentElement('beforeend', styleTag);

具体性将照顾其他部分。 然后,您可以动态地删除和添加样式标签。 这是使用库和在DOM中操纵样式表数组的简单替代方法。 祝你编码愉快!


在主流浏览器(Chrome、Firefox、Edge)中,insertAdjacentElement 方法需要两个参数,第一个参数用于确定相对于参考元素的位置(请参见此处)。这是最近的更改吗?(将“beforeend”添加到答案中)。 - collapsar
我不喜欢这个解决方案。你的CSS不会被缓存。 - StackSlave
@StackSlave 谁在意这个问题,以及为什么? - Michael

18
一个处理跨浏览器问题的函数:
addCssRule = function(/* string */ selector, /* string */ rule) {
  if (document.styleSheets) {
    if (!document.styleSheets.length) {
      var head = document.getElementsByTagName('head')[0];
      head.appendChild(bc.createEl('style'));
    }

    var i = document.styleSheets.length-1;
    var ss = document.styleSheets[i];

    var l=0;
    if (ss.cssRules) {
      l = ss.cssRules.length;
    } else if (ss.rules) {
      // IE
      l = ss.rules.length;
    }

    if (ss.insertRule) {
      ss.insertRule(selector + ' {' + rule + '}', l);
    } else if (ss.addRule) {
      // IE
      ss.addRule(selector, rule, l);
    }
  }
};

8

我的技巧是使用属性选择器。属性更容易用javascript设置。

CSS

.class{ /*normal css... */}
.class[special]:after{ content: 'what you want'}

javascript

  function setSpecial(id){ document.getElementById(id).setAttribute('special', '1'); }

html

<element id='x' onclick="setSpecial(this.id)"> ...  

6
这个解决方案使用了jQuery - 对于像这样简单的东西,引入一个像jQuery这样大的依赖关系是不好的,尤其是当提问者要求纯Javascript时。 - Tom Ashworth
尽管现在几乎所有的网站都使用jQuery,但我将修改它以使用纯JavaScript。 - Sergio Abreu
1
这个方法是如何改变 .class[special]:after 伪元素的 CSS 属性,比如背景颜色或其他属性的呢? - andreszs
1
感谢@SergioAbreu。通过使用一些技巧,我能够停止CSS关键帧在网页加载时自动运行。 - Shohidul Alam
我很高兴能帮助@ShohidulAlam。 - Sergio Abreu

7

你可以考虑使用CSS变量来实现。这个想法是将想要更改的属性设置为CSS变量。然后,在JavaScript中更改该变量的值。

以下是示例:

function changeColor(newColor) {
  document.documentElement.style.setProperty("--anchor-hover-color", newColor);
  // ^^^^^^^^^^^-- select the root 
}
:root {
  --anchor-hover-color: red;
}

a:hover { 
  color: var(--anchor-hover-color); 
}
<a href="#">Hover over me</a>

<button onclick="changeColor('lime')">Change to lime</button>
<button onclick="changeColor('red')">Change to red</button>


1
这个解决方案对我来说是最简单的路线。为什么要通过添加和删除样式表规则来处理呢?我在我的滑块上使用了相同的逻辑,在我的视频控件中设置动态标题(副标题)字体大小,它非常有效。 - mseifert

5

与其直接使用Javascript设置伪类规则,您可以在不同的CSS文件中以不同方式设置规则,然后使用Javascript关闭一个样式表并打开另一个样式表。详见A List Apart(有更多细节)。

将CSS文件设置为:

<link rel="stylesheet" href="always_on.css">
<link rel="stylesheet" title="usual" href="preferred.css"> <!-- on by default -->
<link rel="alternate stylesheet" title="strange" href="alternate.css"> <!-- off by default -->

然后使用JavaScript在它们之间切换:

function setActiveStyleSheet(title) {
   var i, a, main;
   for(i=0; (a = document.getElementsByTagName("link")<i>); i++) {
     if(a.getAttribute("rel").indexOf("style") != -1
        && a.getAttribute("title")) {
       a.disabled = true;
       if(a.getAttribute("title") == title) a.disabled = false;
     }
   }
}

如果您需要通过 AJAX 请求检索到的值动态更改类,该怎么办?现在您无法创建 CSS 文件... - andreszs

5

还有另一种选择。不要直接操作伪类,而是创建模拟相同效果的真正类,例如“hover”类或“visited”类。使用通常的“.”语法为这些类设置样式,然后在适当事件触发时,可以使用JavaScript向元素添加或删除类。


2
这对于:before和:after伪类不起作用。 - jbyrd
这并不适用于使用通过 AJAX 检索的值更改背景图像。 - andreszs
2
@jbyrd,:before:after是伪元素,而不是类。 - Roy Ling
@royling - 是的,谢谢更正!似乎无法编辑我的评论。 - jbyrd

2

如前所述,浏览器不支持此功能。

如果您不是动态生成样式(例如从数据库中提取),则应该可以通过向页面的 body 添加类来解决此问题。

CSS 代码可能如下:

a:hover { background: red; }
.theme1 a:hover { background: blue; }

而更改此内容的JavaScript代码可能如下:

// Look up some good add/remove className code if you want to do this
// This is really simplified

document.body.className += " theme1";  

出于好奇,element.classList.add 不受良好支持吗?我一直看到人们使用 element.className += - Joel Cornett
2
classList 是一个较新的特性,直到最近才得到良好的支持(请参见 http://caniuse.com/classlist)。 - Nathaniel Reinhart

0
在jQuery中,您可以轻松设置悬停伪类。
$("p").hover(function(){
$(this).css("background-color", "yellow");
}, function(){
$(this).css("background-color", "pink");
});

不是纯粹的JavaScript,但按要求工作。谢谢 - lisandro
不是纯粹的JavaScript,但按要求工作。谢谢。 - undefined

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