.filmstrip {
animation: slide 1s infinite steps(7);
}
@keyframes slide {
to { transform: translate(-700px); }
}
.filmstrip {
/* steps(7) = 7つの変化。最後の変化も含む。 */
animation: slide 1s infinite steps(7);
}
@keyframes slide {
to { transform: translate(-700px); }
}
.filmstrip {
animation: slide 1s infinite steps(6);
}
@keyframes slide {
to { transform: translate(-700px); }
}
.filmstrip {
/* steps(6) = steps(6, end) */
animation: slide 1s infinite steps(6);
}
@keyframes slide {
to { transform: translate(-700px); }
}
.filmstrip {
animation: slide 1s infinite steps(6, start);
}
@keyframes slide {
to { transform: translate(-700px); }
}
.filmstrip {
/* 新しい! jump-none! */
animation: slide 1s infinite steps(7, jump-none);
}
@keyframes slide {
to { transform: translate(-700px); }
}
jump-none
, jump-both
transitionrun
→ transitionが生成された 🆕
→ transitionend
を待ってもオッケー 🙆♂️
transitioncancel
→ 要素が消えた🗑️
(削除されたり、再生成されたり、
display:none
になったり)
→ transitionend
を待たない方が良い ❌
transitionstart
(animationstart
と同様)
animationcancel
(transitioncancel
と同様)
transitioncancel
たちanimationcancel
transitionstart
のみ
animationcancel
Element.animate
.
const uniqueKeyframesName = generateUuid();
document.styleSheets[0].insertRule(
`@keyframes ${uniqueKeyframesName} {
from { transform: scale(0) }
95% { transform: scale(${fullSize}) }
to { transform: scale(0) }
}`
);
star.style.animation =
`${uniqueKeyframesName} ${duration}ms ` +
`${delay}ms infinite`;
// 要素がなくなったら、@keyframesも削除してね!
transitionrun
, transitioncancel
など
Element.animate()
を利用して…
star.animate(
[
{ transform: 'scale(0)' },
{ transform: `scale(${fullSize})`, offset: 0.95 },
{ transform: 'scale(0)' },
],
{ easing, duration, delay, iterations: Infinity }
);
Element.animate()
を利用して…
const starAnimation = star.animate(
[
{ transform: 'scale(0)' },
{ transform: `scale(${fullSize})`, offset: 0.95 },
{ transform: 'scale(0)' },
],
{ easing, duration, delay, iterations: Infinity }
);
// starAnimation.reverse();
// starAnimation.cancel();
// starAnimation.updatePlaybackRate(0.5);
starAnimation.finished.then(() => { ... });
Element.animate()
.body, .head {
animation-timing-function: steps(4);
}
.head {
animation-timing-function: steps(4);
}
@keyframes drop-head {
60% { transform: rotate(45deg) }
}
@keyframes drop-head {
0% {
transform: none;
animation-timing-function: steps(4);
}
50% {
transform: rotate(45deg);
animation-timing-function: steps(4);
}
100% { transform: none; }
}
head.animate(
{
// 暗黙の0%/100%キーフレームの機能は
// まだChrome/Firefoxのリリース版に入っていない
transform: ['none', 'rotate(60deg)', 'none'],
offset: [0, 0.6, 1],
},
{
duration: 2000,
iterations: Infinite,
easing: 'steps(4)'
}
);
Element.animate
.
head.animate(
{
transform: ['none', 'rotate(60deg)', 'none'],
offset: [0, 0.6, 1],
easing: 'ease-in',
},
{
duration: 2000,
iterations: Infinite,
easing: 'steps(4)'
}
);
Element.animate
.
Element.getAnimations()
document.addEventListener('transitionrun', evt => {
if (evt.propertyName !== 'transform') {
return;
}
const transition = evt.target
.getAnimations()
.find(animation => animation.transitionProperty === 'transform');
const keyframes = transition.effect.getKeyframes();
const distance = calculateDistance(
keyframes[0].transform,
keyframes[1].transform
);
// 700px/秒で動かす
const duration = (distance / 700) * 1000;
transition.effect.updateTiming({ duration });
// 参考: `transition.updatePlaybackRate()`も良い
});
Element.getAnimations
.
Element.getAnimations
to return
transform transition endpoints.
Element.getAnimations()
CSSTransition.setKeyframes()
document.addEventListener('transitionrun', evt => {
if (evt.propertyName !== 'fill') {
return;
}
const transition = evt.target
.getAnimations()
.find(animation => animation.transitionProperty === 'fill');
const keyframes = transition.effect.getKeyframes();
const hslKeyframes = generateHslKeyframes(
keyframes[0].fill,
keyframes[1].fill
);
transition.effect.setKeyframes(hslKeyframes);
});
Element.getAnimations
.
setKeyframes
on
transitions.
CSSTransition.setKeyframes() (Element.getAnimations)
offset-path
.
offset-path
.goose {
offset-path: path('M100 100...');
animation: fly 10s linear infinite;
}
@keyframes fly {
to { offset-distance: 100%; }
}
offset-path
offset-anchor
は設定で無効)
offset-anchor
は設定で無効)
transform
and opacity
offset-path
.
prefers-reduced-motion: reduce | no-preference
div {
animation: ...
transition: ...
}
@media (prefers-reduced-motion: reduce) {
* {
animation-name: none !important;
transition-property: none !important;
/*
* 例えばtransitionイベントが必要なら…
* transition-duration: 0.01s !important;
* transition-delay: 0s !important;
*/
}
}
// ブラウザー対応を確認
if (!('animate' in elem)) {
return;
}
// ユーザー対応を確認
if (matchMedia('(prefers-reduced-motion)').matches) {
return;
}
// アニメーションしよう~
prefers-reduced-motion
jump-none
transitioncancel
Element.animate
Element.animate
Element.getAnimations
Element.getAnimations
offset-path
prefers-reduced-motion