CSS显示属性上的过渡


1444

我目前正在设计一个CSS“大型下拉菜单”-基本上是一个常规的仅CSS下拉菜单,但其中包含不同类型的内容。

目前,CSS 3过渡似乎不适用于'display'属性,即,您不能进行从display: nonedisplay: block(或任何组合)的任何过渡。

当有人将鼠标悬停在顶层菜单项之一上时,是否可以使上例中的第二层菜单“淡入”?

我知道您可以在visibility:属性上使用过渡,但是我想不出一种有效使用过渡的方法。

我也尝试过使用高度,但是不幸地失败了。

我还知道使用JavaScript实现此功能很简单,但是我想挑战一下自己仅使用CSS,而且我想说的还有点不足。


如果将CSS过渡应用于opacity属性而不是将其应用于显示,是否可以正常工作?
Paul D. Waite,2010年

13
位置:绝对;可见性:隐藏;与显示相同:无;
贾瓦德2012年

8
@Jawad:仅当您添加类似内容时z-index:0
DanMan

7
@Jawad:建议不要使用,visibility: hidden除非您希望屏幕阅读器阅读它(而典型的浏览器则不会)。它仅定义元素的可见性(例如说opacity: 0),并且仍然是可选择的,可单击的以及以前的样子;它只是不可见。
Forest Katsch

1
pointer-eventsIE 8,9,10 不支持IE,因此并非总是可以的
Steven Pribilinskiy 2015年

Answers:


1349

您可以连接两个或两个以上的过渡,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>

(不要忘记transition属性的供应商前缀。)

更多的细节在这篇文章


10
这个答案似乎比其他答案要少,并且达到了我们期望的显示效果:无/块;谢谢。节省了我很多时间。
布伦丹2012年

21
是的,这是一个问题,即使它不可见,它后面的任何东西都将重叠。我发现使用height:0是更好的解决方案
Josh Bedo

739
很好,但是问题是“隐藏可见性”元素仍然占据空间,而“不显示”则不占据空间。
Rui Marques

41
我可能会丢失一些东西,但是为什么要同时更改可见性和不透明度?不会将不透明度设置为0来隐藏元素-为什么还需要将可见性设置为“隐藏”?
GMA 2014年

21
@GeorgeMillo如果仅设置不透明度,则该元素实际上仍在页面呈现中(例如,您不能单击“思想”)。
2014年

800

您需要通过其他方式隐藏该元素才能使其正常工作。

我通过<div>绝对定位两个s并将隐藏的设置为来达到效果opacity: 0

如果您甚至将display属性从切换noneblock,也不会在其他元素上进行转换。

要变通解决此问题,请始终将元素设置为display: block,但通过调整以下任何一种方法隐藏该元素:

  1. 将设置height0
  2. 将设置opacity0
  3. 将元素放置在另一个具有的元素的框架之外overflow: hidden

可能还有更多解决方案,但是如果将元素切换为,则无法执行过渡display: none。例如,您可以尝试尝试以下操作:

div {
    display: none;
    transition: opacity 1s ease-out;
    opacity: 0;
}
div.active {
    opacity: 1;
    display: block;
}

但是,这并不工作。根据我的经验,我发现这无济于事。

因此,您将始终需要保留元素display: block-但您可以通过执行以下操作来解决该问题:

div {
    transition: opacity 1s ease-out;
    opacity: 0;
    height: 0;
    overflow: hidden;
}
div.active {
    opacity: 1;
    height: auto;
}

29
感谢Jim的详尽回答。如果display:属性完全更改,那么所有转换都将无效,这一事实绝对是正确的。真可惜-我想知道背后的原因是什么。在旁注中,在我原始问题中发布的同一链接上,您可以看到我的立场。我唯一的(小)问题是页面加载时在Chrome [5.0.375.125]中,随着元素加载到页面上,您可以看到菜单迅速消失。Firefox 4.0b2和Safari 5.0绝对不错... bug或我错过的东西?
RichardTape 2010年

7
我同意这是正确的,并将为此做出贡献;迎接未来的旅行者。我在Chrome中找到了一个visibility:hidden; opacity:0; -webkit-transition: all .2s ease-in-out;可行的解决方案,但发现它在iPhone 4上失败了:这不仅不能正确转换,而且目标元素也永远不会出现。质量检查会使您,我和您的妈妈失望。
SimplGy 2011年

1
您实际上也可以转换可见性属性。.只是说
Cu7l4ss 2012年

