← Catalogue

CTA Pill

Bouton pill avec une pastille fléchée qui permute avec le label au survol.

#cta#hover#pill#bouton

Aperçu

CTA Pill

Code source

HTML
<a href="#" class="wtl-cta" data-cta-swap>
<span class="wtl-cta__icon" aria-hidden="true">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
<path d="M5 12h14" />
<path d="m13 6 6 6-6 6" />
</svg>
</span>
<span class="wtl-cta__label">Discuter de votre projet</span>
</a>
CSS
/* CTA Pill - pastille fléchée qui permute avec le label au survol.
Réutilisable : aucune dépendance, police Geist. */
.wtl-cta {
--cta-bg: #ffcc00; /* fond du pill */
--cta-ink: #151313; /* pastille + texte */
display: inline-flex;
align-items: center;
justify-content: space-between;
gap: 12px;
height: 48px;
padding: 0 16px 0 6px;
border-radius: 9999px;
background: var(--cta-bg);
text-decoration: none;
font-family: "Geist", system-ui, sans-serif;
overflow: hidden;
}
.wtl-cta__icon {
flex: none;
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 9999px;
background: var(--cta-ink);
color: var(--cta-bg); /* couleur de la flèche */
}
.wtl-cta__label {
color: var(--cta-ink);
font-size: 16px;
line-height: 24px;
font-weight: 500;
white-space: nowrap;
}
/* Swap circle/texte au survol - pointeur fin uniquement */
@media (hover: hover) and (pointer: fine) {
.wtl-cta__icon,
.wtl-cta__label {
transition: transform 0.45s cubic-bezier(0.7, 0, 0.3, 1);
will-change: transform;
}
.wtl-cta:hover .wtl-cta__icon {
transform: translateX(var(--swap-first, 0));
}
.wtl-cta:hover .wtl-cta__label {
transform: translateX(var(--swap-last, 0));
}
}
JS
// CTA Pill - calcule les décalages pour permuter la pastille et le label.
(function () {
function setup() {
document.querySelectorAll(".wtl-cta[data-cta-swap]").forEach(function (btn) {
var first = btn.firstElementChild;
var last = btn.lastElementChild;
if (!first || !last) return;
var cs = getComputedStyle(btn);
var pl = parseFloat(cs.paddingLeft) || 0;
var pr = parseFloat(cs.paddingRight) || 0;
var gap = parseFloat(cs.columnGap) || parseFloat(cs.gap) || 0;
var fw = first.offsetWidth;
var lw = last.offsetWidth;
// La pastille glisse à droite, le label prend sa place à gauche.
btn.style.setProperty("--swap-first", lw + gap + pr - pl + "px");
btn.style.setProperty("--swap-last", pr - (pl + fw + gap) + "px");
});
}
setup();
window.addEventListener("load", setup);
window.addEventListener("resize", setup);
})();