Angular CSS 原生动画实战指南:@keyframes、过渡与 enter/leave 动画

发布时间:2026/10/27 21:21:53

Angular CSS 原生动画实战指南:@keyframes、过渡与 enter/leave 动画 Angular CSS 原生动画实战指南keyframes、过渡与 enter/leave 动画【免费下载链接】angularDeliver web apps with confidence 项目地址: https://gitcode.com/GitHub_Trending/an/angular本文基于 Angular 官方文档站指南 Using CSS to animate your application系统讲解在 Angular 应用中用纯 CSS而非 Angular 动画包实现完整动画体验的全部技术路径从keyframes定义可复用动画、类切换触发过渡、starting-styles与animate.enter/animate.leave处理进出场到交错stagger、并行组合、排序动画等复杂序列以及通过 Web Animations API 对动画进行编程式控制。读完本文你可以不依赖任何动画库仅用原生 CSS 少量 TypeScript 就覆盖日常开发中的绝大多数动画场景。一、为什么选择原生 CSS 动画CSS 提供了一套完整且强大的动画工具可以直接在 Angular 应用组件样式中创建丰富、流畅的动效。如果你尚未写过原生 CSS 动画可以先熟悉 MDN 的 CSS Animations 指南、W3Schools 的 CSS3 Animations 教程以及 Net Ninja 的 CSS Animation 系列视频然后再回到本指南。Angular 官方文档站为此指南配套了一个可交互示例应用所有示例组件都位于 adev/src/content/examples/animations/src/app/native-css 目录每篇文章中的代码块均可在该目录找到原始文件。二、创建可复用的 keyframes 动画通过keyframes可以把动画定义放在一个共享 CSS 文件中让应用各处复用同一组关键帧。官方示例定义了一个名为sharedAnimation的关键帧并用.animated-class类将它绑定到元素上——只要把该 class 加到某个元素上动画就会触发。来自 animations.csskeyframes sharedAnimation { to { height: 0; opacity: 1; background-color: red; } } .animated-class { animation: sharedAnimation 1s; }使用方式很简单在模板中通过类绑定或:host、if等条件渲染让元素获得animated-class类即触发 1 秒的sharedAnimation关键帧动画。关键帧本身与具体组件解耦是跨组件复用最自然的手段。三、用 CSS 类动画化状态切换很多场景需要动画化两个状态之间的变化例如元素的“打开/关闭”。做法是为每个状态定义一个 class并在其中用transition描述属性如何从当前值平滑过渡到目标值。来自 animations.css.open { height: 200px; opacity: 1; background-color: yellow; transition: all 1s; } .closed { height: 100px; opacity: 0.8; background-color: blue; transition: all 1s; }open/closed两个状态的触发是在组件模板中切换元素上的 CSS 类。类绑定的具体写法[class.xxx]expression与直接动画化行内样式的写法可参考 模板绑定指南 中的 CSS 类/样式属性绑定章节。3.1 过渡、时长与缓动函数调整时序timing、延迟delay与缓动easing几乎出现在每个动画中。CSS 提供了两种等价的方式分别指定独立属性或使用简写属性。对关键帧动画使用animation-duration、animation-delay、animation-timing-function或animation简写对不使用keyframes的过渡动画则使用transition-duration、transition-delay、transition-timing-function与transition简写。来自 animations.css/* 关键帧动画的时序控制 */ .example-element { animation-duration: 1s; animation-delay: 500ms; animation-timing-function: ease-in-out; } .example-shorthand { animation: exampleAnimation 1s ease-in-out 500ms; } /* 过渡动画的时序控制 */ .example-element { transition-duration: 1s; transition-delay: 500ms; transition-timing-function: ease-in-out; transition-property: margin-right; } .example-shorthand { transition: margin-right 1s ease-in-out 500ms; }两个简写的取值顺序都是名称/属性 时长 缓动 延迟。注意transition-property可以精确指定参与过渡的属性避免transition: all带来的不可预期行为下面的开/合示例即采用了transition-property的精确写法。3.2 完整示例类切换触发开/合动画动画的触发机制是当某个类出现在元素上时动画发生移除该类后元素回到该元素其他 CSS 规则定义的样子。下面这组官方示例完整展示了信号signal驱动的类切换 CSS 过渡的组合。open-close.tsimport {Component, signal} from angular/core; Component({ selector: app-open-close, templateUrl: open-close.html, styleUrls: [open-close.css], }) export class OpenClose { isOpen signal(true); toggle() { this.isOpen.update((isOpen) !isOpen); } }open-close.htmlh2Open / Close Example/h2 button typebutton classtoggle-btn (click)toggle()Toggle Open/Close/button div classopen-close-container [class.open]isOpen() pThe box is now {{ isOpen() ? Open : Closed }}!/p /divopen-close.css:host { display: block; margin-top: 1rem; } .open-close-container { border: 1px solid #dddddd; margin-top: 1em; padding: 20px 20px 0px 20px; font-weight: bold; font-size: 20px; height: 100px; opacity: 0.8; background: #3b82f6; color: #ebebeb; transition-property: height, opacity, background-color, color; transition-duration: 1s; } .toggle-btn { background: transparent; border: 1px solid var(--primary-contrast, black); color: var(--primary-contrast, black); padding: 10px 24px; border-radius: 8px; cursor: pointer; } .open { transition-duration: 0.5s; height: 200px; opacity: 1; background: #475569; color: #f9fafb; }要点解读默认样式收起态定义了height: 100px与transition-property: height, opacity, background-color, color因此任何向.open态或从.open态返回的属性变化都会走 1 秒过渡.open类覆盖了目标状态值height: 200px等并把transition-duration单独调为0.5s实现了“打开快、收起慢”的非对称节奏——这是纯 CSS 状态机的典型技巧不同状态各自拥有不同的过渡参数模板中[class.open]isOpen()把布尔信号与类绑定isOpen.update()完成状态翻转。四、过渡与触发器4.1 用 CSS Grid 动画化 auto 高度“从固定高度过渡到内容自适应高度auto”是经典难题因为height: auto无法直接插值。纯 CSS 的优雅解法是 CSS Grid 的fr行高技巧把容器设为单列 Grid在0fr与1fr之间过渡子元素借助overflow: hidden裁切溢出即可实现视觉上的高度自动展开/收起。auto-height.ts 与 auto-height.html 沿用上文的信号 [class.open]模式button typebutton classtoggle-btn (click)toggle()Toggle Open/Close/button div classcontainer [class.open]isOpen() div classcontent pThe box is now {{ isOpen() ? Open : Closed }}!/p /div /divauto-height.css.container { display: grid; grid-template-rows: 0fr; overflow: hidden; transition: grid-template-rows 1s; } .container.open { grid-template-rows: 1fr; } .container .content { min-height: 0; transition: visibility 1s; padding: 0 20px; visibility: hidden; margin-top: 1em; font-weight: bold; font-size: 20px; background: #3b82f6; color: #ebebeb; overflow: hidden; } .container.open .content { visibility: visible; }关键细节grid-template-rows: 0fr → 1fr的过渡是核心——fr单位参与插值0fr即“占 0 高度”1fr即“占满内容所需高度”子元素.content必须overflow: hidden且通过min-height: 0解除 Grid 子项的默认最小高度约束否则折叠时内容会撑破容器visibility同步用 1 秒过渡让收起时内容淡出的时间点与高度变化一致。如果你的浏览器支持范围足够新还可以直接使用calc-size()它是动画化 auto 尺寸的“真正解法”可查阅 MDN 的calc-size()文档了解用法。4.2 元素进入视图的动画animate.enter当元素因条件渲染“进入”DOM 时可以用 Angular 的animate.enter指令它在元素进入视图的那一刻应用指定的动画类。insert.htmlnav button typebutton classtoggle-btn (click)toggle()Toggle Element/button /nav if (isShown()) { div classinsert-container animate.enterenter-animation pThe box is inserted/p /div }insert.css.insert-container { border: 1px solid #dddddd; margin-top: 1em; padding: 20px; font-weight: bold; font-size: 20px; } .enter-animation { animation: slide-fade 1s; } keyframes slide-fade { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }insert.ts 中的isShown signal(false)配合if控制插入/移除当if分支首次渲染、div进入 DOM 时animate.enter添加enter-animation类slide-fade关键帧播放一次从下方 20px、透明滑入到原位。4.3 元素离开视图的动画animate.leave离场动画与入场对称用animate.leave指定元素离开视图时应用的 CSS 类。官方示例里容器本身还用starting-style定义了自己的入场初始值透明而离场则交给.deleting类的过渡完成。remove.htmlif (isShown()) { div classinsert-container animate.leavedeleting pThe box is inserted/p /div }remove.css.insert-container { border: 1px solid #dddddd; margin-top: 1em; padding: 20px; font-weight: bold; font-size: 20px; opacity: 1; transition: opacity 200ms ease-in; starting-style { opacity: 0; } } .deleting { opacity: 0; transform: translateY(20px); transition: opacity 500ms ease-out, transform 500ms ease-out; }工作流元素插入时由starting-style声明初始opacity: 0随后过渡到opacity: 1200ms 淡入当isShown变为false、元素即将被移除时animate.leave先加上deleting类执行 500ms 的淡出 下移动画结束后元素才被真正移出 DOM——这保证了“先播完离场动画再删除”的语义。注意子组件的animate.leave动画只在同一组件模板内触发。嵌套组件的animate.leave动画不会因为父元素被移除而触发。更多细节见 Enter and Leave animations 指南。4.4 数字增减动画increment / decrement数字递增/递减是应用中的常见模式数值变化时让文本快速放大变色再回弹。这个示例展示了“手动加类 监听animationend事件移除类”的完整生命周期管理。increment-decrement.tsimport {Component, ElementRef, OnInit, signal, viewChild} from angular/core; Component({ selector: app-increment-decrement, templateUrl: increment-decrement.html, styleUrls: [increment-decrement.css], }) export class IncrementDecrement implements OnInit { num signal(0); el viewChildElementRefHTMLParagraphElement(el); ngOnInit() { this.el()?.nativeElement.addEventListener(animationend, (ev) { if (ev.animationName.endsWith(decrement) || ev.animationName.endsWith(increment)) { this.animationFinished(); } }); } modify(n: number) { const targetClass n 0 ? increment : decrement; this.num.update((v) (v n)); this.el()?.nativeElement.classList.add(targetClass); } animationFinished() { this.el()?.nativeElement.classList.remove(increment, decrement); } ngOnDestroy() { this.el()?.nativeElement.removeEventListener(animationend, this.animationFinished); } }increment-decrement.htmlh3Increment and Decrement Example/h3 section p #elNumber {{ num() }}/p div classcontrols button typebutton (click)modify(1)/button button typebutton (click)modify(-1)-/button /div /sectionincrement-decrement.css 中定义了两组关键帧.increment { animation: increment 300ms; } .decrement { animation: decrement 300ms; } keyframes increment { 33% { color: green; transform: scale(1.3, 1.2); } 66% { color: green; transform: scale(1.2, 1.2); } 100% { transform: scale(1, 1); } } keyframes decrement { 33% { color: red; transform: scale(0.8, 0.9); } 66% { color: red; transform: scale(0.9, 0.9); } 100% { transform: scale(1, 1); } }这条示例完整体现了纯 CSS 动画在 Angular 中的典型工程模式模板引用#elviewChild拿到 DOM 元素句柄状态变化时手动classList.add(increment | decrement)监听animationend事件按animationName校验后移除类——类移除后关键帧动画即结束为下一次触发做好准备关键帧用 33% / 66% / 100% 三段做“放大—回落”的弹性节奏。4.5 禁用动画的三种方式当需要让某些动画不播放时文档给出了三条路径方式一强制置空的自定义类。定义一个把animation和transition都设为none的类应用到元素上即可阻止该元素上任何动画.no-animation { animation: none !important; transition: none !important; }你可以把它作用在单个元素上也可以作用到整个 DOM 或 DOM 的某个区段以全局强制。但要注意这会连带阻止动画事件的触发。如果你的逻辑依赖等待动画事件来完成元素移除例如离场动画结束后才删除节点这种方案会失效——文档给出的替代做法是把动画时长设为 1 毫秒既接近瞬时又保留事件语义。方式二prefers-reduced-motion媒体查询。利用系统级的prefers-reduced-motion媒体查询MDN 有专页说明该查询在用户系统偏好“减少动态效果”时自动关闭所有动画这是无障碍a11y层面的标准做法。方式三程序化地阻止添加动画类。在组件逻辑里直接控制不添加触发动画的类动画自然不播放。这是最可控、也最容易与业务状态联动的方式。4.6 动画回调事件如果需要在动画生命周期的特定时点执行逻辑DOM 提供了完整的事件监听面关键帧动画事件animationstart、animationend、animationiteration每次循环迭代、animationcancel过渡事件transitionstart、transitionrun、transitionend、transitioncancel。Web Animations API 还暴露了远超 CSS 声明式能力的编程接口可查阅 MDN 的 Web Animations API 文档了解全貌。注意事件冒泡bubbling当父、子元素都在做动画时子元素的事件会冒泡到父元素上。此时应考虑stopPropagation()或检查事件对象中的animationName、正在过渡的属性等信息确认自己响应的是目标节点的事件而不是从子节点冒泡上来的事件。五、复杂动画序列真实应用的动画往往不止一个淡入淡出而是多个动画组合编排。5.1 列表项交错stagger动画让列表中每一项依次延迟入场形成级联效果核心是animation-delay/transition-delay配合每项的索引。官方示例把索引写入 CSS 自定义属性--index用calc()计算逐项延迟stagger.htmlh1Stagger Example/1 button typebutton classtoggle-btn (click)refresh()Refresh/button div classitems-container if (show()) { ul classitems for (item of items; track $index) { li classitem style--index: {{ $index }}{{ item }}/li } /ul } /divstagger.css.items .item { transition-property: opacity, transform; transition-duration: 500ms; transition-delay: calc(200ms * var(--index)); starting-style { opacity: 0; transform: translateX(-10px); } }stagger.ts 的refresh()先把show置为false10ms 后再置回true通过“移除再插入”重新触发starting-style驱动的入场过渡。拆解要点每个li通过内联样式携带--index0、1、2……transition-delay: calc(200ms * var(--index))使第 n 项晚 200ms×n 开始过渡天然形成瀑布节奏starting-style声明了元素首次出现在文档中时的起始样式透明 左移 10px之后过渡到默认样式实现无需keyframes的入场动画外层if (show())的整体插拔是重播手段——这也说明for项在“移除并重新加入”时会重新触发入场动画见下文排序示例。5.2 并行动画Parallel Animationsanimation简写支持在一条声明里列出多个动画每个动画可拥有独立的时长与延迟从而在一个元素上并行组合多个效果.target-element { animation: rotate 3s, fade-in 2s; }在这个例子中rotate3s与fade-in2s同时开始、同时结束各自的生命周期互不干扰。这是纯 CSS 下“组合出复杂效果”最轻量的手段。5.3 列表重排序动画reorderfor循环中的项目在数据顺序变化时会被移除并重新加入这会触发入场动画——配合starting-styles即starting-style块即可获得“换位/重排时重新淡入”的效果也可以改用animate.enter达到同样的行为。对于被移除的项目用animate.leave播放离场动画reorder.htmlh1Reordering List Example/1 button typebutton classtoggle-btn (click)randomize()Randomize/button ul classitems for (item of items; track item) { li classitem animate.leavefade{{ item }}/li } /ulreorder.css.items .item { transition-property: opacity, transform; transition-duration: 500ms; starting-style { opacity: 0; transform: translateX(-10px); } } .items .item.fade { animation: fade-out 500ms; } keyframes fade-out { from { opacity: 1; } to { opacity: 0; } }reorder.ts 的randomize()通过 Fisher-Yates 风格的洗牌重排items数组模板以track item追踪项身份身份不变的项保持 DOM 节点仅顺序改变而被判定移除的项在离开前由animate.leavefade播放fade-out关键帧。这样重排既有序变化又有离场/重入的视觉反馈。六、动画的编程式控制除了声明式地“加类即播放”还可以直接从元素上取回正在运行的动画对象调用 DOM 的Element.getAnimations()它会返回该元素上所有Animation实例的数组。拿到Animation对象后Web Animations API 提供的能力远超旧版动画包的AnimationPlayer——你可以对每个动画cancel()、play()、pause()、reverse()乃至操作currentTime、playbackRate等属性。对绝大多数“控制动画”的需求这套原生 API 已经足够。七、延伸阅读如果你想继续深入 Angular 的动画体系可以阅读文档站中的以下指南Enter and Leave animations进入与离开动画 ——animate.enter/animate.leave的完整语义与边界Route transition animations路由过渡动画 —— 路由切换场景的动画方案动画指南总入口guide/animations。小结场景核心技术参考实现跨组件复用keyframes 共享 CSS 类animations.css状态切换[class.x]transitionopen-close.cssauto 高度Grid0fr → 1fr过渡auto-height.css入场/离场animate.enter/animate.leavestarting-styleinsert.css、remove.css数字增减手动加类 animationend移除类increment-decrement.ts级联/交错transition-delay: calc(200ms * var(--index))stagger.css列表重排for移除重插 starting-styleanimate.leavereorder.ts编程控制Element.getAnimations() Web Animations APIDOM 标准 API关闭动画.no-animation类 /prefers-reduced-motion/ 不添加类见“禁用动画”一节纯 CSS 方案的优势在于零依赖、性能好合成层属性transform/opacity可走 GPU 加速、且与 Angular 信号驱动的响应式模型天然契合组件只负责翻转信号与类CSS 负责一切视觉插值。掌握本文的类切换、starting-style、animate.enter/animate.leave与事件回调四条主线即可覆盖 Angular 应用中绝大多数动画需求。【免费下载链接】angularDeliver web apps with confidence 项目地址: https://gitcode.com/GitHub_Trending/an/angular创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/10/27 13:15:21

