Questo è uno di quegli effetti hover che sembrano sofisticati ma girano su quasi zero codice: un bordo circolare fluido che cresce attorno a un link social, in sincrono con l’icona che cambia colore. La sorpresa è che GSAP non anima mai il bordo — fa solo il toggle di una classe, e il CSS gestisce tutta l’animazione dietro le quinte.
È una bella vetrina di due feature CSS poco usate — i conic gradient e la regola @property — più il tema ricorrente di questo corso: usa GSAP solo dove serve davvero.
Come funziona
Il colore dell’icona è puro CSS. Il link è un cerchio (display: flex, centrato, border-radius: 100%, sfondo scuro) con un’icona SVG il cui path usa fill: currentColor. Il trucco: se imposti il colore sull’embed dell’icona, sovrascrive quello ereditato, quindi un hover sul genitore non lo raggiunge. Metti invece il colore sul link genitore, aggiungi una transizione di font-color e imposta il colore nello stato hover — ora l’icona eredita e anima grigio → verde in hover, senza JavaScript.
Il bordo è un’illusione. Non c’è nessuna proprietà border. Avvolgi il link in un cerchio leggermente più grande (section_link-wrapper, border-radius: 100%); il link interno ne copre gran parte, lasciando visibile solo un anello sottile. Dai a quell’anello uno sfondo conic-gradient (conic perché il colore si diffonde radialmente attorno a un cerchio), e anima quanto il gradiente si riempie — da niente fino a tutto il giro — e si legge come un bordo che si disegna da solo.
@property rende animabile il gradiente. Non puoi transizionare fluidamente una variabile CSS normale — il browser la tratta come testo. Quindi registra la quantità di riempimento con la regola @property (syntax: '<percentage>', inherits: true, initial-value: 0%), che dice al browser che è un valore reale e tipizzato. Metti una transition su quella proprietà (0.8s, expo) e una regola che la porta a 100% quando è presente una classe on-hover. All’incirca:
<!-- Embed sul body, caricato prima della sezione -->
<style>
@property --double-fill {
syntax: '<percentage>';
inherits: true;
initial-value: 0%;
}
[data-animate-link-border] {
transition: --double-fill 0.8s cubic-bezier(0.16, 1, 0.3, 1);
background: conic-gradient(var(--green-yellow) var(--double-fill), transparent 0);
}
[data-animate-link-border].on-hover {
--double-fill: 100%;
}
</style>
L’unico compito di GSAP è la classe. Un’interazione hover (mouse-enter + mouse-leave) usa una action set per fare il toggle della classe on-hover sul wrapper — colpito via data-animate-link-border con un filtro direct parent of trigger così solo il wrapper del link su cui passi è interessato. La transizione CSS fa il resto: fill a 100% all’enter, di nuovo a 0% al leave. Dato che è guidato da attributi, duplicare il link “funziona e basta” — ognuno anima in modo indipendente.
Come si usa
-
Link + icona. Link block (
section_link): flex centrato,7remquadrato, sfondo scuro,border-radius: 100%. Dentro, un embed con il tuo SVG (pathfill: currentColor),display: flex. Metti il colore sul link (non sull’embed), aggiungi una transizione difont-color(0.8s expo) e imposta il colore nello stato hover. -
Wrapper del finto bordo. Avvolgi il link in
section_link-wrapper: quadrato leggermente più grande, flex centrato,border-radius: 100%. Aggiungi l’attributodata-animate-link-border. -
Il CSS. Aggiungi un embed sul body con il CSS
@property+ conic-gradient qui sopra (mettilodisplay: nonee trascinalo sopra la sezione così carica per primo). -
Registra la classe. Aggiungi un
divnascosto con la classeon-hover(idealmente in uno style guide) così Webflow la mantiene e GSAP può farne il toggle. -
L’interazione. Aggiungi
data-animate-linkal link. Crea un’interazione hover con mouse-enter + mouse-leave; una action set che fa il toggle della classeon-hover, targetdata-animate-link-borderfiltrato per direct parent of trigger. Abilita il codice custom (o pubblica) per testare — il CSS non standard non gira nella preview semplice.
Il CSS esatto (colori, stop del gradiente) sta nel cloneable — lo snippet qui sopra è la sua forma; verifica i valori sul cloneable.