从JavaScript设置CSS伪类规则


125

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

因此类似于CSS代码:a:hover { color: red }在JS中。

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

Answers:


192

您不能单独在特定元素上设置伪类的样式,就像在内联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';

较旧的浏览器和次要的浏览器可能都不支持这两种语法。动态样式表修改很少完成,因为这样做很烦人,很少需要,而且历史上很麻烦。


32
为什么不选择这个作为答案?
SZH


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 2012年

3
不建议只将样式表应用于特定元素,因为每当样式表更改时,浏览器都会重新浏览整个文档。stubbornella.org/content/2009/03/27/...
约翰内斯·埃瓦尔德

29

为此建立了一个小型库,因为我确实认为存在用于处理JS中样式表的有效用例。原因是:

  • 设置必须计算或检索的样式-例如,从cookie设置用户首选的字体大小。
  • 设置行为(而非美学)样式,尤其是针对UI小部件/插件开发人员。制表符,轮播等通常仅需要一些基本的CSS即可运行-不应为核心功能要求样式表。
  • 比内联样式更好,因为CSS规则适用于所有当前和将来的元素,并且在Firebug /开发人员工具中查看时不会使HTML混乱。

17

应付跨浏览器问题的函数:

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);
    }
  }
};

7

只需将css放在模板字符串中即可。

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

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

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

特殊性将处理其余的工作。然后,您可以动态删除和添加样式标签。这是库和DOM中的样式表数组的一种简单替代方法。编码愉快!


insertAdjacentElement在主要的浏览器(Chrome,Firefox,Edge)中需要2个参数,其中第一个用于建立相对于reference元素的位置(请参见此处)。这是最近的变化吗?(在答案前加上“ beforeend”)。
collapsar

6

我的技巧是使用属性选择器。通过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)"> ...  

4
此解决方案使用jQuery –在发问者要求使用纯Java脚本的情况下,引入像jQuery这样大小的依赖项很简单,就很糟糕。
Tom Ashworth 2013年

尽管目前所有网站通常都使用jQuery,但我将其修改为使用纯JavaScript。
塞尔吉奥·阿布雷乌

1
究竟该方法如何更改.class [special]:伪元素之后的CSS属性,例如背景色或其他?
andreszs 2014年

5

还有另一种选择。与其直接操作伪类,不如创建对相同事物建模的真实类,例如“ hover”类或“ visited”类。用通常的“。”样式设置类的样式。语法,然后您可以使用JavaScript在适当的事件触发时从元素中添加或删除类。


2
这不适用于:before和:after伪类。
2014年

这不适用于更改通过AJAX检索的值的背景图像。
andreszs 2014年

1
@jbyrd :before和&:after是伪元素,不是类。
罗伊·灵

@royling-是的,感谢您的纠正!似乎无法编辑我的评论。
jbyrd

4

您可以在不同的CSS文件中以不同的方式设置规则,而不是使用javascript直接设置伪类规则,然后使用Javascript关闭一个样式表,然后再打开另一个样式表。一种方法在A List Apart(有关详细信息,请参阅 qv)中进行了描述。

将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 2014年

2

如前所述,这不是浏览器支持的功能。

如果您不是动态提出样式(即从数据库中提取样式等),则应该可以通过在页面正文中添加类来解决此问题。

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 +=
乔尔·科内特

2
班级名册是一个较新的功能,并没有像它有很好的支持,直到最近相当(见caniuse.com/classlist
纳撒尼尔·莱因哈特


-1

在jquery中,您可以轻松设置悬停伪类。

$("p").hover(function(){
$(this).css("background-color", "yellow");
}, function(){
$(this).css("background-color", "pink");
});

-1

这是一个包含两个功能的解决方案:addCSSclass将新的CSS类添加到文档中,而toggleClass将其打开

该示例显示了将自定义滚动条添加到div

// If newState is provided add/remove theClass accordingly, otherwise toggle theClass
function toggleClass(elem, theClass, newState) {
  var matchRegExp = new RegExp('(?:^|\\s)' + theClass + '(?!\\S)', 'g');
  var add = (arguments.length > 2 ? newState : (elem.className.match(matchRegExp) === null));

  elem.className = elem.className.replace(matchRegExp, ''); // clear all
  if (add) elem.className += ' ' + theClass;
}

function addCSSclass(rules) {
  var style = document.createElement("style");
  style.appendChild(document.createTextNode("")); // WebKit hack :(
  document.head.appendChild(style);
  var sheet = style.sheet;

  rules.forEach((rule, index) => {
    try {
      if ("insertRule" in sheet) {
        sheet.insertRule(rule.selector + "{" + rule.rule + "}", index);
      } else if ("addRule" in sheet) {
        sheet.addRule(rule.selector, rule.rule, index);
      }
    } catch (e) {
      // firefox can break here          
    }
    
  })
}

let div = document.getElementById('mydiv');
addCSSclass([{
    selector: '.narrowScrollbar::-webkit-scrollbar',
    rule: 'width: 5px'
  },
  {
    selector: '.narrowScrollbar::-webkit-scrollbar-thumb',
    rule: 'background-color:#808080;border-radius:100px'
  }
]);
toggleClass(div, 'narrowScrollbar', true);
<div id="mydiv" style="height:300px;width:300px;border:solid;overflow-y:scroll">
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a eros metus. Nunc dui felis, accumsan nec aliquam quis, fringilla quis tellus. Nulla cursus mauris nibh, at faucibus justo tincidunt eget. Sed sodales eget erat consectetur consectetur. Vivamus
  a diam volutpat, ullamcorper justo eu, dignissim ante. Aenean turpis tortor, fringilla quis efficitur eleifend, iaculis id quam. Quisque non turpis in lacus finibus auctor. Morbi ullamcorper felis ut nulla venenatis fringilla. Praesent imperdiet velit
  nec sodales sodales. Etiam eget dui sollicitudin, tempus tortor non, porta nibh. Quisque eu efficitur velit. Nulla facilisi. Sed varius a erat ac volutpat. Sed accumsan maximus feugiat. Mauris id malesuada dui. Lorem ipsum dolor sit amet, consectetur
  adipiscing elit. Sed a eros metus. Nunc dui felis, accumsan nec aliquam quis, fringilla quis tellus. Nulla cursus mauris nibh, at faucibus justo tincidunt eget. Sed sodales eget erat consectetur consectetur. Vivamus a diam volutpat, ullamcorper justo
  eu, dignissim ante. Aenean turpis tortor, fringilla quis efficitur eleifend, iaculis id quam. Quisque non turpis in lacus finibus auctor. Morbi ullamcorper felis ut nulla venenatis fringilla. Praesent imperdiet velit nec sodales sodales. Etiam eget
  dui sollicitudin, tempus tortor non, porta nibh. Quisque eu efficitur velit. Nulla facilisi. Sed varius a erat ac volutpat. Sed accumsan maximus feugiat. Mauris id malesuada dui.
</div>


-2

如果使用REACT,则有一种叫做镭的物质。在这里非常有用:

  • 如果指定了交互样式,则将处理程序添加到props中,例如onMouseEnter表示:hover,必要时包装现有处理程序

  • 如果通过悬停触发了任何处理程序,则Radium调用setState来更新组件状态对象上特定于Radium的字段

  • 在重新渲染时,通过在Radium特定状态下查找元素的键或ref来解析所有适用的交互式样式,例如:hover。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.