Gerard Sans | Axiom 🇬🇧 PRO
Founder of Axiom Masterclass, professional trainings // Forging skills for the new era of AI. GDE in AI, Cloud & Angular. Building London's tech & art nexus @nextai_london. Speaker | MC | Trainer.
slides.com/gerardsans | @gerardsans
Text
850
950
Angular In Flip Flops
source: blog
SELECTOR
a.active:hover {
color: #333;
}
PROPERTY
VALUE
DECLARATION
:hover
:link
:active
:target
:not(selector)
:focus
::first-letter
::first-line
::before
::after
::selection
Element style
Element id
class/attribute selectors
element selectors
last CSS rule wins
source: blog
source: blog
<html>
<head>
<script src="https://unpkg.com/web-animations-js@2.2.5"></script>
...
</head>
<body>
<my-app>
loading...
</my-app>
</body>
</html>
npm install web-animations-js --save
// src/polyfills.ts
import 'web-animations-js';DURATION
START
END
Not all CSS properties are animatable (list)
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
PROPERTY
transition: color 5s ease-in 1s;
DURATION
TIMING
DELAY
DURATION
0%
100%
KEYFRAMES
NAME
animation: fade 5s 1s infinite linear;
DURATION
DELAY
ITERATIONS
TIMING
@keyframes fade {
0% { opacity: 1; }
100% { opacity: 0; }
}
@keyframes fade {
from { opacity: 1; }
to { opacity: 0; }
}
fadeIn
fadeOut
TRANSITIONS
STATE
STATE
fadeIn => fadeOut
fadeOut => fadeIn
fadeIn <=> fadeOut
void
*
void => * :enter
* => void :leave
void <=> *
STATE
STATE
// 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)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';
}
}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'))
]);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'))
])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})
])
))
])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) { }
} $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)
}
export const revealGroup = trigger('revealGroup', [
transition(':enter', [
query('*', style({ opacity: 0 })),
group([
query('*', animate(2000, style({ opacity: 1 })))
])
])
]);export const revealGroup = trigger('revealGroup', [
transition(':enter', [
query('*', style({ opacity: 0 })),
sequence([
query('*', animate(2000, style({ opacity: 1 })))
query('*', animate(1000, style({ color: 'red' })))
])
])
]);export const revealStagger = trigger('revealStagger', [
transition(':enter', [
query('*', style({ opacity: 0 })),
query('*', stagger(1000, [
animate(2000, style({ opacity: 1 }))
])
)
])
]);export const reveal = trigger('reveal', [
transition(':enter', [
query('@fade', [
animateChild()
]),
query('@*', [
animateChild()
]),
])
]);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;
}
}const routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: Home,
data: {
animation: { value: 'home' }
}
},
{ path: '**', component: NotFound }
];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%)' }
]),
])
])
]).visible.advert {
will-change: transform;
}
.visible.advert:hover {
transform: scale(1.2);
}
By Gerard Sans | Axiom 🇬🇧
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!
Founder of Axiom Masterclass, professional trainings // Forging skills for the new era of AI. GDE in AI, Cloud & Angular. Building London's tech & art nexus @nextai_london. Speaker | MC | Trainer.