Angular
Animations (v4.2+)
slides.com/gerardsans | @gerardsans
Text
Google Developer Expert
Master of Ceremonies
Blogger
International Speaker
Angular Trainer (v4+)
Community Leader
850
950
Angular In Flip Flops
CSS Introduction
Cascading Style Sheets
- Styling HTML Elements
- CSS rules
- Specificity and order
- Box model
HTML Page life-cycle
source: blog
CSS Rule
SELECTOR
a.active:hover {
color: #333;
}
PROPERTY
VALUE
DECLARATION
pseudo classes/elements
:hover
:link
:active
:target
:not(selector)
:focus
::first-letter
::first-line
::before
::after
::selection
Specificity and Order
-
Element style
-
Element id
-
class/attribute selectors
-
element selectors
-
last CSS rule wins
Box Model
source: blog
Animations
Introduction
- Build on top of Web Animations API
- CSS Transitions
- CSS Animations (@keyframes)
Web Animations API
Background
source: blog
index.html
<html>
<head>
<script src="https://unpkg.com/web-animations-js@2.2.5"></script>
...
</head>
<body>
<my-app>
loading...
</my-app>
</body>
</html>
Angular CLI 1.0
npm install web-animations-js --save
// src/polyfills.ts
import 'web-animations-js';
CSS Transitions
DURATION
START
END
CSS Transitions
CSS Transitions
- Define an initial and final state
- Intermediate states are calculated automatically
- We can choose which CSS properties we want to affect
-
Not all CSS properties are animatable (list)
Animatable CSS
all background* border* bottom box-shadow clip clip-path color filter font* height left margin* mask* offset* opacity outline* padding* perspective* right text-decoration text-shadow top transform vertical-align visibility width z-index
transition
PROPERTY
transition: color 5s ease-in 1s;
DURATION
TIMING
DELAY
timing function/easing
CSS Animations
DURATION
0%
100%
CSS Animations
KEYFRAMES
CSS Animations
- Define any number of states between the initial and final state
- Changes from states are calculated automatically
- We can choose which CSS properties we want to affect
CSS Animation
NAME
animation: fade 5s 1s infinite linear;
DURATION
DELAY
ITERATIONS
TIMING
CSS Animation
@keyframes fade {
0% { opacity: 1; }
100% { opacity: 0; }
}
CSS Animation
@keyframes fade {
from { opacity: 1; }
to { opacity: 0; }
}
Angular Animations
fadeIn
fadeOut
States & Transitions
TRANSITIONS
STATE
STATE
fadeIn => fadeOut
fadeOut => fadeIn
fadeIn <=> fadeOut
States & Transitions
void
*
Special Keywords
void => * :enter
* => void :leave
void <=> *
STATE
STATE
Animations Setup
// npm install --save @angular/animations
// app.module.ts
import {Component, NgModule} from '@angular/core';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
@Component({ })
export class App { }
@NgModule({
imports: [ BrowserModule, BrowserAnimationsModule ],
declarations: [ App ],
bootstrap: [ App ]
})
export class AppModule {}
platformBrowserDynamic().bootstrapModule(AppModule)
Animation
Animation Example
import {fade} from './animations';
@Component({
selector: 'my-app',
template: `<button [@fade]='fade' (click)="toggleFade()">Fade</button>`,
animations: [ fade ]
})
export class App {
fade = 'fadeIn';
toggleFade(){
this.fade = this.fade === 'fadeIn' ? 'fadeOut' : 'fadeIn';
}
}
Animation Example
import {
trigger, transition, state, style, animate
} from '@angular/animations';
export const fade = trigger('fade', [
state('fadeIn', style({ opacity: 1 })),
state('fadeOut', style({ opacity: 0.1 })),
transition('fadeIn <=> fadeOut', animate('2000ms linear'))
]);
demo
Keyframes
Keyframes Example
import {
trigger, transition, state, style, animate, keyframes
} from '@angular/animations';
export const grow = trigger('grow' , [
state('small', style({ transform: 'scale(1)' })),
state('large', style({ transform: 'scale(1.4)' })),
transition('small <=> large', animate('200ms linear'))
])
Keyframes Example
import {
trigger, transition, state, style, animate, keyframes
} from '@angular/animations';
export const grow = trigger('grow' , [
state('small', style({ transform: 'scale(1)' })),
state('large', style({ transform: 'scale(1.4)' })),
transition('small <=> large', animate('200ms linear', keyframes([
style({transform: 'scale(1.6)', offset: 0}),
style({transform: 'scale(1.4)', offset: 1})
])
))
])
Animation
Callbacks
Animation Callbacks
import {fade} from './animations';
@Component({
selector: 'my-app',
template: `<img [@fade]='fade'
(@fade.start)="start($event)"
(@fade.done)="done($event) >`,
animations: [ fade ]
})
export class App {
start(e) { }
done(e) { }
}
Callback Event
$event == {
element: any, // div element
triggerName: string, // "fade"
phaseName: string // "start" or "done"
fromState: string, // "in" or "out"
toState: string, // "in" or "out"
totalTime: number, // 1000 (milliseconds)
}
demo
New in Angular 4.2
Animations
Orchestration
Animate in Parallel
export const revealGroup = trigger('revealGroup', [
transition(':enter', [
query('*', style({ opacity: 0 })),
group([
query('*', animate(2000, style({ opacity: 1 })))
])
])
]);
Animate in Sequence
export const revealGroup = trigger('revealGroup', [
transition(':enter', [
query('*', style({ opacity: 0 })),
sequence([
query('*', animate(2000, style({ opacity: 1 })))
query('*', animate(1000, style({ color: 'red' })))
])
])
]);
query + stagger
export const revealStagger = trigger('revealStagger', [
transition(':enter', [
query('*', style({ opacity: 0 })),
query('*', stagger(1000, [
animate(2000, style({ opacity: 1 }))
])
)
])
]);
demo
query + animateChild
export const reveal = trigger('reveal', [
transition(':enter', [
query('@fade', [
animateChild()
]),
query('@*', [
animateChild()
]),
])
]);
Router Transitions
Router transitions
import { routerAnimations } from './router.animations';
@Component({
template: `
<div [@routerAnimations]="routeTransition(outlet)">
<router-outlet #outlet="outlet"></router-outlet>
</div>
`,
animations: [ routerAnimations ]
})
export class App {
routeTransition(outlet) {
const routeAnimation = outlet.activatedRouteData['animation'] || {};
return routeAnimation['value'] || null;
}
}
Routes Setup
const routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: Home,
data: {
animation: { value: 'home' }
}
},
{ path: '**', component: NotFound }
];
Router Animations
export const routerAnimations = trigger('routerAnimations', [
transition('about <=> home', [
query(':enter, :leave', style({ position: 'fixed', width:'100%' })),
group([
query(':enter', [
style({ transform: 'translateX(100%)' }),
animate('0.5s ease-in-out', style({ transform: 'translateX(0%)' }))
]),
query(':leave', [
style({ transform: 'translateX(0%)' }),
animate('0.5s ease-in-out', style({ transform: 'translateX(100%)' }
]),
])
])
])
demo
Performance
Considerations
- Avoid unnecessary layout/repaint
- Use opacity, transform
- Hardware acceleration (avoid)
- transform: translateZ(0)
Saving Resources
.visible.advert {
will-change: transform;
}
.visible.advert:hover {
transform: scale(1.2);
}
Why use Animations?
Benefits
- Improved UX ✨
- Immersive interactions
- Better engagement
- User happiness 😃
Thanks!
Animations Workshop (v4.2+)
By Gerard Sans
Animations Workshop (v4.2+)
How we can use Angular to achieve complex Animations. We will cover Web Animations API and how we can use Angular together with field-tested animation techniques providing examples for CSS transitions/animations. We will also study browser compatibility and performance to achieve reliable and silky smooth animations. Let's bring our Angular skills to the awesome world of animations!
- 3,399