Louis Hoebregts
<svg>
<filter>
<feTurbulence baseFrequency="0.02" numOctaves="3" result="n" seed="0">
<animate attributeName="seed" from="1" to="9" dur="1s" repeatCount="indefinite" />
</feTurbulence>
<feDisplacementMap in="SourceGraphic" in2="n" scale="6" />
</filter>
</svg>
@keyframes spin {
to {
transform: rotate(1turn);
}
}
.eye {
transform-box: fill-box;
transform-origin: center;
animation: 1s spin linear infinite;
}
.eye.left {
animation-direction: reverse;
}
function render () {
requestAnimationFrame(render);
ctx.clearRect(0, 0, width, height);
spines.forEach(spine => {
const spine = spines[i];
spine.update();
spine.draw();
});
}
requestAnimationFrame(render);
@keyframes breathe {
0% {
transform: scale(1);
background: hotpink;
}
50% {
background: darkorange;
}
100% {
transform: scale(1.5);
background: greenyellow;
}
}
div {
animation: breathe 3s infinite alternate ease-in-out;
}
element.animate(
keyframes,
options
);
const keyframes = [
{
transform: 'scale(1)',
background: 'hotpink'
},
{
background: 'darkorange'
},
{
transform: 'scale(1.5)',
background: 'greenyellow'
}
];
const keyframes = [
{
background: 'hotpink'
},
{
background: 'darkorange'
},
{
transform: 'scale(1.5)',
background: 'greenyellow'
}
];
const keyframes = {
transform: ['scale(1)', 'scale(1.5)'],
background: ['hotpink', 'darkorange', 'greenyellow']
};
const keyframes = {
transform: ['scale(1.5)'],
background: ['hotpink', 'darkorange', 'greenyellow']
};
[{
background: 'orchid',
// offset: 0
}, {
background: 'darkorange',
offset: 0.8
}, {
background: 'greenyellow',
// offset: 1
}]
{
background: ['orchid', 'darkorange', 'greenyellow'],
offset: [0, 0.8]
}
@keyframes shades {
0% {
background: orchid;
}
80% {
background: darkorange;
}
100% {
background: greenyellow;
}
}
WAAPI
CSS
WAAPI
const options = {
duration: 3000,
iterations: Infinity,
direction: 'alternate',
easing: 'ease-in-out'
};
animation-duration: 2s, 2000ms;
duration: 3000
animation-fill-mode: forwards;
fill: 'forwards'
animation-timing-function: ease-out;
easing: 'ease-out'
animation-iteration-count: infinite;
iterations: Infinity
¯\_(ツ)_/¯
iterationStart: 1
const keyframes = {
transform: ['scale(1.5)'],
background: ['hotpink', 'darkorange', 'greenyellow']
};
const options = {
duration: 3000,
iterations: Infinity,
direction: 'alternate',
easing: 'ease-in-out'
};
document.querySelector('.box').animate(keyframes, options);
const element = document.querySelector('.box');
const keyframes = {
transform: ['scale(1.5)'],
background: ['hotpink', 'darkorange', 'greenyellow']
};
const options = {
duration: 3000,
iterations: Infinity,
direction: 'alternate',
easing: 'ease-in-out'
};
const effect = new KeyframeEffect(element, keyframes, options);
const animation = new Animation(effect);
animation.play();
// Solution 1
const animation = document.querySelector('.box').animate({
transform: ['scale(1.5)'],
background: ['hotpink', 'darkorange', 'greenyellow']
}, {
duration: 2000,
fill: 'forwards'
});
// Solution 2
const animation = new Animation(keyframeEffect);
document.querySelector('.pause').addEventListener('click', () => {
animation.pause();
});
document.querySelector('.play').addEventListener('click', () => {
animation.play();
});
animation.oncancel = () => console.log('Cancelled');
animation.onfinish = () => console.log('Finished');
animation.currentTime;
animation.playbackRate;
animation.playState; // Read only
<details>
<summary>Click to expand this details</summary>
<div class="content">
<p>
Lorem, ipsum dolor sit amet...
</p>
<img src="bear.jpg" alt="A brown bear in a river">
<p>
Facilis ducimus iure officia quos possimus...
</p>
</div>
</details>
details[open] .content {
animation: fade-in 0.6s ease-in-out;
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
class Dropdown {
constructor(el) {}
onClick() {
this.el.style.overflow = 'hidden';
this.el.open ? this.shrink() : this.open();
}
open() {
this.el.style.height = `${this.el.offsetHeight}px`;
requestAnimationFrame(() => this.expand());
}
expand() {
const startHeight = `${this.el.offsetHeight}px`;
const endHeight = `${this.summary.offsetHeight + this.content.offsetHeight}px`;
this.el.animate({
height: [startHeight, endHeight]
}, { duration: 300 })
.onfinish = () => this.onAnimationFinish();
}
onAnimationFinish() {
this.el.style.height = this.el.style.overflow = '';
}
}
const particle = document.createElement('span');
particle.classList.add('particle');
document.body.appendChild(particle);
const destinationX = e.clientX + (Math.random() - 0.5) * innerWidth;
const destinationY = e.clientY + (Math.random() - 0.8) * innerHeight;
particle.animate({
transform: [
`translate(${e.clientX}px, ${e.clientY}px)`,
`translate(${destinationX}px, ${destinationY}px)`
],
opacity: [1, 1, 0],
offset: [0, 0.7]
}, {
duration: 1000 + Math.random() * 1000,
easing: 'cubic-bezier(0, .9, .57, 1)',
delay: Math.random() * 200
})
.onfinish = () => particle.remove();
Vue.component("list-item", {
props: ["index", "text"],
template: `<li>
<span>{{ text }}</span>
<button @click='onDeleteClick($event, index)'>Remove</button>
</li>`,
methods: {
onDeleteClick: function (event, index) {
this.$el.animate({
height: [`${this.$el.offsetHeight}px`, "0px"]
}, {
duration: 400,
easing: "ease-out"
}).onfinish = () => app.list.splice(index, 1);
}
}
});
08.08.2020
if (document.body.animate) {
// WAAPI is supported by the browser
}
// WAAPI is not supported by the browser
if (!document.body.animate) return;
08.08.2020
const fadein = new KeyframeEffect(box,
{
opacity: [0, 1]
}, {
duration: 500,
easing: 'ease-out'
}
);
const slidein = new KeyframeEffect(box,
{
transform: ['translateY(-100vh)', 'translateY(0vh)'],
opacity: [0, 1]
}, {
duration: 500,
easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)'
}
);
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
new Animation(fadein, document.timeline).play();
} else {
new Animation(slidein, document.timeline).play();
}
const scrolltimeline = new ScrollTimeline({
source: document.documentElement,
timeRange: 2000,
startScrollOffset: '50vh',
endScrollOffset: '150vh'
});
new Animation(keyframeEffect, scrolltimeline).play();
Chrome & Edge behind flag - 08.08.2020
Bounce, Elastic,...
© Cacti illustrations from Freepik