我有2个div
,其中一个是通过display:none;
隐藏的。两者在属性right
上具有相同的CSS过渡。
如果我通过JQuery更改属性right
并通过使用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()
,它将起作用。但是我的问题是;那是错误还是正常行为?
编辑不是Transitions on the display: property的重复项,这是因为这里的问题不是关于动画显示属性还是可见性
答案 0 :(得分:2)
要清楚地了解这种情况,您需要了解CSSOM和DOM之间的关系。
在previous Q/A中,我对 redraw 过程的工作方式进行了一些开发。
基本上,分三个步骤,DOM操作,重排和绘制。
CSS过渡通过从一种状态过渡到另一种状态而起作用。为此,他们查看元素的最后计算值以创建初始状态。
由于浏览器仅在需要时才重新计算所计算的样式,因此在过渡开始时,您应用的所有DOM操作均无效。
所以在您的第一种情况下,当计算过渡的初始状态时,我们有
.b { computedStyle: {display: none} }
...就是这样。
因为,是的,display: none
对CSSOM的功能是如此强大;如果元素具有display: none
,则无需绘制,就不存在。
因此,我什至不确定转换算法是否会启动,但是即使这样,初始状态对于 any 可转换值也将是无效的,因为所有计算值都为null。
您的.a
元素自开始就可见,不存在此问题,可以进行过渡。
如果您能够使其延迟工作(由$.animate
引起),那是因为在确实更改了display
属性的DOM manip'和此延迟的DOM manip的执行之间'会触发过渡,浏览器确实触发了重排(例如,由于屏幕之间出现了垂直同步,并且触发了 paint 操作)。
现在,这不是问题的一部分,但是由于我们确实了解会发生什么,因此我们也可以更好地控制它。
实际上,some DOM methods确实需要具有最新的计算值。例如Element.getBoundingClientRect
或element.offsetHeight
或getComputedStyle(element).height
等。所有这些都需要整页具有更新的计算值,以便正确进行装箱(例如元素可以有一定的余量或多或少地推动它,等等。
这意味着我们不必知道浏览器何时触发此 reflow ,我们可以在需要时强制其执行。
但是请记住,页面上的所有元素都需要更新,这不是一个小操作,如果浏览器宽容地这样做,则有充分的理由。
因此,最好偶尔使用它,每帧最多使用一次。
幸运的是,Web API使我们能够在绘制操作发生之前钩住一些js代码:requestAnimationFrame。
因此,最好的方法是在此预绘画回调中仅强制执行一次重排,并从该回调中调用需要更新值的所有内容。
$('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>
答案 1 :(得分:1)
没有参数的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>
答案 2 :(得分:0)
我个人将其显示后检查该元素是否可见。然后继续通过jQuery。
像这样:gulp-eslint package description
$('button').on('click',function(){
var b = $('.b');
b.show();
if(b.is(":visible")) {
$('.b').css('right','80%');
$('.a').css('right','80%');
}
});
答案 3 :(得分:0)
在节目上开始过渡的问题与尝试在加载时开始过渡的问题相同。 CSS不支持在元素显示的同一帧上开始动画,这真是令人讨厌。在此处查看答案:css3 transition animation on load?
解决方案是使用关键帧而不是过渡。但是然后您就不能正确执行变量,因为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>
答案 4 :(得分:-1)
检查这个小提琴只需添加一个超时时间
$('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>
答案 5 :(得分:-2)
这不是错误,jQuery show()
函数使用400ms
来显示元素,只需使用show(0)
$('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 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>