虽然标题里写的是伪元素, 不过这篇文章主要是说::before 和::after, 其余几个伪元素 (::first-letter::first-line::selection 等) 由于没有 content 属性, 所以本文一笔带过, 其实方法是一样的
伪元素的重点在于一个伪, 虽然它们可以被浏览器渲染引擎识别并正确渲染, 然而伪元素本身并不是 DOM 元素, 所以无法被 js 直接操作因此任何基于 JS 直接选取 DOM 元素的 CSS 更改方法对伪元素都不起作用 (JQ 看似万能, 这个问题上是直接就栽了因为 JQ 的选择符都是基于 DOM 元素) 关于 JS 和 JQ 选择器, 可以参考这两篇文档: Selectors API Level 1jQuery Selectors
获取伪元素的属性值
虽然 JS 里没有可以直接操作伪元素的选择符, 然而获取其 CSS 属性的方法还是有的
window.getComputedStyle
利用 window.getComputedStyle 方法选择到伪元素, 然后利用 getPropertyValue 方法获取对应的属性的值
根据 MDN 的文档,
window.getComputedStyle(element[, pseudoElt]);
此方法包含两个参数, 一个是元素本身另一个是元素的伪元素
js 语法实例(完整 DEMO 在线链接点击预览):
- var div=document.querySelector('div');
- var fontSize=window.getComputedStyle(div,'::before').getPropertyValue('font-size');// 获取 before 伪元素的字号大小
关于这个方法, 详解可以参考这篇文章:
获取元素 CSS 值之 getComputedStyle 方法熟悉
更改伪元素的属性值
window.getComputedStyle 方法虽然可以获取到伪元素的属性值, 然而根据该方法名字也知道其只能获取 CSS 样式, 并无法更改 css 属性, 那么如果想要用 js 动态更改伪元素属性值的话, 该怎么处理呢?
思路有以下几个:
js 更改 data - 属性值来更改伪元素的 content 值
创建多个 class, 通过切换 class 来达到改变样式的目的
利用 CSSStyleSheet 的 insertRule 方法来添加样式
利用内部 css 样式的高优先级来覆盖外部 css
以上实现思路的推荐程度依次递减
利用 DOM 的 data - 属性来更改 content 的值
data-* 是 html5 新增的 DOM 元素属性, 作用大致可以理解为标记具体用法可以参考 MDN 的这篇文章. 而伪元素的 content 属性值除了常规赋值外, 还有一种特殊的 attr()方法来获取
- HTML:
- <div class="test" data-text="TEXT" data-color="red"></div>
- CSS:
- .test::before{
- content: attr(data-text);
- }
结果:
TEXT
另外 content 其实可以多个 attr 连写, 而且 attr()内的可以是 DOM 元素的任意属性 (比如 class 等, 甚至非 W3C 标准属性也支持, 不过不推荐这么做) 所以很方便凑一些模版文字像下面这种写法也是完全没问题的注意用空格连接, 不要用 "+" 号
- EXAM:
- .test::before {
- content: '我的类是' attr(class) '想要变成' attr(data-color);
- }
虽然 W3C 给 attr()赋予了无限可能性, 包括 color,width 等属性在未来都有希望用这个方法更改, 然而目前只有 content 支持该方法, 其余的都还是草稿状态, 尚未有浏览器支持之所以把这个方法放在第一位只是因为相比别的实现手法来说, 这个方法真的太简单太优雅
但是如果真的想要改伪元素里的 color 等元素呢?
更改 class 来实现伪元素样式的更改
把这个方法放到推荐位第二位估计会被很多人骂我: 卧槽, 这么简单又没逼格的办法你竟然放到第二位! 太没水平了不过再看完后面两种方法后或许你会对这种看法有所改观
这个方法的优点是简单好用且无兼容性问题缺点是多了一些其实用处不大的 class, 很像是 jQuery 类选择器中毒患者的做法; 另外不适合多状态的场景(比如实时改变伪元素文字大小等)
实现过于简单就不贴代码了
前面的 class 切换大法可能让人感觉不痛快, 这里来个高大上 (伪) 点的方法:
利用 CSSStyleSheet 的 insertRule 方法来添加样式
这部分内容和 W3C 标准牵连比较多, 加上较冷门, 没多少人关注, 个人目前啃不动标准, 所以这部分内容不会做深入分析, 理解可能也会有问题, 望斧正
CSSStyleSheet 是浏览器存放页面内所有 css 样式表的对象方法(不包括行内样式), 每个 link 和 style 标签都代表一个 CSSStyleSheet 对象, 获取他们可以用 document.styleSheets 方法(需要注意的是虽然 styleSheets 方法返回的结果把 link 标签引进的外部样式也算进去了, 但是非 IE 浏览器没办法获取到他们的 cssRules 属性, 只有内嵌的 style 标签内的元素可以被获取到)
- document.styleSheets[0].insertRule('.test::before{color:green}',0)//chrome,firefox 等非 IE 浏览器使用
- document.styleSheets[0].addRule('.test::before{color:green}',0)//IE 系列浏览器使用
/ 虽然部分浏览器也可以通过 id 来指定,'document.styleSheets.id.insertRule()'这种写法在 chrome 和 IE 下都行得通, 但是 firefox 会返回'undefined', 所以建议还是使用 index 值来获取 stylesheet /
.insertRule 的语法是 stylesheet.insertRule(rule, index), 另一个参数是 index, 意思是在对应的 styleSheets 里的 cssRules 样式表中的位置, 这个值越大则样式优先级越高, 但是值不能超过当前样式表规则 (cssRules) 长度(CSS 中先定义的样式总是会被后定义的覆盖就是这个缘故), 当值小于 cssRules 长度时, 添加的样式规则会插入到 index 值定义的位置, 之前其余的规则依次顺延
addrule 和 insertRule 方法本质上没区别, 只是后者不被 IE 浏览器识别, 所以前者作为浏览器兼容方法存在(下文为节省篇幅, 以 insertRule 方法指代此两种方法)
上面的代码看似简单一行, 然而却不是每次都有效的原因有以下几点:
document.styleSheets 虽然按照 style 和 link 的顺序返回对应的 StyleSheetList, 然而第一个如果是 link 而不是 style, 前面讲过此时无法获取对应的 cssRules, 则 document.styleSheets[0].cssRules 为 null,insertRule 方法不起作用(此情况只针对非 IE 浏览器, IE 浏览器正常, 但是定义的早往往意味着被后面的样式覆盖, 所以意义不大)
同上, 如果页面内没有内嵌样式的 style 标签, 则 insertRule 方法也无法发挥作用
index 值不够大的话很有可能会早于 css 文件开始的定义位置, 导致被覆盖因此有个折衷办法就是给添加的样式增加! important, 虽然我个人比较反感这么做
由此可见此方法的局限性, 但是这种方法的优雅之处在于避免了直接写内嵌样式, 而是通过 css api 来做更改相比下面的方法来说, 稍微好点
但是这种方法好像局限性有点大啊?
HEAD 中添加 style 标签强制覆盖初始属性
这个方法是利用内部 css 样式的高优先级来覆盖外部 css, 好处是简单易理解, 实现简单坏处就是吃相太难看, 过于粗暴
- var style=document.createElement('style');
- style.innerHTML=".test::before{color:green}";// 添加样式内容的话也可以用上面提到过的 insertRule, 相对例子里的硬编码会更优雅点
- document.head.appendChild(style);
看到这里可能有些人反应过来了, 其实加 style 标签这种方法可以是 insertRule 实现方法的大前提因为不是所有页面一开始都有内嵌的 style 样式的这种方法虽然不是很好, 但是有时候却又确确实实是必须的比如拖动滑块改变伪元素内文字大小这个需求
来源: http://www.qdfuns.com/article/18169/1cff24a7674d050d0316c3f15f3e03e2.html