【CSS進階】原生JS getComputedStyle等方法解析

發表於2016-03-16

最近一直在研讀 jQuery 原始碼,初看原始碼一頭霧水毫無頭緒,真正靜下心來細看寫的真是精妙,讓你感嘆程式碼之美。

其結構明晰,高內聚、低耦合,兼具優秀的效能與便利的擴充套件性,在瀏覽器的相容性(功能缺陷、漸進增強)優雅的處理能力以及 Ajax 等方面周到而強大的定製功能無不令人驚歎。

另外,閱讀原始碼讓我接觸到了大量底層的知識。對原生JS 、框架設計、程式碼優化有了全新的認識,接下來將會寫一系列關於 jQuery 解析的文章。

我在 github 上關於 jQuery 原始碼的全文註解,感興趣的可以圍觀一下。jQuery v1.10.2 原始碼註解

 

言歸正傳,本文講的是原生 JS 獲取、設定元素最終樣式的方法。可能平時框架使用習慣了,以 jQuery 為例,使用 .css() 介面就能便捷的滿足我們的要求。再看看今天要講的 window.getComputedStyle ,就像剛接觸 JS 的時候,看到 document.getElementById  一樣,名字都這麼長,頓生怯意。不過莫慌,我覺得如果我們不是隻想做一個混飯吃的前端,那麼越是底層的東西,如果能夠吃透它,越是能讓人進步。

 

     getComputedStyle 與 getPropertyValue 

getComputedStyle 為何物呢,DOM 中 getComputedStyle 方法可用來獲取元素中所有可用的css屬性列表,以陣列形式返回,並且是隻讀的。IE678 中則用 currentStyle 代替 。

假設我們頁面上存在一個 id 為 id 的元素,那麼使用 getComputedStyle 獲取元素樣式就如下圖所示:

嘗試一下之後可以看到,window.getComputedStyle 獲取的是所有的樣式,如果我們只是要獲取單一樣式,該怎麼做呢。這個時候就要介紹另一個方法 — getPropertyValue 。

用法也很簡單:

 

    IE 下的 currentStyle 與 getAttribute 

說完常規瀏覽器,再來談談老朋友 IE ,與 getComputedStyle 對應,在 IE 中有自己特有的 currentStyle 屬性,與 getPropertyValue 對應,IE 中使用 getAttribute 。

和 getComputedStyle 方法不同的是,currentStyle 要獲得屬性名的話必須採用駝峰式的寫法。也就是如果我需要獲取 font-size 屬性,那麼傳入的引數應該是 fontSize。因此在IE 中要獲得單個屬性的值,就必須將屬性名轉為駝峰形式。

 

    style 與 getComputedStyle 

必須要提出的是,我們使用 element.style 也可以獲取元素的CSS樣式宣告物件,但是其與 getComputedStyle 方法還是有一些差異的。

首先,element.style 是可讀可寫的,而 getComputedStyle  為只讀。

其次,element.style 只可以獲取 style 樣式上的屬性值,而無法得到所有的 CSS 樣式值,什麼意思呢?回顧一下 CSS 基礎,CSS 樣式表的表現有三種方式,

  1. 內嵌樣式(inline Style) :是寫在 HTML 標籤裡面的,內嵌樣式只對該標籤有效。
  2. 內部樣式(internal Style Sheet):是寫在 HTML 的 標籤裡面的,內部樣式只對所在的網頁有效。
  3. 外部樣式表(External Style Sheet):如果很多網頁需要用到同樣的樣式(Styles),將樣式(Styles)寫在一個以 .CSS 為字尾的 CSS 檔案裡,然後在每個需要用到這些樣式(Styles)的網頁裡引用這個 CSS 檔案。

而 element.style 只能獲取被這些樣式表定義了的樣式,而 getComputedStyle 能獲取到所有樣式的值(在不同瀏覽器結果不一樣,chrome 中是 264,在 Firefox 中是238),不管是否定義在樣式表中,譬如:

 

    getComputedStyle 與 defaultView

window.getComputedStyle 還有另一種寫法,就是 document.defaultView.getComputedStyle 。

