Salta al contenuto principale

07 - CSS Anchor Positioning: Tooltip e Dropdown Senza JavaScript

CSS Anchor Positioning: Tooltip e Dropdown Senza JavaScript Costruire un tooltip in JavaScript significa scrivere codice per calcolare la posizione...

Cosa ne pensi di questo articolo?

07 - CSS Anchor Positioning: Tooltip e Dropdown Senza JavaScript
Core Web VitalsFoto:cottonbro studioPexels

In Breve

CSS Anchor Positioning: Tooltip e Dropdown Senza JavaScript Costruire un tooltip in JavaScript significa scrivere codice per calcolare la posizione...

CSS Anchor Positioning: Tooltip e Dropdown Senza JavaScript

Costruire un tooltip in JavaScript significa scrivere codice per calcolare la posizione dell'elemento relativa al suo trigger, aggiornare quella posizione su resize e scroll, gestire i casi edge quando il tooltip finisce fuori dal viewport, e fare tutto questo senza introdurre layout thrashing. Non e complesso, ma e codice ripetitivo che ogni applicazione reinventa da zero.

La CSS Anchor Positioning API risolve questo problema con CSS puro e dichiarativo. Con supporto browser all'86% globale all'inizio del 2026 (Chrome 125+, Edge 125+, Chrome for Android, Safari Technology Preview), la tecnica e matura per la produzione su siti che supportano browser moderni. Permette di "ancorare" un elemento a un altro come punto di riferimento per il posizionamento, con fallback automatici se non c'e abbastanza spazio.

Cosa Imparerai

  • I concetti fondamentali di CSS Anchor Positioning: anchor, positioned element
  • Le proprieta anchor-name e position-anchor
  • La funzione anchor() per il posizionamento relativo
  • Come implementare tooltip, dropdown e context menu in CSS puro
  • I fallback automatici con position-try-fallbacks
  • Come integrare con Popover API per accessibilita completa
  • Progressive enhancement per browser senza supporto

I Concetti Fondamentali

CSS Anchor Positioning introduce due ruoli:

  • L'anchor element (elemento ancora): l'elemento a cui ci ancoriamo. Riceve la proprieta anchor-name con un valore custom identifier (prefisso --).
  • Il positioned element (elemento posizionato): l'elemento che vogliamo posizionare relativamente all'ancora. Deve avere position: absolute o position: fixed, e riceve position-anchor per collegarsi all'ancora.
/* 1. Definisci l'ancora */
.button-trigger {
  anchor-name: --tooltip-anchor;
}

/* 2. Posiziona l'elemento relativamente all'ancora */
.tooltip {
  position: absolute;
  /* Collega questo elemento all'ancora */
  position-anchor: --tooltip-anchor;

  /* Posizionamento usando la funzione anchor() */
  /* anchor(bottom) = il bordo bottom dell'ancora */
  top: calc(anchor(bottom) + 8px);
  /* Centra orizzontalmente rispetto all'ancora */
  left: anchor(center);
  transform: translateX(-50%);
}

La Funzione anchor()

La funzione anchor() risolve a una coordinata relativa al bordo specificato dell'elemento ancora. I valori disponibili sono:

  • anchor(top): bordo superiore dell'ancora
  • anchor(bottom): bordo inferiore dell'ancora
  • anchor(left): bordo sinistro dell'ancora
  • anchor(right): bordo destro dell'ancora
  • anchor(center): centro orizzontale dell'ancora
  • anchor(middle): centro verticale dell'ancora
  • anchor(self-start), anchor(self-end): relativi alla direzione del testo
/* Tooltip sopra il trigger */
.tooltip-top {
  position: absolute;
  position-anchor: --my-anchor;
  bottom: calc(anchor(top) - 8px);
  left: anchor(center);
  transform: translateX(-50%);
}

/* Tooltip a destra del trigger */
.tooltip-right {
  position: absolute;
  position-anchor: --my-anchor;
  top: anchor(center);
  left: calc(anchor(right) + 8px);
  transform: translateY(-50%);
}

/* Dropdown sotto il trigger - allineato a sinistra */
.dropdown {
  position: absolute;
  position-anchor: --dropdown-anchor;
  top: calc(anchor(bottom) + 4px);
  left: anchor(left);
  min-width: anchor-size(width); /* larghezza minima = larghezza dell'ancora */
}