2
如果您将隐藏状态设置为height: 0;而不进行过渡,则过渡将不起作用。我试图这样做只是为了过渡不透明度。我不得不删除height: 0;
chovy

10
非常overflow: hidden感谢,您刚刚赢得了投票!
thiagoh 2015年

277

在撰写本文时,如果您尝试更改display属性,所有主要的浏览器都会禁用CSS转换,但是CSS动画仍然可以正常工作,因此我们可以将其用作解决方法。

示例代码(您可以将其相应地应用于菜单)Demo

将以下CSS添加到样式表:

@-webkit-keyframes fadeIn {
    from { opacity: 0; }
      to { opacity: 1; }
}
@keyframes fadeIn {
    from { opacity: 0; }
      to { opacity: 1; }
}

然后将fadeIn动画应用于父悬停时的孩子(当然还要设置display: block):

.parent:hover .child {
    display: block;
    -webkit-animation: fadeIn 1s;
    animation: fadeIn 1s;
}

更新2019-该方法还支持淡出:

(需要一些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>


3
谢谢你 height: 0上面提到的技巧(用于过渡)似乎不起作用,因为在淡出过渡中将高度设置为0,但此技巧似乎很好。
艾略特·温克勒

41
谢谢,非常有用。但是如何淡出呢?
Illiou 2012年

1
这个答案的第一段不太有意义。浏览器不仅会在您使用该display属性时立即完全禁用所有过渡-确实没有理由这么做。即使他们做到了,为什么动画也可以工作呢?您也不能display在CSS动画中使用该属性。
BoltClock

7
最佳答案,无法通过过渡实现,但可以通过动画实现。
Mikel

6
逆向动画怎么样,那是元素应该慢慢消失的时候?
绿色

77

我怀疑,如果更改了过渡,则禁用过渡的原因display是实际的显示。它并没有改变任何东西,可以令人信服地平滑的动态。

display: none;visibility: hidden;完全不同的两件事。
双方确实有将这个元素隐形的效果,但visibility: hidden;它在布局仍然呈现,但只是不可见如此。
隐藏的元素仍会占用空间,并且仍以内联或作为块,块内联或表或任何display元素指示其呈现为的内容呈现,并相应地占用空间。
其他元素不会自动移动以占据该空间。隐藏元素只是不将其实际像素渲染到输出中。

display: none另一方面实际上阻止元素完全渲染。
它不占用任何布局空间。
现在,本来会占用该元素所占用的部分或全部空间的其他元素也会进行调整,以占据该空间,就好像该元素根本不存在

display不只是另一个视觉属性
它建立了元素的整个渲染模式,比如它是否是一个blockinlineinline-blocktabletable-rowtable-celllist-item,或什么!
每一个都有不同的布局效果,并且没有合理的方法来动画化或平滑地过渡它们(例如,尝试从blockinline或反之亦然的平滑过渡!)。

这就是为什么如果显示发生更改,过渡将被禁用的原因(即使更改是向/或从none- 更改none,这不仅是不可见的,而是其自身的元素渲染模式,这意味着根本不会渲染!)。


8
尽管上面的解决方案可能很好,但对于过渡为何不适用于显示属性的原因得到了明智的解释,这非常令人满意。
kqr 2014年

8
我不同意。完全有道理。如果在转换开始时立即发生display:none to display:block,那将是很好的。对于过渡,如果在过渡结束时从display:block切换到display:none,那将是完美的。
Curtis Yallop 2015年

2
如果您无法想象从点到矩形的动画是什么样子,那么您就遇到了问题。从不占用空间到占用矩形空间的过渡非常明显,例如,每次像使用每个应用程序一样,每次用鼠标将矩形拖出时都执行此操作。由于此失败,有太多涉及最大高度和负边距的骇客,这太荒谬了。唯一有效的方法是缓存“实际”高度,然后使用JavaScript从零动画到缓存的值。伤心。
Triynko

2
Tryniko:display:none不会将元素的大小更改为0 x 0的矩形-它将其从DOM中删除。您可以通过将width和height属性设置为零,从而将一个矩形动画化为一个点,然后其他元素将围绕它流动,就好像它具有“ display:none”,但其“ display”属性将保持“ block”一样;元素仍在DOM中。在display:block和display:none之间设置动画的概念很荒谬:没有中间状态。元素存在于DOM中或不存在,无论元素有多小或不可见。
史蒂夫·索普

1
对离散属性进行动画处理并非荒谬。离散属性display不能像其他属性一样平滑过渡,但这并不意味着时间不重要。能够控制从过渡disply:blockdisplay:none的情况是非常重要的。就像@CurtisYallop所描述的那样。如果我想从过渡opacity:1opacity:0随后的变化display:block,以display:none我应该能够做到这一点。
詹斯

55

代替CSS中不存在的回调,我们可以使用transition-delayproperty。

#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;
}

