Snippets / Animation /

Float

Gentle floating animation using CSS keyframes with translateY, like a UI element hovering in space.

Float
Widely Supported
animation no-js

Quick implementation

@keyframes float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-1rem); }
}

.float-element {
  animation: float 4s ease-in-out infinite;
  box-shadow: 0 1rem 2rem oklch(0 0 0 / 0.2);
}

@media (prefers-reduced-motion: reduce) {
  .float-element {
    animation: none;
  }
}

Prompt this to your LLM

Includes role, constraints, two framework variants, and edge cases to handle.

You are a senior frontend engineer specializing in smooth, performant animations.

Your goal: Implement a gentle floating/bobbing animation that gives the visual impression of an element hovering in space—commonly used for hero sections, badges, or highlight callouts.

Technical constraints:
1. Use CSS @keyframes with translateY transform (GPU-accelerated)
2. Animation cycle should be slow and meditative (3–5 seconds)
3. Use ease-in-out timing function for natural acceleration/deceleration
4. Vertical movement range should be 0.5–1.5rem (subtle, not dramatic)
5. Pair animation with drop shadow or elevation effect for depth perception
6. Must respect prefers-reduced-motion to disable animation for accessibility

Vanilla implementation:
- Define @keyframes with 0% and 50% keyframes for up-down motion
- Apply animation: float 4s ease-in-out infinite to element
- Use box-shadow for depth: inset shadow at top, drop shadow at bottom

React implementation:
- Create a styled component or CSS Module with @keyframes definition
- Wrap element in a container with position: relative
- Apply animation class conditionally on mount
- Use framer-motion as alternative: animate={{ y: -16 }} transition={{ duration: 4, repeat: Infinity }}

Edge cases to handle:
1. Animation should respect prefers-reduced-motion system setting
2. Multiple floating elements should animate in sync (use same duration)
3. Element should not overflow its parent container due to vertical movement
4. Shadow should update position based on vertical offset for realism

Why this matters in 2026

Float animations create a sense of airiness and importance. They're perfect for hero sections, floating action buttons, or highlight badges that should grab attention without being jarring. The gentle bobbing motion draws the eye through micro-interactions while maintaining brand polish and professionalism.

In 2026, users expect motion design to be thoughtful. A well-paced float animation feels intentional and premium, whereas a jerky or fast animation feels cheap. The 4-second cycle is slow enough to be meditative and fast enough to maintain visual interest without becoming distracting.

The logic

The float animation moves an element up and then back down using translateY. At the 0% and 100% keyframes, the element is at its starting position (translateY(0)). At 50%, it's moved upward by 1 rem. The ease-in-out timing function ensures smooth acceleration and deceleration, making the motion feel natural rather than mechanical.

The infinite keyword makes the animation loop forever. A 4-second duration is ideal: fast enough to feel dynamic, slow enough to feel purposeful. The drop shadow enhances the floating effect by anchoring the element to an implied ground plane—as the element rises, the shadow shrinks slightly (achieved through consistent shadow positioning).

Accessibility & performance

Accessibility: Infinite animations on the page can be distracting or triggering for users with attention disorders, vestibular disorders, or ADHD. The prefers-reduced-motion: reduce query should disable this animation completely. Consider providing a toggle in settings if floating animations are core to your branding.

Performance: The translateY transform is GPU-accelerated and causes zero layout thrashing. Floating animations have virtually zero performance cost and can run on dozens of elements simultaneously without impacting frame rates. The drop shadow can be expensive at scale; use filter: drop-shadow() instead of box-shadow for better performance with complex shapes.