22 CSS Transition Effects 13 / 22

Ripple Effect on Click

Material Design ripple: JS inserts a wave span at click coordinates with contained, outlined and text buttons, FABs, chips, list items and cards.

CSS + JS MIT licensed
Live Demo Open in tab

This is a full-page demo — interact inside the frame above, or open it in the playground for the full-screen experience.

Open in playground

The code

<div class="wrap">
  <h1>CSS Ripple Effect</h1>
  <p class="sub">Material Design ripple on click — click any element below to trigger the wave</p>

  <span class="sl">Contained buttons</span>
  <div class="grid">
    <button class="mat-btn mat-contained ripple c-purple"><span>Primary</span></button>
    <button class="mat-btn mat-contained ripple c-pink"><span>Secondary</span></button>
    <button class="mat-btn mat-contained ripple c-teal"><span>Success</span></button>
    <button class="mat-btn mat-contained ripple c-orange"><span>Warning</span></button>
  </div>

  <span class="sl">Outlined + text buttons</span>
  <div class="grid">
    <button class="mat-btn mat-outlined ripple c-purple"><span>Outlined</span></button>
    <button class="mat-btn mat-outlined ripple c-pink"><span>Outlined</span></button>
    <button class="mat-btn mat-text ripple c-teal"><span>Text button</span></button>
    <button class="mat-btn mat-text ripple c-orange"><span>Text button</span></button>
  </div>

  <span class="sl">FABs + chips</span>
  <div style="display:flex;gap:16px;align-items:flex-start;flex-wrap:wrap;margin-bottom:48px">
    <button class="mat-fab ripple c-purple">✚</button>
    <button class="mat-fab ripple c-pink">♥</button>
    <button class="mat-fab ripple c-teal">↑</button>
    <button class="mat-fab ripple c-orange">✎</button>
  </div>

  <span class="sl">Filter chips</span>
  <div class="mat-chips" id="chips">
    <div class="mat-chip ripple selected c-purple" data-chip>All</div>
    <div class="mat-chip ripple" data-chip>Design</div>
    <div class="mat-chip ripple" data-chip>Development</div>
    <div class="mat-chip ripple" data-chip>Marketing</div>
    <div class="mat-chip ripple" data-chip>Research</div>
    <div class="mat-chip ripple" data-chip>Strategy</div>
  </div>

  <span class="sl">List items</span>
  <div class="mat-list">
    <div class="mat-list-item ripple"><div class="mat-list-icon" style="--ic:#e8eaf6">📧</div><div class="mat-list-text"><div class="mat-list-title">Inbox</div><div class="mat-list-sub">3 unread messages</div></div></div>
    <div class="mat-list-item ripple"><div class="mat-list-icon" style="--ic:#fce4ec">⭐</div><div class="mat-list-text"><div class="mat-list-title">Starred</div><div class="mat-list-sub">12 starred items</div></div></div>
    <div class="mat-list-item ripple"><div class="mat-list-icon" style="--ic:#e0f7fa">📤</div><div class="mat-list-text"><div class="mat-list-title">Sent</div><div class="mat-list-sub">All sent messages</div></div></div>
    <div class="mat-list-item ripple"><div class="mat-list-icon" style="--ic:#fff3e0">🗑️</div><div class="mat-list-text"><div class="mat-list-title">Trash</div><div class="mat-list-sub">Auto-deleted in 30 days</div></div></div>
  </div>

  <span class="sl">Cards</span>
  <div class="grid-2">
    <div class="mat-card ripple"><h3>📊 Analytics Report</h3><p>Monthly performance summary across all tracked campaigns and organic channels.</p></div>
    <div class="mat-card ripple"><h3>🚀 Deploy Pipeline</h3><p>Automated CI/CD with staging, canary release and one-click rollback capability.</p></div>
  </div>
</div>
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap');
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Roboto',sans-serif;background:#fafafa;color:#212121;min-height:100vh;padding:60px 24px}
.wrap{max-width:1000px;margin:0 auto}
h1{font-size:clamp(2rem,5vw,3rem);font-weight:700;text-align:center;margin-bottom:8px;letter-spacing:-.02em}
.sub{text-align:center;color:#757575;margin-bottom:56px}
.sl{font-size:.65rem;font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:#9e9e9e;margin-bottom:16px;display:block}
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:20px;margin-bottom:48px}
.grid-2{display:grid;grid-template-columns:1fr 1fr;gap:20px;margin-bottom:48px}
@media(max-width:600px){.grid-2{grid-template-columns:1fr}}

/* RIPPLE CORE */
.ripple{position:relative;overflow:hidden;cursor:pointer;user-select:none;-webkit-tap-highlight-color:transparent}
.ripple-wave{position:absolute;border-radius:50%;transform:scale(0);animation:trn13-ripple .6s cubic-bezier(.4,0,.2,1) forwards;pointer-events:none}
@keyframes trn13-ripple{to{transform:scale(4);opacity:0}}

/* Material Buttons */
.mat-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;font-family:'Roboto';font-weight:500;font-size:.875rem;letter-spacing:.089em;text-transform:uppercase;padding:0 24px;height:36px;border:none;border-radius:4px;cursor:pointer;position:relative;overflow:hidden;transition:box-shadow .28s cubic-bezier(.4,0,.2,1)}
.mat-btn span{position:relative;z-index:1}

/* Contained */
.mat-contained{background:var(--c,#6200ea);color:#fff;box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12)}
.mat-contained:hover{box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12)}
.mat-contained .ripple-wave{background:rgba(255,255,255,.3)}

/* Outlined */
.mat-outlined{background:transparent;color:var(--c,#6200ea);border:1px solid currentColor}
.mat-outlined .ripple-wave{background:rgba(var(--crgb,98,0,234),.12)}

/* Text */
.mat-text{background:transparent;color:var(--c,#6200ea)}
.mat-text .ripple-wave{background:rgba(var(--crgb,98,0,234),.12)}

/* FAB */
.mat-fab{width:56px;height:56px;border-radius:50%;background:var(--c,#6200ea);color:#fff;font-size:1.2rem;border:none;cursor:pointer;position:relative;overflow:hidden;display:grid;place-items:center;box-shadow:0 3px 5px -1px rgba(0,0,0,.2),0 6px 10px 0 rgba(0,0,0,.14),0 1px 18px 0 rgba(0,0,0,.12);transition:box-shadow .28s}
.mat-fab:hover{box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}
.mat-fab .ripple-wave{background:rgba(255,255,255,.3)}

/* Card ripple */
.mat-card{background:#fff;border-radius:4px;padding:24px;cursor:pointer;position:relative;overflow:hidden;box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12);transition:box-shadow .28s}
.mat-card:hover{box-shadow:0 3px 3px -2px rgba(0,0,0,.2),0 3px 4px 0 rgba(0,0,0,.14),0 1px 8px 0 rgba(0,0,0,.12)}
.mat-card .ripple-wave{background:rgba(0,0,0,.08)}
.mat-card h3{font-size:1rem;font-weight:500;margin-bottom:8px;position:relative;z-index:1}
.mat-card p{font-size:.875rem;color:#757575;line-height:1.5;position:relative;z-index:1}

/* List ripple */
.mat-list{background:#fff;border-radius:4px;overflow:hidden;box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12);margin-bottom:48px}
.mat-list-item{display:flex;align-items:center;gap:16px;padding:16px;cursor:pointer;position:relative;overflow:hidden;border-bottom:1px solid rgba(0,0,0,.12);transition:background .15s}
.mat-list-item:last-child{border:0}
.mat-list-item:hover{background:rgba(0,0,0,.04)}
.mat-list-item .ripple-wave{background:rgba(0,0,0,.08)}
.mat-list-icon{width:40px;height:40px;border-radius:50%;background:var(--ic,#e8eaf6);display:grid;place-items:center;font-size:1.1rem;flex:0 0 40px;position:relative;z-index:1}
.mat-list-text{position:relative;z-index:1}
.mat-list-title{font-size:.875rem;font-weight:500}
.mat-list-sub{font-size:.75rem;color:#757575;margin-top:2px}

/* Chip ripple */
.mat-chips{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:48px}
.mat-chip{display:inline-flex;align-items:center;gap:6px;padding:0 12px;height:32px;border-radius:16px;background:#e0e0e0;font-size:.875rem;font-weight:500;cursor:pointer;position:relative;overflow:hidden;transition:background .2s}
.mat-chip:hover,.mat-chip.selected{background:#bdbdbd}
.mat-chip.selected{background:var(--c,#6200ea);color:#fff}
.mat-chip .ripple-wave{background:rgba(0,0,0,.1)}
.mat-chip.selected .ripple-wave{background:rgba(255,255,255,.3)}

/* colours */
.c-purple{--c:#6200ea;--crgb:98,0,234}
.c-pink{--c:#e91e63;--crgb:233,30,99}
.c-teal{--c:#009688;--crgb:0,150,136}
.c-orange{--c:#ff5722;--crgb:255,87,34}
.c-indigo{--c:#3f51b5;--crgb:63,81,181}

@media (prefers-reduced-motion:reduce){.ripple-wave{animation:none !important}}
// Ripple on click
document.querySelectorAll('.ripple').forEach(el => {
  el.addEventListener('click', e => {
    const rect = el.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    const size = Math.max(rect.width, rect.height) * 2;
    const wave = document.createElement('span');
    wave.className = 'ripple-wave';
    wave.style.cssText = `width:${size}px;height:${size}px;left:${x - size/2}px;top:${y - size/2}px`;
    el.appendChild(wave);
    wave.addEventListener('animationend', () => wave.remove());
  });
});
// Chip toggle
document.getElementById('chips').addEventListener('click', e => {
  const chip = e.target.closest('[data-chip]');
  if(!chip) return;
  chip.classList.toggle('selected');
});

Search CodeFronts

Loading…