CSS 显示属性上的转换
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3331353/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Transitions on the CSS display property
提问by RichardTape
I'm currently designing a CSS 'mega dropdown' menu - basically a regular CSS-only dropdown menu, but one that contains different types of content.
我目前正在设计一个 CSS 'mega dropdown' 菜单 - 基本上是一个常规的 CSS-only 下拉菜单,但包含不同类型的内容。
At the moment, it appears that CSS 3 transitions don't apply to the 'display' property, i.e., you can't do any sort of transition from display: none
to display: block
(or any combination).
目前,似乎 CSS 3 过渡不适用于 'display' 属性,即,您不能进行任何类型的从display: none
to display: block
(或任何组合)的过渡。
Is there a way for the second-tier menu from the above example to 'fade in' when someone hovers over one of the top level menu items?
当有人将鼠标悬停在顶级菜单项之一上时,是否有办法让上述示例中的二级菜单“淡入”?
I'm aware that you can use transitions on the visibility:
property, but I can't think of a way to use that effectively.
我知道您可以在visibility:
属性上使用转换,但我想不出有效使用它的方法。
I've also tried using height, but that just failed miserably.
我也试过使用高度,但那只是惨败。
I'm also aware that it's trivial to achieve this using JavaScript, but I wanted to challenge myself to use just CSS, and I think I'm coming up a little short.
我也知道使用 JavaScript 来实现这一点很简单,但我想挑战自己只使用 CSS,我想我有点短。
采纳答案by Guillermo
You can concatenate two transitions or more, and visibility
is what comes handy this time.
您可以连接两个或更多过渡,visibility
这一次很方便。
div {
border: 1px solid #eee;
}
div > ul {
visibility: hidden;
opacity: 0;
transition: visibility 0s, opacity 0.5s linear;
}
div:hover > ul {
visibility: visible;
opacity: 1;
}
<div>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
(Don't forget the vendor prefixes to the transition
property.)
(不要忘记transition
属性的供应商前缀。)
More details are in this article.
更多细节在这篇文章中。
回答by Jim Jeffers
You need to hide the element by other means in order to get this to work.
您需要通过其他方式隐藏元素才能使其工作。
I accomplished the effect by positioning both <div>
s absolutely and setting the hidden one to opacity: 0
.
我通过<div>
绝对定位两个s 并将隐藏的一个设置为opacity: 0
.
If you even toggle the display
property from none
to block
, your transition on other elements will not occur.
如果您甚至将display
属性从切换none
到block
,您在其他元素上的过渡将不会发生。
To work around this, always allow the element to be display: block
, but hide the element by adjusting any of these means:
要解决此问题,请始终允许元素为display: block
,但通过调整以下任一方法来隐藏元素:
- Set the
height
to0
. - Set the
opacity
to0
. - Position the element outside of the frame of another element that has
overflow: hidden
.
- 将 设置
height
为0
。 - 将 设置
opacity
为0
。 - 将元素定位在另一个具有 的元素的框架之外
overflow: hidden
。
There are likely more solutions, but you cannot perform a transition if you toggle the element to display: none
. For example, you may attempt to try something like this:
可能有更多解决方案,但如果将元素切换为 ,则无法执行转换display: none
。例如,您可以尝试尝试以下操作:
div {
display: none;
transition: opacity 1s ease-out;
opacity: 0;
}
div.active {
opacity: 1;
display: block;
}
But that will notwork. From my experience, I have found this to do nothing.
但是,这并不工作。根据我的经验,我发现这无济于事。
Because of this, you will always need to keep the element display: block
- but you could get around it by doing something like this:
因此,您将始终需要保留元素display: block
- 但您可以通过执行以下操作来绕过它:
div {
transition: opacity 1s ease-out;
opacity: 0;
height: 0;
overflow: hidden;
}
div.active {
opacity: 1;
height: auto;
}
回答by Salman von Abbas
At the time of this post all major browsers disable CSS transitions if you try to change the display
property, but CSS animations still work fine so we can use them as a workaround.
在撰写本文时,如果您尝试更改display
属性,所有主要浏览器都会禁用 CSS 转换,但 CSS 动画仍然可以正常工作,因此我们可以将它们用作解决方法。
Example Code(you can apply it to your menu accordingly) Demo:
示例代码(您可以相应地将其应用于您的菜单)演示:
Add the following CSS to your stylesheet:
将以下 CSS 添加到您的样式表中:
@-webkit-keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
Then apply the fadeIn
animation to the child on parent hover (and of course set display: block
):
然后将fadeIn
动画应用到父悬停上的孩子(当然还有 set display: block
):
.parent:hover .child {
display: block;
-webkit-animation: fadeIn 1s;
animation: fadeIn 1s;
}
Update 2019 - Method that also supports fading out:
2019 年更新 - 也支持淡出的方法:
(Some JavaScript code is required)
(需要一些 JavaScript 代码)
// We need to keep track of faded in elements so we can apply fade out later in CSS
document.addEventListener('animationstart', function (e) {
if (e.animationName === 'fade-in') {
e.target.classList.add('did-fade-in');
}
});
document.addEventListener('animationend', function (e) {
if (e.animationName === 'fade-out') {
e.target.classList.remove('did-fade-in');
}
});
div {
border: 5px solid;
padding: 10px;
}
div:hover {
border-color: red;
}
.parent .child {
display: none;
}
.parent:hover .child {
display: block;
animation: fade-in 1s;
}
.parent:not(:hover) .child.did-fade-in {
display: block;
animation: fade-out 1s;
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
<div class="parent">
Parent
<div class="child">
Child
</div>
</div>
回答by Joel_MMCC
I suspect that the reasonthat transitions are disabled if display
is changed is because of what display actually does. It does notchange anything that could conceivably be smoothly animated.
我怀疑转换被禁用的原因display
是因为显示实际上做了什么。它并没有改变任何东西,可以令人信服地平滑的动态。
display: none;
and visibility: hidden;
are two entirelydifferent things.
Both do have the effect of making the element invisible, but with visibility: hidden;
it's still rendered in the layout, but just not visiblyso.
The hidden element still takes up space, and is still rendered inline or as a block or block-inline or table or whatever the display
element tells it to render as, and takes up space accordingly.
Other elements do notautomatically move to occupy that space. The hidden element just doesn't render its actual pixels to the output.
display: none;
并且visibility: hidden;
是完全不同的两件事。
两者都有使元素不可见的效果,但visibility: hidden;
它仍然在布局中呈现,只是不可见。
隐藏元素仍然占用空间,并且仍然被内联或作为块或块内联或表格或display
元素告诉它渲染的任何内容,并相应地占用空间。
其他元素不会自动移动以占据该空间。隐藏元素只是不会将其实际像素呈现给输出。
display: none
on the other hand actually preventsthe element from rendering entirely.
It does not take up anylayout space.
Other elements that would've occupied some or all of the space taken up by this element now adjust to occupy that space, as if the element simply did not exist at all.
display: none
另一方面实际上阻止元素完全呈现。
它不占用任何布局空间。
其他原本会占用该元素所占用空间的部分或全部空间的其他元素现在会调整以占用该空间,就好像该元素根本不存在一样。
display
is not just another visual attribute.
It establishes the entire rendering mode of the element, such as whether it's a block
, inline
, inline-block
, table
, table-row
, table-cell
, list-item
, or whatever!
Each of those have very different layout ramifications, and there would be no reasonable way to animate or smoothly transition them (try to imagine a smooth transition from block
to inline
or vice-versa, for instance!).
display
不仅仅是另一个视觉属性。
它建立了元素的整个渲染模式,例如它是block
, inline
, inline-block
, table
, table-row
, table-cell
, list-item
, 还是什么的!
每一个都有非常不同的布局分支,并且没有合理的方法来动画或平滑过渡它们(例如,尝试想象从block
到inline
或反之亦然的平滑过渡!)。
This is why transitions are disabled if display changes (even if the change is to or from none
— none
isn't merely invisibility, it's its own element rendering mode that means no rendering at all!).
这就是为什么在显示更改时禁用过渡的原因(即使更改是来自或来自none
-none
不仅仅是不可见,它自己的元素渲染模式意味着根本没有渲染!)。
回答by Webars
Instead of callbacks, which don't exist in CSS, we can use transition-delay
property.
我们可以使用transition-delay
属性来代替 CSS 中不存在的回调。
#selector {
overflow: hidden; // Hide the element content, while height = 0
height: 0; opacity: 0;
transition: height 0ms 400ms, opacity 400ms 0ms;
}
#selector.visible {
height: auto; opacity: 1;
transition: height 0ms 0ms, opacity 600ms 0ms;
}
So, what's going on here?
那么,这里发生了什么?
When
visible
class is added, bothheight
andopacity
start animation without delay (0 ms), thoughheight
takes 0 ms to complete animation (equivalent ofdisplay: block
) andopacity
takes 600 ms.When
visible
class is removed,opacity
starts animation (0 ms delay, 400 ms duration), and height waits 400 ms and only then instantly (0 ms) restores initial value (equivalent ofdisplay: none
in the animation callback).
当
visible
类被添加,既height
和opacity
无延迟启动动画(0毫秒),尽管height
需要0ms到完整的动画(当量display: block
)和opacity
花费600毫秒。当
visible
类被移除时,opacity
开始动画(0 毫秒延迟,400 毫秒持续时间),高度等待 400 毫秒,然后才立即(0 毫秒)恢复初始值(相当于display: none
动画回调中的)。
Note, this approach is better than ones using visibility
. In such cases, the element still occupies the space on the page, and it's not always suitable.
请注意,这种方法比使用visibility
. 在这种情况下,元素仍然占据页面上的空间,并不总是合适的。
For more examples please refer to this article.
更多例子请参考这篇文章。
回答by robocat
display
is not one of the properties that transition works upon.
display
不是过渡作用的属性之一。
See Animatable CSS propertiesfor the list of CSS properties that can have transitions applied to them. See CSS Values and Units Module Level 4, Combining Values: Interpolation, Addition, and Accumulationfor how they are interpolated.
有关可以应用过渡的 CSS 属性列表,请参阅可动画 CSS 属性。请参阅CSS Values and Units Module Level 4, Combining Values: Interpolation, Addition, and Accumulation了解它们的插值方式。
Up to CSS 3 was listed in 9.1. Properties from CSS(just close the warning popup)
在9.1中列出了 CSS 3 。来自 CSS 的属性(只需关闭警告弹出窗口)
I've also tried using height, but that just failed miserably.
我也试过使用高度,但那只是惨败。
Last time I had to do this, I used max-height
instead, which is an animatable property (although it was a bit of a hack, it did work), but beware that it may be very janky for complex pages or users with low-end mobile devices.
上次我不得不这样做时,我max-height
改用了,这是一个可动画的属性(虽然它有点hack,但确实有效),但要注意它对于复杂页面或使用低端移动设备的用户可能非常笨拙设备。
回答by Manish Pradhan
You can add a custom animation to the block property now.
您现在可以向块属性添加自定义动画。
@keyframes showNav {
from {opacity: 0;}
to {opacity: 1;}
}
.subnav-is-opened .main-nav__secondary-nav {
display: block;
animation: showNav 250ms ease-in-out both;
}
In this demo the sub-menu changes from display:none
to display:block
and still manages to fade.
在这个演示中,子菜单从display:none
变为display:block
并且仍然设法消失。
回答by feklee
According to W3C Working Draft 19 November 2013display
is not an animatable property. Fortunately, visibility
is animatable. You may chain its transition with a transition of opacity (JSFiddle):
根据W3C 工作草案,2013 年 11 月 19 日display
不是动画属性。幸运的是,visibility
是动画。您可以将其转换与不透明度转换(JSFiddle)链接起来:
HTML:
<a href="http://example.com" id="foo">Foo</a> <button id="hide-button">Hide</button> <button id="show-button">Show</button>
CSS:
#foo { transition-property: visibility, opacity; transition-duration: 0s, 1s; } #foo.hidden { opacity: 0; visibility: hidden; transition-property: opacity, visibility; transition-duration: 1s, 0s; transition-delay: 0s, 1s; }
JavaScript for testing:
var foo = document.getElementById('foo'); document.getElementById('hide-button').onclick = function () { foo.className = 'hidden'; }; document.getElementById('show-button').onclick = function () { foo.className = ''; };
HTML:
<a href="http://example.com" id="foo">Foo</a> <button id="hide-button">Hide</button> <button id="show-button">Show</button>
CSS:
#foo { transition-property: visibility, opacity; transition-duration: 0s, 1s; } #foo.hidden { opacity: 0; visibility: hidden; transition-property: opacity, visibility; transition-duration: 1s, 0s; transition-delay: 0s, 1s; }
用于测试的 JavaScript:
var foo = document.getElementById('foo'); document.getElementById('hide-button').onclick = function () { foo.className = 'hidden'; }; document.getElementById('show-button').onclick = function () { foo.className = ''; };
Note that if you just make the link transparent, without setting visibility: hidden
, then it would stay clickable.
请注意,如果您只是将链接设置为透明,而没有设置visibility: hidden
,那么它将保持可点击状态。
回答by Pawel
Edit: display none is not being applied in this example.
编辑:在此示例中未应用 display none。
@keyframes hide {
0% {
display: block;
opacity: 1;
}
99% {
display: block;
}
100% {
display: none;
opacity: 0;
}
}
What's happening above is that through 99% of the animation display is set to block while the opacity fades out. In the last moment display property is set to none.
上面发生的事情是,当不透明度逐渐消失时,99% 的动画显示设置为阻止。在最后一刻显示属性设置为无。
And the most important bit is to retain the last frame after the animation ends using animation-fill-mode: forwards
最重要的一点是使用 animation-fill-mode: forwards 保留动画结束后的最后一帧
.hide {
animation: hide 1s linear;
animation-fill-mode: forwards;
}
Here are two examples: https://jsfiddle.net/qwnz9tqg/3/
这里有两个例子:https: //jsfiddle.net/qwnz9tqg/3/
回答by Sasa Milenkovic
My neat JavaScript trick is to separate the entire scenario into two different functions!
我巧妙的 JavaScript 技巧是将整个场景分成两个不同的函数!
To prepare things, one global variable is declared and one event handler is defined:
为了做好准备,声明了一个全局变量并定义了一个事件处理程序:
var tTimeout;
element.addEventListener("transitionend", afterTransition, true);//firefox
element.addEventListener("webkitTransitionEnd", afterTransition, true);//chrome
Then, when hiding element, I use something like this:
然后,当隐藏元素时,我使用这样的东西:
function hide(){
element.style.opacity = 0;
}
function afterTransition(){
element.style.display = 'none';
}
For reappearing the element, I am doing something like this:
为了重新出现元素,我正在做这样的事情:
function show(){
element.style.display = 'block';
tTimeout = setTimeout(timeoutShow, 100);
}
function timeoutShow(){
element.style.opacity = 1;
}
It works, so far!
到目前为止,它有效!