Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/pbakaus/impeccable/llms.txt

Use this file to discover all available pages before exploring further.

Focus on high-impact moments: one well-orchestrated page load with staggered reveals creates more delight than scattered micro-interactions.

Duration: The 100/300/500 Rule

Timing matters more than easing. These durations feel right for most UI:
DurationUse CaseExamples
100-150msInstant feedbackButton press, toggle, color change
200-300msState changesMenu open, tooltip, hover states
300-500msLayout changesAccordion, modal, drawer
500-800msEntrance animationsPage load, hero reveals
Exit animations are faster than entrances—use ~75% of enter duration.

Easing: Pick the Right Curve

Don’t use ease. It’s a compromise that’s rarely optimal.
Instead:
CurveUse ForCSS
ease-outElements enteringcubic-bezier(0.16, 1, 0.3, 1)
ease-inElements leavingcubic-bezier(0.7, 0, 0.84, 0)
ease-in-outState toggles (there → back)cubic-bezier(0.65, 0, 0.35, 1)
For micro-interactions, use exponential curves—they feel natural because they mimic real physics (friction, deceleration):
/* Quart out - smooth, refined (recommended default) */
--ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);

/* Quint out - slightly more dramatic */
--ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);

/* Expo out - snappy, confident */
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
Avoid bounce and elastic curves. They were trendy in 2015 but now feel tacky and amateurish. Real objects don’t bounce when they stop—they decelerate smoothly. Overshoot effects draw attention to the animation itself rather than the content.

The Only Two Properties You Should Animate

transform and opacity only—everything else causes layout recalculation.
/* Good - composited properties */
.card {
  transition: transform 300ms ease-out, opacity 300ms ease-out;
}

.card:hover {
  transform: translateY(-4px);
  opacity: 0.9;
}

/* Bad - causes layout recalculation */
.card {
  transition: width 300ms, height 300ms, margin 300ms;
}
For height animations (accordions), use grid-template-rows: 0fr → 1fr instead of animating height directly:
.accordion-content {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 300ms ease-out;
}

.accordion.open .accordion-content {
  grid-template-rows: 1fr;
}

.accordion-content > * {
  overflow: hidden;
}

Staggered Animations

Use CSS custom properties for cleaner stagger:
.list-item {
  animation: fade-in 500ms ease-out;
  animation-delay: calc(var(--i, 0) * 50ms);
}
<div class="list-item" style="--i: 0">Item 1</div>
<div class="list-item" style="--i: 1">Item 2</div>
<div class="list-item" style="--i: 2">Item 3</div>
Cap total stagger time—10 items at 50ms = 500ms total. For many items, reduce per-item delay or cap staggered count.

Reduced Motion

This is not optional. Vestibular disorders affect ~35% of adults over 40.
/* Define animations normally */
.card {
  animation: slide-up 500ms ease-out;
}

/* Provide alternative for reduced motion */
@media (prefers-reduced-motion: reduce) {
  .card {
    animation: fade-in 200ms ease-out;  /* Crossfade instead of motion */
  }
}

/* Or disable entirely */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
What to preserve: Functional animations like progress bars, loading spinners (slowed down), and focus indicators should still work—just without spatial movement.

Perceived Performance

Nobody cares how fast your site is—just how fast it feels. Perception can be as effective as actual performance.

The 80ms Threshold

Our brains buffer sensory input for ~80ms to synchronize perception. Anything under 80ms feels instant and simultaneous. This is your target for micro-interactions.

Active vs Passive Time

Passive waiting (staring at a spinner) feels longer than active engagement. Strategies to shift the balance:
  • Preemptive start: Begin transitions immediately while loading (iOS app zoom, skeleton UI). Users perceive work happening.
  • Early completion: Show content progressively—don’t wait for everything. Video buffering, progressive images, streaming HTML.
  • Optimistic UI: Update the interface immediately, handle failures gracefully. Instagram likes work offline—the UI updates instantly, syncs later. Use for low-stakes actions; avoid for payments or destructive operations.

Easing Affects Perceived Duration

Ease-in (accelerating toward completion) makes tasks feel shorter because the peak-end effect weights final moments heavily. Ease-out feels satisfying for entrances, but ease-in toward a task’s end compresses perceived time.
Caution: Too-fast responses can decrease perceived value. Users may distrust instant results for complex operations (search, analysis). Sometimes a brief delay signals “real work” is happening.

Performance

Don’t use will-change preemptively—only when animation is imminent (:hover, .animating):
.card:hover {
  will-change: transform;
}

.card {
  will-change: auto;  /* Reset after animation */
}
For scroll-triggered animations, use Intersection Observer instead of scroll events; unobserve after animating once. Create motion tokens for consistency (durations, easings, common transitions):
:root {
  --duration-instant: 100ms;
  --duration-fast: 200ms;
  --duration-normal: 300ms;
  --duration-slow: 500ms;
  
  --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
  --ease-in-quart: cubic-bezier(0.5, 0, 0.75, 0);
  --ease-in-out-quart: cubic-bezier(0.65, 0, 0.35, 1);
}

Guidelines

DO

  • Use motion to convey state changes—entrances, exits, feedback
  • Use exponential easing (ease-out-quart/quint/expo) for natural deceleration
  • For height animations, use grid-template-rows transitions instead of animating height directly
  • Always respect prefers-reduced-motion
  • Use staggered animations with capped total duration

DON’T

  • Animate layout properties (width, height, padding, margin)—use transform and opacity only
  • Use bounce or elastic easing—they feel dated and tacky; real objects decelerate smoothly
  • Animate everything (animation fatigue is real)
  • Use >500ms for UI feedback
  • Ignore prefers-reduced-motion
  • Use animation to hide slow loading

Build docs developers (and LLMs) love