那么,这是怎么回事?

  1. visible类被添加,既heightopacity无延迟启动动画(0毫秒),尽管height需要0ms到完整的动画(当量display: block)和opacity花费600毫秒。

  2. visible类被移除时,opacity开始动画(0毫秒延迟,400毫秒持续时间),以及高度400等待毫秒和仅然后立即(0毫秒)恢复初始值(相当于display: none在动画回调)。

请注意,这种方法比使用的方法更好visibility。在这种情况下,元素仍然占据页面上的空间,并且并不总是适合。

有关更多示例,请参阅本文


8
感到惊讶的是,它没有更多的支持-这个聪明的解决方案以某种方式完美地起作用。
大张旗鼓'18

3
它只能与height:100%在某些情况下可能破坏布局的作品一起使用。很好的解决方案,如果那不是问题。少数双向工作之一。
Fabian von Ellerts

这很棒!在我的情况下,我能够进一步简化它,因为我希望淡出动画时间与淡入时间相同。而不是使用transition: height 0ms 0ms, opacity 600ms 0ms,我只是使用transition-delay: 0s
雅各布·洛克德

52

display 不是过渡所依据的属性之一。

有关可以应用过渡的CSS属性列表,请参见Animatable CSS属性。请参阅CSS值和单位模块级别4,组合值:插值,加法和累加,以了解如何进行插值。

9.1中最多列出了CSS 3 CSS中的属性(仅关闭警告弹出窗口)

我也尝试过使用高度,但是不幸地失败了。

上次我必须这样做时,我max-height改用了这是一个可动画处理的属性(虽然有点hack,但它确实起作用了),但请注意,对于复杂的页面或使用低端移动设备的用户而言,它可能会显得非常笨拙设备。


该链接不再直接指向可设置动画的属性部分。
林安德(Andrew Lam)

1
@AndrewLam固定。谢谢。
robocat

34

您现在可以将自定义动画添加到block属性。

@keyframes showNav {
  from {opacity: 0;}
  to {opacity: 1;}
}
.subnav-is-opened .main-nav__secondary-nav {
  display: block;
  animation: showNav 250ms ease-in-out both;
}

演示版

在此演示中,子菜单从display:none变为display:block,但仍设法消失。


应该myfirstshowNav这里吗?那Firefox呢?不幸的是,我在您提到的演示页面上找不到相关的内容。
塞巴斯蒂安·沃姆(MessevérMeer)2014年

谢谢@SebastianG。我已经进行了更正,并在上面添加了更多信息。
Manish Pradhan

@Sebastian vom Meer:较旧的Firefox版本需要使用“ -moz-”供应商前缀,请参见编辑后的代码
Herr_Schwabullek 2015年

23
除非我缺少某些内容,否则“演示”链接将不再显示子菜单转换。
现实的

1
对于不占用空间的对象(例如显示:无)到占空间的对象(显示:块)的正确过渡是尺寸的扩展,而不是淡入。如果将可见性问题隐藏(占用空间但不可见)到可见,则大小保持不变,并且适合淡入。这些答案都不能解决问题。
Triynko

21

根据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:

    var foo = document.getElementById('foo');
    
    document.getElementById('hide-button').onclick = function () {
        foo.className = 'hidden';
    };
    
    document.getElementById('show-button').onclick = function () {
        foo.className = '';
    };

请注意,如果仅使链接透明,而不进行设置 visibility: hidden,则它将保持可单击状态。


1
我在jsfiddle示例中根本看不到任何过渡
Gino

@Gino我通过更改0为来修复它0s。显然,过去我用于测试的浏览器支持无单位零次数。但是,无单位时间属于2016年9月29日发布W3C候选建议书的一部分。
feklee '16

应该对此进行更多投票。我发现它是最好的解决方案之一。
亚瑟·塔拉索夫

延迟的使用只是了解其工作原理的最佳逻辑。设置动画并隐藏。取消隐藏并设置动画。对我来说是完美的解决方案
Bruno PitteliGonçalves18年

