Swipe to dismiss
Map swipe distance to travel and opacity with resistance before the threshold.
Live preview
Dragging an element off-screen to close it, like a drawer or toast.
Definition and close-term distinctions
English definitions are preserved verbatim from Animation Vocabulary; translations and distinctions help you choose precisely.
swipe-to-dismissSwipe to dismiss
滑动关闭Dragging an element off-screen to close it, like a drawer or toast.
把元素拖出屏幕以关闭它,例如抽屉或提示消息。
rubber-bandingRubber-banding
橡皮筋回弹Resistance and snap-back when you drag past a boundary (the iOS overscroll feel).
拖过边界时出现阻力并回弹,类似 iOS 的过度滚动手感。
Rubber-banding resists and returns after a boundary is crossed; Swipe to dismiss removes an element after a threshold.
Decide before this motion ships
Purpose, frequency, trigger, timing, interruptibility, and gesture rules shape the implementation.
Map swipe distance to travel and opacity so the dismissal outcome stays predictable.
Use for medium-frequency notifications, drawers, or item actions, with a button alternative for essential content.
Trigger after drag crosses an activation threshold, locking to the primary axis first.
Track with resistance before the threshold, exit after crossing it, and spring back when the threshold is missed.
Reverse progress immediately with drag direction, using current position to settle after pointercancel.
Avoid conflicts with page scrolling through touch-action, and provide undo or an explicit close button.
Use a static close button and immediate removal with undo feedback, removing large off-screen travel.
Copy into your interface
Current parameters update visual-state CSS, semantic HTML, the required vanilla JS runtime, and an interaction prompt.
.motion-demo.motion-demo--swipe-to-dismiss {
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--swipe-to-dismiss *, .motion-demo.motion-demo--swipe-to-dismiss *::before, .motion-demo.motion-demo--swipe-to-dismiss *::after {
box-sizing: border-box;
}
.motion-demo.motion-demo--swipe-to-dismiss .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--swipe-to-dismiss .motion-line {
display: block;
width: 100%;
height: 0.5rem;
background: #e4e4e7;
border-radius: 999px;
}
.motion-demo.motion-demo--swipe-to-dismiss .motion-line:last-child { width: 62%; }
.motion-demo.motion-demo--swipe-to-dismiss .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--swipe-to-dismiss .motion-button:focus-visible { outline: 3px solid rgb(37 99 235 / 32%); outline-offset: 3px; }
.motion-demo.motion-demo--swipe-to-dismiss .motion-action-row {
display: flex;
justify-content: center;
gap: 0.5rem;
margin-top: 0.85rem;
}
.motion-demo.motion-demo--swipe-to-dismiss .motion-replay-scene {
width: min(100%, 22rem);
display: grid;
place-items: center;
}
.motion-demo.motion-demo--swipe-to-dismiss .motion-pausable-scene {
width: min(100%, 22rem);
display: grid;
place-items: center;
}
.motion-demo.motion-demo--swipe-to-dismiss button.motion-surface {
color: inherit;
font: inherit;
text-align: start;
cursor: pointer;
}
.motion-demo.motion-demo--swipe-to-dismiss .motion-replay-button,
.motion-demo.motion-demo--swipe-to-dismiss .motion-undo-button,
.motion-demo.motion-demo--swipe-to-dismiss .motion-dismiss-button,
.motion-demo.motion-demo--swipe-to-dismiss .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--swipe-to-dismiss .motion-replay-button:focus-visible,
.motion-demo.motion-demo--swipe-to-dismiss .motion-undo-button:focus-visible,
.motion-demo.motion-demo--swipe-to-dismiss .motion-dismiss-button:focus-visible,
.motion-demo.motion-demo--swipe-to-dismiss .motion-pause-button:focus-visible,
.motion-demo.motion-demo--swipe-to-dismiss [data-reorder-item]:focus-visible,
.motion-demo.motion-demo--swipe-to-dismiss [data-swipe-target]:focus-visible {
outline: 3px solid rgb(37 99 235 / 32%);
outline-offset: 3px;
}
.motion-demo.motion-demo--swipe-to-dismiss .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--swipe-to-dismiss .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--swipe-to-dismiss .motion-state-stack { position: relative; width: min(100%, 18rem); height: 9rem; }
.motion-demo.motion-demo--swipe-to-dismiss .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--swipe-to-dismiss .motion-state--to { background: #18181b; color: white; }
.motion-demo.motion-demo--swipe-to-dismiss .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--swipe-to-dismiss .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--swipe-to-dismiss .motion-text-stack { position: relative; width: min(100%, 18rem); min-height: 4rem; }
.motion-demo.motion-demo--swipe-to-dismiss svg { width: min(100%, 20rem); height: auto; }
.motion-demo.motion-demo--swipe-to-dismiss .motion-swipe-shell { width: min(100%, 18rem); text-align: center; }
.motion-demo.motion-demo--swipe-to-dismiss .motion-surface { width: 100%; touch-action: pan-y; user-select: none; }
.motion-demo.motion-demo--swipe-to-dismiss .motion-surface.is-dragging { cursor: grabbing; }
.motion-demo.motion-demo--swipe-to-dismiss .motion-undo-button[hidden] { display: none; }
@keyframes motion-swipe-to-dismiss-reduced-fade {
from { opacity: 0.84; }
to { opacity: 1; }
}
.force-reduced-motion .motion-demo.motion-demo--swipe-to-dismiss {
animation: motion-swipe-to-dismiss-reduced-fade 160ms cubic-bezier(0.23, 1, 0.32, 1) both !important;
}
.force-reduced-motion .motion-demo.motion-demo--swipe-to-dismiss *,
.force-reduced-motion .motion-demo.motion-demo--swipe-to-dismiss *::before,
.force-reduced-motion .motion-demo.motion-demo--swipe-to-dismiss *::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--swipe-to-dismiss .motion-button,
.force-reduced-motion .motion-demo.motion-demo--swipe-to-dismiss [data-reorder-item],
.force-reduced-motion .motion-demo.motion-demo--swipe-to-dismiss [data-swipe-target],
.force-reduced-motion .motion-demo.motion-demo--swipe-to-dismiss [data-spring-target] {
transform: none !important;
}
.force-reduced-motion .motion-demo.motion-demo--swipe-to-dismiss .motion-path { stroke-dashoffset: 0 !important; }
.force-reduced-motion .motion-demo.motion-demo--swipe-to-dismiss .motion-word--from { opacity: 0 !important; visibility: hidden; }
.force-reduced-motion .motion-demo.motion-demo--swipe-to-dismiss .motion-word:not(.motion-word--from) { opacity: 1 !important; filter: none !important; transform: none !important; }
@media (prefers-reduced-motion: reduce) {
.motion-demo.motion-demo--swipe-to-dismiss {
animation: motion-swipe-to-dismiss-reduced-fade 160ms cubic-bezier(0.23, 1, 0.32, 1) both !important;
}
.motion-demo.motion-demo--swipe-to-dismiss *, .motion-demo.motion-demo--swipe-to-dismiss *::before, .motion-demo.motion-demo--swipe-to-dismiss *::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--swipe-to-dismiss .motion-button,
.motion-demo.motion-demo--swipe-to-dismiss [data-reorder-item],
.motion-demo.motion-demo--swipe-to-dismiss [data-swipe-target],
.motion-demo.motion-demo--swipe-to-dismiss [data-spring-target] {
transform: none !important;
}
.motion-demo.motion-demo--swipe-to-dismiss .motion-path { stroke-dashoffset: 0 !important; }
.motion-demo.motion-demo--swipe-to-dismiss .motion-word--from { opacity: 0 !important; visibility: hidden; }
.motion-demo.motion-demo--swipe-to-dismiss .motion-word:not(.motion-word--from) { opacity: 1 !important; filter: none !important; transform: none !important; }
}Pre-delivery review
- Distinguish dismissal from rubber-band boundary feedback.
- Test slow drag, fast flick, short travel, and cancellation paths.
Keep information accessible
Use a static close button and immediate removal with undo feedback, removing large off-screen travel.
Parameter reference
| Parameter | Range / options | Default | Purpose |
|---|---|---|---|
duration | 80ms–1200ms | 240ms | Controls the time required for one motion cycle. |
distance | 0px–240px | 96px | Controls how far the element travels. |
resistance | 0%–90% | 65% | Adjusts resistance. |
ease | Soft / Snap / Calm / Linear | Snap | Controls how velocity changes over time. |