JSFiddle - React, Tailwind, and code Playground

by Jordan Sayner

HTML

<div class="card-wrapper">
  <div class="card">
    <h2>Card Title</h2>
    <p>Card description...</p>
  </div>
  <div class="card">
    <h2>Another title</h2>
    <p>More information...</p>
  </div>
  <div class="card">
    <h2>Another title</h2>
    <p>More information...</p>
  </div>
  <div class="card">
    <h2>Another title</h2>
    <p>More information...</p>
  </div>
  <div class="card">
    <h2>Another title</h2>
    <p>More information...</p>
  </div>
  <div class="card">
    <h2>Another title</h2>
    <p>More information...</p>
  </div>
  <div class="card">
    <h2>Another title</h2>
    <p>More information...</p>
  </div>
  <div class="card">
    <h2>Another title</h2>
    <p>More information...</p>
  </div>
</div>

CSS

.card-wrapper {
  display: flex;
  flex-direction: column;
  margin: 0 auto;
  position: relative;
}

.card {
  background-color: #fff;
  border-radius: 5px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
  padding: 20px;
  margin-bottom: 20px; /* Adjust spacing between cards */
  position: sticky;
  top: var(--card-offset, 0);
  transition: transform 0.2s ease-in-out, filter 0.2s ease-in-out;
  aspect-ratio: 1220 / 766;
}

JavaScript

document.addEventListener('scroll', function() {
  const cards = document.querySelectorAll('.card');
  const viewportHeight = window.innerHeight;

  cards.forEach((card, index) => {
    const rect = card.getBoundingClientRect();
    const scrollPosition = window.scrollY + rect.top;

    if (rect.top <= 100) {
      const scaleValue = Math.max(0.8, 1 - (100 - rect.top) / 100);
      const blurValue = Math.min(4, (100 - rect.top) / 10); // Adjusted divisor for more aggressive blur
      card.style.transform = `scale(${scaleValue})`;
      card.style.filter = `blur(${blurValue}px)`;
      card.style.zIndex = 0;
    } else {
      card.style.transform = 'scale(1)';
      card.style.filter = 'blur(0px)';
      card.style.zIndex = 1;
    }
  });
});