Slide-up
Entry animation that slides an element up from below with a fade-in. Uses @keyframes with transform and opacity for smooth GPU compositing.
Quick implementation
@keyframes slide-up {
from {
opacity: 0;
transform: translateY(1.5rem);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.slide-up {
animation: slide-up 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
}
/* Staggered children */
.slide-up:nth-child(1) { animation-delay: 0s; }
.slide-up:nth-child(2) { animation-delay: 0.1s; }
.slide-up:nth-child(3) { animation-delay: 0.2s; }
/* Custom property stagger (more scalable) */
.slide-up {
animation-delay: calc(var(--i, 0) * 0.1s);
}
@media (prefers-reduced-motion: reduce) {
.slide-up {
animation: none;
opacity: 1;
transform: none;
}
}
Prompt this to your LLM
Includes role, constraints, two framework variants, and edge cases to handle.
You are a senior frontend engineer building polished entry animations.
Goal: A slide-up entry animation using @keyframes that moves an element from below and fades it in simultaneously — no JavaScript, no animation libraries.
Technical constraints:
- The keyframe animates only transform (translateY) and opacity — these are GPU-composited properties and will not trigger layout or paint.
- Use animation-fill-mode: both so elements stay invisible before their delay fires and visible after they complete.
- Default timing: 0.5s with cubic-bezier(0.22, 1, 0.36, 1) — this is an "ease out" spring-like curve that feels natural for entries.
- Stagger using either :nth-child selectors or a --i CSS custom property with calc().
- translateY value should be around 1.5rem — large enough to feel intentional, small enough not to feel dramatic.
- Wrap in @media (prefers-reduced-motion: reduce) — set animation: none, opacity: 1, transform: none.
Framework variant (pick one):
A) Vanilla CSS class applied directly to elements or a container's children.
B) React component — accept children, staggerDelay (number in seconds), and className props; inject --i inline style per child.
Edge cases to handle:
- Elements hidden behind animation-delay must not flash visible before the animation starts — animation-fill-mode: both handles this.
- Long lists: cap the stagger delay so items beyond ~10 don't wait more than 1s total.
- Re-triggering: wrap the animation in a class toggled by JavaScript for scroll-reveal scenarios.
- Overflow during animation: parent container may need overflow-x: clip if translateX variants are used.
Return HTML + CSS.
Why this matters in 2026
The slide-up entry is one of the most universal animation patterns in product UI — dashboards, modals, cards, list items. It communicates "content has arrived" without demanding attention the way a bounce or spin does. The reason it's worth getting right in CSS rather than reaching for a JavaScript animation library is straightforward: @keyframes on transform and opacity runs entirely on the GPU compositor thread, costing zero JavaScript parse time and zero layout recalculations.
The logic
The keyframe starts at opacity: 0 and translateY(1.5rem) — invisible and shifted down — and ends at fully opaque with no translation. animation-fill-mode: both is critical: backwards applies the from state before the animation begins (preventing a visible flash during a delay), and forwards holds the to state after it ends (preventing a snap back). Staggering with calc(var(--i, 0) * 0.1s) scales cleanly to any number of children — set style="--i: 3" on the fourth item and the delay is calculated automatically. The cubic-bezier curve mimics a spring: fast initial movement that decelerates sharply, which feels more physical than a linear or ease-in-out curve.
Accessibility & performance
The @media (prefers-reduced-motion: reduce) block must explicitly reset opacity: 1 and transform: none in addition to setting animation: none — otherwise elements with a pending delay would remain invisible, effectively hiding content from users who opt out of motion. Both transform and opacity are on the browser's compositor allowlist, meaning they are animated on a separate thread without touching the main thread layout engine. This ensures the animation stays at 60fps even when JavaScript is executing or the page is doing other work.