Animation
Image scaling on hover
Section titled “Image scaling on hover”
This is a card
Use it to provide a small amount of information, link to another webpage, and give your page visual interest.
---
const { customClasses } = Astro.props;
const defaultClasses = "card theme container";
const classes = customClasses
? `${defaultClasses} ${customClasses}`
: defaultClasses;
---
<div class={classes}>
<div class="image">
<img src="/images/card-padilla.jpg" alt="" />
</div>
<div class="card-body l-stack">
<h2>
<a href="#">This is a card</a>
</h2>
<p>
Use it to provide a small amount of information, link to another webpage,
and give your page visual interest.
</p>
</div>
</div> .card.-animation-scale-image {
.image {
position: relative;
overflow: hidden;
}
&:hover img {
scale: 1.1;
}
img {
transition: scale 200ms linear;
}
} Dropshadow on hover
Section titled “Dropshadow on hover”I like this drop shadow generator
This is a card
Use it to provide a small amount of information, link to another webpage, and give your page visual interest.
.card.-animation-lift {
box-shadow: 0 0 0 rgba(0, 0, 0, 0);
translate: 0 0;
transition: all 150ms linear;
&:hover {
box-shadow: var(--shadow-elevation-medium);
translate: 0 -3px;
}
}
Buttons
Section titled “Buttons”Animated Arrow
Section titled “Animated Arrow”Arrow Reveal
<div class="l-stack">
<a class="button -animation-arrow" href="/" style="margin-right: auto;">
Learn More
<svg width="20" viewBox="0 0 23 23">
<g id="chevron">
<polygon
points="11.3 0 9.7 1.6 18.3 10.2 18.3 10.2 19.5 11.3 18.3 12.5 18.3 12.5 9.7 21.1 11.3 22.7 22.7 11.3 11.3 0"
fill="currentColor"></polygon>
</g>
<g id="stem">
<polygon
points="18.3 10.2 15.1 10.2 0 10.2 0 12.5 15.1 12.5 18.3 12.5 19.5 11.3 18.3 10.2"
fill="currentColor"></polygon>
</g>
</svg>
</a>
</div> .button.-animation-arrow {
position: relative;
transition: all 150ms ease;
display: flex;
gap: 8px;
color: white;
&:hover {
padding-right: calc(16px + 20px);
}
svg {
position: absolute;
right: 16px;
top: 50%;
translate: 0 -50%;
width: 13px;
}
svg * {
transition: all 150ms ease;
}
#chevron {
transform: scale(0);
transform-origin: right center;
}
#stem {
transform: scaleX(0);
transform-origin: right center;
}
&:hover #chevron {
transform: scale(1);
}
&:hover #stem {
transform: scaleX(1);
transition-delay: 75ms;
}
} Arrow Bounce
Note: animating path d attribute is not supported by Safari.
<div class="l-stack">
<a
class="button -animation-arrow-bounce"
href="/"
style="margin-right: auto;"
>
Learn More
<svg
width="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-arrow-right-icon lucide-arrow-right"
>
<path class="shaft" d="M5 12h14"></path>
<path class="tip" d="m12 5 7 7-7 7"></path>
</svg>
</a>
</div> .button.-animation-arrow-bounce {
--spring-easing: linear(0,
0.011,
0.045 1.7%,
0.181 3.6%,
0.896 9.8%,
1.136 12.4%,
1.283 14.7%,
1.325,
1.347 17.2%,
1.351,
1.347,
1.334,
1.313 20.6%,
1.249 22.6%,
1.052 27.4%,
0.969 29.7%,
0.907 32.3%,
0.889,
0.879 35%,
0.878 36.7%,
0.89,
0.913 40.6%,
0.981 45.3%,
1.01 47.6%,
1.032,
1.042 52.7%,
1.043 54.5%,
1.039 56.5%,
0.997 65.4%,
0.989,
0.986 70.2% 74.4%,
1.001 83%,
1.005 87.3% 92%,
1);
--spring-duration: 1s;
path {
transition: all var(--spring-duration) var(--spring-easing);
transform-origin: center;
}
&:hover .shaft {
d: path("\
M 5,12\
h 17\
");
}
&:hover .tip {
d: path("\
M 15,7\
l 7,5\
l -7 5\
");
}
} Plus/Minus Toggle
function attacheMouseEnterAnimation(triggerNode, applyAnimation, removeAnimation, animationDuration = 150) {
triggerNode.addEventListener("mouseenter", () => {
applyAnimation();
window.setTimeout(() => {
removeAnimation();
}, animationDuration);
});
}
const btns = document.querySelectorAll(".-animation-scale");
btns.forEach((btn) => {
attacheMouseEnterAnimation(
btn,
() => btn.classList.add("-animating"),
() => btn.classList.remove("-animating")
);
}); .button.-animation-scale {
--easing-function: linear(0, 0.011, 0.045 1.7%, 0.181 3.6%, 0.896 9.8%, 1.136 12.4%, 1.283 14.7%, 1.325,
1.347 17.2%, 1.351, 1.347, 1.334, 1.313 20.6%, 1.249 22.6%, 1.052 27.4%,
0.969 29.7%, 0.907 32.3%, 0.889, 0.879 35%, 0.878 36.7%, 0.89, 0.913 40.6%,
0.981 45.3%, 1.01 47.6%, 1.032, 1.042 52.7%, 1.043 54.5%, 1.039 56.5%,
0.997 65.4%, 0.989, 0.986 70.2% 74.4%, 1.001 83%, 1.005 87.3% 92%, 1);
position: relative;
background-color: transparent;
}
.button.-animation-scale:before {
content: "";
position: absolute;
inset: 0;
width: 100%;
height: 100%;
background-color: var(--black);
z-index: -1;
transition: transform 1.5s var(--easing-function);
}
.-animating:before {
transform: scale(1.05);
} .button.-animation-fill {
position: relative;
overflow: hidden;
>* {
color: var(--black);
transition: color 300ms linear;
position: relative;
z-index: 2;
}
&:before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--black);
translate: 0 100%;
transition: translate 200ms var(--ease-out-5);
z-index: 1;
}
&:hover>* {
color: var(--white);
}
&:hover:before {
translate: 0 0;
}
}
Border & Font Weight
Section titled “Border & Font Weight”This requires using a variable font to transition the weight and box-shadow to transition the border.
.button.-animation-border-font-weight {
transition: all 150ms ease;
>* {
transition: all 150ms ease;
font-weight: 500;
}
&:hover {
box-shadow: 0 0 0 3px currentColor;
>* {
font-weight: 800;
}
}
}
Loading State
Section titled “Loading State”.loading-spinner-wrapper {
width: 250px;
height: 250px;
position: relative;
border: 1px solid rgb(0 0 0 / 0.1);
}
.loading-spinner {
--icon-loading-spinner: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLWxvYWRlci1jaXJjbGUtaWNvbiBsdWNpZGUtbG9hZGVyLWNpcmNsZSI+PHBhdGggZD0iTTIxIDEyYTkgOSAwIDEgMS02LjIxOS04LjU2Ii8+PC9zdmc+);
position: absolute;
inset: 50%;
translate: -50% -50%;
width: 35px;
aspect-ratio: 1 / 1;
background-image: var(--icon-loading-spinner);
background-size: contain;
background-position: center;
animation-name: rotate;
animation-duration: 750ms;
animation-iteration-count: infinite;
animation-timing-function: linear;
&:before {
content: "";
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(0 0 0 / 0.15);
border-radius: 100%;
scale: 1.5;
}
}
@keyframes rotate {
to {
rotate: 360deg;
}
}