Modern CSS Animations
Keyframe animations for cards, icons, loaders and headings - drop a class on an element and it comes alive.
1Pulse Wave Effect
Sends expanding rings out of a button, avatar or status dot to draw the eye. Class: fx-pulse-wave-effect
Jonah Harlow
Live now<div class="flex flex-wrap items-center justify-center gap-4 p-4 h-full" style="min-height:200px">
<button type="button" class="btn btn-primary rounded-full inline-flex items-center justify-center text-xl fx-pulse-wave-effect" style="width:4rem;height:4rem" aria-label="Start live session"><i class="bi bi-broadcast" aria-hidden="true"></i></button>
<div class="flex items-center gap-2">
<img src="../assets/img/avatar-2.svg" alt="Portrait of the host" class="rounded-full fx-pulse-wave-effect" width="48" height="48">
<div>
<div class="font-semibold small">
Jonah Harlow
</div>
<span class="badge text-bg-success">Live now</span>
</div>
</div>
</div>
/* CSS (already in assets/css/effects.css) */
.fx-pulse-wave-effect { animation: fx-pulse-wave-effect-pulse 2s ease-out infinite; }
@keyframes fx-pulse-wave-effect-pulse {
0% { box-shadow: 0 0 0 0 rgba(var(--wt-primary-rgb), .55), 0 0 0 0 rgba(var(--wt-primary-rgb), .35); }
70% { box-shadow: 0 0 0 16px rgba(var(--wt-primary-rgb), 0), 0 0 0 32px rgba(var(--wt-primary-rgb), 0); }
100% { box-shadow: 0 0 0 0 rgba(var(--wt-primary-rgb), 0), 0 0 0 0 rgba(var(--wt-primary-rgb), 0); }
}
@media (prefers-reduced-motion: reduce) {
.fx-pulse-wave-effect, .fx-pulse-wave-effect::before, .fx-pulse-wave-effect::after, .fx-pulse-wave-effect *, .fx-pulse-wave-effect *::before, .fx-pulse-wave-effect *::after { animation: none !important; transition: none !important; }
}2Morphing Blob
Turns a shape or a photo frame into an organic blob that slowly changes its outline. Class: fx-morphing-blob
<div class="flex flex-wrap items-center justify-center gap-4 p-4 h-full" style="min-height:200px">
<div class="fx-morphing-blob" style="width:150px;height:150px">
<img src="../assets/img/square-3.svg" alt="Product photo in a blob frame" class="">
</div>
<div class="fx-morphing-blob" style="width:90px;height:90px">
</div>
</div>
/* CSS (already in assets/css/effects.css) */
.fx-morphing-blob {
border-radius: 42% 58% 63% 37% / 41% 44% 56% 59%;
background: linear-gradient(135deg, var(--wt-primary), var(--wt-secondary));
overflow: hidden;
animation: fx-morphing-blob-morph 9s ease-in-out infinite;
}
.fx-morphing-blob img { width: 100%; height: 100%; object-fit: cover; display: block; }
@keyframes fx-morphing-blob-morph {
0%, 100% { border-radius: 42% 58% 63% 37% / 41% 44% 56% 59%; }
33% { border-radius: 70% 30% 46% 54% / 30% 39% 61% 70%; }
66% { border-radius: 30% 70% 70% 30% / 53% 30% 70% 47%; }
}
@media (prefers-reduced-motion: reduce) {
.fx-morphing-blob, .fx-morphing-blob::before, .fx-morphing-blob::after, .fx-morphing-blob *, .fx-morphing-blob *::before, .fx-morphing-blob *::after { animation: none !important; transition: none !important; }
}3Multi-Layer Spinner
A loading indicator made of three counter-rotating rings in the theme colours. Class: fx-multi-layer-spinner
Loading...
Preparing your dashboard
<div class="flex flex-wrap items-center justify-center gap-4 p-4 h-full" style="min-height:200px">
<div class="text-center">
<div class="fx-multi-layer-spinner" role="status">
<span class="sr-only">Loading...</span>
</div>
<p class="small text-muted mt-4 mb-0">Preparing your dashboard</p>
</div>
</div>
/* CSS (already in assets/css/effects.css) */
.fx-multi-layer-spinner {
position: relative; display: inline-block; width: 4rem; height: 4rem; border-radius: 50%;
border: 4px solid transparent; border-top-color: var(--wt-primary);
animation: fx-multi-layer-spinner-spin 1.1s linear infinite;
}
.fx-multi-layer-spinner::before, .fx-multi-layer-spinner::after { content: ""; position: absolute; border-radius: 50%; border: 4px solid transparent; }
.fx-multi-layer-spinner::before { inset: 4px; border-top-color: var(--wt-secondary); animation: fx-multi-layer-spinner-spin 1.7s linear infinite reverse; }
.fx-multi-layer-spinner::after { inset: 14px; border-top-color: var(--wt-accent); animation: fx-multi-layer-spinner-spin .8s linear infinite; }
@keyframes fx-multi-layer-spinner-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
.fx-multi-layer-spinner, .fx-multi-layer-spinner::before, .fx-multi-layer-spinner::after, .fx-multi-layer-spinner *, .fx-multi-layer-spinner *::before, .fx-multi-layer-spinner *::after { animation: none !important; transition: none !important; }
}