Optimize animations and transitions

will-change is apparently not enough to run GPU-enabled animations, use translateZ on top of it
This commit is contained in:
2020-04-09 20:23:24 +02:00
parent 7a44d5b0ed
commit be0f4c8b59
16 changed files with 75 additions and 43 deletions

View File

@@ -16,7 +16,7 @@
"serve": "node server/server.js" "serve": "node server/server.js"
}, },
"dependencies": { "dependencies": {
"animejs": "^3.1.0", "animejs": "^3.2.0",
"compression": "^1.7.4", "compression": "^1.7.4",
"imagesloaded": "^4.1.4", "imagesloaded": "^4.1.4",
"lazysizes": "^5.2.0", "lazysizes": "^5.2.0",

8
pnpm-lock.yaml generated
View File

@@ -1,5 +1,5 @@
dependencies: dependencies:
animejs: 3.1.0 animejs: 3.2.0
compression: 1.7.4 compression: 1.7.4
imagesloaded: 4.1.4 imagesloaded: 4.1.4
lazysizes: 5.2.0 lazysizes: 5.2.0
@@ -1043,10 +1043,10 @@ packages:
node: '>=0.4.2' node: '>=0.4.2'
resolution: resolution:
integrity: sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= integrity: sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=
/animejs/3.1.0: /animejs/3.2.0:
dev: false dev: false
resolution: resolution:
integrity: sha512-BjnCroPPQPEAngT0M89pz9TBcOGgOFLnVoq3+jV2upl4rn60k57/AXvESTnuILsNgOEjGuhMEOMp7IlQzk40kA== integrity: sha512-zhtGl5cS0G2f5DfciMO8uwWpnx06nfFnHlXYYXHBazHep1Lyd6kEtBQP+9hpYKE0dBZjIigHp9VpMO95ZfXQJQ==
/ansi-escapes/4.3.1: /ansi-escapes/4.3.1:
dependencies: dependencies:
type-fest: 0.11.0 type-fest: 0.11.0
@@ -4872,7 +4872,7 @@ specifiers:
'@rollup/plugin-commonjs': ^11.0.2 '@rollup/plugin-commonjs': ^11.0.2
'@rollup/plugin-node-resolve': ^7.1.1 '@rollup/plugin-node-resolve': ^7.1.1
'@rollup/plugin-replace': ^2.3.1 '@rollup/plugin-replace': ^2.3.1
animejs: ^3.1.0 animejs: ^3.2.0
autoprefixer: ^9.7.6 autoprefixer: ^9.7.6
babel-plugin-module-resolver: ^4.0.0 babel-plugin-module-resolver: ^4.0.0
compression: ^1.7.4 compression: ^1.7.4

View File

@@ -18,6 +18,7 @@ export const animateIn = scope => {
tl.add({ tl.add({
targets: scope, targets: scope,
translateY: [32, 0], translateY: [32, 0],
translateZ: [0, 0],
opacity: [0, 1], opacity: [0, 1],
complete: event => event.animatables[0].target.removeAttribute('style') complete: event => event.animatables[0].target.removeAttribute('style')
}) })
@@ -25,7 +26,8 @@ export const animateIn = scope => {
// Photo: Active // Photo: Active
tl.add({ tl.add({
targets: scope.querySelector('.is-active picture'), targets: scope.querySelector('.is-active picture'),
translateY: [8, 0] translateY: [8, 0],
translateZ: [0, 0]
}, 100) }, 100)
// Photo: Prev // Photo: Prev
@@ -33,6 +35,7 @@ export const animateIn = scope => {
targets: scope.querySelector('.is-prev picture'), targets: scope.querySelector('.is-prev picture'),
translateY: [8, 0], translateY: [8, 0],
translateX: [64, 0], translateX: [64, 0],
translateZ: [0, 0],
rotate: window.innerWidth >= 768 ? [-2, 0] : [0, 0] rotate: window.innerWidth >= 768 ? [-2, 0] : [0, 0]
}, 100) }, 100)
@@ -41,6 +44,7 @@ export const animateIn = scope => {
targets: scope.querySelector('.is-next picture'), targets: scope.querySelector('.is-next picture'),
translateY: [8, 0], translateY: [8, 0],
translateX: [-48, 0], translateX: [-48, 0],
translateZ: [0, 0],
rotate: window.innerWidth >= 768 ? [2, 0] : [0, 0] rotate: window.innerWidth >= 768 ? [2, 0] : [0, 0]
}, 100) }, 100)

