Animation and Interaction principles
This training will be a quick overview of the basic principles of animation and how we can use them in our projects. Animators have been taking flat, 2D lines on paper and giving them life and intrigue for longer than the web has around. We can always learn a thing or two from them.
Rendering issues
Please note that this article was originally hosted and rendered using standard Markdown and has been converted to MDX, which does not allow for the same amount of HTML being rendered on the page. Until we fix or find a different rendering solution, the code has been changed to be visible on the page, but will require a copy/paste as well as the styles (found at the bottom of this page)
Why is it important?
Secondary Feedback
Animations and Interactions are a form of secondary feedback for the user. In the example below, which button do you think is more likely to work when clicked?
<div class="example">
*button hover example
<div class="exampleContent exCentered">
<button class="btnB">button</button>
<button class="btnG">button</button>
</div>
</div>
Do you remember back in the day when site’s took FOREVER to load? You would click a link, go grab a snack, maybe take a bathroom break, and come back just to find that it was frozen and wasn’t loading at all? Let’s avoid that.
::: tip QUESTION How are you suppsed to know if a static page is frozen? :cold_face:
Uncertainty = More Frustration! :::
Direction
Let’s face it, humans are all pretty easily distracted. If used properly, you can direct the attention of your users where you need them to look. In the example below, which button looks like it needs the most immediate attention?
<div class="example">*pulsating button example
<div class="exampleContent exCentered">
<button class="btnG">button</button>
<button class="btnG" id="btnPulse">button</button>
<button class="btnG">button</button>
</div>
</div>
Polish
Ever been to an airport thats still under construction? Elevators don’t work work, revolving doors are stuck, automatic soap despensers don’t detect your hand. You know, like SLC airport every time I’ve been for some reason. I mean it was still operational, I did get to my destination and back, but it lacked polish. Same goes for animations and interactions on your site.
The 12 Principles of Animation
Even though these were originally created for 2D hand drawn animation, they can still be used for the web as well. Try to imagine scenarios where each of these could be applied.
1. Squash and Stretch
<div class="example">*don't forget to change the transition origin to where the point of impact or force is being applied!
<div class="exampleContent exCenteredBtm">
<div class="circle" id="squash"></div>
<div class="circle" id="stretch"></div>
</div>
</div>
2. Anticipation
<div class="example">*wait for it....
<div class="exampleContent exCenteredBtm">
<div class="circle"></div>
</div>
</div>
3. Staging
<div class="example">*It can be hard to see whats happening with the circle turned away from the user
<div class="exampleContent exCenteredBtm">
<div class="circle" id="staging"></div>
</div>
</div>
4. Straight Ahead and Pose to Pose
<div class="example">*Straight ahead is similary to using Transform while Pose to Pose is like CSS Animations
<div class="exampleContent exCenteredBtm" id="p2p">
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
</div>
</div>
5. Followthrough and Overlapping
<div class="example">*too much speed = overshooting
<div class="exampleContent exCenteredBtm">
<div class="circle" id="followthrough"></div>
</div>
</div>
6. Slow in + Out
<div class="example">*In this example, the ball eases out as it goes up and eases in as it falls
<div class="exampleContent exCenteredBtm">
<div class="circle" id="slowin"></div>
</div>
</div>
7. Arc
<div class="example">*An easy way to attain a perfect arc is to wrap the bouncing object in a container, and then move the container.
<div class="exampleContent exCenteredBtm">
<div id="arc"><div class="circle" id="arcBall"></div></div>
</div>
</div>
8. Secondary Action
<div class="example">*notice as the ball hits the "ground", it squashes. That is a secondary action
<div class="exampleContent exCenteredBtm">
<div class="circle" id="secondaryAction"></div>
</div>
</div>
9. Timing
<div class="example">*REMEMBER, people are easily distracted
<div class="exampleContent exCenteredBtm">
<div class="circle" id="slowBounce"></div>
<div class="circle" id="goodBounce"></div>
</div>
</div>
10. Exageration
<div class="example">*Notice how the ball is being held in the air and stretched before finally descending like in old cartoons.
<div class="exampleContent exCenteredBtm">
<div class="circle" id="exageration"></div>
</div>
</div>
11. Solid Drawing
<div class="example">*well.. its solid I guess
<div class="exampleContent exCenteredBtm">
<div class="circle"></div>
</div>
</div>
12. Appeal
<div class="example">*This is a bit of a tough one to show. Just remember that if what you make looks good, but goes against one of the principles, keep with it. They're more like guidlines anyway.
</div>
Takeaway
If you want to throw out all of the previous information, at least just hold on to the following two principles:
<style>
:root {
--radius:4px;
--border:2px solid var(--c-border-dark);
--marginSmall:10px;
--marginMedium:20px;
--marginLarge:50px;
--marginXLarge:100px;
--marginXXLarge:150px;
--padding:10px 20px;
}
.example{
position: relative;
background:var(--c-bg-light);
height:180px;
width:50%;
min-width: 150px;
margin:var(--marginSmall) 0;
color: var(--c-text-lightest);
border-radius: var(--radius);
padding:var(--marginSmall)
}
.exampleContent {
box-sizing: border-box;
position: absolute;
padding:var(--marginSmall);
top: 0;
left: 0;
width: 100%;
height: 100%;
}
button {
background: var(--c-bg-light);
color: var(--c-text-light);
border: var(--border);
padding:.5em 1em;
}
.circle{
height: 40px;
width: 40px;
border-radius: 50%;
background: var(--c-brand);
}
.exCentered {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
}
.exCenteredBtm {
display: flex;
align-items: flex-end;
justify-content: center;
gap: 10px;
}
.btnG:hover {
background: var(--c-bg-lighter);
border-color: var(--c-border);
color: var(--c-text);
cursor: pointer;
}
#btnPulse {
outline: var(--border);
outline-offset: -2px;
animation: pulse 2000ms infinite ease-out;
}
#squash {
animation: squash 1s infinite ease-out;
transform-origin: center bottom;
}
#stretch {
animation: stretch 1s infinite ease-out;
transform-origin: center bottom;
animation-delay: 400ms;
}
#staging {
width:5px;
animation: squash 1s infinite ease-out;
transform-origin: center bottom;
}
#p2p .circle:nth-child(2) , #p2p .circle:nth-child(4) {
box-sizing: border-box;
margin-bottom: 58px;
transform:rotate(50deg) scaleX(.9) scaleY(1.1);
background: transparent;
border: var(--border);
opacity: 100%;
}
#p2p .circle:nth-child(4) {
transform: rotate(-60deg) scaleX(.9) scaleY(1.1);
opacity: 60%;
}
#p2p .circle:nth-child(3) {
margin-bottom: 75px;
box-sizing: border-box;
background: transparent;
opacity: 80%;
border: var(--border);
}
#p2p .circle:nth-child(5) {
transform: scaleX(1.2) scaleY(.8);
transform-origin: center bottom;
background: transparent;
opacity: 40%;
box-sizing: border-box;
border: var(--border);
}
#p2p .circle::after {
text-align: center;
display: block;
width: 100%;
position: relative;
top: 10px;
color: var(--c-text);
font-size: 12px;
}
#p2p .circle:nth-child(1)::after {
content: '0%';
}
#p2p .circle:nth-child(2)::after {
content: '25%';
transform:rotate(-50deg) scaleX(1) scaleY(1);
}
#p2p .circle:nth-child(3)::after {
content: '50%';
}
#p2p .circle:nth-child(4)::after {
transform:rotate(60deg) scaleX(1) scaleY(1);
content: '75%';
}
#p2p .circle:nth-child(5)::after {
content: '100%';
}
#followthrough {
transform: translate(-100px);
animation: followthrough 4s cubic-bezier(.13,1.48,.99,1.11) infinite;
}
#slowin, #arcBall, #secondaryAction {
animation: bounce 1s infinite;
transform-origin: center bottom;
}
#arc {
animation: arc 2s linear infinite;
transform-origin: center bottom;
}
#slowBounce {
animation: bounce 3s infinite;
transform-origin: center bottom;
}
#goodBounce {
animation: bounce 700ms infinite;
transform-origin: center bottom;
}
#exageration {
animation: bounceEXTRA 1s infinite;
}
/*=================ANIMATIONS==================*/
@keyframes pulse {
0% {outline-offset: -2px;outline-color:#2C6853ff;}
50% {outline-offset: 10px;outline-color:#2C685300}
100% {outline-offset: 10px;outline-color:#2C685300}
}
@keyframes squash {
0% {transform: scaleX(1) scaleY(1);}
25% {transform: scaleX(1.2) scaleY(.8);}
50% {transform: scaleX(1) scaleY(1);}
100% {transform: scaleX(1) scaleY(1);}
}
@keyframes stretch {
0% {transform: scaleX(1) scaleY(1);}
25% {transform: scaleX(.7) scaleY(1.3);}
50% {transform: scaleX(1) scaleY(1);}
100% {transform: scaleX(1) scaleY(1);}
}
@keyframes followthrough {
0% {transform: translate(-100px);}
20% {transform: translate(100px);}
100% {transform: translate(100px);}
}
@keyframes bounce {
0% {transform: translateY(0px);animation-timing-function: cubic-bezier(0,.53,.64,1.01);}
46% {transform: translateY(-80px) scaleX(1) scaleY(1);animation-timing-function: cubic-bezier(.48,.06,1,.51);}
92% {transform: translateY(0px) scaleX(1) scaleY(1);}
96% {transform: translateY(0px) scaleX(1.2) scaleY(.8);}
100% {transform: translateY(0px) scaleX(1) scaleY(1);}
}
@keyframes bounceEXTRA {
0% {transform: translateY(0px);animation-timing-function: cubic-bezier(0,1,.12,1.01);}
46% {transform: translateY(-80px) scaleX(1) scaleY(1);animation-timing-function: cubic-bezier(.48,.06,1,.51);}
92% {transform: translateY(0px) scaleX(.8) scaleY(1.2);}
96% {transform: translateY(0px) scaleX(1.2) scaleY(.8);}
100% {transform: translateY(0px) scaleX(1) scaleY(1);}
}
@keyframes arc {
0% {transform: translate(-50px);}
46% {transform: translate(50px);}
50% {transform: translate(50px);}
96% {transform: translate(-50px);}
100% {transform: translate(-50px);}
}
</style>