sections · pricing

Pricing (cartes) avec fondu au scroll

3 offres tarifaires en cartes, dont une mise en avant, qui apparaissent en fondu au scroll. Même mécanisme que 'Pricing avec fondu au scroll' (liste), en version cartes.

Effets

Voir le code source
<style>
.bn-pricing-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1.25rem;
  align-items: start;

  padding: 2rem;
  font-family: 'Inter', sans-serif;
  background: #0B0F10;
}

/* Fondu par défaut (peu visible), amené à 1 par la classe
   "is-visible" que script.js ajoute au scroll */
.bn-pricing-cards__row {
  opacity: 0.3;
  transform: translateY(16px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.bn-pricing-cards.fx-fade-scroll .bn-pricing-cards__row.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.bn-pricing-cards:not(.fx-fade-scroll) .bn-pricing-cards__row {
  opacity: 1;
  transform: none;
}

.bn-pricing-cards__card {
  position: relative;
  padding: 1.75rem;
  border: 1px solid rgba(230, 228, 221, 0.12);
  border-radius: 10px;
}

.bn-pricing-cards__card--highlight {
  border-color: #E6E4DD;
  background: rgba(230, 228, 221, 0.03);
}

.bn-pricing-cards__badge {
  position: absolute;
  top: -11px;
  left: 50%;
  transform: translateX(-50%);

  padding: 0.2rem 0.8rem;
  border-radius: 999px;
  background: #E6E4DD;
  color: #0B0F10;
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.bn-pricing-cards__card h3 {
  color: #E6E4DD;
  font-size: 1rem;
  margin: 0 0 0.75rem;
}

.bn-pricing-cards__price {
  color: #E6E4DD;
  font-size: 1.8rem;
  font-weight: 700;
  margin: 0 0 1.25rem;
}

.bn-pricing-cards__price span {
  font-size: 0.8rem;
  font-weight: 400;
  color: #5C6160;
}

.bn-pricing-cards__card ul {
  list-style: none;
  margin: 0 0 1.5rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.bn-pricing-cards__card li {
  color: #979793;
  font-size: 0.8rem;
}

.bn-pricing-cards__btn {
  display: block;
  text-align: center;
  padding: 0.65rem;
  border: 1px solid rgba(230, 228, 221, 0.3);
  border-radius: 999px;
  color: #E6E4DD;
  text-decoration: none;
  font-size: 0.82rem;
  font-weight: 600;
}

.bn-pricing-cards__btn:hover {
  border-color: #E6E4DD;
}

.bn-pricing-cards__btn--primary {
  background: #E6E4DD;
  color: #0B0F10;
  border-color: #E6E4DD;
}

</style>

<section class="bn-pricing-cards fx-fade-scroll" data-fx-root>

  <article class="bn-pricing-cards__card bn-pricing-cards__row">
    <h3>Basic</h3>
    <p class="bn-pricing-cards__price">0€<span>/mois</span></p>
    <ul>
      <li>✓ Accès aux cours gratuits</li>
      <li>✓ Accès communauté</li>
      <li>✓ Projets limités</li>
    </ul>
    <a href="#" class="bn-pricing-cards__btn">Commencer</a>
  </article>

  <article class="bn-pricing-cards__card bn-pricing-cards__card--highlight bn-pricing-cards__row">
    <span class="bn-pricing-cards__badge">Populaire</span>
    <h3>Pro</h3>
    <p class="bn-pricing-cards__price">19€<span>/mois</span></p>
    <ul>
      <li>✓ Tous les cours &amp; contenus</li>
      <li>✓ Retours sur projets</li>
      <li>✓ Certificats</li>
      <li>✓ Support prioritaire</li>
    </ul>
    <a href="#" class="bn-pricing-cards__btn bn-pricing-cards__btn--primary">Essai gratuit</a>
  </article>

  <article class="bn-pricing-cards__card bn-pricing-cards__row">
    <h3>Équipe</h3>
    <p class="bn-pricing-cards__price">49€<span>/mois</span></p>
    <ul>
      <li>✓ Tout Pro inclus</li>
      <li>✓ Gestion d'équipe</li>
      <li>✓ Analytique avancée</li>
      <li>✓ Branding personnalisé</li>
    </ul>
    <a href="#" class="bn-pricing-cards__btn">Contacter les ventes</a>
  </article>

</section>


<script>
/* ==========================================================
   PRICING (CARTES) — FONDU AU SCROLL
   Même mécanisme exactement que "Pricing avec fondu au scroll"
   (liste) : écoute le scroll de la vraie page contenant ce
   composant, révèle chaque carte quand elle entre dans l'écran.
   ========================================================== */

(function () {
  const root = document.querySelector('.bn-pricing-cards[data-fx-root]');
  if (!root) return;

  const cards = document.querySelectorAll('.bn-pricing-cards__row');
  const isInsideFrame = Boolean(window.frameElement);
  const scrollTarget = isInsideFrame ? window.parent : window;

  function frameOffsetTop() {
    return isInsideFrame ? window.frameElement.getBoundingClientRect().top : 0;
  }

  function viewportHeight() {
    return isInsideFrame ? window.parent.innerHeight : window.innerHeight;
  }

  function update() {
    if (!root.classList.contains('fx-fade-scroll')) {
      cards.forEach((card) => card.classList.add('is-visible'));
      return;
    }

    const offset = frameOffsetTop();
    cards.forEach((card) => {
      const cardTop = offset + card.getBoundingClientRect().top;
      card.classList.toggle('is-visible', cardTop < viewportHeight() * 0.9);
    });
  }

  scrollTarget.addEventListener('scroll', update, { passive: true });
  window.addEventListener('resize', update);
  update();
})();

</script>