[英]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 操作、回流和繪制。
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.offsetHeight
或getComputedStyle(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>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.