anchor-size(): Dimensioni Relative all'Ancora

Oltre alla funzione anchor() per le coordinate, anchor-size() permette di accedere alle dimensioni dell'elemento ancora:

/* Il dropdown ha la stessa larghezza del trigger */
.dropdown {
  min-width: anchor-size(width);

  /* Altezza massima pari al 50% dell'altezza dell'ancora */
  max-height: calc(anchor-size(height) * 0.5);
}

Tooltip Accessibile: CSS Anchor + Popover API

La combinazione ottimale per tooltip accessibili nel 2026 e CSS Anchor Positioning con la Popover API. La Popover API gestisce automaticamente il focus management, il click-outside per chiudere, e l'accessibilita ARIA. CSS Anchor Positioning gestisce il posizionamento visivo.

<!-- HTML: Popover API + Anchor Positioning -->
<button
  popovertarget="tooltip-content"
  class="btn-with-tooltip"
>
  Hover per info
</button>

<div
  id="tooltip-content"
  popover="hint"
  class="tooltip"
  role="tooltip"
>
  Informazione contestuale utile all'utente
</div>
/* CSS: Anchor + Popover */
.btn-with-tooltip {
  anchor-name: --btn-anchor;
}

.tooltip {
  /* Stili base del tooltip */
  position: absolute;
  position-anchor: --btn-anchor;

  /* Posiziona sotto il pulsante */
  top: calc(anchor(bottom) + 8px);
  left: anchor(center);
  transform: translateX(-50%);

  /* Reset stili popover */
  margin: 0;
  border: 1px solid #e2e8f0;
  border-radius: 6px;
  padding: 8px 12px;
  background: white;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  font-size: 0.875rem;
  max-width: 280px;
  width: max-content;

  /* Animazione di entrata */
  opacity: 0;
  transition: opacity 0.15s ease;

  /* Stato visibile (Popover API) */
  &:popover-open {
    opacity: 1;
  }
}

/* Freccia del tooltip */
.tooltip::before {
  content: '';
  position: absolute;
  top: -8px;
  left: 50%;
  transform: translateX(-50%);
  border: 4px solid transparent;
  border-bottom-color: #e2e8f0;
}

.tooltip::after {
  content: '';
  position: absolute;
  top: -7px;
  left: 50%;
  transform: translateX(-50%);
  border: 4px solid transparent;
  border-bottom-color: white;
}

Dropdown Menu Completo

Un esempio piu completo: un dropdown menu da un pulsante "Azioni" con CSS Anchor Positioning e Popover API per la gestione accessibile del focus:

<!-- Bottone trigger -->
<button
  class="actions-btn"
  popovertarget="actions-menu"
  aria-haspopup="true"
>
  Azioni ▼
</button>

<!-- Menu dropdown -->
<menu
  id="actions-menu"
  popover="auto"
  class="dropdown-menu"
>
  <li><button>Modifica</button></li>
  <li><button>Duplica</button></li>
  <li class="separator"></li>
  <li><button class="danger">Elimina</button></li>
</menu>
/* CSS del dropdown */
.actions-btn {
  anchor-name: --actions-anchor;
}

.dropdown-menu {
  position: absolute;
  position-anchor: --actions-anchor;

  /* Allinea il bordo sinistro del menu con il pulsante */
  top: calc(anchor(bottom) + 4px);
  left: anchor(left);

  /* Larghezza minima pari al pulsante */
  min-width: anchor-size(width);

  /* Reset stili menu */
  margin: 0;
  padding: 4px 0;
  list-style: none;
  background: white;
  border: 1px solid #e2e8f0;
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);

  /* Animazione */
  opacity: 0;
  scale: 0.95;
  transform-origin: top left;
  transition: opacity 0.15s, scale 0.15s;

  &:popover-open {
    opacity: 1;
    scale: 1;
  }
}

.dropdown-menu li button {
  display: block;
  width: 100%;
  padding: 8px 16px;
  text-align: left;
  border: none;
  background: none;
  cursor: pointer;
  font-size: 0.875rem;

  &:hover {
    background: #f8fafc;
  }

  &.danger {
    color: #ef4444;
  }
}

.dropdown-menu .separator {
  height: 1px;
  background: #e2e8f0;
  margin: 4px 0;
}

Fallback Automatici con position-try-fallbacks

