解決transition動畫與display衝突的幾種方法

demo(若是沒有顯示,請查看源地址http://jsfiddle.net/ihardcoder/HNduT/2/)所示,基本的效果是在點擊「Translate」按鈕後,藍色區域透明度變爲0,而後隱藏display:none;點擊Reset按鈕後,首先顯示藍色區域display:block,而後透明度逐漸恢復至1,代碼以下:javascript

 1 var btn1 = $("#testbtn1");
 2 var btn2 = $("#testbtn2");
 3 var container = $("#container");
 4 
 5 btn1.on('click', function(e) {
 6     container.css({
 7         "transition": "opacity 1s",
 8         "-webkit-transition": "opacity 1s",
 9         "-moz-transition": "opacity 1s",
10         "-o-transition": "opacity 1s",
11         "-ms-transition": "opacity 1s",
12         "opacity": "0.1"
13          });
14     setTimeout(function() {
15         container.css("display", "none");
16     }, 1000);
17 });
18 btn2.on('click', function(e) {
19     container.css("display","block");
20     container.css("display");
21     container.css("opacity","1");
22 });

上述代碼中第20行看起來很奇怪,可能會有人疑問這句代碼的做用,事實是,若是沒有這句代碼,在點擊Reset後獲得的效果是:藍色區域瞬間顯示出來,並無透明度改變的過渡效css

至於產生這種現象的緣由,深層次的機制我也還沒有搞明白,暫時理解爲CSS3的transition過渡不支持display的改變,直接操做display會破壞transition的動畫,因此在第14行經過setTimeout將opacity的transition動畫與display的操做分隔。java

而第20行代碼的目的,我是這樣理解的,瀏覽器的UI線程在處理UI操做時,將多個css屬性的set操做加入在同一個tick中處理(關於瀏覽器處理tick機制,請參考http://www.infoq.com/cn/articles/javascript-high-performance-animation-and-page-rendering?utm_source=infoq&utm_medium=popular_links_homepage),也就是說,若是不插入第20行代碼,第19行和第21行的css屬性set操做將會被同時執行,因此將會獲得瞬間顯示出來的效果;第20行代碼實際上是css屬性的get操做,個人理解是,若是在兩個css屬性的set操做中間插入get操做,UI線程在處理的時候將會按順序執行,display的操做和opacity的操做在不一樣的tick中被執行,這樣便的到咱們想要的過渡效果。web

第二種方法,因爲display對transition的破壞做用,還有另一種方法來hack,沒有錯,就是setTimeout!(這貨徹底是js的大殺器!)代碼以下:chrome

1  btn2.on('click', function(e) {
2     container.css("display","block");
3     setTimeout(function(){
4        container.css("opacity","1");
5     },delay);
6  });

可是用setTimeout的方法有一個弊端,第5行的delay在不一樣的瀏覽器(甚至不一樣版本的相同瀏覽器)中須要設置不一樣的數值,經本人測試,chrome35和IE10下delay=0便可,Firefox30下delay>=14.瀏覽器

第三種解決方法是經過window.requestAnimationFram來實現,代碼以下:測試

1 btn2.on('click', function(e) {
2       container.css("display","block");
3       requestanimationframe(function(){
4          container.css("opacity","1");
5       });
6    });

requestAnimationFram的做用是將opacity的操做推遲到下一個tick中處理,從而將display的操做分隔開,基本原理與setTimeout相同。動畫

另外,關於display爲什麼會破壞transition動畫,目前本人仍未找到相關資料來證實其內部機制,個人我的理解是,display的操做會觸發瀏覽器的reflow操做,而transition支持的效果只是觸發瀏覽器的repaint操做,回到上面的demo,若是咱們經過visibility屬性來控制顯示與隱藏,則不會破壞transition的效果。因此,能夠暫時這麼認爲:reflow與repaint的混合會破壞transition的動畫效果,至於更深層次的緣由嘛,借我借我一雙慧眼吧~spa

相關文章
相關標籤/搜索