Gerard Sans
@gerardsans
Gerard Sans
@gerardsans
SANS
GERARD
Spoken at 111 events in 27 countries
900
1.6K
DURATION
opacity: 0;
opacity: 1;
PROPERTY
transition: opacity 1s ease-in 1s;
DURATION
TIMING
DELAY
<div class="container">
<div class="circle base elastic"></div>
</div>
.circle {
border-radius: 50%;
position: absolute; opacity:0;
will-change: opacity, transform;
}
.base {
transition: opacity 1s ease,
transform 1s ease;
}
.elastic {
transition-timing-function:
cubic-bezier(.8,-0.6,0.2,1.5);
}
.container:hover .circle {
transform: translateX(80px);
opacity:1;
}
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
DURATION
0%
100%
KEYFRAMES
NAME
animation: fade 1s 1s infinite linear;
DURATION
DELAY
ITERATIONS
TIMING
<div class="circle base elastic"></div>
.base {
animation: fade 2s infinite;
}
@keyframes fade {
0% {
transform: translateX(0px);
opacity: 0;
}
40%, 60% {
transform: translateX(80px);
opacity: 1;
}
100% {
transform: translateX(0px);
opacity: 0;
}
}
60 FPS
Time
16.66ms
16.66ms
16.66ms
1000/60ms
paint
frame
paint
frame
paint
frame
😃
paint
frame
paint
frame
60 FPS
Time
16.66ms
16.66ms
16.66ms
😱
Move
transform: translateX(10px);
Resize
transform: scale(0.5);
Rotate
transform: rotate(1turn);
Fade
opacity: 0;
<div class="circle base elastic"></div>
.base {
animation: move 2s infinite;
}
.elastic {
animation-timing-function:
cubic-bezier(.8,-0.6,0.2,1.5);
}
@keyframes move {
0% {
transform: translateX(-250px);
}
40%, 60% {
transform: translateX(50px);
}
100% {
transform: translateX(250px);
}
}
<div class="square base linear"></div>
.base {
animation: spin 2s infinite;
}
.linear {
animation-timing-function: linear;
}
@keyframes spin {
to {
transform: rotate(1turn);
}
}
<div class="circle base"></div>
.base {
animation: size 2s infinite;
}
@keyframes size {
0%, 40%, 100% {
transform: scale(1);
}
25%, 60% {
transform: scale(1.1);
}
}
fadeIn
fadeOut
TRANSITIONS
STATE
STATE
fadeIn => fadeOut
fadeOut => fadeIn
opacity: 1
opacity: 0
animate('400ms linear')
animate('400ms linear')
fadeOut <=> fadeIn
animate('400ms linear')
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 })),
transition('fadeIn <=> fadeOut', animate('400ms linear'))
]);
void
*
void => *
STATE
STATE
:enter
scale(1)
opacity 1
scale(0.5)
opacity 0
*
void
* => void
STATE
STATE
:leave
scale(0.5)
opacity 0
scale(1)
opacity 1
sequence
group
time
class="container"
class="item"
class="item"
query(selector)
query('.item')
class="container"
class="item"
class="item"
query('.item:enter')
class="container"
class="item"
class="item"
class="item"
added
animateChild
time
time
Builder
`(${x}, ${y})`
(100, 50)
Player
Template
1
2
(100, 50)
3
build()
play()
import {AnimationBuilder} from "@angular/animations";
export class MyComponent {
constructor(
private elem: ElementRef,
private builder: AnimationBuilder
) {
const player = this.playerMoveTo({ x: 100, y: 100 });
player.play();
}
playerMoveTo(to) {
const moveAnimation = this.builder.build([
animate('1s', style({ transform: `translate(${x}px, ${y}px)` }))
]);
return moveAnimation.create(this.elem.nativeElement
, {params: { x: to.x, y: to.y }});
}
}
constructor(
private elem: ElementRef
) {
// find out center
this.mx = elem.nativeElement.offsetWidth/2;
this.my = elem.nativeElement.offsetHeight/2;
}
ngOnInit() {
const mouseMove$ = fromEvent(document, 'mousemove')
.pipe(map(e => ({ x: e.pageX, y: e.pageY })));
mouseMove$.subscribe({
next: e => {
this.lastPosition = { x: e.x-this.mx, y: e.y-this.my };
const player = this.playerMoveTo(this.lastPosition);
player.play();
}
})
}