<main>
<div id="control"></div>
<div id="iterations"></div>
</main>
<p>This demo requires the Web Animations API and support for the <code>iterationComposite</code> property in the <code>Animation</code>'s effect options, such as Firefox Nightly 59+</p>
div {
width: var(--size);
height: var(--size);
border: 2vmin solid hsl(var(--hue,43), 95%, 54%);
border-radius: 30%;
transform: rotate(0deg) translateX(0vmin) translateZ(0vmin);
transform-origin: 50% 50%;
position: absolute;
opacity: 0;
}
#control {
--hue: 183;
}
main {
--size: 10vmin;
width: var(--size);
height: var(--size);
position: relative;
transform: translateZ(-400vmin);
transform-style: preserve-3d;
}
body {
perspective: 10vmin;
perspective-origin: 50% 50%;
}
/* Styles for explainer pieces: notes, body, button*/
body {
min-height: 100vh;
display: flex;
justify-content: space-around;
align-items: center;
overflow: hidden;
background: hsl(223, 40%, 12%);
color: #fafdff;
font-family: system-ui, -apple-system, 'Segoe UI', sans-serif;
perspective: 100vmax;
}
*, *::before, *::after {
box-sizing: border-box;
}
body > p {
position: absolute;
z-index: 1;
bottom: 0;
left: 0;
right: 0;
padding: 1rem;
text-align: center;
line-height: 1.35;
}
.supported body > p {
display: none;
}
const iterationComposite = document.getElementById('iterations');
const control = document.getElementById('control');
const iterations = 400;
const duration = 20;
const angle = 5;
const tx = .125;
const tz = 1;
const opacity = 1 / iterations;
if (control.animate) {
let animation = iterationComposite.animate([
{
transform: `rotate(${angle}deg) translateX(${tx}vmin) translateZ(${tz}vmin)`,
opacity: opacity,
offset: 1
}
], {
duration: duration,
direction: 'normal',
iterations: iterations,
easing: 'linear',
fill: 'forwards',
iterationComposite: 'accumulate'
});
animation.onfinish = () => {
animation.reverse();
};
let animationControl = control.animate([
{
transform: `rotate(${iterations * angle}deg) translateX(${iterations * tx}vmin) translateZ(${iterations * tz}vmin)`,
opacity: iterations * opacity,
offset: 1
}
], {
duration: duration * iterations,
direction: 'reverse',
iterations: 1,
easing: 'linear',
fill: 'both'
});
animationControl.onfinish = () => {
animationControl.reverse();
};
if (animation.effect && animation.effect.iterationComposite === 'accumulate') {
document.documentElement.classList.add('supported');
}
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.