12 CSS Ripple Effects 07 / 12

CSS Heartbeat Pulse Ripple Effect

A cardiac monitor UI — a large animated heart icon with three concentric fill-pulse rings and two stroke rings, a looping SVG ECG trace with animated stroke-dashoffset, vital-signs stat tiles and a blinking LIVE indicator.

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="rpl-07">
  <div class="rpl-07__bg" id="rpl-07-bg"></div>

  <div class="rpl-07__header">
    <h1>Heartbeat Pulse Ripple Effect</h1>
    <p>CSS keyframe animation with multi-wave pulse rings and ECG trace</p>
  </div>

  <div class="rpl-07__hero">
    <div class="rpl-07__pulse"></div>
    <div class="rpl-07__pulse"></div>
    <div class="rpl-07__pulse"></div>
    <div class="rpl-07__ring-border"></div>
    <div class="rpl-07__ring-border"></div>
    <div class="rpl-07__heart">❤️</div>
    <div class="rpl-07__bpm"><b>72</b> BPM</div>
  </div>

  <div class="rpl-07__ecg">
    <div class="rpl-07__ecg-label">ECG · Lead II</div>
    <svg viewBox="0 0 560 64" preserveAspectRatio="none">
      <path class="rpl-07__ecg-line"
        d="M0,32 L40,32 L48,32 L52,28 L56,32 L60,32 L66,8 L70,60 L74,20 L78,32 L84,32
           L124,32 L132,32 L136,28 L140,32 L144,32 L150,8 L154,60 L158,20 L162,32 L168,32
           L208,32 L216,32 L220,28 L224,32 L228,32 L234,8 L238,60 L242,20 L246,32 L252,32
           L292,32 L300,32 L304,28 L308,32 L312,32 L318,8 L322,60 L326,20 L330,32 L336,32
           L376,32 L384,32 L388,28 L392,32 L396,32 L402,8 L406,60 L410,20 L414,32 L420,32
           L460,32 L468,32 L472,28 L476,32 L480,32 L486,8 L490,60 L494,20 L498,32 L560,32"/>
    </svg>
  </div>

  <div class="rpl-07__stats">
    <div class="rpl-07__stat">
      <div class="num">72</div>
      <div class="lbl">BPM</div>
    </div>
    <div class="rpl-07__stat">
      <div class="num">98%</div>
      <div class="lbl">SpO₂</div>
    </div>
    <div class="rpl-07__stat">
      <div class="num">120</div>
      <div class="lbl">SBP</div>
    </div>
    <div class="rpl-07__stat">
      <div class="num">80</div>
      <div class="lbl">DBP</div>
    </div>
  </div>

  <div class="rpl-07__live">
    <div class="rpl-07__dot"></div>
    Live monitoring · CSS animation only
  </div>
</div>
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;600;700;800&display=swap');