Uno dei problemi piu noiosi dei tooltip e dei dropdown e gestire i casi in cui non c'e abbastanza spazio: un tooltip che finisce fuori dal viewport in alto o a sinistra deve essere riposizionato automaticamente.

CSS Anchor Positioning risolve questo con position-try-fallbacks, che specifica una lista di posizionamenti alternativi che il browser testa in sequenza:

/* Definisci i posizionamenti alternativi */
@position-try --below {
  top: calc(anchor(bottom) + 8px);
  bottom: auto;
  left: anchor(center);
  right: auto;
}

@position-try --above {
  top: auto;
  bottom: calc(anchor(top) + 8px);
  left: anchor(center);
  right: auto;
}

@position-try --right {
  top: anchor(center);
  left: calc(anchor(right) + 8px);
  right: auto;
  bottom: auto;
}

@position-try --left {
  top: anchor(center);
  right: calc(anchor(left) + 8px);
  left: auto;
  bottom: auto;
}

.tooltip {
  position: absolute;
  position-anchor: --my-anchor;

  /* Posizionamento default: sotto */
  top: calc(anchor(bottom) + 8px);
  left: anchor(center);
  transform: translateX(-50%);

  /* Fallback: prova prima sopra, poi destra, poi sinistra */
  position-try-fallbacks: --above, --right, --left;

  /* Fallback finale: usa la prima opzione disponibile nel viewport */
  position-try-order: most-block-size;
}

Progressive Enhancement per Browser Senza Supporto

Per browser che non supportano ancora CSS Anchor Positioning (Firefox stabile non lo supporta ancora all'inizio del 2026), usa @supports per fornire un fallback:

/* Fallback: tooltip sempre visibile o con JS */
.tooltip {
  /* Stili di default accessibili: mostro un title attribute */
  display: none; /* nascosto, gestito da JS fallback */
}

/* Se il browser supporta anchor positioning: CSS puro */
@supports (anchor-name: --test) {
  .trigger {
    anchor-name: --my-anchor;
  }

  .tooltip {
    display: block; /* visibile, gestito da CSS */
    position: absolute;
    position-anchor: --my-anchor;
    top: calc(anchor(bottom) + 8px);
    left: anchor(center);
    transform: translateX(-50%);

    /* Nascosto di default, mostrato su hover/focus */
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s;
  }

  .trigger:hover + .tooltip,
  .trigger:focus + .tooltip {
    opacity: 1;
    pointer-events: auto;
  }
}

/* JavaScript fallback per browser legacy */
if (!CSS.supports('anchor-name', '--test')) {
  // Import libreria JS per tooltip
  import('./tooltip-fallback.js').then(module => module.init());
}

Firefox: Supporto Ancora Limitato

All'inizio del 2026, Firefox non supporta ancora CSS Anchor Positioning nella versione stabile (e in sviluppo attivo). Questo significa che il 20-25% degli utenti desktop su Firefox vedra il fallback. Usa @supports per assicurarti che l'esperienza sia sempre funzionale, anche senza anchor positioning.

Next Steps

Hai ora tooltip e dropdown declarativi in CSS puro. Il prossimo articolo della serie esplora la View Transitions API: come implementare animazioni fluide di navigazione native nel browser, sia per Single Page Applications che per Multi-Page Applications, senza librerie di terze parti.

Conclusioni

CSS Anchor Positioning e una delle aggiunte piu attese al linguaggio CSS degli ultimi anni. Elimina una categoria intera di codice JavaScript - il calcolo manuale delle coordinate di posizionamento - sostituendola con CSS dichiarativo che il browser gestisce nativamente, inclusi i fallback automatici e l'aggiornamento su scroll e resize.

Con supporto all'86% dei browser globali, puoi gia adottarla come enhancement progressivo, assicurandoti che i browser legacy abbiano comunque un'esperienza funzionale. La combinazione con la Popover API per la gestione dell'accessibilita rappresenta lo stack moderno e completo per la costruzione di UI overlay nel 2026.

Prova Questi Strumenti

Strumenti gratuiti correlati a questo argomento.

Commenti

Caricamento commenti...

Accedi per commentare

Discuti questo articolo nella community

Unisciti al gruppo Telegram per discutere con altri sviluppatori, fare domande e condividere le tue esperienze.

Ti è piaciuto questo articolo?

Esplora altri contenuti sul blog o scopri i miei progetti