本篇文章主要講述CSS3 transition規範和在不一樣瀏覽器之間的使用差別,我要談的是技術背景,主要討論在使用CSS過渡的過程當中所未預料到的問題。
結構 (HTML),表現(CSS),以及行爲(JavaScript)相分離並非什麼新鮮的事情,然而 CSS 能跨越這個界限而且能夠在短時間內獲得實際的應用,這還真的是一個徹底不一樣的討論話題。
幾周前,我開發一個 JavaScript 模塊,在可以使用 CSS 過渡的條件下,JavaScript 端又沒法獲取到實現過渡的方式。實際遇到的問題是這二者根本沒有辦法同步,通過屢次的測試後,我只能放棄。而個人測試結果正是本文所講述的。
首先,咱們要說一下getcomputedstyle(),是一種用 JavaScript 返回瀏覽器渲染CSS的屬性值的方法。 這個方法能夠查看「DOM Level 2: getComputedStyle()」和「CSS Level 2: Computed Values」。
這對於像 font-size 這樣的屬性, 經過一個參數即可以轉換爲像素值。 但對於能夠縮寫的屬性值,例如 margin ,一些瀏覽器則返回爲空。再就是那些同一屬性的不一樣屬性值,例如 font-weight 的值 bold 和700。WebKit也有一個小bug,它會從僞對象中提取出屬性值。
這裏所講述的瀏覽器之間的差別是2013年1月在使用 Firefox18(Gecko),Opera 12.12 (Presto), Internet Explorer10(Trident),Safari 瀏覽器6.0.2(WebKit),Chrome 23(WebKit) 以及 Gecko 和 WebKit的 Nightly build channels。
事不宜遲,讓咱們來一塊兒看一下規範與實際狀況的差別,爲了方便,我省略了各瀏覽器的前綴。在文中我經過建立一個 CSS3 Transitions Test Suite 來發現問題。
一、指定過渡
CSS3 transitions 規範定義瞭如下四個 CSS 屬性:
css
transition-propertycss3
transition-duration瀏覽器
transition-delay異步
transition-timing-function
編輯器
過渡屬性
transition-property 是用來指定當元素其中一個屬性改變時執行 transition 效果。系統默認值是 all,這意味着瀏覽器可以以動畫形式呈現全部的可過渡屬性(transition-duration持續時間超過0s),該屬性支持單個值或以逗號隔開的多個值列表(跟其餘全部transition-*屬性同樣)。
規範規定,一個瀏覽器應該接受並保存任何它不能識別的屬性。所以,下面的例子中將會看到持續2秒的 padding 過渡:ide
<font face="inherit">transition-property:foobar,padding;
函數
transition-duration:1s,2s;</font>性能
複製代碼測試
不一樣於規範的是,上面的狀況在 WebKit 下會解析爲 transition-property: all。 而 Firefox 和 Opera 會解析爲 transition-property: all, padding.
過渡持續時間
transition-duration 屬性規定了一個過渡從初始狀態到目標狀態的持續時間。它接受以秒或毫秒的值(例如,2.3S和2300ms都是指2.3秒)。
儘管規範明確規定了過渡值必須爲正數,但 Opera 仍接受-5S的值,至少對於getComputedStyle()來講是這樣的。雖然規範中並無限制屬性值的大小,但 Opera 和 IE 不接受低於10ms的值。而 WebKit 在 getComputedStyle()執行中有個小bug,例如:返回值0.009999999776482582s會取代0.01s。
過渡延遲時間
transition-delay 屬性規定了在執行一個過渡以前的等待時間,一樣使用值。Delay 能夠是負值,但這會致使動畫沒法平滑過渡。
IE 和 Opera 不接受 transition-duration 在-10ms和10ms之間的值。WebKit 的 floating point 也會在這兒出現。
transition-timing-function 屬性規定了過渡效果的時間曲線。包括cubic-bezier(x1, y1, x2, y2), step(, start|end),和預先定義的 cubic-bezier 曲線關鍵詞,linear, ease, ease-in, ease-out和ease-in-out。在使用 LEA Verou 特有的 cubic-bezier 曲線編輯器時,cubic-bezier 背後的公式就變得再也不重要。儘管 cubic-bezier 曲線會平滑過渡,可是step()函數會在一個固定的間隔跳到下一個值。這樣便會產生逐幀動畫的效果;如「Pure CSS3 Typing Animation With steps()」。
linear 的計算值一般表示爲 cubic-bezier(0, 0, 1, 1)—— WebKit除外。但 WebKit 仍然會返回 cubic-bezier(0.25, 0.1, 0.25, 1),而不是 ease。規範規定 X 值的必須介於0和1之間,y 值能夠超過該範圍,而WebKit 容許 X 超過此範圍,而 Android 瀏覽器(4.0版本)卻混淆了x和y的範圍。
2 過渡完成
我前面已經提到了 CSS 過渡異步運行的問題。規範說起了 TransitionEnd 事件容許 JavaScript 與已完成的過渡同步進行。但可惡的是該規範對此並沒具體闡述。事實上,它只是簡單地說明單個事件會由於已完成過渡的屬性而被終止。
規範指出縮寫屬性(如padding)應爲包括其在內的全部屬性(padding-top,padding-right,等等)實現過渡,它並無說哪一個屬性應該在 TransitionEnd 事件中被具體命名。然而即便過渡被定義爲縮寫屬性(如padding),Gecko,Trident 和 Presto 對於普通書寫的子屬性(如padding-top)一樣能夠實現過渡,而 WebKit 則會阻止過渡。 若是你指定 transition-property: padding,WebKit 會爲 padding 執行過渡, 但 transition-property: all 這樣就會針對 padding-left 執行新的過渡。而當 padding 正執行過渡時, iPhone 6.0.1 的 Safari 瀏覽器在也能夠執行 font-size 和 line-height的過渡。動畫
<font face="inherit">.example{padding:1px;transition-property:padding;transition-duration:1s;}
.example:hover{padding:10px;}</font>
複製代碼
以上 CSS 將在不一樣瀏覽器下觸發不一樣的 TransitionEnd:
Gecko,Trident,Presto:
padding-top,padding-right,padding-bottom,padding-left
WebKit:
padding
<font face="inherit">.example {padding: 1px;transition-property: all, padding;transition-duration:1s;}
.example:hover{padding:10px;}</font>
複製代碼
以上 CSS 將在不一樣瀏覽器下觸發不一樣的TransitionEnd:
Gecko,Trident,Presto,WebKit:
padding-top,padding-right,padding-bottom,padding-left
Safari 6.0.1 on iPhone:
padding-top, padding-right, padding-bottom, padding-left, font-size, line-height
你能夠指定負值 transition-delay 來「快速實現」轉換。可是transition-duration: 1s; transition-delay: -1s; 在 Gecko 和 WebKit 下執行轉換並會當即跳轉至目標值。而Trident 和 Presto 將不會觸發任何事件。
WebKit在 getComputedStyle() 上遇到的浮點問題也一樣存在於 TransitionEnd.elapsedTime 中,全部的瀏覽器如此。 Math.round(event.elapsedTime * 1000) / 1000 可輔助修復。
WebKit 和 IE 瀏覽器下執行 background-position,會觸發對 background-position-x 和 background-position-y 的 TransitionEnd,而不是 background-position 的TransitionEnd。
因此,即便你知道過渡正在執行,你也不能依賴已有的 TransitionEnd.propertyName。儘管你能夠編寫大量的 JavaScript 來彌補,但在沒有對每個屬性進行恰當性能檢測的狀況下,即便你採用最新方法也將沒法實現。
3 過渡屬性
規範列出了瀏覽器支持動畫過渡的一些CSS屬性。固然也包括CSS2.1的屬性。還有一些能夠動態變化的新屬性,如 Flexible Box Layout。
該屬性數值類型很是重要。margin-top 接受和值,但根據可過渡CSS屬性列表,只有是可實現動畫效果。但這並不能讓瀏覽器開發商避開值實現過渡。然而,word-spacing 屬性除外。該屬性包括值,但沒有瀏覽器能以動畫形式顯示。
撇開 TransitionEnd 事件,若是在過渡發生的指定時間內,getComputedStyle()值從A變到B,該屬性就會從值A過渡爲值B。若是沒有執行,例如「CSS屬性值發生變化」,那麼也許應該仔細覈查下DOM。setTimeout()的解析度還不夠好以達到快速過渡(小於幾百毫秒的持續時間),這時候requestAnimationFrame()就是你的幫手。在重繪前會提醒你,並提供了一些中間值供參考。除了opera,其餘的均可以支持。