深入理解grep:从基础用法到日志排查实战

“每天一个Linux命令”系列:grep,这可能是你最常用的排查工具 老规矩,今天这个系列轮到 grep。 我最早接触 Linux 的时候,其实不太理解为什么大家天天把 grep 挂在嘴边。直到有次线上服务出问题,我需要在几万行日志里…

2026/10/25 3:54:41

Rust NLL 详解:从词法作用域到程序点的借用检查进化

你大概率遇到过这种场面:代码逻辑清清楚楚,上一行刚读完某个引用,下一行想对原变量做一次修改,编译器却甩出一句cannot borrow as mutable because it is also borrowed as immutable,把整个作用域都冻结了。我第一次遇…

2026/10/24 4:14:12

多模型架构实战:GLM 与 Gemini CLI 的融合接入指南

做 AI 编码工具最头疼的一件事,就是赌模型。HagiCode 从最初只支持单一后端开始,被用户反复追问“能不能接入 GLM”“能不能走 Gemini CLI”之后,我终于意识到多模型不是加分项,而是生存项。这次改动把 GLM 全系模型正式接入&…

2026/10/27 21:21:09

C++ list迭代器实现原理与STL设计解析

1. 为什么需要关注list迭代器的实现细节?在C标准库中,list作为双向链表容器,其迭代器的实现远比vector这类连续存储容器的迭代器复杂得多。很多开发者在使用list时,往往只停留在"能用迭代器遍历"的层面,却不…

