Loop

Compare loop direction, count, pauses, and rhythm while controlling distraction.

Preview

Live preview

An animation that repeats, a set number of times or infinitely.

Preview
Authoritative vocabulary

Definition and close-term distinctions

English definitions are preserved verbatim from Animation Vocabulary; translations and distinctions help you choose precisely.

Canonical termloop

Loop

循环
Authoritative definition

An animation that repeats, a set number of times or infinitely.

Chinese translation

按指定次数或无限重复播放的动画。

Browse all 91 terms
Design contract

Decide before this motion ships

Purpose, frequency, trigger, timing, interruptibility, and gesture rules shape the implementation.

Purpose

Control repeat direction, count, and pauses so loops communicate activity or waiting with limited distraction.

Frequency

Run only while the underlying state persists and avoid permanent loops in ordinary content.

Trigger

Trigger from loading, live, demo, or explicit play state, pausing when offscreen.

Enter / exit

Pause on a stable frame between iterations and settle promptly when the state ends.

Interruptibility

Resume from current progress after pause and cancel old loops with timer cleanup on state changes.

Gesture and keyboard

Allow hover, focus, and user controls to pause, with keyboard and assistive-technology support.

Reduced-motion strategy

Stop automatic looping and show a representative static frame with explicit status text.

Output

Copy into your interface

Current parameters update visual-state CSS, semantic HTML, the required vanilla JS runtime, and an interaction prompt.

Updates with parameters
motion.css
.motion-demo.motion-demo--loop {
  position: relative;
  display: grid;
  place-items: center;
  width: min(100%, 34rem);
  min-height: 15rem;
  padding: 2rem;
  overflow: hidden;
  color: #18181b;
  background: #fafafa;
  border: 1px solid #e4e4e7;
  border-radius: 12px;
  isolation: isolate;
}

.motion-demo.motion-demo--loop *, .motion-demo.motion-demo--loop *::before, .motion-demo.motion-demo--loop *::after {
  box-sizing: border-box;
}

.motion-demo.motion-demo--loop .motion-surface {
  position: relative;
  display: grid;
  gap: 0.65rem;
  width: min(100%, 18rem);
  padding: 1.25rem;
  background: #ffffff;
  border: 1px solid #e4e4e7;
  border-radius: 8px;
  box-shadow: 0 1px 2px rgb(0 0 0 / 6%), 0 10px 28px rgb(0 0 0 / 7%);
}

.motion-demo.motion-demo--loop .motion-line {
  display: block;
  width: 100%;
  height: 0.5rem;
  background: #e4e4e7;
  border-radius: 999px;
}

.motion-demo.motion-demo--loop .motion-line:last-child { width: 62%; }

.motion-demo.motion-demo--loop .motion-button {
  position: relative;
  min-height: 2.75rem;
  padding: 0.75rem 1.1rem;
  color: white;
  font: inherit;
  font-weight: 700;
  background: #18181b;
  border: 0;
  border-radius: 7px;
  cursor: pointer;
}

.motion-demo.motion-demo--loop .motion-button:focus-visible { outline: 3px solid rgb(37 99 235 / 32%); outline-offset: 3px; }

.motion-demo.motion-demo--loop .motion-action-row {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 0.85rem;
}

.motion-demo.motion-demo--loop .motion-replay-scene {
  width: min(100%, 22rem);
  display: grid;
  place-items: center;
}

.motion-demo.motion-demo--loop .motion-pausable-scene {
  width: min(100%, 22rem);
  display: grid;
  place-items: center;
}

.motion-demo.motion-demo--loop button.motion-surface {
  color: inherit;
  font: inherit;
  text-align: start;
  cursor: pointer;
}

.motion-demo.motion-demo--loop .motion-replay-button,
.motion-demo.motion-demo--loop .motion-undo-button,
.motion-demo.motion-demo--loop .motion-dismiss-button,
.motion-demo.motion-demo--loop .motion-pause-button {
  min-height: 2.75rem;
  padding: 0.65rem 0.9rem;
  color: #18181b;
  font: 650 0.78rem/1 ui-sans-serif, system-ui, sans-serif;
  background: #ffffff;
  border: 1px solid #d4d4d8;
  border-radius: 7px;
  cursor: pointer;
}

.motion-demo.motion-demo--loop .motion-replay-button:focus-visible,
.motion-demo.motion-demo--loop .motion-undo-button:focus-visible,
.motion-demo.motion-demo--loop .motion-dismiss-button:focus-visible,
.motion-demo.motion-demo--loop .motion-pause-button:focus-visible,
.motion-demo.motion-demo--loop [data-reorder-item]:focus-visible,
.motion-demo.motion-demo--loop [data-swipe-target]:focus-visible {
  outline: 3px solid rgb(37 99 235 / 32%);
  outline-offset: 3px;
}