14

编辑:在此示例中,不显示任何内容。

@keyframes hide {
  0% {
    display: block;
    opacity: 1;
  }
  99% {
    display: block;
  }
  100% {
    display: none;
    opacity: 0;
  }
}

上面发生的是,在不透明度逐渐消失的情况下,通过99%的动画显示被设置为阻止。最后一刻,display属性设置为none。

最重要的一点是使用animation-fill-mode保留动画结束后的最后一帧:

.hide {
   animation: hide 1s linear;
   animation-fill-mode: forwards;
}

这是两个示例:https : //jsfiddle.net/qwnz9tqg/3/


这个解决方案display: none行不通吗?
Bart Calixto

应该是“动画填充模式:转发”而不是“转发”
Alex

编辑必须是六个字符,我只能建议编辑,因此要发表评论
Alex

1
@Alex Ok。错字固定。有趣的是,我的答案甚至没有按预期工作,但是逻辑上认为这样做会合乎逻辑,因此我会一直保留它,直到浏览器支持它为止。
Pawel

3
正如您在设置游标的小提琴中看到的那样display: none,实际上从未实现过。jsfiddle.net/3e6sduqh
robstarbuck

13

我的JavaScript巧妙技巧是将整个场景分为两个不同的功能

为了准备事情,声明了一个全局变量并定义了一个事件处理程序:

  var tTimeout;
  element.addEventListener("transitionend", afterTransition, true);//firefox
  element.addEventListener("webkitTransitionEnd", afterTransition, true);//chrome

然后,当隐藏元素时,我使用如下代码:

function hide(){
  element.style.opacity = 0;
}

function afterTransition(){
  element.style.display = 'none';
}

为了重新显示该元素,我正在执行以下操作:

function show(){
  element.style.display = 'block';
  tTimeout = setTimeout(timeoutShow, 100);
}

function timeoutShow(){
  element.style.opacity = 1;
}

到目前为止,一切正常!


这确实有效是因为有时间延迟,而不是因为javascript命令位于单独的函数中。在许多情况下,时间延迟似乎是一个不错的解决方案:)

10

我今天遇到了这种情况,并使用了position: fixed我正在重用的模式。我不能保留它display: none,然后对其进行动画处理,因为它刚刚出现在外观上,并且z-index(和负值等)也做得很奇怪。

我也使用了height: 0to height: 100%,但仅在出现模态时有效。这与您使用过的left: -100%东西相同。

然后令我惊讶的是,有一个简单的答案。瞧!

首先,您的隐藏模式。注意heightis 0,并检查height过渡中的声明...它有一个a 500ms比我的opacitytransition 更长。请记住,这会影响向外的淡出过渡:将模态恢复为其默认状态。

#modal-overlay {
    background: #999;
    background: rgba(33,33,33,.2);
    display: block;
    overflow: hidden;
    height: 0;
    width: 100%;
    position: fixed;
    top: 0;
    left: 0;
    opacity: 0;
    z-index: 1;
    -webkit-transition: height 0s 500ms, opacity 300ms ease-in-out;
       -moz-transition: height 0s 500ms, opacity 300ms ease-in-out;
            -ms-transition: height 0s 500ms, opacity 300ms ease-in-out;
         -o-transition: height 0s 500ms, opacity 300ms ease-in-out;
        transition: height 0s 500ms, opacity 300ms ease-in-out;
}

其次,您的可见模态。假设您将设置.modal-activebody。现在height100%,我的转换也已更改。我希望height立即更改,并opacity接受300ms

.modal-active #modal-overlay {
    height: 100%;
    opacity: 1;
    z-index: 90000;
    -webkit-transition: height 0s, opacity 300ms ease-in-out;
       -moz-transition: height 0s, opacity 300ms ease-in-out;
        -ms-transition: height 0s, opacity 300ms ease-in-out;
         -o-transition: height 0s, opacity 300ms ease-in-out;
            transition: height 0s, opacity 300ms ease-in-out;
}

就是这样,它就像一种魅力。


Upvoting您对准厂商前缀属性👍的风格
乔治·格林

9

从这些答案中的一些以及其他建议中,以下内容非常适合悬停菜单(特别是我将其与Bootstrap  3结合使用):

