Morph

Create continuous transformation between before and after layouts of a shared element.

Preview

Live preview

One shape smoothly turns into another shape, e.g. Dynamic Island.

Preview
Morph
Authoritative vocabulary

Definition and close-term distinctions

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

Canonical termmorph

Morph

形变
Authoritative definition

One shape smoothly turns into another shape, e.g. Dynamic Island.

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

Turn one shape smoothly into another while preserving object identity.

Frequency

Reserve for low-frequency brand marks, icons, and high-value state changes; keep common controls subtler.

Trigger

Trigger when the object's state genuinely changes, with understandable correspondence between shapes.

Enter / exit

Use one geometric object and interpolation path across states, normalizing path points when needed.

Interruptibility

Retarget from the current interpolated shape instead of returning to an endpoint.

Gesture and keyboard

Map gesture-driven morph progress continuously to input, with keyboard toggles for discrete controls.

Reduced-motion strategy

Use a static state replacement or short crossfade while preserving object position and size.

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--morph {
  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--morph *, .motion-demo.motion-demo--morph *::before, .motion-demo.motion-demo--morph *::after {
  box-sizing: border-box;
}

.motion-demo.motion-demo--morph .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--morph .motion-line {
  display: block;
  width: 100%;
  height: 0.5rem;
  background: #e4e4e7;
  border-radius: 999px;
}

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

.motion-demo.motion-demo--morph .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--morph .motion-button:focus-visible { outline: 3px solid rgb(37 99 235 / 32%); outline-offset: 3px; }

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

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

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

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

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

.motion-demo.motion-demo--morph .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--morph .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--morph .motion-state-stack { position: relative; width: min(100%, 18rem); height: 9rem; }
.motion-demo.motion-demo--morph .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--morph .motion-state--to { background: #18181b; color: white; }

.motion-demo.motion-demo--morph .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--morph .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--morph .motion-text-stack { position: relative; width: min(100%, 18rem); min-height: 4rem; }
.motion-demo.motion-demo--morph svg { width: min(100%, 20rem); height: auto; }

.motion-demo.motion-demo--morph .motion-surface { width: min(100%, 18rem); transform-origin: center; animation: motion-morph 260ms cubic-bezier(0.23, 1, 0.32, 1) both; }
@keyframes motion-morph { from { opacity: 0.65; transform: translateX(-17px) scale(0.86); } to { opacity: 1; transform: none; } }

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

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

.force-reduced-motion .motion-demo.motion-demo--morph *,
.force-reduced-motion .motion-demo.motion-demo--morph *::before,
.force-reduced-motion .motion-demo.motion-demo--morph *::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--morph .motion-button,
.force-reduced-motion .motion-demo.motion-demo--morph [data-reorder-item],
.force-reduced-motion .motion-demo.motion-demo--morph [data-swipe-target],
.force-reduced-motion .motion-demo.motion-demo--morph [data-spring-target] {
  transform: none !important;
}

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

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

  .motion-demo.motion-demo--morph *, .motion-demo.motion-demo--morph *::before, .motion-demo.motion-demo--morph *::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--morph .motion-button,
  .motion-demo.motion-demo--morph [data-reorder-item],
  .motion-demo.motion-demo--morph [data-swipe-target],
  .motion-demo.motion-demo--morph [data-spring-target] {
    transform: none !important;
  }

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

Pre-delivery review

  • Distinguish morphing from shared-element and layout transitions.
  • Check intermediate shapes for self-intersection or flicker.
Accessibility

Keep information accessible

Reduced motion

Use a static state replacement or short crossfade while preserving object position and size.

Parameters

Parameter reference

ParameterRange / optionsDefaultPurpose
duration80ms–1200ms260msControls the time required for one motion cycle.
modeShape morph / Continuity transition / Shared element / Layout changeShape morphSelects how continuity is preserved between states.
distance0px–120px48pxControls how far the element travels.
scale70%–105%86%Controls the starting size relative to the final state.
easeSoft / Snap / Calm / LinearSoftControls how velocity changes over time.