当前位置:首页 > 文章列表 > 文章 > 前端 > CSS @starting-style 怎样为弹窗补上首次进入动画

CSS @starting-style 怎样为弹窗补上首次进入动画

来源:17golang原创 2026-11-01 10:47:57 0浏览 收藏
热门推荐
漫画APP
动画内容聚合,热门资源快捷查看
立即下载

弹窗第一次出现时,很多人会发现 transition 写了却没有淡入:元素之前没有可供比较的已渲染状态,或者它从 display: none 直接变成可见状态,浏览器没有普通过渡所需的“上一帧”。解决办法是用 @starting-style 明确提供首次进入的起始值,再把 display 配进允许离散变化的过渡中。

官方资料:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/%40starting-style

把弹窗动画拆成默认隐藏态、首次进入起始态和打开完成态:@starting-style 只负责没有上一帧时从哪里开始,transition-behavior: allow-discrete 负责让 display 在动画边界翻转。这样进入时能淡入,退出时也不会立即消失。

先区分首次进入与普通返回

普通过渡通常是“旧样式 → 新样式”。但 dialog.showModal() 会让弹窗从不可见状态进入顶层,首次显示时并没有一个已经绘制过的可见样式可以当作起点。此时只写下面的最终样式和 transition,弹窗仍可能直接出现:

.settings-dialog {
  /* 让透明度和位移变化使用同一段过渡 */
  transition: opacity 220ms ease, transform 220ms ease;
  opacity: 1;
  transform: translateY(0);
}

@starting-style 的职责是为“第一次样式更新”提供起始值。它不是永久状态,也不是替代默认样式的隐藏规则;弹窗已经显示过以后,关闭再打开时会回到默认隐藏态和新的进入起始态之间的过渡。

CSS starting-style 弹窗三种状态的静态关系说明图
图1:状态结构说明图,展示弹窗首次进入、显示完成和隐藏返回之间的静态关系。

给 dialog 建立三种 CSS 状态

先只处理透明度和轻微位移,不急着加入复杂阴影或缩放。默认的 dialog 状态保持隐藏并准备退出;dialog:open 描述打开后的最终状态;嵌套在打开规则里的 @starting-style 则给第一次进入提供透明和位移起点:

.settings-dialog {
  /* 默认状态用于关闭后的回退,也作为退出动画的终点 */
  opacity: 0;
  transform: translateY(12px) scale(0.98);
  transition:
    opacity 220ms ease,
    transform 220ms ease,
    display 220ms allow-discrete;
}

.settings-dialog:open {
  /* 打开状态是进入动画的终点 */
  opacity: 1;
  transform: translateY(0) scale(1);

  @starting-style {
    /* 首次显示没有上一帧时,从这里开始过渡 */
    opacity: 0;
    transform: translateY(12px) scale(0.98);
  }
}

这里有一个容易混淆的地方:进入时使用的是 @starting-style → :open,关闭时则是 :open → 默认规则。也就是说,@starting-style 不会在每一次普通样式变化中持续介入,不能把它当成永久的“关闭状态”。

把 display 放进离散过渡

如果弹窗在退出时立刻变成 display: none,透明度还没有来得及变成 0,元素就已经从渲染树中消失,用户看到的结果就是“没有淡出”。将 display 列入 transition,并使用 allow-discrete,可以让这个离散属性在动画边界翻转,而不是用连续插值。

.settings-dialog {
  /* display 不是连续数值,所以显式允许离散过渡 */
  transition-behavior: allow-discrete;
  transition:
    opacity 220ms ease,
    transform 220ms ease,
    display 220ms allow-discrete;
}

.settings-dialog:not(:open) {
  /* 关闭状态保留到退出动画结束,再由 display 隐藏 */
  display: none;
}

在从隐藏到可见的方向,display 会在动画开始时切到可见值,使透明度和位移有机会播放;从可见到隐藏的方向,display 会尽量延迟到动画结束再翻转。这样做的关键不是给 display 设置一个“中间值”,而是让它配合连续属性的可见时间窗口。

dialog display 离散过渡和 allow-discrete 的静态边界说明图
图2:离散过渡说明图,展示 display 翻转边界与淡入淡出属性的配合关系。

用最小 HTML、CSS 和 JavaScript 连接状态