nav .dropdown-menu {
    display: block;
    overflow: hidden;
    max-height: 0;
    opacity: 0;
    transition: max-height 500ms, opacity 300ms;
    -webkit-transition: max-height 500ms, opacity 300ms;
}
nav .dropdown:hover .dropdown-menu {
    max-height: 500px;
    opacity: 1;
    transition: max-height 0, opacity 300ms;
    -webkit-transition: max-height 0, opacity 300ms;
}

如果您同时指定了两个值heightmax-height则也可以使用,因为s height:auto不允许使用transition。的悬浮值max-height需要大于height菜单的可能。


2
这是一个很好的技巧,但有一个缺点。过渡时间取决于高度。如果有多个具有可变高度的菜单,那么高度接近max-height的那些元素将具有很好的动画效果。但是,较短的动画会设置得太快,从而产生不一致的体验。
用户

8

我找到了解决此问题的更好方法,您可以使用CSS动画,并使显示效果很棒。

    .item {
     display: none;
}

.item:hover {
     display: block;
     animation: fade_in_show 0.5s
}

@keyframes fade_in_show {
     0% {
          opacity: 0;
          transform: scale(0)
     }
     100% {
          opacity: 1;
          transform: scale(1)
     }
}

感谢您提供的有用提示,效果很好。
Sedat Kumcu

6

我已经多次遇到这个问题,现在简单地讲:

.block {
  opacity: 1;
  transition: opacity 250ms ease;
}

.block--invisible {
  pointer-events: none;
  opacity: 0;
}

通过添加该类block--invisible,整个Elements将不可单击,但是其后面的所有Elements都将因为pointer-events:none所有主要浏览器都支持(所有IE <11)。


你能举一个例子吗?
GarethAS'9

1
这很好用,但应注意,指针事件不适用于11以下的IE
user1702965

在11以下的IE中添加了注释
DominikAngerer

如果您需要在所有内容(例如菜单)上都说一遍元素,那么坦白地说,这是最干净的方法,因为2019年的支持很可靠pointer-events
Josh Davenport

5

更改overflow:hiddenoverflow:visible。效果更好。我这样使用:

#menu ul li ul {
    background-color:#fe1c1c;
    width:85px;
    height:0px;
    opacity:0;
    box-shadow:1px 3px 10px #000000;
    border-radius:3px;
    z-index:1;
    -webkit-transition:all 0.5s ease;
    -moz-transition:all 0.6s ease;
}

#menu ul li:hover ul  {
    overflow:visible;
    opacity:1;
    height:140px;
}

visible更好,因为overflow:hidden行为完全像个display:none


这一张是我的票。谢谢!
Dan Loewenherz

5

不需要JavaScript,也不需要极大的最大高度。而是max-height在文本元素上设置您的字体,并使用字体相对单位,例如remem。这样,您可以将最大高度设置为大于容器的高度,同时避免菜单关闭时的延迟或“弹出”:

的HTML

<nav>
  <input type="checkbox" />
  <ul>
    <li>Link 1</li>
    <li>Link 1</li>
    <li>Link 1</li>
    <li>Link 1</li>
  </ul>
</nav>

的CSS

nav input + ul li { // Notice I set max-height on li, not ul
   max-height: 0;
}

nav input:checked + ul li {
   max-height: 3rem; // A little bigger to allow for text-wrapping - but not outrageous
}

在此处查看示例:http : //codepen.io/mindfullsilence/pen/DtzjE


与此类似,您可以在文本上设置行高并将其转换为零。如果里面只有文本,这将隐藏容器。
vicmortelmans 2014年

为什么选票这么少?这是一个很好的答案,可能是我使用的答案。
mwilcox

@mwilcox因为它使用固定的高度,所以在处理动态内容时(这是估计的高度)甚至是不好的。而且仅在文本内容上有用。
Fabian von Ellerts

5

在写完Guillermo的可接受答案之后,2012-04-03的CSS过渡规范更改了可见性过渡的行为,现在可以以更短的方式解决此问题,而无需使用transition-delay:

.myclass > div {
                   transition:visibility 1s, opacity 1s;
                   visibility:hidden;  opacity:0
               }
.myclass:hover > div
               {   visibility:visible; opacity:1 }

为两个转换指定的运行时间通常应该是相同的(尽管可见性的时间稍长一点也不成问题)。

对于运行版本,请参阅我的博客文章CSS Transition Visibility

写下问题“显示的过渡:属性”的标题,并回应Rui Marques和josh对已接受答案的评论:

如果使用display或visible属性是不相关的,则此解决方案适用(如在此问题中可能的情况)。

它不会像那样完全删除元素display:none,只是使其不可见,但仍停留在文档流中并影响后续元素的位置。

完全删除类似于元素的过渡display:none可以使用高度(如其他答案和注释所示),max-height或margin-top / bottom来完成,另请参见 如何过渡height:0; 达到高度:自动;使用CSS?和我的博客文章Display and Height属性上CSS过渡解决方法

回应GeorgeMillo的评论:需要两个属性和两个过渡:不透明度属性用于创建淡入和淡出动画以及可见性属性,以避免元素仍然对鼠标事件做出反应。需要对不透明性进行过渡以实现视觉效果,并需要对可见性进行过渡以延迟隐藏,直到淡出完成为止。


4

我终于找到了解决方案,方法是opacity与结合使用position absolute(隐藏时不占用空间)。

.toggle {
  opacity: 0;
  position: absolute;
  transition: opacity 0.8s;
}

.parent:hover .toggle {
  opacity: 1;
  position: static;
}

4

我怀疑只是开始CSS转换的任何人都会很快发现,如果您同时修改display属性(block / none),它们将不起作用。尚未提到的一种解决方法是,您可以继续使用它display:block/none来隐藏/显示元素,但是可以将其不透明度设置为0,这样即使它是display:block,它仍然是不可见的。

然后淡入,添加另一个CSS类,例如“ on”,将不透明度设置为1并定义不透明度的过渡。就像您想象的那样,您将不得不使用JavaScript将“ on”类添加到元素中,但是至少您仍在使用CSS进行实际的过渡。

PS:如果您发现自己需要同时做这两项display:block,并同时添加“ on”类,请使用setTimeout推迟后者。否则,浏览器只会同时看到这两种情况并禁用过渡。


太好了,谢谢!我写了另一个答案,并给出了一个实际适用的示例display:none
mojuba

4

它很简单,如下所示:)

@keyframes fadeout {
    0% { opacity: 1; height: auto; }
    90% { opacity: 0; height: auto; }
    100% { opacity: 0; height: 0;
}
animation: fadeout linear 0.5s 1 normal forwards !important;

使它渐渐消失,然后再制造height 0;。另外,请确保使用转发,使其保持最终状态。


这将在删除班级时立即重置,所以这不是一个好主意
Sean T

2

该解决方案具有出色的兼容性,但我还没有看到它:

.hidden-element {
  position: absolute;
  z-index: -1;
  pointer-events: none;
  visibility: hidden;
  opacity: 0;
  transition: visibility 0s, opacity .5s ease-out;
}

.hidden-element.visible {
  position: static;
  z-index: auto;
  pointer-events: auto;
  visibility: visible;
  opacity: 1;
}

说明:它使用了visibility: hidden技巧(与“显示并动画”一步式兼容),但是它使用了组合position: absolute; z-index: -1; pointer-events: none;来确保隐藏的容器不会占用空间并且不会对用户交互做出响应


1
但是,改变position仍然会令元素变混蛋,不是吗?
Arsylum

好吧,偏离路线:position: absolute表示该元素不占用任何空间,如说明中所述。当它切换到position: static并显示时,它将像普通元素一样占用空间,这是此问题的重点。我建议你试试看!
Christophe Marois,

2
是的 但是,如果我理解正确,那么问题就在于过渡。如“平滑动画”。
Arsylum

2

您可以使用显示功能使它按预期的自然方式工作-但您必须使用Javascript或其他人提出的在另一个标签中包含一个标签的巧妙技巧,以限制浏览器使其正常工作。我不在乎内部标签,因为它会使CSS和尺寸进一步复杂化,因此这是Javascript解决方案:

https://jsfiddle.net/b9chris/hweyecu4/17/

从类似以下的框开始:

<div id="box" class="hidden">Lorem</div>

一个隐藏的盒子。

div.hidden {
    display: none;
}
#box {
    transition: opacity 1s;
}

我们将使用相关q / a中的技巧,检查offsetHeight即时限制浏览器:

https://stackoverflow.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/hweyecu4/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的工作原理,但足以说明,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/hweyecu4/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 ms,然后通过添加的类开始过渡,我们使它出现,然后按需要扩展,而不是只是在没有任何动画的情况下跳到屏幕上。换一种方式发生类似的情况,除了我们等到动画结束之前再应用隐藏。

