发布时间:2026/9/7 15:25:04
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/9/7 15:25:04

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

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

2026/9/7 15:25:04

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

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

2026/9/7 15:20:02

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

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

2026/9/7 19:15:37

IOPaint 低内存模式实战:4GB 显存也能跑 Stable Diffusion

IOPaint 低内存模式实战:4GB 显存也能跑 Stable Diffusion 【免费下载链接】IOPaint Image inpainting tool powered by SOTA AI Model. Remove any unwanted object, defect, people from your pictures or erase and replace(powered by stable diffusion) any th…

2026/9/7 19:15:37

信创环境下百度UE编辑器识别WORD粘贴格式的实用适配方案

我没有直接操作过信创目录里那几款政务系统的UE集成,但基于在信创环境下做政务系统前端改造的踩坑经验,这个问题我可以负责任地告诉你:百度UE(UEditor/UMEditor)默认情况下,几乎无法完美识别直接从WORD粘贴…

2026/9/7 19:15:37

纯CSS卡片式布局:从盒模型到阴影间距的实战指南

卡片式布局现在是前端日常开发里绕不开的基本功,不管是后台管理系统的数据看板,还是移动端的信息流页面,甚至个人博客的文章列表,拆开来看都是一张张卡片。很多初学者能写出“看着像卡片”的界面——有背景色、有圆角、有阴影&…

2026/9/7 0:47:43

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/7 0:14:19

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/7 0:14:17

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/7 0:03:36

基于YOLOv8和PyQt5的麦穗稻穗检测识别系统设计与实现

这次我们来看一个把目标检测算法和桌面端工具结合得很典型的项目:基于 YOLOv8 PyQt5 的麦穗稻穗检测识别系统。这个项目本身不是新概念,但它的价值在于落地形态很完整。YOLOv8 负责核心的麦穗稻穗目标检测,PyQt5 负责提供可视化的桌面交互界…

2026/9/7 0:03:36

UL 1642锂电池安全标准全解析:测试项目、认证流程与避坑指南

简介:UL 1642是锂电池安全领域的重要规范,本中文版资源适合锂电池制造商、检测机构工程师及产品认证相关人员阅读,用于理解电池在设计与制造层面的安全要求、测试方法与合规要点。资源共1个PDF文件,压缩包大小834KB,便…

2026/9/7 0:03:36

BS EN 13814-1-2019游乐设施安全标准:设计与制造核心要点解析

简介:BS EN 13814-1:2019是英国采纳欧洲标准EN 13814-1:2019的正式版本,由BSI标准出版,重点规定游乐设施和游乐设备在设计与制造环节的安全准则,与BS EN 13814-2:2019、BS EN 13814-3:2019共同取代旧版BS EN 13814:2004。该标准面…

2026/9/7 16:23:03

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/6 19:33:50

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/6 10:19:40

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…