Skip to main content

Animation

Animation Property

animation formal syntax:

  • animation-name.
  • animation-duration.
  • animation-timing-function: <easing-function>.
  • animation-delay: 支持负值.
  • animation-iteration-count:
    • infinite | <number> 执行次数.
    • 支持 0 与小数.
    • 不支持负值.
  • animation-direction:
    • normal: 0%->100% 方向.
    • reverse: 100%->0% 方向.
    • alternate/alternate-reverse: 不断交替方向.
  • animation-fill-mode: forwards/backwards/both.
  • animation-play-state: paused/running.
@media only screen and (prefers-reduced-motion: reduce) {
.element {
animation: none;
}
}

Animation Fill Mode

animation-fill-mode:

  • forwards: 动画结束后, 应用动画最后一帧属性值.
  • backwards: 动画开始前, 应用动画第一帧属性值.
  • both: 同时应用上述两种效果.
animation-directionanimation-iteration-countlast keyframe
normaleven or odd100%
reverseeven or odd0%
alternateeven0%
alternateodd100%
alternate-reverseeven100%
alternate-reverseodd0%
normal/alternate00%
reverse/alternate-reverse0100%
animation-directionfirst keyframe
normal/alternate0%
reverse/alternate-reverse100%

Animation Play State

利用 animation-paly-state 与 JavaScript 添加 .animate 类控制动画开始和停止.

div {
animation-play-state: paused;
}

:checked ~ div {
animation-play-state: running;
}
@media only screen and (prefers-reduced-motion: reduce) {
.to-animate {
animation: none;
}
}

.to-animate {
animation: animationName 1.5s linear;
animation-iteration-count: infinite;
animation-play-state: paused;
}

.animate {
animation-play-state: running;
}
element.classList.add('animate')
setTimeout(() => element.classList.remove('animate'), duration)

Animation Timeline

Implement scroll-driven animation with CSS animation-timeline:

  • scroll() timeline.
  • view() timeline.
@media not (prefers-reduced-motion) {
footer::after {
position: fixed;
inset-inline-start: 0;
bottom: 0;
width: 100%;
height: 1em;
content: '';
transform-origin: top left;
animation: grow-progress linear;
animation-timeline: scroll();
}

@keyframes grow-progress {
from {
transform: scaleX(0);
}

to {
transform: scaleX(1);
}
}
}
@media not (prefers-reduced-motion) {
img {
animation: slide-in;
animation-timeline: view();
animation-range: 0% 50%;
}

@keyframes slide-in {
0% {
opacity: 0;
transform: translateX(100%);
}

100% {
opacity: 1;
transform: translateX(0%);
}
}
}

Offset Animation

offset, animating an element along a defined path:

.path {
/* Offset position */
offset: auto;
offset: 10px 30px;
offset: none;

/* Offset path */
/* stylelint-disable-next-line function-no-unknown */
offset: ray(45deg closest-side);
offset: url('arc.svg');
offset: path('M 100 100 L 300 100 L 200 300 z');

/* Offset path with distance and/or rotation */
offset: url('circle.svg') 100px;
offset: url('circle.svg') 40%;
offset: url('circle.svg') 30deg;
offset: url('circle.svg') 50px 20deg;

/* Including offset anchor */
/* stylelint-disable-next-line function-no-unknown */
offset: ray(45deg closest-side) / 40px 20px;
offset: url('arc.svg') 2cm / 0.5cm 3cm;
offset: url('arc.svg') 30deg / 50px 100px;
}

Animation Patterns

Animation FLIP Pattern

  • First: 初始状态.
  • Last: 动画结束状态.
  • Invert: last 至 first 的 transform 属性.
  • Play: transition: transform .2s linear.
@media only screen and (prefers-reduced-motion: reduce) {
.scale-up {
transition: none;
}
}

/* first: scale(1), last: scale(1.2) */
.scale-up {
transform: scale(0.8);
transition: transform 0.2s linear;
}

.scale-up:hover,
.scale-up:focus {
transform: none;
}

Animation Bounce Cache Pattern

  • First -100.
  • Then +5/+20.
  • Finally 0.
  • 切换动画时, 需要先把之前的动画清除: 防止出现闪烁 Bug.

Animation Helper

  • opacity.
  • overflow: hidden.
  • transform: scale/translate.
  • transition.
  • animation-delay.
  • width/height
  • max-width/max-height.
  • margin.
  • border-*.
  • background.
  • background-position.
  • background with multiple gradient.
  • Single box-shadow
  • Multiple box-shadow.
  • *-clip-*.
  • mask-*.
  • filter.
  • backdrop-filter.
  • Pseudo element (::before/::after).
  • Pseudo class (:hover/:focus/:target).
  • Changing top/right/bottom/left of pseudo element can change animation start point: e.g. bottom: 0, right: 0 change width/height from 0 to 100%, size animation will start from bottom-right corner.
.animation-container {
z-index: -1;
overflow: hidden;
}
/* 直接动画 */
.div {
animation-name: name;
animation-duration: 1s;
animation-timing-function: cubic-bezier(0.42, 0, 0.58, 1);
animation-delay: 0.5s;
}

/* hover 后再播放动画, 高级化 transform + transition */
.div:hover,
.div:focus {
animation-name: name;
animation-duration: 1s;
animation-timing-function: cubic-bezier(0.42, 0, 0.58, 1);
animation-delay: 0.5s;
}

Animation API

DOM events:

  • animationiteration: triggered after each animation iteration.
  • animationend: triggered after an animation completes.
  • animationstart: triggered at the start of an animation.

GreenSock Library

TweenMax

TweenMax.fromTo(element, 1, { x: 0 }, { x: 100 })

TimelineMax

const tl = new TimelineMax()
tl.staggerFrom(
[
'#Cap_1 > g > path:nth-child(1)',
'#Cap_1 > circle:nth-child(7)',
'#Cap_1 > path:nth-child(6)',
'#Cap_1 > circle:nth-child(5)',
],
1,
{
scaleY: 0,
scaleX: 0,
transformOrigin: 'center',
ease: Bounce.easeOut,
stagger: 0.2,
}
)

Animation References