注意:我在.animate(maxWidth)这里是为了避免setTimeout比赛条件。setTimeout当您或其他人不知道它的代码而很快引入隐藏的错误时。.animate()容易被杀死.stop()。我只是用它在标准fx队列上放置50毫秒或2000毫秒的延迟,在此之上,其他基于此的编码人员可以轻松找到/解决这些延迟。


1

我有一个类似的问题,找不到答案。后来,一些Google搜索将我引到了这里。考虑到我没有找到我想要的简单答案,我偶然发现了既优雅又有效的解决方案。

事实证明visibilityCSS属性具有一个collapse通常用于表项的值。但是,如果在其他任何元素上使用它,则可以有效地将它们呈现为隐藏,几乎display: hidden与元素相同,但具有增加的功能:该元素不占用任何空间,并且您仍可以为该元素设置动画。

以下是此操作的一个简单示例。

function toggleVisibility() {
  let exampleElement = document.querySelector('span');
  if (exampleElement.classList.contains('visible')) {
    return;
  }
  exampleElement.innerHTML = 'I will not take up space!';
  exampleElement.classList.toggle('hidden');
  exampleElement.classList.toggle('visible');
  setTimeout(() => {
    exampleElement.classList.toggle('visible');
    exampleElement.classList.toggle('hidden');
  }, 3000);
}
#main {
  display: flex;
  flex-direction: column;
  width: 300px;
  text-align: center;
}

.hidden {
  visibility: collapse;
  opacity: 0;
  transition: visibility 2s, opacity 2s linear;
}

.visible {
  visibility: visible;
  opacity: 1;
  transition: visibility 0.5s, opacity 0.5s linear;
}
<div id="main">
  <button onclick="toggleVisibility()">Click Me!</button>
  <span class="hidden"></span>
  <span>I will get pushed back up...</span>
</div>


1

这个问题最简单的通用解决方案是:随意display:none在CSS中进行指定,但是您将block使用JavaScript 将其更改为(或其他任何形式),然后还必须将一个类添加到有问题的元素中用setTimeout()进行过渡。就这样。

即:

<style>
    #el {
        display: none;
        opacity: 0;
    }
    #el.auto-fade-in {
        opacity: 1;
        transition: all 1s ease-out; /* Future, future, please come sooner! */
        -webkit-transition: all 1s ease-out;
        -moz-transition: all 1s ease-out;
        -o-transition: all 1s ease-out;
    }
</style>

<div id=el>Well, well, well</div>

<script>
    var el = document.getElementById('el');
    el.style.display = 'block';
    setTimeout(function () { el.className = 'auto-fade-in' }, 0);
</script>

已在最新的正常浏览器中进行了测试。显然,它不应在Internet Explorer 9或更早版本中运行。


1

我认为SalmanPK最接近答案。它会使用以下CSS动画来淡入或淡出项目。但是,显示属性不能平滑地动画,只有不透明动画。

@-webkit-keyframes fadeIn {
    from { opacity: 0; }
      to { opacity: 1; }
}

@-webkit-keyframes fadeOut {
    from { opacity: 1; }
      to { opacity: 0; }
}

如果要对从显示块移动到不显示的元素进行动画处理,我看不到仅使用CSS就可以实现。您必须获取高度并使用CSS动画来降低高度。如下面的示例所示,使用CSS可以做到这一点,但是要知道需要为元素设置动画的确切高度值将非常棘手。

jsFiddle 示例

的CSS

@-webkit-keyframes pushDown {
  0% {
    height: 10em;
  }
  25% {
    height: 7.5em;
  }
  50% {
    height: 5em;
  }
  75% {
    height: 2.5em;
  }
  100% {
    height: 0em;
  }
}

.push-down {
    -webkit-animation: pushDown 2s forwards linear;
}

的JavaScript

var element = document.getElementById("element");

// Push item down
element.className = element.className + " push-down";

1

您可以使用过渡事件来执行此操作,因此您可以为过渡构建两个CSS类,一个CSS类容纳动画,另一个不显示display状态。并且在动画结束后切换它们吗?就我而言,如果我按下一个按钮,可以再次显示div,然后删除两个类。

尝试下面的代码段...

