interactions · curseur

Curseur personnalisé

Remplace le curseur natif par un cercle qui suit la souris et change d'aspect selon l'élément survolé (lien, zone de drag...). Nécessite du JavaScript.

Voir le code source
<style>
.bn-cursor-zone {
  position: relative;
  min-height: 260px;
  overflow: hidden;

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

  /* On masque le curseur natif du navigateur DANS cette zone
     uniquement — c'est ce qui rend le curseur personnalisé crédible */
  cursor: none;
}

.bn-cursor-zone__hint {
  color: #979793;
  font-size: 0.85rem;
  margin: 0 0 2rem;
}

.bn-cursor-zone__row {
  display: flex;
  gap: 1.5rem;
}

.bn-cursor-zone__link {
  color: #E6E4DD;
  text-decoration: underline;
  font-size: 0.9rem;
}

.bn-cursor-zone__drag {
  padding: 0.6rem 1.2rem;
  border: 1px solid rgba(230, 228, 221, 0.3);
  border-radius: 999px;
  background: none;
  color: #E6E4DD;
  font-size: 0.85rem;
}

.bn-custom-cursor {
  position: absolute;
  top: 0;
  left: 0;
  width: 20px;
  height: 20px;

  border: 1px solid #E6E4DD;
  border-radius: 50%;

  pointer-events: none;
  transform: translate(-50%, -50%);
  /* Se déplace en douceur plutôt que de suivre pile la souris —
     donne un effet plus organique */
  transition: width 0.2s ease, height 0.2s ease, background 0.2s ease,
    transform 0.08s linear;

  opacity: 0;
}

.bn-cursor-zone:hover .bn-custom-cursor {
  opacity: 1;
}

/* États : grandit et se remplit selon l'élément survolé */
.bn-custom-cursor.is-over-link {
  width: 44px;
  height: 44px;
  background: rgba(230, 228, 221, 0.15);
}

.bn-custom-cursor.is-over-drag {
  width: 56px;
  height: 56px;
  background: #E6E4DD;
  border-color: transparent;
}

</style>

<div class="bn-cursor-zone" data-fx-root>
  <p class="bn-cursor-zone__hint">Déplacez votre souris dans cette zone.</p>

  <div class="bn-cursor-zone__row">
    <a href="#" class="bn-cursor-zone__link" data-cursor="link">Un lien</a>
    <button type="button" class="bn-cursor-zone__drag" data-cursor="drag">Zone "drag"</button>
  </div>

  <!-- Le curseur personnalisé lui-même : un simple rond positionné
       en absolu, déplacé par script.js pour suivre la souris -->
  <div class="bn-custom-cursor" data-custom-cursor></div>
</div>


<script>
/* ==========================================================
   CURSEUR PERSONNALISÉ
   Un rond suit la souris à l'intérieur de la zone (dont le curseur
   natif est masqué en CSS), et change de taille/couleur selon
   qu'il survole un lien, une zone "drag", ou rien de particulier.
   ========================================================== */

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

  const cursor = zone.querySelector('[data-custom-cursor]');

  zone.addEventListener('mousemove', (event) => {
    const rect = zone.getBoundingClientRect();
    cursor.style.transform = `translate(${event.clientX - rect.left}px, ${event.clientY - rect.top}px) translate(-50%, -50%)`;
  });

  zone.querySelectorAll('[data-cursor]').forEach((el) => {
    el.addEventListener('mouseenter', () => {
      cursor.classList.add(`is-over-${el.dataset.cursor}`);
    });
    el.addEventListener('mouseleave', () => {
      cursor.classList.remove(`is-over-${el.dataset.cursor}`);
    });
  });
})();

</script>