Home / Snippets / Animation & Motion /

Pulse

Scale pulse and ring pulse — two variants for live indicators.

Widely Supported
animationno-js

Quick implementation

/* Variant 1: Scale pulse */
@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.15); }
}

.pulse {
  animation: pulse 1.5s ease-in-out infinite;
}

/* Variant 2: Ring pulse (expanding border) */
.pulse-ring {
  position: relative;
}

.pulse-ring::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2px solid oklch(0.72 0.19 265);
  animation: pulse-ring 1.5s ease-out infinite;
}

@keyframes pulse-ring {
  0%   { transform: scale(1); opacity: 1; }
  100% { transform: scale(2); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .pulse, .pulse-ring::after { animation: none; }
}

Prompt this to your LLM

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

You are a senior frontend engineer building a CSS animation library.

Goal: Two pulse animation variants — a scale pulse and a ring (expanding border) pulse. No JavaScript.

Technical constraints:
- Scale pulse: transform: scale() only — no layout shift.
- Ring pulse: ::after pseudo-element that scales up and fades out.
- Use oklch() for all colors, not hex or rgba().
- Both animations should be infinite and smooth (ease-in-out / ease-out).
- Include @media (prefers-reduced-motion: reduce) to disable both.

Framework variant (pick one):
A) Vanilla CSS classes applicable to any element.
B) React component — accept variant ("scale" | "ring"), color, and size props.

Edge cases to handle:
- Pulse should not cause layout shift for surrounding elements.
- Ring pulse needs position: relative on the parent element.
- Both variants should work on circles and rectangles.

Return CSS.

Why this matters in 2026

Pulse animations signal "live" or "active" state — think notification dots, recording indicators, and online status badges. Two CSS classes replace what many teams build with JavaScript animation libraries.

The logic

The scale pulse uses transform: scale(1.15) at the midpoint, creating a breathing effect. The ring pulse uses a ::after pseudo-element that scales up while fading out, creating an expanding ring. Both use transform and opacity — the two cheapest properties to animate on the GPU compositor.

Accessibility & performance

Infinite animations can be distracting for users with vestibular disorders. @media (prefers-reduced-motion: reduce) stops both variants entirely. For non-critical indicators, consider using a subtle pulse that only runs a few times rather than infinitely. Both animations use compositor-only properties for 60fps rendering.