兩者的用法完全一樣,在 jQuery v1.10.2 中,使用的就是 window.getComputedStyle 。如下

 

也有特例,檢視 stackoverflow ,上面提及到在 Firefox 3.6 ,不使用 document.defaultView.getComputedStyle 會出錯。不過畢竟 FF3.6 已經隨歷史遠去,現在可以放心的使用 window.getComputedStyle。

用一張圖總結一下:

原生JS獲取CSS樣式的方法

 

   原生JS實現CSS樣式的get與set

說了這麼多,接下來將用原生 JS 實現一個小元件,實現 CSS 的 get 與 set,相容所有瀏覽器。

完整的元件程式碼在我的 github 上,戳我直接看程式碼

 

  getStyle(elem, style)

對於 CSS 的 set ,對於支援 window.getComputedStyle 的瀏覽器而言十分簡單,只需要直接呼叫。

 

反之,如果是 IE 瀏覽器,則有一些坑。

 

  opacity 透明度的設定

在早期的 IE 中要設定透明度的話,有兩個方法:

  1. alpha(opacity=0.5)
  2. filter:progid:DXImageTransform.Microsoft.gradient( GradientType= 0 , startColorstr = ‘#ccccc’, endColorstr = ‘#ddddd’ );

因此在 IE 環境下,我們需要針對透明度做一些處理。先寫一個 IE 下獲取透明度的方法:

 

  float 樣式的獲取

float 屬性是比較重要的一個屬性,但是由於 float 是 ECMAScript 的一個保留字。(ECMAScript保留字有哪些?戳這裡

所以在各瀏覽器中都會有代替的寫法,比如說在標準瀏覽器中為 cssFloat,而在 IE678 中為 styleFloat 。經測試,在標準瀏覽器中直接使用 getPropertyValue(“float”) 也可以獲取到 float 的值。而 IE678 則不行,所以針對 float ,也需要一個 HACK。

 

  width | height 樣式的獲取

然後是元素的高寬,對於一個沒有設定高寬的元素而言,在 IE678 下使用 getPropertyValue(“width|height”) 得到的是 auto 。而標準瀏覽器會直接返回它的 px 值,當然我們希望在 IE 下也返回 px 值。

這裡的 HACK 方法是使用 element.getBoundingClientRect() 方法。

element.getBoundingClientRect() — 可以獲得元素四個點相對於文件檢視左上角的值 top、left、bottom、right ,通過計算就可以容易地獲得準確的元素大小。

 

  獲取樣式的駝峰表示法

上文已經提及了,在IE下使用 currentStyle 要獲得屬性名的話必須採用駝峰式的寫法。

 

OK,需要 HACK 的點已經提完了。那麼在 IE 下,獲取樣式的寫法:

  setStyle(elem, style, value)

說完 get ,再說說 setStyle ,相較於getStyle ,setStyle 則便捷很多,因為不管是標準瀏覽器還是 IE ,都可以使用 element.style.cssText 對元素進行樣式的設定。

cssText — 一種設定 CSS 樣式的方法,但是它是一個銷燬原樣式並重建的過程,這種銷燬和重建,會增加瀏覽器的開銷。而且在 IE 中,如果 cssText(假如不為空),最後一個分號會被刪掉,所以我們需要在其中新增的屬性前加上一個 ”;”  。

只是在 IE 下的 opacity 需要額外的進行處理。明瞭易懂,直接貼程式碼:

到這裡,原生 JS 實現的 getStyle 與 setStyle 就實現了,完整的程式碼可以戳這裡檢視。可以看到,一個簡單介面的背後,都是有涉及了很多方面東西。雖然瀏覽器相容性是一個坑,但是爬坑的過程卻是我們沉澱自己的最好時機。

jQuery 這樣的框架可以幫助我們走的更快,但是毫無疑問,去弄清底層實現,掌握原生 JS 的寫法,可以讓我們走得更遠。

 

原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

如果本文對你有幫助,請點下推薦,寫文章不容易。

最後,本文元件示例的程式碼貼在 我的github 上。

我在 github 上關於 jQuery 原始碼的全文註解,感興趣的可以圍觀一下。jQuery v1.10.2 原始碼註解 

相關文章