簡體   English   中英

如果元素開始隱藏,則 css 過渡不起作用

[英]css transition doesn't work if element start hidden

我有 2 個div ,其中一個通過display:none;隱藏display:none; . 雙方對財產相同的CSS過渡right

如果我更改屬性right通過jQuery和顯示隱藏div ,無論是使用$.css('display','none')$.show()$.toggle()等,隱藏的div立即逼平結束位置

 $('button').on('click',function(){ $('.b').show(); $('.b').css('right','80%'); $('.a').css('right','80%'); })
 body { width:800px; height:800px; } div { width:50px; height:50px; background-color:#333; position:absolute; display:none; right:5%; top:0; transition:right .5s cubic-bezier(0.645, 0.045, 0.355, 1); color: white; } .a { display:block; top:60px; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class='a'>A </div> <div class='b'>B </div> <button>Launch</button>

如果我使用$.animate()它將起作用。 但我的問題是; 這是錯誤還是正常行為?

編輯不是顯示上的過渡的重復:屬性導致這里的問題不是動畫顯示屬性也不是可見性

要想看清情況,就需要了解 CSSOM 和 DOM 的關系。

之前的問答中,我對重繪過程的工作原理有了一些了解。
基本上分為三個步驟,DOM 操作、回流和繪制。

  • 第一個( DOM 操作)只是修改一個 js 對象,並且都是同步的。
  • 第二個(回流,又名布局)是我們感興趣的,而且有點復雜,因為只有一些 DOM 方法和繪制操作需要它。 它包括更新所有 CSS 規則並重新計算頁面上每個元素的所有計算樣式。
    作為一個相當復雜的操作,瀏覽器會盡量少做。
  • 第三個 ( paint ) 每秒最多只執行 60 次(僅在需要時)。

CSS 轉換通過從一種狀態轉換到另一種狀態來工作。 為此,他們查看元素的最后計算值以創建初始狀態。
由於瀏覽器僅在需要時才重新計算計算出的樣式,因此在過渡開始時,您應用的所有 DOM 操作均無效。

所以在你的第一個場景中,當計算轉換的初始狀態時,我們有

.b { computedStyle: {display: none} }

......就是這樣。

因為,是的,這就是display: none的強大display: none CSSOM display: none 如果一個元素有display: none ,那么它不需要被繪制,它不存在。

所以我什至不確定轉換算法是否會啟動,但即使它啟動了,初始狀態對於任何可轉換值也是無效的,因為所有計算值都為空。

從一開始就可見的.a元素沒有這個問題,可以轉換。

如果你能夠讓它延遲工作(由$.animate引起),那是因為在確實改變了display屬性的 DOM manip' 和觸發轉換的這個延遲的 DOM manip' 的執行之間,瀏覽器確實觸發了回流(例如,因為屏幕垂直同步在兩者之間啟動並且繪制操作被觸發)。


現在,這不是問題的一部分,但既然我們確實更了解發生了什么,我們也可以更好地控制它

事實上,一些 DOM 方法確實需要有最新的計算值。 例如Element.getBoundingClientRect ,或element.offsetHeightgetComputedStyle(element).height等。所有這些都需要整個頁面更新計算值,以便正確進行裝箱(例如,元素可以有一個邊距推動它更多或少等)。

這意味着我們不必知道瀏覽器何時會觸發回流,我們可以強制它在我們想要的時候這樣做。

但是請記住,頁面上的所有元素都需要更新,這不是一個小操作,如果瀏覽器手頭寬大,那是有充分理由的。

所以最好偶爾使用它,每幀最多使用一次。

幸運的是,Web API 使我們能夠在此繪制操作發生之前掛鈎一些 js 代碼: requestAnimationFrame

所以最好的辦法是在這個 pre-paint 回調中只強制我們重排一次,並從這個回調中調用所有需要更新值的東西。

 $('button').on('click',function(){ $('.b').show(); // apply display:block synchronously requestAnimationFrame(() => { // wait just before the next paint document.body.offsetHeight; // force a reflow // trigger the transitions $('.b').css('right','80%'); $('.a').css('right','80%'); }); })
 body { width:800px; height:800px; } div { width:50px; height:50px; background-color:#333; position:absolute; display:none; right:5%; top:0; transition:right .5s cubic-bezier(0.645, 0.045, 0.355, 1); color: white; } .a { display:block; top:60px; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class='a'>A </div> <div class='b'>B </div> <button>Launch</button>

但說實話,設置起來並不總是那么容易,所以如果你確定它會偶爾被觸發,你可能會很懶惰並同步進行:

 $('button').on('click',function(){ $('.b').show(); // apply display:block document.body.offsetHeight; // force a reflow // trigger the transitions $('.b').css('right','80%'); $('.a').css('right','80%'); })
 body { width:800px; height:800px; } div { width:50px; height:50px; background-color:#333; position:absolute; display:none; right:5%; top:0; transition:right .5s cubic-bezier(0.645, 0.045, 0.355, 1); color: white; } .a { display:block; top:60px; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class='a'>A </div> <div class='b'>B </div> <button>Launch</button>

沒有參數的 jQuery show()基本上是這樣做的

$('.b').css('display', 'block');

所以你正在做的是這個

$('button').on('click',function(){
  $('.b').css('display', 'block');
  $('.b').css('right','80%');
  $('.a').css('right','80%');
})

這基本上與

$('button').on('click',function(){
  $('.b').css({
    'display': 'block',
    'right': '80%'
  });
  $('.a').css('right','80%');
})

但是,如果同時更改顯示,則無法轉換任何內容。

show()調用添加一個持續時間值,比僅僅改變display做一些更復雜的事情。 它會將元素添加到這樣的動畫隊列中

$('.b').css({
  'display': 'block', 
  'overflow': 'hidden',
  'height': '0',
  'width': '0',
  'margin': '0',
  'width': '0',
  'opacity': '0'
});
$('.b').animate({
  height: '50px',
  padding: '0px',
  margin: '0px', 
  width: '50px', 
  opacity: '1'
}, 0)

所以你需要做的是將0 (零)的持續時間值作為參數放入show()調用中

 $('button').on('click',function(){ $('.b').show(0); $('.b').css('right','80%'); $('.a').css('right','80%'); })
 body { width:800px; height:800px; } div { width:50px; height:50px; background-color:#333; position:absolute; display:none; right:5%; top:0; transition:right .5s .1s cubic-bezier(0.645, 0.045, 0.355, 1); color: white; } .a { display:block; top:60px; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class='a'>A </div> <div class='b'>B </div> <button>Launch</button>

就個人而言,我會檢查元素在顯示后是否可見。 然后繼續通過jQuery。

像這樣: https : //jsfiddle.net/789su6xb/

$('button').on('click',function(){

    var b = $('.b');
    b.show();

    if(b.is(":visible")) {
        $('.b').css('right','80%');
        $('.a').css('right','80%');
    }

});

在節目中開始過渡的問題與嘗試在加載時開始過渡的問題相同。 CSS 不支持在元素顯示的同一幀上啟動動畫,這真的很煩人。 在此處查看答案: 加載時的 css3 過渡動畫?

解決方案是使用關鍵幀而不是過渡。 但是你不能正確地做一個變量,它在 CSS 文件中被硬編碼為 80%。

 $('button').on('click',function(){ $('.b').show(); $('.b').addClass('goLeft'); $('.a').addClass('goLeft'); })
 body { width:800px; height:800px; } div { width:50px; height:50px; background-color:#333; position:absolute; display:none; right:5%; top:0; color: white; } .goLeft { animation-name: goLeft; animation-duration: .5s; animation-iteration-count: 1; animation-play-state: running; animation-fill-mode: forwards; animation-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1); } .a { display:block; top:60px; } @keyframes goLeft { from { right: 5%; } to { right: 80%; } }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class='a'>A </div> <div class='b'>B </div> <button>Launch</button>

檢查這個小提琴只需要添加一個超時

 $('button').on('click',function(){ $('.b').show(); setTimeout(function(){ $('.b').css('right','80%'); $('.a').css('right','80%'); }, 0); })
 body { width:800px; height:800px; } div { width:50px; height:50px; background-color:#333; position:absolute; display:none; right:5%; top:0; transition:right .5s cubic-bezier(0.645, 0.045, 0.355, 1); } .a { display:block; top:20%; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class='a'> </div> <div class='b'> </div> <button>Launch</button>

https://jsfiddle.net/qu2pybch/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM