rippleRipple
涟漪A circle expanding from the point of a tap, confirming the press.
圆形从轻触点向外扩散,用来确认按压操作。
Expand a restrained ripple from the input coordinate for precise touch feedback.
A circle expanding from the point of a tap, confirming the press.
English definitions are preserved verbatim from Animation Vocabulary; translations and distinctions help you choose precisely.
rippleA circle expanding from the point of a tap, confirming the press.
圆形从轻触点向外扩散,用来确认按压操作。
Purpose, frequency, trigger, timing, interruptibility, and gesture rules shape the implementation.
Expand a restrained ripple from the actual input coordinate to confirm the touch point.
Use for medium-frequency, larger touch targets; dense desktop controls can use lighter press feedback.
Trigger on pointerdown, positioning the center from coordinates relative to the control.
Expand and fade from the touch point, removing the ripple node afterward while the control stays stable.
Allow repeated presses to finish independently while capping concurrent ripple nodes.
Keyboard activation uses the control center, and the ripple layer never intercepts pointer events.
Remove expansion and keep an immediate background or outline change.
Current parameters update visual-state CSS, semantic HTML, the required vanilla JS runtime, and an interaction prompt.
.motion-demo.motion-demo--ripple {
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--ripple *, .motion-demo.motion-demo--ripple *::before, .motion-demo.motion-demo--ripple *::after {
box-sizing: border-box;
}
.motion-demo.motion-demo--ripple .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--ripple .motion-line {
display: block;
width: 100%;
height: 0.5rem;
background: #e4e4e7;
border-radius: 999px;
}
.motion-demo.motion-demo--ripple .motion-line:last-child { width: 62%; }
.motion-demo.motion-demo--ripple .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--ripple .motion-button:focus-visible { outline: 3px solid rgb(37 99 235 / 32%); outline-offset: 3px; }
.motion-demo.motion-demo--ripple .motion-action-row {
display: flex;
justify-content: center;
gap: 0.5rem;
margin-top: 0.85rem;
}
.motion-demo.motion-demo--ripple .motion-replay-scene {
width: min(100%, 22rem);
display: grid;
place-items: center;
}
.motion-demo.motion-demo--ripple .motion-pausable-scene {
width: min(100%, 22rem);
display: grid;
place-items: center;
}
.motion-demo.motion-demo--ripple button.motion-surface {
color: inherit;
font: inherit;
text-align: start;
cursor: pointer;
}
.motion-demo.motion-demo--ripple .motion-replay-button,
.motion-demo.motion-demo--ripple .motion-undo-button,
.motion-demo.motion-demo--ripple .motion-dismiss-button,
.motion-demo.motion-demo--ripple .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--ripple .motion-replay-button:focus-visible,
.motion-demo.motion-demo--ripple .motion-undo-button:focus-visible,
.motion-demo.motion-demo--ripple .motion-dismiss-button:focus-visible,
.motion-demo.motion-demo--ripple .motion-pause-button:focus-visible,
.motion-demo.motion-demo--ripple [data-reorder-item]:focus-visible,
.motion-demo.motion-demo--ripple [data-swipe-target]:focus-visible {
outline: 3px solid rgb(37 99 235 / 32%);
outline-offset: 3px;
}
.motion-demo.motion-demo--ripple .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--ripple .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--ripple .motion-state-stack { position: relative; width: min(100%, 18rem); height: 9rem; }
.motion-demo.motion-demo--ripple .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--ripple .motion-state--to { background: #18181b; color: white; }
.motion-demo.motion-demo--ripple .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--ripple .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--ripple .motion-text-stack { position: relative; width: min(100%, 18rem); min-height: 4rem; }
.motion-demo.motion-demo--ripple svg { width: min(100%, 20rem); height: auto; }
.motion-demo.motion-demo--ripple .motion-button { position: relative; overflow: hidden; isolation: isolate; }
.motion-demo.motion-demo--ripple .motion-button > :not(.motion-ripple-ink) { position: relative; z-index: 1; }
@keyframes motion-ripple-reduced-fade {
from { opacity: 0.84; }
to { opacity: 1; }
}
.force-reduced-motion .motion-demo.motion-demo--ripple {
animation: motion-ripple-reduced-fade 160ms cubic-bezier(0.23, 1, 0.32, 1) both !important;
}
.force-reduced-motion .motion-demo.motion-demo--ripple *,
.force-reduced-motion .motion-demo.motion-demo--ripple *::before,
.force-reduced-motion .motion-demo.motion-demo--ripple *::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--ripple .motion-button,
.force-reduced-motion .motion-demo.motion-demo--ripple [data-reorder-item],
.force-reduced-motion .motion-demo.motion-demo--ripple [data-swipe-target],
.force-reduced-motion .motion-demo.motion-demo--ripple [data-spring-target] {
transform: none !important;
}
.force-reduced-motion .motion-demo.motion-demo--ripple .motion-path { stroke-dashoffset: 0 !important; }
.force-reduced-motion .motion-demo.motion-demo--ripple .motion-word--from { opacity: 0 !important; visibility: hidden; }
.force-reduced-motion .motion-demo.motion-demo--ripple .motion-word:not(.motion-word--from) { opacity: 1 !important; filter: none !important; transform: none !important; }
@media (prefers-reduced-motion: reduce) {
.motion-demo.motion-demo--ripple {
animation: motion-ripple-reduced-fade 160ms cubic-bezier(0.23, 1, 0.32, 1) both !important;
}
.motion-demo.motion-demo--ripple *, .motion-demo.motion-demo--ripple *::before, .motion-demo.motion-demo--ripple *::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--ripple .motion-button,
.motion-demo.motion-demo--ripple [data-reorder-item],
.motion-demo.motion-demo--ripple [data-swipe-target],
.motion-demo.motion-demo--ripple [data-spring-target] {
transform: none !important;
}
.motion-demo.motion-demo--ripple .motion-path { stroke-dashoffset: 0 !important; }
.motion-demo.motion-demo--ripple .motion-word--from { opacity: 0 !important; visibility: hidden; }
.motion-demo.motion-demo--ripple .motion-word:not(.motion-word--from) { opacity: 1 !important; filter: none !important; transform: none !important; }
}Remove expansion and keep an immediate background or outline change.
| Parameter | Range / options | Default | Purpose |
|---|---|---|---|
duration | 80ms–1200ms | 160ms | Controls the time required for one motion cycle. |
size | 120%–360% | 220% | Adjusts ripple size. |
opacity | 8%–40% | 24% | Adjusts ripple opacity. |