原生js获取css伪类元素并设置属性


改编自

一、伪元素有哪些

首先,先简单说一下伪元素都有哪些。伪元素有六个,分别是 ::after::before::first-line::first-letter::selection::backdrop

在各大网页中最常用的伪元素,是::after::before

这几个伪元素的语意可参考另外一篇文章《CSS伪元素选择器 总结》。

在CSS3中,建议伪元素使用两个冒号(::)语法,而不是一个冒号 (??,目的是为了区分伪类和伪元素。大多数浏览器都支持这两种表示语法。只有 ::selection 永远只能以两个冒号开头(:??。因为IE8只支持单冒号的语法,所以,如果你想兼容IE8,保险的做法是使用单冒号。

二、获取伪元素的属性值

获取伪元素的属性值可以使用 window.getComputedStyle() 方法,获取伪元素的CSS样式声明对象。然后利用getPropertyValue()方法或直接使用键值访问都可以获取对应的属性值。

语法:window.getComputedStyle(element[, pseudoElement])

参数如下:

element(Object):伪元素所在的DOM元素;
pseudoElement(String):伪元素类型。可选值有:”:after”、”:before”、”:first-line”、”:first-letter”、”:selection”、”:backdrop”;

举个例子:

// HTML代码
// CSS代码 #myId:before { content: "hello world!"; display: block; width: 100px; height: 100px; background: red; } // JS代码 var myIdElement = document.getElementById("myId"); var beforeStyle = window.getComputedStyle(myIdElement, ":before"); console.log(beforeStyle); // [CSSStyleDeclaration Object] console.log(beforeStyle.width); // 100px console.log(beforeStyle.getPropertyValue("width")); // 100px console.log(beforeStyle.content); // "hello world!"

备注:

1.getPropertyValue()和直接使用键值访问,都可以访问CSSStyleDeclaration Object。它们两者的区别有:

  • 对于float属性,如果使用键值访问,则不能直接使用getComputedStyle(element, null).float,而应该是cssFloat与styleFloat;
  • 使用键值,则属性的键需要使用驼峰写法,如:style.backgroundColor
    使用getPropertyValue(), 不用驼峰,例如:style.getPropertyValue(“border-top-color”)
  • getPropertyValue()方法在IE9+和其他现代浏览器中都支持;在IE6~8中,可以使用getAttribute()方法来代替;

2.伪元素默认是”display: inline”。如果没有定义display属性,即使在CSS中显式设置了width的属性值为固定的大小如”100px”,但是最后获取的width值仍是”auto”。这是因为行内元素不能自定义设置宽高。解决办法是给伪元素修改display属性为”block”、”inline-block”或其他

三、更改伪元素的样式

方法1. 更换class来实现伪元素属性值的更改:

举个栗子:

// CSS代码
.red::before { 
content: "red"; 
color: red; 
}
.green::before { 
content: "green"; 
color: green;
}
// HTML代码
内容内容内容内容
// jQuery代码 $(".red").removeClass('red').addClass('green'); 1234567891011121314

方法2. 操作 document.styleSheets

Document.styleSheets 只读属性,返回一个由 StyleSheet 对象组成的 StyleSheetList,每个 StyleSheet 对象都是一个文档中链接或嵌入的样式表。 ——MDN

document.styleSheets的大概结构

  document.styleSheets = {
    CSSStyleSheet_0: {
      cssRules: {
        selectorText: '', // selector名字,比如div            
        style: {}  // 具体样式
      },
      rules: {},
      ...
    },
    CSSStyleSheet_1...
  }

CSSStyleSheet的样子

image-20220501182651042

insertRule(rule [,index])deleteRule(index)
添加的rule,优先级特性跟css的一样: 先看优先级, 同优先级的index靠后的优先

document.styleSheets[0].cssRules.length     // 已经定义好的 css 规则数
document.styleSheets[0].cssRules			// 已经定义好的 css 规则的 array
document.styleSheets[0].cssRules			// 已经定义好的 css 规则的 array
document.styleSheets[0].insertRule(cssRule, index)	


let index = document.styleSheets[0].cssRules.length  // 查看现有的css数组的length
document.styleSheets[0].insertRule('html::after {animation-name:test;animation-duration: 1s;animation-timing-function: ease-in-out;border: 10px solid red;}', index); // 在现有的css数组的末尾, 添加一个新的css rule

MDN官网的示例function: Function to add a stylesheet rule

/**
 * Add a stylesheet rule to the document (it may be better practice to dynamically change classes, so style information can be kept in
 * genuine stylesheets and avoid adding extra elements to the DOM).
 * Note that an array is needed for declarations and rules since ECMAScript does not guarantee a predictable object iteration order, and since CSS is
 * order-dependent.
 * @param {Array} rules Accepts an array of JSON-encoded declarations
 * @example
        addStylesheetRules([
          ['h2', // Also accepts a second argument as an array of arrays instead
            ['color', 'red'],
            ['background-color', 'green', true] // 'true' for !important rules
          ],
          ['.myClass',
            ['background-color', 'yellow']
          ]
        ]);
*/
function addStylesheetRules (rules) {
  var styleEl = document.createElement('style');

  // Append