.rpl-07, .rpl-07 *, .rpl-07 *::before, .rpl-07 *::after { box-sizing: border-box; margin: 0; padding: 0; }
.rpl-07 ::selection { background: #fb2d5c; color: #fff; }

.rpl-07 {
  font-family: 'Nunito', sans-serif;
  background: linear-gradient(160deg, #0d0009 0%, #1a0010 40%, #0d000b 100%);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 48px;
  padding: 60px 24px;
  color: #ffe8ee;
  overflow: hidden;
  position: relative;
}

/* subtle particles background */
.rpl-07__bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}
.rpl-07__bg-dot {
  position: absolute;
  border-radius: 50%;
  background: rgba(251,45,92,0.35);
  animation: rpl-07-float linear infinite;
}
@keyframes rpl-07-float {
  0% { transform: translateY(0) scale(1); opacity: 0.6; }
  100% { transform: translateY(-100vh) scale(0.2); opacity: 0; }
}

.rpl-07__header {
  text-align: center;
  z-index: 2;
}
.rpl-07__header h1 {
  font-size: clamp(1.6rem, 4vw, 2.4rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  color: #ffe8ee;
}
.rpl-07__header p {
  margin-top: 8px;
  color: rgba(255,232,238,0.45);
  font-weight: 300;
  font-size: 0.9rem;
}

/* ─── Hero heartbeat ─── */
.rpl-07__hero {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 220px; height: 220px;
  z-index: 2;
}

/* Pulse rings */
.rpl-07__pulse {
  position: absolute;
  border-radius: 50%;
  background: rgba(251,45,92,0.15);
  animation: rpl-07-pulse 1.5s ease-out infinite;
}
.rpl-07__pulse:nth-child(1) { width: 100%; height: 100%; animation-delay: 0s; }
.rpl-07__pulse:nth-child(2) { width: 100%; height: 100%; animation-delay: 0.5s; }
.rpl-07__pulse:nth-child(3) { width: 100%; height: 100%; animation-delay: 1.0s; }
@keyframes rpl-07-pulse {
  0%   { transform: scale(0.8); opacity: 1; }
  100% { transform: scale(1.7); opacity: 0; }
}

/* Ring borders */
.rpl-07__ring-border {
  position: absolute;
  border-radius: 50%;
  border: 2px solid rgba(251,45,92,0.6);
  animation: rpl-07-ring 1.5s ease-out infinite;
}
.rpl-07__ring-border:nth-child(4) { width: 100%; height: 100%; animation-delay: 0s; }
.rpl-07__ring-border:nth-child(5) { width: 100%; height: 100%; animation-delay: 0.5s; }
@keyframes rpl-07-ring {
  0%   { transform: scale(0.85); opacity: 0.9; }
  100% { transform: scale(1.65); opacity: 0; }
}

/* The heart itself */
.rpl-07__heart {
  position: relative;
  z-index: 3;
  font-size: 72px;
  line-height: 1;
  animation: rpl-07-beat 1.5s ease-in-out infinite;
  filter: drop-shadow(0 0 20px rgba(251,45,92,0.7)) drop-shadow(0 0 40px rgba(251,45,92,0.3));
}
@keyframes rpl-07-beat {
  0%, 100% { transform: scale(1); }
  14%      { transform: scale(1.18); }
  28%      { transform: scale(1); }
  42%      { transform: scale(1.12); }
  70%      { transform: scale(1); }
}

/* BPM display */
.rpl-07__bpm {
  position: absolute;
  bottom: -36px;
  font-size: 0.75rem;
  color: rgba(255,232,238,0.5);
  letter-spacing: 0.1em;
}
.rpl-07__bpm b { color: #fb2d5c; font-weight: 800; font-size: 1.1rem; }

/* ECG line SVG */
.rpl-07__ecg {
  z-index: 2;
  width: min(560px, 100%);
  background: rgba(251,45,92,0.04);
  border: 1px solid rgba(251,45,92,0.15);
  border-radius: 12px;
  padding: 18px 20px;
  overflow: hidden;
  position: relative;
}
.rpl-07__ecg-label {
  font-size: 0.65rem;
  color: rgba(251,45,92,0.5);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  margin-bottom: 10px;
}
.rpl-07__ecg svg {
  width: 100%;
  height: 64px;
  overflow: visible;
}
.rpl-07__ecg-line {
  fill: none;
  stroke: #fb2d5c;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  filter: drop-shadow(0 0 4px rgba(251,45,92,0.6));
  stroke-dasharray: 1000;
  stroke-dashoffset: 1000;
  animation: rpl-07-draw 3s linear infinite;
}
@keyframes rpl-07-draw {
  to { stroke-dashoffset: 0; }
}

/* Stats row */
.rpl-07__stats {
  display: flex;
  gap: 24px;
  z-index: 2;
  flex-wrap: wrap;
  justify-content: center;
}
.rpl-07__stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  background: rgba(251,45,92,0.06);
  border: 1px solid rgba(251,45,92,0.15);
  border-radius: 12px;
  padding: 16px 22px;
  min-width: 100px;
}
.rpl-07__stat .num {
  font-size: 1.5rem;
  font-weight: 800;
  color: #fb2d5c;
  line-height: 1;
}
.rpl-07__stat .lbl {
  font-size: 0.7rem;
  color: rgba(255,232,238,0.4);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

/* Animated live indicator */
.rpl-07__live {
  display: flex;
  align-items: center;
  gap: 8px;
  z-index: 2;
  font-size: 0.75rem;
  color: rgba(255,232,238,0.4);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.rpl-07__dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: #fb2d5c;
  box-shadow: 0 0 8px #fb2d5c;
  animation: rpl-07-blink 1.5s steps(2) infinite;
}
@keyframes rpl-07-blink { 50% { opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .rpl-07__pulse, .rpl-07__ring-border, .rpl-07__heart, .rpl-07__bg-dot, .rpl-07__ecg-line, .rpl-07__dot { animation: none !important; }
  .rpl-07__pulse { opacity: 0.2; }
}
(function() {
  const bg = document.getElementById('rpl-07-bg');
  for (let i = 0; i < 20; i++) {
    const d = document.createElement('div');
    d.className = 'rpl-07__bg-dot';
    const size = Math.random() * 4 + 1;
    d.style.cssText = `
      width:${size}px;height:${size}px;
      left:${Math.random()*100}%;
      top:${Math.random()*100}%;
      animation-duration:${Math.random()*8+6}s;
      animation-delay:${Math.random()*-8}s;
    `;
    bg.appendChild(d);
  }
})();

Search CodeFronts

Loading…