您可以让它以您期望的自然方式工作 - 使用 display - 但您必须限制浏览器才能使其工作,使用 Javascript 或其他人建议的将一个标签放在另一个标签内的花哨技巧。我不在乎内部标签,因为它进一步复杂化了 CSS 和尺寸,所以这里是 Javascript 解决方案:
https://jsfiddle.net/b9chris/hweeyecu4/17/
从如下框开始:
<div id="box" class="hidden">Lorem</div>
一个隐藏的盒子。
div.hidden {
display: none;
}
#box {
transition: opacity 1s;
}
我们将使用在相关问答中发现的一个技巧,检查 offsetHeight 来立即限制浏览器:
https://.com/a/16575811/176877
首先,一个将上述技巧形式化的库:
$.fn.noTrnsn = function () {
return this.each(function (i, tag) {
tag.style.transition = 'none';
});
};
$.fn.resumeTrnsn = function () {
return this.each(function (i, tag) {
tag.offsetHeight;
tag.style.transition = null;
});
};
接下来,我们将用它来显示一个框,并将其淡入:
$('#button').on('click', function() {
var tag = $('#box');
if (tag.hasClass('hidden'))
tag.noTrnsn().removeClass('hidden')
.css({ opacity: 0 })
.resumeTrnsn().css({ opacity: 1 });
else
tag.css({ opacity: 0 });
});
这会使框淡入淡出。因此, .noTrnsn()
关闭过渡,然后我们删除 hidden
类, display
从 none
到其默认值 block
。然后我们将不透明度设置为 0 以准备淡入。现在我们已经设置好了舞台,我们使用 重新打开过渡 .resumeTrnsn()
。最后,通过将不透明度设置为 1 来启动过渡。
如果没有这个库,显示和不透明度的改变都会给我们带来不理想的结果。如果我们只是删除库调用,我们根本就不会得到任何过渡。
请注意,上面的代码不会在淡出动画结束时再次将显示设置为无。不过,我们可以做得更漂亮。让我们用一个从 0 开始淡入并增加高度的动画来实现这一点。
想要!
https://jsfiddle.net/b9chris/hweeyecu4/22/
#box {
transition: height 1s, opacity 1s;
}
我们现在正在转换高度和不透明度。请注意,我们没有设置高度,这意味着它是默认值。 auto
按照惯例,这不能转换 - 从自动移动到像素值(如 0)将不会产生任何转换。我们将使用库和另一种库方法解决这个问题:
$.fn.wait = function (time, fn) {
if (time)
this.delay(time);
if (!fn)
return this;
var _this = this;
return this.queue(function (n) {
fn.call(_this);
n();
});
};
这是一种便捷方法,让我们可以参与 jQuery 现有的 fx/动画队列,而无需 jQuery 3.x 中现在排除的任何动画框架。我不会解释 jQuery 的工作原理,但可以说, .queue()
和 .stop()
管道可以帮助我们防止动画相互干扰。
让我们为向下滑动的效果添加动画。
$('#button').on('click', function() {
var tag = $('#box');
if (tag.hasClass('hidden')) {
// Open it
// Measure it
tag.stop().noTrnsn().removeClass('hidden').css({
opacity: 0, height: 'auto'
});
var h = tag.height();
tag.css({ height: 0 }).resumeTrnsn()
// Animate it
.css({ opacity: 1, height: h })
.wait(1000, function() {
tag.css({ height: 'auto' });
});
} else {
// Close it
// Measure it
var h = tag.noTrnsn().height();
tag.stop().css({ height: h })
.resumeTrnsn()
// Animate it
.css({ opacity: 0, height: 0 })
.wait(1000, function() {
tag.addClass('hidden');
});
}
});
此代码首先检查 #box
其类,看它当前是否处于隐藏状态。但是,它使用 wait()
库调用实现了更多功能,即 hidden
在滑出/淡入淡出动画的末尾添加类,如果它确实处于隐藏状态,您会期望找到它 - 而上面的简单示例无法做到这一点。这恰好也启用了反复显示/隐藏元素的功能,这是上一个示例中的一个错误,因为隐藏的类从未恢复。
您还可以看到 CSS 和类更改在之后被调用, .noTrnsn()
通常为动画设置阶段,包括进行测量,例如 #box
在调用之前测量最终高度而不向用户显示 .resumeTrnsn()
,并将其从完全设置的阶段动画到其目标 CSS 值。
旧答案
https://jsfiddle.net/b9chris/hweeyecu4/1/
您可以通过以下方式实现点击转换:
function toggleTransition() {
var el = $("div.box1");
if (el.length) {
el[0].className = "box";
el.stop().css({maxWidth: 10000}).animate({maxWidth: 10001}, 2000, function() {
el[0].className = "box hidden";
});
} else {
el = $("div.box");
el[0].className = "box";
el.stop().css({maxWidth: 10001}).animate({maxWidth: 10000}, 50, function() {
el[0].className = "box box1";
});
}
return el;
}
someTag.click(toggleTransition);
CSS 正如你所猜测的:
.hidden {
display: none;
}
.box {
width: 100px;
height: 100px;
background-color: blue;
color: yellow;
font-size: 18px;
left: 20px;
top: 20px;
position: absolute;
-webkit-transform-origin: 0 50%;
transform-origin: 0 50%;
-webkit-transform: scale(.2);
transform: scale(.2);
-webkit-transition: transform 2s;
transition: transform 2s;
}
.box1{
-webkit-transform: scale(1);
transform: scale(1);
}
关键是限制显示属性。通过删除隐藏类,然后等待 50 毫秒, 然后 通过添加的类开始转换,我们可以让它出现,然后像我们想要的那样展开,而不是让它在没有任何动画的情况下闪现在屏幕上。反过来也会出现类似的情况,只是我们等到动画结束后再应用隐藏。
注意:我 .animate(maxWidth)
在这里滥用以避免 setTimeout
竞争条件。 setTimeout
当您或其他人不知情的情况下拿起代码时,很快就会引入隐藏的错误。 .animate()
可以很容易地被杀死 .stop()
。我只是用它在标准 fx 队列上放置 50 毫秒或 2000 毫秒的延迟,这样其他在此基础上构建的程序员就很容易找到/解决。