Sylva Studio
Back to blog

Motion on the Web: Less Is Always More

Every animation should earn its place. Here's our framework for knowing when to move and when to stay still.

Motion on the Web: Less Is Always More

Animation is the easiest way to make a website feel premium — and the easiest way to make it feel annoying. The difference comes down to restraint.

The Rule of Purpose

Every animation needs to answer one question: what does this help the user understand? If the answer is "nothing, it just looks cool," cut it.

Good reasons to animate:

  • Showing a state change (loading, success, error)
  • Guiding attention to new content
  • Creating continuity between views
  • Providing feedback on interaction

Bad reasons to animate:

  • Because the library supports it
  • Because the inspiration site did it
  • Because the page feels "empty" without it

Duration Matters More Than Easing

Most web animations are too slow. Here's the timing we follow:

| Interaction | Duration | Why | |-------------|----------|-----| | Button hover | 150ms | Instant feedback, no waiting | | Tooltip appear | 200ms | Quick but not jarring | | Modal open | 250ms | Smooth entrance without delay | | Page transition | 300ms | Enough to feel intentional | | Orchestrated entrance | 400–600ms | Complex sequences, staggered |

Anything longer and users are waiting instead of engaging. The exception: scroll-triggered reveals can be slower (600–800ms) because the user controls the pace.

The Properties That Matter

Always animate (GPU-accelerated, no jank):

transform: translateY(), scale(), rotate()
opacity: 0 → 1
filter: blur()

Avoid animating (triggers layout recalculation):

width, height
margin, padding
top, left, right, bottom
font-size

Use will-change sparingly and only when you've measured the impact. It's a hint, not a magic fix — overuse actually hurts performance.

Our Animation Stack

For most projects, we reach for:

  • CSS transitions — for simple hover states and micro-interactions
  • Framer Motion — for React-based orchestrated animations
  • GSAP — for complex scroll-driven sequences and timeline control
  • Lenis — for smooth scroll normalization

We avoid animation libraries that add more than 10KB to the bundle for simple effects. If a CSS transition can do the job, use it.

Real Example: Scroll-Triggered Reveals

The reveal pattern we use across most of our sites:

.reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.reveal.visible {
  opacity: 1;
  transform: translateY(0);
}

Simple. Lightweight. No library needed. Combined with an Intersection Observer, it handles 90% of scroll-triggered animation needs.

Performance Is a Feature

An animation that causes jank is worse than no animation. Before shipping any animation:

  1. Test on a mid-range Android device — not your M3 MacBook Pro
  2. Check the Performance tab — look for long frames (>16ms)
  3. Verify compositor-only — green indicators in the Layers panel
  4. Test with reduced motion — respect prefers-reduced-motion always

We treat motion as a design material with the same rigor as typography or color. It has rules, it has a budget, and it should always serve the user first.

Related articles