下面的示例只负责打开和关闭原生弹窗。JavaScript 不参与动画计算,只改变 dialog 的生命周期状态;动画全部交给 CSS。代码中的注释说明了打开、关闭和资源监听的职责边界:



显示设置

选择保存后关闭弹窗。

const openButton = document.querySelector("#open-settings");
const dialog = document.querySelector("#settings-dialog");

// 打开动作只改变 dialog 状态,进入动画由 CSS 接管。
openButton.addEventListener("click", () => {
  if (!dialog.open) {
    dialog.showModal();
  }
});

// 原生 form method="dialog" 会调用 close(),无需手工移除节点。
dialog.addEventListener("close", () => {
  // 这里可以同步表单结果,但不要在此处直接设置 display:none。
  console.log("dialog result:", dialog.returnValue);
});

如果你使用自定义按钮而不是 method="dialog",关闭时调用 dialog.close("cancel") 即可。不要为了播放动画先把节点删除;节点一旦被删除,就没有退出过渡可以承载了。

兼容与降级边界

@starting-style 和离散属性过渡属于较新的 CSS 能力。写稿时 MDN 将 @starting-style 标为 Baseline 2024,但旧浏览器或受限运行环境仍可能不支持。降级策略应优先保证弹窗能打开和关闭,再把动画当作增强:

/* 不支持新规则时,至少保留可见的原生 dialog 行为 */
.settings-dialog {
  opacity: 1;
  transform: none;
}

@supports (transition-behavior: allow-discrete) {
  /* 支持离散过渡的环境再启用 display 与进入起始值 */
  .settings-dialog {
    opacity: 0;
    transform: translateY(12px);
    transition:
      opacity 220ms ease,
      transform 220ms ease,
      display 220ms allow-discrete;
  }

  .settings-dialog:open {
    opacity: 1;
    transform: translateY(0);

    @starting-style {
      /* 只在支持这组特性时提供首次进入起点 */
      opacity: 0;
      transform: translateY(12px);
    }
  }
}

还要注意用户的减少动态效果设置。弹窗是信息入口,不能因为动画而降低可读性:

@media (prefers-reduced-motion: reduce) {
  /* 减少动态时缩短过渡,保留状态变化和可访问性 */
  .settings-dialog {
    transition-duration: 1ms;
  }
}

排查清单:动画仍然不出现时看哪里

  1. 确认选择器确实命中了同一个 dialog,不要把 @starting-style 写到另一个组件作用域里。
  2. 确认进入和退出的连续属性有明确的默认值与打开值,至少先检查 opacity 和 transform。
  3. 确认 display 出现在过渡列表中,并且使用了 allow-discrete。
  4. 确认关闭逻辑没有同步删除节点、设置内联 display:none 或跳过原生 close() 生命周期。
  5. 确认页面没有启用 prefers-reduced-motion 分支后把时长压到几乎不可见。

最小可用的判断标准是:首次打开能从透明、偏移状态进入;重复关闭时仍能看见短暂退出;不支持新特性时弹窗仍然可以正常使用。达到这三个条件,再考虑阴影、遮罩和更复杂的层级动画。

常见问题

@starting-style 能替代 CSS animation 吗?

它主要服务于 CSS transition 的首次样式更新。若使用关键帧动画,起始帧可以直接写在 from 或 0% 中,不需要用 @starting-style。

为什么打开动画有了,关闭动画还是没有?

通常是关闭时立即变成 display:none 或节点被删除。把 display 作为允许离散过渡的属性,并让关闭状态留到过渡完成,才能给透明度和位移留下播放时间。

必须使用原生 dialog 才能用这个规则吗?

不是。任何首次加入 DOM 或从不可见状态变为可见的元素都可以使用,但原生 dialog 的打开、关闭和顶层显示场景更容易暴露“没有上一帧”的问题。

不支持 allow-discrete 时应该怎么办?

保留无动画的可见状态作为降级,或者用 JavaScript 在状态切换后再添加类名。不要让兼容分支阻止用户打开和关闭弹窗。

css
版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
CSS transition-behavior allow-discrete 的显示切换CSS transition-behavior allow-discrete 的显示切换
上一篇
CSS transition-behavior allow-discrete 的显示切换
CSS field-sizing: content 怎样让输入框宽度跟随内容
下一篇
CSS field-sizing: content 怎样让输入框宽度跟随内容
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    821次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    816次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    905次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    876次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    698次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码