2026/10/27 21:21:09

E2E端到端测试实战:从Playwright选型到CI稳定性治理

e2e,全称 end-to-end,端到端。过去半年我一直在折腾这三个字母——不是写业务代码,而是确保业务代码在真实用户路径上不翻车。如果你正打算给项目接端到端测试,或者已经被一套三天两头 flaky 的 E2E 套件折磨到怀疑人生&#xff0…

2026/10/27 21:21:09

Agent-Reach:构建多智能体系统的可靠通信与编排层

做多智能体系统时,我踩过最大的坑不是模型幻觉,而是 Agent 之间的通信。曾经有次线上跑一套工单处理流程,三个 Agent 协同干活,A 把待复核的任务发给 B,结果 B 没收到,消息被 C 消费了——原因是大家都在同…

2026/10/27 21:21:09

哈希表原理与Java实现:从基础到优化

1. 哈希表基础概念与核心价值哈希表(Hash Table)是每个程序员都应该掌握的基础数据结构之一。我在实际开发中经常用它来优化查询性能,特别是在处理需要快速查找、插入和删除的场景时。简单来说,哈希表通过键值对(key-v…

2026/10/27 21:21:09

OpenMontage:开源自动化剪辑工作流,让视频创作效率翻倍

做了这么多年视频内容工具,我最深的感受是:大多数创作者的瓶颈不是没想法,而是被剪辑这件事本身拖垮了。素材要切、卡点要对、转场要调、字幕要加,一条3分钟的片子背后常常是几十段原始素材和两三个小时的机械操作。OpenMontage就…

2026/10/27 21:16:09

Clawdbot:模块化爬虫工具的核心架构与实战应用

1. Clawdbot 到底是什么? 第一次听说Clawdbot这个名字时,我也是一头雾水。直到上周在调试一个分布式爬虫项目时,偶然发现同事的代码里引用了这个库,才真正开始了解它。简单来说,Clawdbot是一个专门为数据采集场景设计的…

2026/10/27 14:24:03

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/27 9:34:54

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/27 0:59:21

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式19_“模式选错”的典型代价

“模式选错”的典型代价 摘要 在软件工程中,设计模式、架构模式、并发模式乃至团队协作模式的选择,往往在项目早期就决定了后续的开发效率和维护成本。本文通过多个真实场景,剖析“模式选错”带来的典型代价——包括返工成本、技术债务累积、…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式20_新手推荐路径

新手推荐路径 摘要 在 AI 辅助开发工具快速普及的今天,新手面对最多的困惑往往不是"工具够不够强",而是"我该从哪一步开始用"。本文提出一条经过实践验证的三阶段学习路径:先从 Ask(问答式交互)起…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