$(document).ready(function() {
  // Assign transition event
  $("table").on("animationend webkitAnimationEnd", ".visibility_switch_off", function(event) {
    // We check if this is the same animation we want
    if (event.originalEvent.animationName == "col_hide_anim") {
      // After the animation we assign this new class that basically hides the elements.
      $(this).addClass("animation-helper-display-none");
    }

  });

  $("button").click(function(event) {

    $("table tr .hide-col").toggleClass(function() {
      // We switch the animation class in a toggle fashion...
      // and we know in that after the animation end, there
      // is will the animation-helper-display-none extra
      // class, that we nee to remove, when we want to
      // show the elements again, depending on the toggle
      // state, so we create a relation between them.
      if ($(this).is(".animation-helper-display-none")) {
        // I'm toggling and there is already the above class, then
        // what we want it to show the elements , so we remove
        // both classes...
        return "visibility_switch_off animation-helper-display-none";
      }
      else {
        // Here we just want to hide the elements, so we just
        // add the animation class, the other will be added
        // later be the animationend event...
        return "visibility_switch_off";
      }
    });
  });
});
table th {
  background-color: grey;
}

table td {
  background-color: white;
  padding: 5px;
}

.animation-helper-display-none {
  display: none;
}

table tr .visibility_switch_off {
  animation-fill-mode: forwards;
  animation-name: col_hide_anim;
  animation-duration: 1s;
}

@-webkit-keyframes col_hide_anim {
  0% {opacity: 1;}
  100% {opacity: 0;}
}

@-moz-keyframes col_hide_anim {
  0% {opacity: 1;}
  100% {opacity: 0;}
}

@-o-keyframes col_hide_anim {
  0% {opacity: 1;}
  100% {opacity: 0;}
}

@keyframes col_hide_anim {
  0%   {opacity: 1;}
  100% {opacity: 0;}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
  <theader>
    <tr>
      <th>Name</th>
      <th class='hide-col'>Age</th>
      <th>Country</th>
    </tr>
  </theader>
  <tbody>
    <tr>
      <td>Name</td>
      <td class='hide-col'>Age</td>
      <td>Country</td>
    </tr>
  </tbody>
</table>

<button>Switch - Hide Age column with fadeout animation and display none after</button>


0

如果您使用jQuery设置类,则可以100%使用:

$(document).ready(function() {
  $('button').click(function() {
    var container = $('.container');
    
    if (!container.hasClass('active')) {
      container.addClass('show').outerWidth();
      container.addClass('active');
    }
    else {
      container.removeClass('active').one('transitionend', function() {
        container.removeClass('show');
      });
    }
  });
});
.container {
  display: none;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.container.show {
  display: flex;
}
 
.container.active {
  opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button type="button">Toggle</button>

<div class="container">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>

当然,你可以只使用jQuery .fadeIn().fadeOut()功能,但设置类,而不是优势是要过渡到比其他的显示值的情况下block(如与默认的.fadeIn().fadeOut())。

在这里,我过渡到flex具有不错的淡入淡出效果的显示。


0

除了使用display元素外,您还可以将其存储在“屏幕外”元素中,直到需要它为止,然后将其位置设置为所需的位置并同时进行变换。但是,这带来了很多其他设计问题,因此您的工作量可能会有所不同。

display无论如何,您可能都不想使用,因为您希望屏幕阅读器可以访问该内容,这在大多数情况下都应遵守可见性规则-即,如果眼睛不可见,它会不会显示为代理的内容。


0

您可以简单地使用CSS 可见性:隐藏/可见而不是显示:none / block

div {
    visibility:hidden;
    -webkit-transition: opacity 1s ease-out;
    -moz-transition: opacity 1s ease-out;
    -o-transition: opacity 1s ease-out;
    transition: opacity 1s ease-out;
    opacity: 0;
}

parent:hover > div {
    opacity: 1;
    visibility: visible;
}

5
但这保留了空间,留下了一个空洞。如果要折叠空间,则必须设置高度或其他属性的动画。
Marcy Sutton 2013年

0

我启动了一个名为Toggle Display Animate的开源框架项目。

该骨架帮助器将使您可以轻松模仿jQuery的显示/隐藏,但具有CSS 3过渡动画。

它使用类切换,因此除了display:none | block | table | inline等之外,您还可以对元素使用任何CSS方法,以及可以想到的其他替代用法。

其主要设计目的是用于元素切换状态,并且它支持还原状态,在该状态下,隐藏对象可让您反向运行关键帧或播放替代动画以隐藏元素。

我正在研究的概念的大多数标记是CSS,实际上很少使用JavaScript。

这里有一个演示:http : //marcnewton.co.uk/projects/toggle-display-animate/

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.