利用javascript獲取並修改僞元素的值

雖然標題裏寫的是僞元素,不過這篇文章主要是說::before::after,其他幾個僞元素(::first-letter::first-line::selection等)因爲沒有content屬性,因此本文一筆帶過,其實方法是同樣的。
僞元素的重點在於一個,雖然它們能夠被瀏覽器渲染引擎識別並正確渲染,然而僞元素自己並非DOM元素,因此沒法被js直接操做——所以任何基於JS直接選取DOM元素的CSS更改方法對僞元素都不起做用。(JQ看似萬能,這個問題上是直接就栽了。由於JQ的選擇符都是基於DOM元素)關於JS和JQ選擇器,能夠參考這兩篇文檔: Selectors API Level 1jQuery Selectorsjavascript

獲取僞元素的屬性值

雖然JS裏沒有能夠直接操做僞元素的選擇符,然而獲取其CSS屬性的方法仍是有的。php

window.getComputedStyle

利用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

  1. js更改data-*屬性值來更改僞元素的contentcss3

  2. 建立多個class,經過切換class來達到改變樣式的目的git

  3. 利用CSSStyleSheet的insertRule方法來添加樣式github

  4. 利用內部css樣式的高優先級來覆蓋外部csschrome

以上實現思路的推薦程度依次遞減

利用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樣式表的對象方法(不包括行內樣式),每一個linkstyle標籤都表明一個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值定義的位置,以前其他的規則依次順延。

addruleinsertRule方法本質上沒區別,只是後者不被IE瀏覽器識別,因此前者做爲瀏覽器兼容方法存在。(下文爲節省篇幅,以insertRule方法指代此兩種方法。)

上面的代碼看似簡單一行,然而卻不是每次都有效的。緣由有如下幾點:

  1. document.styleSheets雖然按照stylelink的順序返回對應的StyleSheetList,然而第一個若是是link而不是style,前面講過此時沒法獲取對應的cssRules,則document.styleSheets[0].cssRulesnullinsertRule方法不起做用。(此狀況只針對非IE瀏覽器,IE瀏覽器正常,可是定義的早每每意味着被後面的樣式覆蓋,因此意義不大)

  2. 同上,若是頁面內沒有內嵌樣式的style標籤,則insertRule方法也沒法發揮做用。

  3. 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樣式的。這種方法雖然不是很好,可是有時候卻又確確實實是必須的——好比「拖動滑塊改變僞元素內文字大小」這個需求。

練習

功能需求

  1. 拖動滑塊改變僞元素內的文字大小

  2. 且僞元素內隨時顯示當前字號

  3. 經過一個按鈕能夠改變僞元素內文字顏色

這個需求能夠將本文前面提到的四種改變僞元素樣式的方法都塞進去。具體實現參照DEMO,再也不作具體分析:

http://codepen.io/chitanda/pen/OVBJEw/


參考文獻

  1. getComputedStyle()

    1. Window.getComputedStyle()

    2. 獲取元素CSS值之getComputedStyle方法熟悉

  2. attr-notation

    1. W3C CSS3-Attribute References: ‘attr()’

    2. MDN ATTR()

  3. CSSRules

    1. CSSRule object

    2. MDN insertRule

    3. Dynamic style - manipulating CSS with JavaScript

    4. Add Rules to Stylesheets with JavaScript

    5. Modify pseudo element styles with JavaScript

    6. Add css-rules to an existing stylesheet

相關文章
相關標籤/搜索