You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MDN CSS动画示例中fade-out动画在Firefox与Safari中失效的问题求助

MDN CSS动画示例中fade-out动画在Firefox与Safari中失效的问题求助

大家好,我在复刻MDN「使用CSS动画」章节的最后一个切换显示/隐藏的示例时碰到了兼容性问题,想请各位帮忙看看:

问题现象

  • 淡入(fade-in)动画完全正常:点击空白区域或按任意键,带红边框的div会平滑淡入显示
  • 淡出(fade-out)动画失效:再次触发切换时,div会突然消失,完全看不到0.7秒的过渡效果

测试环境

  • 失效的浏览器:
    • Firefox 139.0.4 → 升级到140.0.0(MacOS Sonoma 14.7.4)后仍失效
    • Safari 18.3.1 (19620.2.4.111.9, 19620)
  • 正常的浏览器:Chrome 138.0.7204.50 (Official Build) (x86_64)

我当前的完整代码

HTML

<p> Click anywhere on the screen or press any key to toggle the <code>&lt;div&gt;</code> between hidden and showing. </p>
<div>
  This is a <code>&lt;div&gt;</code> element that animates between <code>display: none; opacity: 0</code> and <code>display: block; opacity: 1</code>. Neat, huh?
</div>
<p> This is another paragraph to show that <code>display: none;</code> is being applied and removed on the above <code>&lt;div&gt; </code>. If only its <code>opacity</code> was being changed, it would always take up the space in the DOM. </p>

CSS

html { height: 100vh; }

div {
  font-size: 1.6rem;
  padding: 20px;
  border: 3px solid red;
  border-radius: 20px;
  width: 480px;
  opacity: 0;
  display: none;
}

/* Animation classes */
div.fade-in {
  display: block;
  animation: fade-in 0.7s ease-in forwards;
}

div.fade-out {
  animation: fade-out 0.7s ease-out forwards;
}

/* Animation keyframes */
@keyframes fade-in {
  0% { opacity: 0; display: none; }
  100% { opacity: 1; display: block; }
}

@keyframes fade-out {
  0% { opacity: 1; display: block; }
  100% { opacity: 0; display: none; }
}

JavaScript

const divElem = document.querySelector("div");
const htmlElem = document.querySelector(":root");

htmlElem.addEventListener("click", showHide);
document.addEventListener("keydown", showHide);

function showHide() {
  if (divElem.classList[0] === "fade-in") {
    divElem.classList.remove("fade-in");
    divElem.classList.add("fade-out");
  } else {
    divElem.classList.remove("fade-out");
    divElem.classList.add("fade-in");
  }
}

问题根源分析

这个问题的核心在于:display是CSS规范中明确的「不可动画属性」。

Chrome浏览器做了特殊兼容处理,会忽略动画中display的变化,优先执行opacity的过渡;但Firefox和Safari严格遵循规范,当动画关键帧中出现display: none时,浏览器会直接触发这个属性变更,导致整个淡出动画被“跳过”,元素直接消失。

解决方案

我们需要避开在动画中操作display,这里提供两种稳妥的实现方案:


方案1:用visibility替代display控制显示(推荐)

visibility是可动画属性,搭配opacity可以实现视觉隐藏+占位/不占位的效果(若要完全不占位,可配合height、padding等属性的过渡)。

修改后的关键CSS代码:

div {
  font-size: 1.6rem;
  padding: 20px;
  border: 3px solid red;
  border-radius: 20px;
  width: 480px;
  opacity: 0;
  visibility: hidden;
  /* 可选:完全消除占位,添加以下过渡属性 */
  height: 0;
  padding: 0;
  border-width: 0;
  transition: height 0.7s ease-out, padding 0.7s ease-out, border-width 0.7s ease-out;
}

div.fade-in {
  visibility: visible;
  /* 恢复初始占位属性 */
  height: auto;
  padding: 20px;
  border-width: 3px;
  animation: fade-in 0.7s ease-in forwards;
}

/* 动画关键帧仅控制opacity */
@keyframes fade-in {
  0% { opacity: 0; }
  100% { opacity: 1; }
}

@keyframes fade-out {
  0% { opacity: 1; }
  100% { opacity: 0; visibility: hidden; }
}

方案2:用JS监听动画结束事件再设置display: none

保留display属性,但等fade-out动画完全结束后,再通过JS设置display: none,避免打断动画流程:

修改后的JavaScript代码:

function showHide() {
  if (divElem.classList.contains("fade-in")) {
    divElem.classList.remove("fade-in");
    divElem.classList.add("fade-out");
    // 单次监听动画结束事件
    divElem.addEventListener("animationend", function handleFadeOutEnd() {
      divElem.style.display = "none";
      divElem.removeEventListener("animationend", handleFadeOutEnd);
    }, { once: true });
  } else {
    divElem.style.display = "block";
    divElem.classList.remove("fade-out");
    divElem.classList.add("fade-in");
  }
}

同时调整CSS关键帧,移除display相关代码:

@keyframes fade-in {
  0% { opacity: 0; }
  100% { opacity: 1; }
}

@keyframes fade-out {
  0% { opacity: 1; }
  100% { opacity: 0; }
}

这两种方案都能在三大浏览器中实现一致的淡入淡出效果,大家可以根据需求选择~

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 14:43:07