如何过渡CSS的display和opacity属性

138

我遇到了一个关于CSS3动画的问题。

.child {
    opacity: 0;
    display: none;

    -webkit-transition: opacity 0.5s ease-in-out;
    -moz-transition: opacity 0.5s ease-in-out;
    transition: opacity 0.5s ease-in-out;
}

.parent:hover .child {
    opacity: 0.9;
    display: block;
}

如果我删除对display的更改,此代码才能正常工作。

我想在悬停后更改显示方式,但透明度应使用转换进行更改。


2
如果CSS不像其他人建议的那样起作用,这里有一个非常简单的Javascript代码可以实现淡入淡出效果。 - Abhranil Das
3
没有人提到过animation-fill-mode: forwards;。因此,在这种情况下,透明度动画运行后,display会恢复为none。使用这个CSS设置可以保持动画的最后状态,所以它是display: block - Matthew
16个回答

160

根据Michael的答案,这是应该使用的实际CSS代码

.parent:hover .child
{
    display: block;

    -webkit-animation: fadeInFromNone 0.5s ease-out;
    -moz-animation: fadeInFromNone 0.5s ease-out;
    -o-animation: fadeInFromNone 0.5s ease-out;
    animation: fadeInFromNone 0.5s ease-out;
}

@-webkit-keyframes fadeInFromNone {
    0% {
        display: none;
        opacity: 0;
    }

    1% {
        display: block;
        opacity: 0;
    }

    100% {
        display: block;
        opacity: 1;
    }
}

@-moz-keyframes fadeInFromNone {
    0% {
        display: none;
        opacity: 0;
    }

    1% {
        display: block;
        opacity: 0;
    }

    100% {
        display: block;
        opacity: 1;
    }
}

@-o-keyframes fadeInFromNone {
    0% {
        display: none;
        opacity: 0;
    }

    1% {
        display: block;
        opacity: 0;
    }

    100% {
        display: block;
        opacity: 1;
    }
}

@keyframes fadeInFromNone {
    0% {
        display: none;
        opacity: 0;
    }

    1% {
        display: block;
        opacity: 0;
    }

    100% {
        display: block;
        opacity: 1;
    }
}

22
当鼠标移开时,如何实现淡出到无? - Green
5
可以使用百分之几分之一的数值,比如0.001%,而不是1%,这样可以减少"开始"的延迟,特别是在较长的动画持续时间下更加明显。请注意,不要改变原本的意思。 - Zach Saucier
2
“-o-keyframes”指令实际上是无用的,因为第一个支持动画的Opera版本已经基于webkit。 - Rico Ocepek
@RicoOcepek 在 Opera Mini Beta 上进行了测试,它可以在没有“-o-”的情况下正常工作。谢谢! - keanu_reeves
1
截至2022年,浏览器前缀(-webkit-, -o-, 和 -moz-)已经变得相当无用了,因为自2015年以来,浏览器已经支持无需前缀的关键帧动画了。 https://caniuse.com/mdn-css_at-rules_keyframes - Alexis Delrieu

63
如果可能 - 使用visibility而非display
例如:
.child {
    visibility: hidden;
    opacity: 0;
    transition: opacity 0.3s, visibility 0.3s;
}

.parent:hover .child {
    visibility: visible;
    opacity: 1;
    transition: opacity 0.3s, visibility 0.3s;
}

29
visibility属性的问题在于它并没有隐藏元素,只是让元素变得不可见。因此,该元素仍会占用空间。 - Samuel
9
不仅是隐形的,而且对事件(例如点击等)也是透明的。不改变显示意味着不会重新排版文档,这是一件好事。大多数应该通过不透明度淡入/淡出的元素可能都应该具有固定或绝对位置。 - Rasmus Kaj
你可以使用 visibility: collapse; 让元素不占用空间。这自然也会使其无法被点击。 - Kaligule

44

你可以使用CSS动画实现:

0% display:none ; opacity: 0;
1% display: block ; opacity: 0;
100% display: block ; opacity: 1;

好主意,我成功地在悬停期间使用animation-fill-mode保持了元素的显示,但是当我移开鼠标时,元素消失了。 - Alexis Delrieu
3
你可以使用fill-mode: forwards来保持动画完成后的更改。 - Michael Mullany

20

我用这个来实现它。当鼠标悬停时,它们会淡出,但隐藏时不占用空间,非常完美!

.child {
    height: 0px;
    opacity: 0;
    visibility: hidden;
    transition: all .5s ease-in-out;
}

.parent:hover .child {
    height: auto;
    opacity: 1;
    visibility: visible;
}

18

这种解决方法是有效的:

  1. 定义一个“关键帧”:

    @-webkit-keyframes fadeIn { 
      0% { opacity: 0; }
      20% { opacity: 0; }
      40% { opacity: 0.3; }
      60% { opacity: 0.5; }
      80% { opacity: 0.9; }
      100% { opacity: 1; }
    }
    
    @keyframes fadeIn {
      0% { opacity: 0; }
      20% { opacity: 0; }
      40% { opacity: 0.3; }
      60% { opacity: 0.5; }
      80% { opacity: 0.9; }
      100% { opacity: 1; }
    }
    
  2. 在“悬停”时使用此“关键帧”:

  3. div a span { 
      display: none;
    }
    
    div a:hover span {
      display: block;
    
      -webkit-animation-name: fadeIn;
      -webkit-animation-duration: 1s;
      animation-name: fadeIn;
      animation-duration: 1s;
    }
    

你可以简单地使用 0% { opacity: 0; } 100% { opacity: 1; } 来定义关键帧。 - doublejosh

