Navigazione da Tastiera
Consentire a tutti gli utenti di navigare in modo efficiente senza mouse
Scorciatoie da tastiera
- Tab
- Navigare tra elementi interattivi
- Shift + Tab
- Navigazione all'indietro
- Entrée / Espace
- Attivare pulsanti e link
- Échap
- Chiudere modal e menu
- ↑ ↓
- Navigare in liste e menu
Navigazione da tastiera nelle liste
❌ Esempio negativo
Menu con solo navigazione Tab:
<!-- Negativo: Solo navigazione Tab -->
<div class="menu">
<div tabindex="0">🏠 Home</div>
<div tabindex="0">📋 Progetti</div>
<div tabindex="0">👥 Team</div>
<div tabindex="0">📊 Statistiche</div>
<div tabindex="0">⚙️ Impostazioni</div>
</div>
<!-- L'utente deve premere Tab 5 volte -->
<!-- Nessuna navigazione con frecce -->
<!-- Nessuna semantica di menu -->✅ Esempio positivo
Menu con navigazione frecce:
💡 Usa ↑ ↓ per navigare, Invio per selezionare
<!-- Positivo: navigazione con frecce con roving tabindex -->
<div
role="menu"
@keydown="handleKeydown"
>
<div
v-for="(item, i) in items"
role="menuitem"
:tabindex="selected === i ? 0 : -1"
@focus="selected = i"
:class="{ selected: selected === i }"
>
{{ item }}
</div>
</div>// Navigazione con frecce con roving tabindex
function handleKeydown(e) {
switch(e.key) {
case 'ArrowDown':
selected = (selected + 1) % items.length
break
case 'ArrowUp':
selected = selected === 0
? items.length - 1
: selected - 1
break
case 'Enter':
selectItem(selected)
break
}
}Spiegazione: Le liste navigabili da tastiera consentono di utilizzare i tasti freccia per spostarsi tra gli elementi, oltre alla classica navigazione con Tab.
Stili di focus visibili
❌ Esempio negativo
Prova a navigare con Tab in questa area:
/* ❌ Rimuove tutti gli indicatori di focus */
*:focus {
outline: none !important;
}
button:focus,
a:focus,
input:focus {
outline: none !important;
}<!-- ❌ Problemi di accessibilità: -->
<button>Pulsante 1</button> <!-- Nessun type, focus invisibile -->
<button>Pulsante 2</button> <!-- Nessun type, focus invisibile -->
<a href="#">Link</a> <!-- Focus invisibile -->
<input type="text" /> <!-- Focus invisibile -->
<!-- Navigazione da tastiera impossibile da seguire visivamente -->✅ Esempio positivo
Prova a navigare con Tab in questa area:
/* ✅ Indicatori di focus visibili e accessibili */
button:focus-visible {
outline: 3px solid #4F46E5;
outline-offset: 2px;
}
input:focus-visible {
border-color: #4F46E5;
outline: 2px solid #4F46E5;
outline-offset: 1px;
}<button type="button">Pulsante 1</button>
<button type="button">Pulsante 2</button>
<a href="#">Link alla pagina</a>
<input type="text" placeholder="Inserisci testo" />Spiegazione: Gli utenti che navigano con la tastiera hanno bisogno di indicatori visivi chiari per sapere dove si trovano sulla pagina.
Link di salto (Skip to content)
❌ Esempio negativo
Contenuto principale
L'utente deve navigare attraverso tutti i link di navigazione...
<!-- Negativo: nessun link di salto -->
<header>
<nav>
<a href="#">Home</a>
<a href="#">Prodotti</a>
<a href="#">Servizi</a>
<!-- 10+ link di navigazione... -->
</nav>
</header>
<main>
<!-- L'utente deve attraversare tutta la navigazione -->
<h1>Contenuto principale</h1>
</main>✅ Esempio positivo
Contenuto principale
L'utente può accedere direttamente qui grazie al link di salto!
/* Link di salto nascosto per default, visibile al focus */
.skip-link {
position: absolute;
top: -100px;
left: 1rem;
z-index: 1000;
padding: 0.5rem 1rem;
background: var(--color-primary);
color: white;
text-decoration: none;
border-radius: 0.625rem;
}
.skip-link:focus {
top: 1rem;
}<a href="#main-content" class="skip-link">
Vai al contenuto principale
</a>
<header>
<nav aria-label="Navigazione principale">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/produits">Prodotti</a></li>
<li><a href="/services">Servizi</a></li>
</ul>
</nav>
</header>
<main id="main-content">
<h1>Contenuto principale</h1>
</main>Spiegazione: I link di salto consentono agli utenti che usano la tastiera di passare direttamente al contenuto principale senza dover attraversare tutta la navigazione.
Modal con focus trap
❌ Esempio negativo
<!-- Negativo: modal senza gestione del focus -->
<div v-if="modalOpen" class="modal-overlay" @click="close">
<div class="modal-content" @click.stop>
<div class="modal-header">
<h3>Conferma azione</h3>
<button @click="close">×</button>
</div>
<div class="modal-body">
<p>Sei sicuro di voler continuare?</p>
<input type="text" placeholder="Motivo (facoltativo)" />
</div>
<div class="modal-footer">
<button @click="close">Annulla</button>
<button @click="confirm">Conferma</button>
</div>
</div>
</div>✅ Esempio positivo
<!-- Positivo: modal con focus trap -->
<div
v-if="modalOpen"
class="modal-overlay"
@click="closeModal"
@keydown.esc="closeModal"
>
<div
class="modal-content"
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
@click.stop
>
<header class="modal-header">
<h2 id="modal-title">Conferma azione</h2>
<button
type="button"
@click="closeModal"
aria-label="Chiudi modal"
class="close-btn"
>×</button>
</header>
<div class="modal-body">
<p>Sei sicuro di voler continuare?</p>
<input
ref="firstInput"
type="text"
placeholder="Motivo (facoltativo)"
@keydown.tab="handleFocusTrap"
/>
</div>
<footer class="modal-footer">
<button
type="button"
@click="closeModal"
@keydown.tab="handleFocusTrap"
>Annulla</button>
<button
type="button"
ref="lastButton"
@click="confirmAction"
@keydown.tab="handleFocusTrap"
>Conferma</button>
</footer>
</div>
</div>// Funzioni essenziali :
// - Auto focus sul primo elemento
// - Focus trap (Tab/Shift+Tab)
// - Chiusura su Escape
// - Ritorno del focus all'elemento trigger
function handleFocusTrap(event) {
const focusableElements = modalContent.querySelectorAll(
'button, input, [tabindex]:not([tabindex="-1"])'
)
const firstElement = focusableElements[0]
const lastElement = focusableElements[focusableElements.length - 1]
if (event.shiftKey && document.activeElement === firstElement) {
event.preventDefault()
lastElement.focus()
} else if (!event.shiftKey && document.activeElement === lastElement) {
event.preventDefault()
firstElement.focus()
}
}Spiegazione: Le modal devono mantenere il focus all'interno e consentire la chiusura con il tasto Escape. Il focus deve tornare all'elemento che ha aperto la modal.