View File

@@ -24,19 +24,22 @@ export const animateIn = scope => {
targets: location.querySelector('img'), targets: location.querySelector('img'),
scale: [1.3, 1], scale: [1.3, 1],
opacity: [0, 1], opacity: [0, 1],
translateZ: [0, 0],
duration: 1800 duration: 1800
}, 100) }, 100)
// Name // Name
tl.add({ tl.add({
targets: location.querySelector('h3'), targets: location.querySelector('h3'),
translateY: ['100%', 0] translateY: ['100%', 0],
translateZ: [0, 0],
}, 150) }, 150)
// Country // Country
tl.add({ tl.add({
targets: location.querySelector('p'), targets: location.querySelector('p'),
translateY: ['100%', 0] translateY: ['100%', 0],
translateZ: [0, 0]
}, 200) }, 200)
// Scroll reveal // Scroll reveal

View File

@@ -18,6 +18,7 @@ export const animateIn = scope => {
tlLocation.add({ tlLocation.add({
targets: scope.querySelectorAll('.photo__location .line span'), targets: scope.querySelectorAll('.photo__location .line span'),
translateY: ['100%', 0], translateY: ['100%', 0],
translateZ: [0, 0],
delay: anime.stagger(120) delay: anime.stagger(120)
}, 200) }, 200)
// Description // Description
@@ -48,7 +49,8 @@ export const animateIn = scope => {
}, 50) }, 50)
photoReveal.add({ photoReveal.add({
targets: scope.querySelector('.photo__picture img'), targets: scope.querySelector('.photo__picture img'),
scale: [1.12, 1] scale: [1.12, 1],
translateZ: [0, 0]
}, 50) }, 50)
// Show photo when image is loaded // Show photo when image is loaded
@@ -67,8 +69,8 @@ export const animateIn = scope => {
const numberPallax = anime({ const numberPallax = anime({
targets: number.querySelector('span'), targets: number.querySelector('span'),
translateY: (window.innerWidth <= 768) ? ['0%', '20%'] : ['-20%', '20%'], translateY: (window.innerWidth <= 768) ? ['0%', '20%'] : ['-20%', '20%'],
duration: 2000,
easing: 'linear', easing: 'linear',
duration: 2000,
autoplay: false autoplay: false
}) })
const numberPallaxAnime = () => parallaxAnime(number, numberPallax) const numberPallaxAnime = () => parallaxAnime(number, numberPallax)

View File

@@ -11,6 +11,7 @@ export const animateIn = (scope, init) => {
const letters = anime({ const letters = anime({
targets: scope.querySelectorAll('span, em span'), targets: scope.querySelectorAll('span, em span'),
translateY: ['100%', 0], translateY: ['100%', 0],
translateZ: [0, 0],
easing: 'easeOutQuart', easing: 'easeOutQuart',
duration: 1000, duration: 1000,
delay: anime.stagger(40, { start: init ? 0 : animDelay }), delay: anime.stagger(40, { start: init ? 0 : animDelay }),

View File

@@ -12,15 +12,17 @@ export const animateIn = () => {
const titleHouses = anime({ const titleHouses = anime({
targets: document.querySelectorAll('#title-houses span'), targets: document.querySelectorAll('#title-houses span'),
translateY: ['-70%', 0], translateY: ['-70%', 0],
translateZ: [0, 0],
easing: 'easeOutQuart',
delay: anime.stagger(80, { start: animDelay }), delay: anime.stagger(80, { start: animDelay }),
duration: animDuration, duration: animDuration
easing: 'easeOutQuart'
}) })
// Parallax on scroll // Parallax on scroll
const translate = anime({ const translate = anime({
targets: '#title-houses', targets: '#title-houses',
translateX: ['7%', '-15%'], translateX: ['7%', '-15%'],
translateZ: [0, 0],
easing: 'linear', easing: 'linear',
duration: animDuration, duration: animDuration,
autoplay: false autoplay: false
@@ -33,6 +35,7 @@ export const animateIn = () => {
targets: document.getElementById('intro-description').querySelectorAll('p, a'), targets: document.getElementById('intro-description').querySelectorAll('p, a'),
opacity: [0, 1], opacity: [0, 1],
translateY: [8, 0], translateY: [8, 0],
translateZ: [0, 0],
easing: 'easeOutQuart', easing: 'easeOutQuart',
duration: animDuration, duration: animDuration,
delay: anime.stagger(200, { start: animDelay + 200 }) delay: anime.stagger(200, { start: animDelay + 200 })
@@ -43,6 +46,7 @@ export const animateIn = () => {
const titleOfReveal = anime({ const titleOfReveal = anime({
targets: titleOf.querySelectorAll('span'), targets: titleOf.querySelectorAll('span'),
translateY: ['100%', 0], translateY: ['100%', 0],
translateZ: [0, 0],
easing: 'easeOutQuart', easing: 'easeOutQuart',
delay: anime.stagger(70), delay: anime.stagger(70),
duration: animDuration, duration: animDuration,
@@ -59,6 +63,7 @@ export const animateIn = () => {
const titleWorldReveal = anime({ const titleWorldReveal = anime({
targets: titleWorld.querySelectorAll('span'), targets: titleWorld.querySelectorAll('span'),
translateY: ['100%', 0], translateY: ['100%', 0],
translateZ: [0, 0],
easing: 'easeOutQuart', easing: 'easeOutQuart',
delay: anime.stagger(70), delay: anime.stagger(70),
duration: animDuration, duration: animDuration,
@@ -67,6 +72,7 @@ export const animateIn = () => {
const titleWorldParallax = anime({ const titleWorldParallax = anime({
targets: titleWorld, targets: titleWorld,
translateX: ['5%', '-3%'], translateX: ['5%', '-3%'],
translateZ: [0, 0],
easing: 'linear', easing: 'linear',
duration: animDuration, duration: animDuration,
autoplay: false autoplay: false

View File

@@ -8,13 +8,24 @@ import { animDuration, animDelay } from 'utils/store'
export const animateIn = () => { export const animateIn = () => {
const tl = anime.timeline({ const tl = anime.timeline({
easing: 'easeOutQuart', easing: 'easeOutQuart',
duration: animDuration duration: animDuration,
delay: animDelay
}) })
// Simple slide and fade on each part of the page // Simple slide and fade on each part of the page
tl.add({ tl.add({
targets: document.querySelectorAll('.page__part'), targets: document.querySelectorAll('.page__part'),
opacity: [0, 1], opacity: [0, 1],
translateY: [8, 0], translateY: [8, 0],
delay: anime.stagger(160, { start: animDelay }) translateZ: [0, 0],
delay: anime.stagger(160)
}) })
// Globe
tl.add({
targets: document.querySelector('.globe'),
opacity: [0, 1],
translateY: ['5%', 0],
translateZ: [0, 0]
}, 200)
} }

View File

@@ -15,7 +15,8 @@ export const animateIn = () => {
// Title: Houses // Title: Houses
tl.add({ tl.add({
targets: '.place__title_houses', targets: '.place__title_houses',
translateY: ['150%', 0] translateY: ['150%', 0],
translateZ: [0, 0]
}) })
// Title: Of // Title: Of
tl.add({ tl.add({
@@ -25,7 +26,8 @@ export const animateIn = () => {
// Title: Place name // Title: Place name
tl.add({ tl.add({
targets: '.place__title_name', targets: '.place__title_name',
translateY: ['150%', 0] translateY: ['150%', 0],
translateZ: [0, 0]
}, 150) }, 150)
// Switcher link // Switcher link
@@ -46,6 +48,7 @@ export const animateIn = () => {
tl.add({ tl.add({
targets: '.place__description', targets: '.place__description',
opacity: [0, 1], opacity: [0, 1],
translateY: [24, 0] translateY: [24, 0],
translateZ: [0, 0]
}, 450) }, 450)
} }

View File

@@ -17,7 +17,8 @@ export const animateIn = () => {
tl.add({ tl.add({
targets: viewer.querySelector('.carousel .wrap'), targets: viewer.querySelector('.carousel .wrap'),
opacity: [0, 1], opacity: [0, 1],
translateY: ['-4%', 0] translateY: ['-4%', 0],
translateZ: [0, 0]
}) })
// Carousel: Number // Carousel: Number
@@ -31,6 +32,7 @@ export const animateIn = () => {
tl.add({ tl.add({
targets: viewer.querySelectorAll('.carousel__dots'), targets: viewer.querySelectorAll('.carousel__dots'),
translateY: [16, 0], translateY: [16, 0],
translateZ: [0, 0],
opacity: [0, 1] opacity: [0, 1]
}, 150) }, 150)
@@ -38,8 +40,8 @@ export const animateIn = () => {
tl.add({ tl.add({
targets: viewer.querySelectorAll('.tip, .viewer__buttons a'), targets: viewer.querySelectorAll('.tip, .viewer__buttons a'),
translateY: [-32, 0], translateY: [-32, 0],
translateZ: [0, 0],
opacity: [0, 1], opacity: [0, 1],
delay: anime.stagger(120), delay: anime.stagger(120),
}, 400) }, 400)
} }

View File

@@ -38,7 +38,7 @@
<div class="counter {className}" bind:this={counter}> <div class="counter {className}" bind:this={counter}>
{#each digits as digit} {#each digits as digit}
<div class="counter__column" style="transform: translateY(-{digit}0%);"> <div class="counter__column" style="transform: translateY(-{digit}0%) translateZ(0);">
{#each numbers as number} {#each numbers as number}
<span>{number}</span> <span>{number}</span>
{/each} {/each}

View File

@@ -45,7 +45,7 @@
> >
<div class="pagination__info">page</div> <div class="pagination__info">page</div>
<div class="pagination__numbers"> <div class="pagination__numbers">
<div class="scroll" style="transform: translateY(-{pageTranslate}%);"> <div class="scroll" style="transform: translateY(-{pageTranslate}%) translateZ(0);">
{#each pagesArray as page} {#each pagesArray as page}
<span>{page}</span> <span>{page}</span>
{/each} {/each}

View File

@@ -65,7 +65,7 @@
&:after { &:after {
opacity: 1; opacity: 1;
transform: translate(-50%, -50%) scale(1); transform: scale(1) translate(-50%, -50%);
} }
} }

View File

@@ -63,7 +63,8 @@
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
transform: scale($scale); box-shadow: 0 pxVW(15) pxVW(60) rgba(#000, 0.3);
transform: scale($scale) translateZ(0);
transition: transform $duration $ease-quart, opacity ($duration / 2) $ease-quart; transition: transform $duration $ease-quart, opacity ($duration / 2) $ease-quart;
pointer-events: none; pointer-events: none;
@extend %willchange; @extend %willchange;
@@ -72,7 +73,7 @@
&.is-active { &.is-active {
opacity: 1; opacity: 1;
z-index: 10; z-index: 10;
transform: scale(1); transform: scale(1) translateZ(0);
pointer-events: auto; pointer-events: auto;
img { img {
@@ -99,32 +100,32 @@
// Previous photo // Previous photo
&.is-prev { &.is-prev {
z-index: 9; z-index: 9;
transform: translate(-40%, 0) scale(0.85); transform: translate(-40%, 0) scale(0.85) translateZ(0);
@include breakpoint (sm) { @include breakpoint (sm) {
z-index: 8; z-index: 8;
transform: translate(-$distance, -1%) rotate(-$angle) scale($scale); transform: translate(-$distance, -1%) rotate(-$angle) scale($scale) translateZ(0);
} }
// Hover // Hover
&.hover { &.hover {
transform: translate(-$distanceHover, -1%) rotate(-$angleHover) scale($scale); transform: translate(-$distanceHover, -1%) rotate(-$angleHover) scale($scale) translateZ(0);
} }
} }
// Next photo // Next photo
&.is-next { &.is-next {
z-index: 8; z-index: 8;
transform: translate(40%, 0) scale(0.85); transform: translate(40%, 0) scale(0.85) translateZ(0);
@include breakpoint (sm) { @include breakpoint (sm) {
z-index: 9; z-index: 9;
transform: translate($distance, -1%) rotate($angle) scale($scale); transform: translate($distance, -1%) rotate($angle) scale($scale) translateZ(0);
} }
// Hover // Hover
&.hover { &.hover {
transform: translate($distanceHover, -1%) rotate($angleHover) scale($scale); transform: translate($distanceHover, -1%) rotate($angleHover) scale($scale) translateZ(0);
} }
} }
} }
@@ -136,7 +137,6 @@
overflow: hidden; overflow: hidden;
width: 100%; width: 100%;
height: 100%; height: 100%;
box-shadow: 0 pxVW(15) pxVW(60) rgba(#000, 0.3);
@extend %willchange; @extend %willchange;
@include breakpoint (sm) { @include breakpoint (sm) {
@@ -271,15 +271,15 @@
// States // States
&.is-prev { &.is-prev {
transform: translateY(-$distance); transform: translateY(-$distance) translateZ(0);
} }
&.is-active { &.is-active {
transform: translateY(0); transform: translateY(0) translateZ(0);
opacity: 1; opacity: 1;
pointer-events: auto; pointer-events: auto;
} }
&.is-next { &.is-next {
transform: translateY($distance); transform: translateY($distance) translateZ(0);
} }
} }
@@ -311,18 +311,18 @@
// Active // Active
&.active button { &.active button {
background-color: $color-secondary; background-color: $color-secondary;
transform: scale(1.25); transform: scale(1.25) translateZ(0);
} }
// Small dot // Small dot
&.small button { &.small button {
transform: scale(0.6); transform: scale(0.6) translateZ(0);
opacity: 0.5; opacity: 0.5;
} }
// Hidden // Hidden
&.hidden { &.hidden {
padding: 0; padding: 0;
transform: scale(0); transform: scale(0) translateZ(0);
opacity: 0; opacity: 0;
width: 0; width: 0;
height: 0; height: 0;

View File

@@ -49,13 +49,13 @@
display: flex; display: flex;
justify-content: center; justify-content: center;
opacity: 0; opacity: 0;
transform: scale(1.1) translateY(24px); transform: scale(1.1) translateY(24px) translateZ(0);
transition: transform 0.8s $ease-quart, opacity 0.8s $ease-quart; transition: transform 0.8s $ease-quart, opacity 0.8s $ease-quart;
// Visible state // Visible state
&.is-visible { &.is-visible {
opacity: 1; opacity: 1;
transform: scale(1) translateY(0); transform: scale(1) translateY(0) translateZ(0);
} }
} }
@@ -66,7 +66,7 @@
top: 50%; top: 50%;
left: 50%; left: 50%;
opacity: 1; opacity: 1;
transform: translate(-50%, -50%); transform: translate(-50%, -50%) translateZ(0);
transform-origin: 50% 50%; transform-origin: 50% 50%;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -79,7 +79,7 @@
// Hidden state // Hidden state
&.is-hidden { &.is-hidden {
transform: scale(1.05) translate(-50%, -50%); transform: scale(1.05) translate(-50%, -50%) translateZ(0);
opacity: 0; opacity: 0;
} }
} }

View File

@@ -57,7 +57,7 @@
.scroll { .scroll {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
transform: translate(0, 0); transform: translate(0, 0) translateZ(0);
text-align: right; text-align: right;
line-height: 0.85; line-height: 0.85;
transition: transform 325ms $ease-cubic; transition: transform 325ms $ease-cubic;
@@ -70,7 +70,7 @@
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -72%); transform: translate(-50%, -72%) translateZ(0);
font-family: $font-serif; font-family: $font-serif;
font-size: rem(18px); font-size: rem(18px);
color: $color-secondary-bright; color: $color-secondary-bright;