6

我稍作修改,但结果非常美观。

.child {
    width: 0px;
    height: 0px;
    opacity: 0;
}

.parent:hover child {
    width: 150px;
    height: 300px;
    opacity: .9;
}

感谢大家。

6
这与屏幕阅读器不兼容:它们会继续读取内容。 - ehdv
1
你可以在.child中添加visibility: hidden; / 在悬停时添加visibility: visible;,这样可以解决屏幕阅读器的问题。 - csilk

6

使用指针事件(pointer-events)也是另一种很好实现此功能的方法:

.child {
    opacity: 0;
    pointer-events: none;

    -webkit-transition: opacity 0.5s ease-in-out;
    -moz-transition: opacity 0.5s ease-in-out;
    transition: opacity 0.5s ease-in-out;
}

.parent:hover .child {
    opacity: 0.9;
    pointer-events: all;
}

很遗憾,在IE10及以下版本中不支持该功能。


4

我曾经遇到同样的问题。尝试使用动画代替过渡 - 正如@MichaelMullany和@Chris所建议的那样 - 但即使我复制并粘贴了“-moz”和“-o”前缀,它也只在webkit浏览器中起作用。

我通过使用visibility而不是display来解决了这个问题。对我而言,这有效,因为我的子元素是position: absolute,所以文档流没有受到影响。这也可能适用于其他人。

这是使用我的解决方案的原始代码:

.child {
    position: absolute;
    opacity: 0;
    visibility: hidden;

    -webkit-transition: opacity 0.5s ease-in-out;
    -moz-transition: opacity 0.5s ease-in-out;
    transition: opacity 0.5s ease-in-out;
}

.parent:hover .child {
    position: relative;
    opacity: 0.9;
    visibility: visible;
}

如果在子元素动画消失时将鼠标悬停回去,它会立即弹回来,因为该元素仅被隐藏。如果你在页面上移动鼠标,这会非常烦人。 - adamj

3
为了在鼠标悬停时实现双向动画,我采用了以下解决方案。希望对某些人有所帮助。
@keyframes fadeOutFromBlock {
  0% {
    position: relative;
    opacity: 1;
    transform: translateX(0);
  }

  90% {
    position: relative;
    opacity: 0;
    transform: translateX(0);
  }

  100% {
    position: absolute;
    opacity: 0;
    transform: translateX(-999px);
  }
}

@keyframes fadeInFromNone {
  0% {
    position: absolute;
    opacity: 0;
    transform: translateX(-999px);
  }

  1% {
    position: relative;
    opacity: 0;
    transform: translateX(0);
  }

  100% {
    position: relative;
    opacity: 1;
    transform: translateX(0);
  }
}

.drafts-content {
  position: relative;
  opacity: 1;
  transform: translateX(0);
  animation: fadeInFromNone 1s ease-in;
  will-change: opacity, transform;

  &.hide-drafts {
    position: absolute;
    opacity: 0;
    transform: translateX(-999px);
    animation: fadeOutFromBlock 0.5s ease-out;
    will-change: opacity, transform;
  }
}

2

我知道,这并不是你问题的真正解决方案,因为你要求

显示 + 不透明度

我的方法解决了一个更普遍的问题,但也许这是背景问题,需要使用displayopacity相结合来解决。

我的愿望是在元素不可见时将其移开。这个解决方案正好做到了这一点:它将元素移到了一边,可以用于过渡效果:

.child {
  left: -2000px;
  opacity: 0;
  visibility: hidden;
  transition: left 0s 0.8s, visibility 0s 0.8s, opacity 0.8s;
}

.parent:hover .child {
  left: 0;
  opacity: 1;
  visibility: visible;
  transition: left 0s, visibility 0s, opacity 0.8s;
}

这段代码不包含任何浏览器前缀或向后兼容的技巧。它只是说明了元素不再需要时如何移动的概念。

有趣的部分是两个不同的过渡定义。当鼠标指针悬停在.parent元素上时,.child元素需要立即放置,然后更改不透明度:

transition: left 0s, visibility 0s, opacity 0.8s;

当没有悬停时,或者鼠标指针移出元素后,必须等待不透明度变化完成后才能将元素移出屏幕:

transition: left 0s 0.8s, visibility 0s 0.8s, opacity 0.8s;

将对象移开是一种可行的替代方案,当设置display:none会破坏布局时。希望我对这个问题有所启发,尽管我没有回答它。

自IE9以来,Microsoft过滤器已被弃用。你觉得在2016年将其添加到答案中有什么特别的原因吗? - TylerH
@TylerH 一个人愿意接触多少用户是个人口味问题。 - Hannes Morgenstern
考虑到它已经被弃用,而且微软不再支持IE<11,因此在最好的情况下使用该属性是值得怀疑的。 - TylerH
@TylerH 通常需要容纳那些不愿或无法升级到新版浏览器的客户。我有一个知名银行作为客户,他们仍在使用IE6并拒绝升级,原因是“种种”。 - Marcus Cunningham
@MarcusCunningham 这个问题标记有 [tag:css3],这完全排除了使用 IE6(以及 IE7 和 IE8)。在 OP 可能编写代码的最早的浏览器中,此答案中的 MS 滤镜已被弃用。对于未来的读者来说,它甚至更加无用,因为它甚至没有得到支持。在回答这个问题时,没有任何理由包含它。然而,这是一个无关紧要的问题,因为汉内斯已经从他的答案中删除了它。 - TylerH
将父元素的height: 0设置不会确保其子元素始终隐藏,除非它具有overflow: hidden - Amr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接