更改显示属性会使不透明度过渡失效。

3
使用JavaScript来改变一个带有transition: opacity 1s属性的元素的不透明度,你期望这个过渡效果需要一秒钟才能完成,这也确实在这里看到了:

onload = e => {
  var p = document.getElementsByTagName("p")[0];

  p.style.opacity = 1;
};
p {
  opacity: 0;
  transition: opacity 1s;
}
<p>
Lorem ipsum...
</p>

However, if the element has display: none and you first change it to display: initial (in order to see it) before changing the opacity the transition no longer works, which you can see here:

onload = e => {
  var p = document.getElementsByTagName("p")[0];

  p.style.display = "initial";
  p.style.opacity = 1;
};
p {
  display: none;
  opacity: 0;
  transition: opacity 1s;
}
<p>
Lorem ipsum...
</p>

为什么会这样呢?
注意:我没有在display属性上使用过渡,也不是在寻找解决方法。

display: none; 的使用场景是什么?当 opacity 设为零时,元素已经不可见了。 - Randy Casburn
1
我不会再次转换显示属性。 - RaminS
6
我没有对显示属性进行转换。 - RaminS
1
@Gendarme 对啊,是这样的。也许只需将问题中的代码取消片段化处理?如果它实际上无法正常工作,那么没有意义使其可运行。 - Mark Amery
1
@MarkAmery:非常抱歉如果我在这里让事情变得更糟,但“edit”标题也很令人困惑。 - Martijn Pieters
显示剩余10条评论
2个回答

1

tldr:你不能在display属性中使用transition。是的,如果一个元素当前的display属性为none,那么你也不能在该元素的任何其他css属性上使用transition属性。


这个问题最干净的解决办法是同时转换width属性和opacity属性。请查看JSFiddle,了解如何使用widthheight属性来复制display:none属性,以便不让元素在文档流中占用任何空间。 <span>元素仅用于演示当其被隐藏时,<p>标签不占用任何空间。 您还可以在下面的代码段中检查代码,但正如您所提到的,由于某些奇怪的原因,在此处过渡无法工作。

var p = document.getElementsByTagName("p")[0];

p.style.width = "50%";
p.style.height = "auto";
p.style.opacity = 1;
html, body{width: 100%; height: 100%; margin: 0; padding: 0;}
p {
  width: 0;
  height:0;
  opacity: 0;
  transition: width 2s, opacity 3.5s;
  float:left;
  margin: 0;
}
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis culpa nobis dolorem voluptates ut odio numquam officia provident quos labore, natus sint doloribus ducimus similique aspernatur, enim, voluptatibus vel facere!

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima, adipisci? Quidem laboriosam sunt, qui non ea placeat laborum deserunt consequatur consequuntur vel, officiis magnam. Vitae officiis, quidem doloribus nesciunt voluptatem!
</p>
<span>Right side text</span>

但是如果你必须使用display:none,那么如css article所示,你可以使用setTimeout()解决方法,在切换显示属性时不是同时设置过渡属性,而是在显示属性切换之后设置过渡属性,就像这样:

var p = document.getElementsByTagName("p")[0];
p.style.display = "block";

setTimeout(function(){p.style.opacity = 1;},1000);
p {
  display: none;
  opacity: 0;
  transition: opacity 1s;
}
<p>
Lorem ipsum...
</p>


我并不是真的想在display属性中使用transition属性。我只是将元素从文档流中移除,然后在对opacity进行transition之前将它们放回。请参见我的答案。我认为我发现了问题所在。 - RaminS
@Gendarme 使用 setInterval() 也是一个好主意。你可以使用任何一种方法来实现这个。 - AndrewL64
这确实是个不错的技巧。我从未想过那个。如果 setInterval 的间隔时间太长,那么它可能会成为一个问题,因此这似乎是更好的解决方法(如果这正是某人正在寻找的)。 - RaminS
@Gendarme 同意。我正准备编辑这个答案,加入在这篇文章中找到的另一种方法,当我自己刚刚搜索如何使用 display 实现这个效果时。 - AndrewL64
我想选择您的答案作为被采纳的答案,但您并没有真正回答问题。我问的是为什么会发生这种情况,而不是寻找解决方法,而您只是简单地说了“您不能使用transition属性与display属性。”这并没有实际意义。我尝试在我的答案中回答它,但最终只是一个假设。您能否尝试回答一下?否则我将不得不选择自己的答案作为被采纳的答案(即使是由其他人编写的,也可以完美地回答问题)。 - RaminS
3
你也可以接受你自己的答案,伙计。没关系。我会尝试搜索更多关于这个问题的信息,并在找到后更新我的答案。谢谢。 - AndrewL64

1
似乎问题在于转换发生(或试图发生)在显示属性更改过程中(意味着它仍然是“none”,因此转换无法工作)。理论上,转换可以在元素具有“display:none”并且仅在将其更改为“display:initial”的过程完成后才变得可见,因为转换时间为一秒钟,而显示属性的更改只是其中的一部分。但是,这似乎不是事实。可以在更改为“display:initial”之前更改具有“display:none”的元素的不透明度,如您在此处所见,因此显然不是问题:

var p = document.getElementsByTagName("p")[0];
p.style.opacity = 0.3;
p.style.display = "initial";
p {
  display: none;
  opacity: 0;
  transition: opacity 1s;
}
<p>
Lorem ipsum...
</p>

当然,之后也可以更改它,因此这似乎只剩下我们的假设作为唯一可能性。

为了确保在启动转换之前第一个过程已经完成,您可以使用类似这样的短延迟,那么就可以轻松搞定:

var p = document.getElementsByTagName("p")[0];

p.style.display = "initial";
setTimeout(function() {
 p.style.opacity = 1;
},100);
p {
  display: none;
  opacity: 0;
  transition: opacity 1s;
}
<p>
Lorem ipsum...
</p>


1
哇,不要在这里使用 setInterval,你希望它只触发一次。此外,最好触发同步回流,例如仅获取 p.offsetLeft 就可以了,但更好的做法是在每帧之前确保一切准备就绪时仅执行一次,因此最好将其挂钩在一个 rAF 回调中,在下一次绘制之前调用 p.style.display = 'initial'; requestAnimationFrame( _ => { p.offsetLeft; p.style.opacity = '1'; }) - Kaiido

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