.motion-demo.motion-demo--loop .motion-status {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.motion-demo.motion-demo--loop .motion-ripple-ink {
  position: absolute;
  width: 12px;
  height: 12px;
  pointer-events: none;
  background: rgb(255 255 255 / 72%);
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(0.95);
  opacity: 0;
}

.motion-demo.motion-demo--loop .motion-state-stack { position: relative; width: min(100%, 18rem); height: 9rem; }
.motion-demo.motion-demo--loop .motion-state { position: absolute; inset: 0; display: grid; place-items: center; padding: 1rem; background: #ffffff; border: 1px solid #e4e4e7; border-radius: 8px; }
.motion-demo.motion-demo--loop .motion-state--to { background: #18181b; color: white; }

.motion-demo.motion-demo--loop .motion-scroll-track > span { color: #71717a; font: 600 0.72rem/1.2 ui-monospace, monospace; letter-spacing: 0.08em; text-transform: uppercase; }
.motion-demo.motion-demo--loop .motion-orbit-item { display: grid; place-items: center; width: 2.5rem; height: 2.5rem; color: white; background: #2563eb; border-radius: 50%; }
.motion-demo.motion-demo--loop .motion-text-stack { position: relative; width: min(100%, 18rem); min-height: 4rem; }
.motion-demo.motion-demo--loop svg { width: min(100%, 20rem); height: auto; }

.motion-demo.motion-demo--loop .motion-orbit-item { animation: motion-loop 1360ms cubic-bezier(0.77, 0, 0.175, 1) 0ms 3 normal; }
@keyframes motion-loop { 0%, 18% { transform: translateX(-54px); } 82%, 100% { transform: translateX(54px); } }

@keyframes motion-loop-reduced-fade {
  from { opacity: 0.84; }
  to { opacity: 1; }
}

.force-reduced-motion .motion-demo.motion-demo--loop {
  animation: motion-loop-reduced-fade 160ms cubic-bezier(0.23, 1, 0.32, 1) both !important;
}

.force-reduced-motion .motion-demo.motion-demo--loop *,
.force-reduced-motion .motion-demo.motion-demo--loop *::before,
.force-reduced-motion .motion-demo.motion-demo--loop *::after {
  animation: none !important;
  animation-delay: 0ms !important;
  animation-iteration-count: 1 !important;
  transition-property: opacity, color, background-color, border-color !important;
  transition-duration: 160ms !important;
  transition-delay: 0ms !important;
  scroll-behavior: auto !important;
}

.force-reduced-motion .motion-demo.motion-demo--loop .motion-button,
.force-reduced-motion .motion-demo.motion-demo--loop [data-reorder-item],
.force-reduced-motion .motion-demo.motion-demo--loop [data-swipe-target],
.force-reduced-motion .motion-demo.motion-demo--loop [data-spring-target] {
  transform: none !important;
}

.force-reduced-motion .motion-demo.motion-demo--loop .motion-path { stroke-dashoffset: 0 !important; }
.force-reduced-motion .motion-demo.motion-demo--loop .motion-word--from { opacity: 0 !important; visibility: hidden; }
.force-reduced-motion .motion-demo.motion-demo--loop .motion-word:not(.motion-word--from) { opacity: 1 !important; filter: none !important; transform: none !important; }

@media (prefers-reduced-motion: reduce) {
  .motion-demo.motion-demo--loop {
    animation: motion-loop-reduced-fade 160ms cubic-bezier(0.23, 1, 0.32, 1) both !important;
  }

  .motion-demo.motion-demo--loop *, .motion-demo.motion-demo--loop *::before, .motion-demo.motion-demo--loop *::after {
    animation: none !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-property: opacity, color, background-color, border-color !important;
    transition-duration: 160ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }

  .motion-demo.motion-demo--loop .motion-button,
  .motion-demo.motion-demo--loop [data-reorder-item],
  .motion-demo.motion-demo--loop [data-swipe-target],
  .motion-demo.motion-demo--loop [data-spring-target] {
    transform: none !important;
  }

  .motion-demo.motion-demo--loop .motion-path { stroke-dashoffset: 0 !important; }
  .motion-demo.motion-demo--loop .motion-word--from { opacity: 0 !important; visibility: hidden; }
  .motion-demo.motion-demo--loop .motion-word:not(.motion-word--from) { opacity: 1 !important; filter: none !important; transform: none !important; }
}
Review notes

Pre-delivery review

  • Pause when the page is hidden or the element is offscreen.
  • Prevent multiple loops from competing for attention in one viewport.
Accessibility

Keep information accessible

Reduced motion

Stop automatic looping and show a representative static frame with explicit status text.

Parameters

Parameter reference

ParameterRange / optionsDefaultPurpose
duration800ms–4000ms1200msControls the rhythm of one full cycle; continuous motion should stay pausable and low-distraction.
pause0ms–800ms160msAdjusts loop pause.
directionNormal / Alternate / ReverseNormalSelects loop direction.
iterations1x–8x3xAdjusts iterations.
infiniteOn / OffOffKeeps the motion looping.