虽然标题里写的是伪元素
,不过这篇文章主要是说::before
和::after
,其他几个伪元素(::first-letter
、::first-line
、::selection
等)因为没有content
属性,因此本文一笔带过,其实方法是同样的。
伪元素的重点在于一个伪,虽然它们能够被浏览器渲染引擎识别并正确渲染,然而伪元素自己并非DOM元素,因此没法被js直接操做——所以任何基于JS直接选取DOM元素的CSS更改方法对伪元素都不起做用。(JQ看似万能,这个问题上是直接就栽了。由于JQ的选择符都是基于DOM元素)关于JS和JQ选择器,能够参考这两篇文档: Selectors API Level 1、jQuery Selectorsjavascript
虽然JS里没有能够直接操做伪元素的选择符,然而获取其CSS属性的方法仍是有的。php
利用window.getComputedStyle
方法选择到伪元素,而后利用getPropertyValue
方法获取对应的属性的值。
根据MDN的文档,css
window.getComputedStyle(element[, pseudoElt]);
此方法包含两个参数,一个是元素自己另外一个是元素的伪元素。
js语法实例(完整DEMO在线连接):html
var div=document.querySelector('div'); var fontSize=window.getComputedStyle(div,'::before').getPropertyValue('font-size');//获取before伪元素的字号大小
关于这个方法,详解能够参考这篇文章:
获取元素CSS值之getComputedStyle方法熟悉java
window.getComputedStyle
方法虽然能够获取到伪元素的属性值,然而根据该方法名字也知道其只能获取CSS样式,并没有法更改css属性,那么若是想要用js动态更改伪元素属性值的话,该怎么处理呢?
思路有如下几个:jquery
js更改data-*
属性值来更改伪元素的content
值css3
建立多个class
,经过切换class
来达到改变样式的目的git
利用CSSStyleSheet的insertRule
方法来添加样式github
利用内部css样式的高优先级来覆盖外部csschrome
以上实现思路的推荐程度依次递减
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切换大法
可能让人感受不痛快,这里来个高大上(伪)点的方法:
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
样式的。这种方法虽然不是很好,可是有时候却又确确实实是必须的——好比“拖动滑块改变伪元素内文字大小”这个需求。
拖动滑块改变伪元素内的文字大小
且伪元素内随时显示当前字号
经过一个按钮能够改变伪元素内文字颜色
这个需求能够将本文前面提到的四种改变伪元素样式的方法都塞进去。具体实现参照DEMO,再也不作具体分析:
http://codepen.io/chitanda/pen/OVBJEw/
getComputedStyle()
attr-notation
CSSRules