CSS Animations
Accessibility
Remove animations for people who suffer from motion sickness.
Apply when no preferences set (default):
@media (prefers-reduced-motion: no-preference) {
.animated {
transition: transform 300ms;
}
}
Or override:
@media (prefers-reduced-motion: reduce) {
.animated {
transition: none;
}
}
Or with JS:
const prefersReducedMotion = !window.matchMedia(
'(prefers-reduced-motion: no-preference)'
).matches
transform
With transform, %
are based on the element's size, transform: translateX(calc(100% + 1px))
translates right by exactly its size + 1px.
Trick to place à close button above a card:
.close-btn {
position: absolute;
top: 0;
right: 0;
transform: translateY(-100%);
}
It avoids messing with the card placement. Place it top right, and translate it above the card.
transitions
Website with various transition animations https://easings.net/ (opens in a new tab)
js free hover navigation menus
A common issue is to:
- hover a menu item
- a list appears
- the mouse loses hover when trying to reach the list
- the list disapears before we can reach the item 🥲
Fix: Use transition-delay
, to make the dropdown last a bit longer.
.menu-list {
opacity: 0;
transition: opacity 400ms;
transition-delay: 300ms;
}
.menu-item:hover .menu-list {
opacity: 1;
transition: opacity 100ms;
transition-delay: 0ms;
}
flicker hover glitch
- a button moves up on hover
- it is no longer hovered
- it comes back down
- gets hovered
- goes up
- ... it flickers
Fix: Use an inner element inside our button -> the button's size increases when the inner element moves up and the glitch doesn't happen.
Animations
pure CSS spinner (infinite rotation)
<style>
@keyframes spin {
from {
transform: rotate(0turn);
}
to {
transform: rotate(1turn);
}
}
.svg-spinner {
animation: spin 1000ms linear infinite;
}
</style>
grow and shrink
Use %
instead of from
and to
and go back to initial state.
<style>
@keyframes grow-and-shrink {
0% {
transform: scale(1);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
.item {
animation: grow-and-shrink 300ms;
}
</style>
This can also be performed via animation-direction: alternate
(or add alternate
to the animation shorthand), which goes over the animation 0% to 100% and then backward from 100% to 0%.
keep start and end styles with both
When entering or exiting an animation it goes back to the element's unanimated styles. Use animation: ... both
to keep initial and final styles from the animation.
CPU to GPU glitch
Sometimes start and end of the animation have minor glitches because CPU hands over to the GPU to do the work and they render a bit differently. You can hint the browser to avoid this.
.subject {
will-change: transform;
}
flipable card
Credits: https://www.joshwcomeau.com/react/folding-the-dom/ (opens in a new tab) Place 2 identical elements on top of each other and flip the back. Set the focus/hover trigger on the parent element to avoid glitches. On hover/focus, rotate both (the back has an offset since it defaults to already flipped).
<style>
.card-wrapper {
perspective: 500px;
}
.card {
position: relative;
display: block;
}
.front,
.back {
width: 200px;
height: 200px;
background: white;
border-radius: 8px;
display: flex;
justify-content: center;
align-items: center;
transition: transform 400ms;
will-change: transform;
backface-visibility: hidden;
}
.back {
position: absolute;
top: 0;
left: 0;
transform: rotateY(-180deg);
}
.card:hover .front,
.card:focus .front {
transform: rotateY(180deg);
}
.card:hover .back,
.card:focus .back {
transform: rotateY(0deg);
}
</style>
<div class="card-wrapper">
<a href="/" class="card">
<div class="front">
<p>This is the front</p>
</div>
<div class="back">
<p>This is the back</p>
</div>
</a>
</div>
Cool on scroll effects via mix-blend-mode
https://robbowen.digital/wrote-about/css-blend-mode-shaders/ (opens in a new tab)
CC BY-NC 4.0 2024 © Shu Ding.