从 JavaScript 设置 CSS 伪类规则

Posted

技术标签:

【中文标题】从 JavaScript 设置 CSS 伪类规则【英文标题】:Setting CSS pseudo-class rules from JavaScript 【发布时间】:2010-09-23 14:06:13 【问题描述】:

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

因此类似于 CSS 代码:JS 中的 a:hover color: red

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

【问题讨论】:

【参考方案1】:

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

较旧和较小的浏览器可能不支持这两种语法。很少进行动态样式表摆弄,因为正确处理非常烦人,很少需要,而且在历史上很麻烦。

【讨论】:

为什么没有选择这个作为答案? 更具体的参考网址:-w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet>-developer.mozilla.org/en/DOM/CSSStyleSheet/insertRule>-developer.apple.com/library/safari/#documentation/…> Firefox:“错误:操作不安全。” @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; 不推荐操作样式表只是为了将样式应用于特定元素,因为它会导致浏览器在每次更改样式表时重排整个文档。 stubbornella.org/content/2009/03/27/…【参考方案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 += classList 是一个较新的功能,直到最近才得到很好的支持(请参阅caniuse.com/classlist)【参考方案3】:

一个处理跨浏览器的函数:

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

【讨论】:

【参考方案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 文件...【参考方案5】:

切换样式表是一种方法。这是一个动态构建样式表的库,因此您可以动态设置样式:

http://www.4pmp.com/2009/11/dynamic-css-pseudo-class-styles-with-jquery/

【讨论】:

【参考方案6】:

我拼凑了small library for this,因为我确实认为在 JS 中操作样式表有有效的用例。原因是:

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

【讨论】:

【参考方案7】:

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

【讨论】:

这不适用于 :before 和 :after 伪类。 这不适用于使用通过 AJAX 检索的值更改背景图像。 @jbyrd, :before & :after 是伪元素,不是类。 @royling - 是的,感谢您的更正!似乎无法编辑我的评论。【参考方案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)"> ...  

【讨论】:

这个解决方案使用了 jQuery——当提问者要求纯 Javascript 时,引入一个 jQuery 大小的依赖项来处理这样简单的事情,这是不好的。 虽然现在几乎所有网站都使用jquery,但我会修改为使用纯javascript。 这个方法到底是如何改变 .class[special]:after 伪元素的 CSS 属性的,比如背景颜色或其他什么?【参考方案9】:

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

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

【讨论】:

【参考方案10】:

如果你使用 REACT ,有一个叫做 radium 的东西。它在这里非常有用:

如果指定了交互样式,则将处理程序添加到道具,例如onMouseEnter for :hover,必要时包装现有的处理程序

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

在重新渲染时,解决任何适用的交互式样式,例如:hover,通过在 Radium-specific 中查找元素的键或 ref 状态

【讨论】:

【参考方案11】:

这里有一个解决方案,包括两个函数: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>

【讨论】:

【参考方案12】:

只需将 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 个参数,第一个参数确定相对于参考元素的位置 (see here)。这是最近的变化吗? (在答案中添加了“beforeend”)。 我不喜欢这个解决方案。您的 CSS 不会被缓存。【参考方案13】:

您可以考虑的一个选项是使用 CSS 变量。这个想法是您将要更改的属性设置为 CSS 变量。然后,在您的 JS 中,更改该变量的值。

见下例

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>

【讨论】:

以上是关于从 JavaScript 设置 CSS 伪类规则的主要内容,如果未能解决你的问题,请参考以下文章

css鼠标悬停伪类

一些css和javascript还有html的属性方法和标签

CSS3使用JAVASCript触发过渡效果

[转] 用javascript修改css伪类的几种方法

csscss选择器,伪类

JavaScript querySelector 和 CSS :target 伪类