Perché la keyboard navigation è critica
La navigazione da tastiera non è un optional. Secondo i dati WebAIM del 2025, il 28,7% degli utenti con disabilità usa esclusivamente la tastiera per navigare. Ma il problema va oltre l’accessibilità: la keyboard navigation è un requisito legale per WCAG 2.1 (AA e AAA) e influenza direttamente SEO e Core Web Vitals.
WordPress di default offre una discreta base per la navigazione da tastiera, ma temi e plugin la rompono costantemente. Come agenzie, dobbiamo testare sistematicamente ogni progetto prima della consegna.
Il costo di non farlo? Multe AGID, contenziosi legali e reputazione danneggiata. Nel 2025, in Italia ci sono stati 147 casi documentati di sanzioni per inaccessibilità web su siti pubblici e privati soggetti a normativa.
Come funziona la keyboard navigation
La navigazione da tastiera si basa su alcuni principi fondamentali che ogni elemento interattivo deve rispettare:
- Tab/Shift+Tab: navigazione sequenziale tra elementi focusabili
- Enter/Space: attivazione di link e pulsanti
- Arrow keys: navigazione in menu, slider, tab panels
- Escape: chiusura di modali e dropdown
- Home/End: salto a inizio/fine di liste e menu
Focus order e tabindex
L’ordine di focus deve seguire il flusso visivo della pagina. WordPress usa l’ordine DOM naturale, che funziona se il CSS non crea layout che divergono dalla struttura HTML.
Il tabindex controlla la focusabilità:
tabindex="0": elemento nel flusso naturaletabindex="-1": focusabile via script, non via Tabtabindex="1+": da evitare sempre, rompe l’ordine naturale
Problema comune: page builder come Elementor e Divi generano strutture HTML che non rispettano l’ordine visivo. Column responsive che si riordinano con flexbox o grid creano focus order illogici.
Focus visibility
Il focus indicator deve essere sempre visibile. WordPress 5.8+ include stili CSS nativi per :focus-visible, ma molti temi li sovrascrivono con:
*:focus {
outline: none;
}
Questo è il peccato capitale dell’accessibilità. Mai rimuovere outline senza fornire un’alternativa visibile.
Testare la keyboard navigation: processo completo
Il testing manuale è insostituibile. Nessun tool automatico cattura tutti i problemi di keyboard navigation. Ecco il processo che usiamo per ogni progetto cliente.
Test manuale base (20-30 minuti)
Disconnetti il mouse. Letteralmente. Usa solo la tastiera per 30 minuti sul sito.
- Apri la homepage e premi Tab ripetutamente
- Verifica che ogni elemento interattivo riceva focus visibile
- Controlla l’ordine di focus: ha senso logico?
- Testa tutti i menu principali e dropdown
- Naviga form di contatto e checkout WooCommerce
- Apri e chiudi modali, lightbox, accordions
- Testa slider e carousel (devono funzionare con arrow keys)
- Verifica che Escape chiuda overlay e menu mobili
Annota ogni punto dove rimani bloccato o il focus scompare.
Tool automatici per screening rapido
Dopo il test manuale, usa questi tool per trovare problemi nascosti:
- axe DevTools (Chrome/Firefox): identifica elementi focusabili senza attributi ARIA corretti
- WAVE: evidenzia problemi di focus order e tabindex errati
- Lighthouse Accessibility: audit automatico in Chrome DevTools
- Sa11y: bookmarklet per check rapidi, ottimo per WordPress
Per WordPress specifico, usa WP Accessibility Helper plugin in staging. Identifica problemi comuni in temi e plugin.
Test con screen reader
Anche se non sei esperto, fai test base con screen reader:
- NVDA (Windows, gratuito): lo standard de facto
- VoiceOver (macOS/iOS): già installato
- JAWS (Windows): il più usato professionalmente, ma costoso
Focus sul rotor di VoiceOver (Cmd+U) o Element List di NVDA (Insert+F7). Devono mostrare tutti i landmark, heading e form field correttamente etichettati.
Problemi comuni in WordPress e fix pratici
Questi sono i problemi che troviamo nel 90% dei siti WordPress client. Con fix testati e funzionanti.
Menu dropdown non accessibili
I menu WordPress nativi non gestiscono keyboard navigation nei sottomenu. Il tema deve implementarla via JavaScript.
Fix con vanilla JavaScript:
// Aggiungi in theme's JS file
document.querySelectorAll('.menu-item-has-children > a').forEach(item => {
item.addEventListener('keydown', function(e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
this.parentElement.classList.toggle('focus');
let submenu = this.nextElementSibling;
if (submenu) {
submenu.querySelectorAll('a')[0]?.focus();
}
}
});
});
Aggiungi CSS per mostrare submenu al focus:
.menu-item-has-children:focus-within > .sub-menu {
display: block;
}
Modal e popup che intrappolano il focus
Quando apri un modal, il focus deve spostarsi nel modal e non poter uscire finché non lo chiudi. Questo si chiama focus trap.
Implementazione con focus-trap library (già usata da Gutenberg):
import { createFocusTrap } from 'focus-trap';
const modalElement = document.querySelector('#myModal');
const focusTrap = createFocusTrap(modalElement, {
escapeDeactivates: true,
clickOutsideDeactivates: true
});
// Quando apri il modal
focusTrap.activate();
// Quando lo chiudi
focusTrap.deactivate();
WordPress 6.2+ include wp.a11y.speak() per annunciare cambiamenti agli screen reader.
Skip links assenti o rotti
Lo skip link permette di saltare la navigazione e andare direttamente al contenuto. Obbligatorio per WCAG 2.1 A.
WordPress non lo include di default. Aggiungilo in header.php prima di tutto:
<a class="skip-link screen-reader-text" href="#main">
Salta al contenuto
</a>
CSS per mostrarlo solo al focus:
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #000;
color: #fff;
padding: 8px 16px;
text-decoration: none;
z-index: 100000;
}
.skip-link:focus {
top: 0;
}
Assicurati che l’ID #main esista e abbia tabindex="-1" per ricevere focus programmatico.
Form senza label associati
Contact Form 7, Gravity Forms e WPForms a volte generano HTML senza <label> correttamente associati.
Verifica con DevTools che ogni input abbia:
- Un
<label>conforche corrisponde all’iddell’input - Oppure
aria-labeloaria-labelledbysull’input - Mai placeholder come unica etichetta (non accessibile)
Fix per Contact Form 7:
[text* your-name id:fullname class:form-control]
[label for:fullname]Nome completo[/label]
Custom button e link non focusabili
Elementi <div> o <span> usati come button con solo onclick non sono accessibili.
Bad:
<div class="btn" onclick="doSomething()">Clicca</div>
Good:
<button type="button" class="btn" onclick="doSomething()">Clicca</button>
Se devi assolutamente usare un div:
<div class="btn" role="button" tabindex="0"
onclick="doSomething()"
onkeydown="if(event.key==='Enter'||event.key===' '){doSomething()}">
Clicca
</div>
Ma seriamente: usa <button>.
Slider e carousel inaccessibili
Slick, Swiper e altri slider popolari hanno pessima accessibilità di default.
Usa Splide.js che ha accessibilità built-in, o configura Swiper 8+ con:
new Swiper('.swiper', {
keyboard: {
enabled: true,
onlyInViewport: true
},
a11y: {
enabled: true,
prevSlideMessage: 'Slide precedente',
nextSlideMessage: 'Slide successiva'
}
});
Assicurati che controlli prev/next siano veri button, non div con background-image.
Testing avanzato per agenzie
Per progetti enterprise o PA, serve testing più rigoroso.
Automated testing con Playwright
Integra test di keyboard navigation in CI/CD:
// test/accessibility.spec.js
import { test, expect } from '@playwright/test';
test('keyboard navigation homepage', async ({ page }) => {
await page.goto('https://example.com');
// Conta elementi focusabili
const focusableElements = await page.locator(
'a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])'
).count();
expect(focusableElements).toBeGreaterThan(5);
// Testa ordine di focus
await page.keyboard.press('Tab');
let firstFocus = await page.locator(':focus').textContent();
expect(firstFocus).toContain('Salta al contenuto');
// Testa apertura menu con keyboard
await page.locator('button[aria-label="Menu"]').press('Enter');
await expect(page.locator('.mobile-menu')).toBeVisible();
// Testa chiusura con Escape
await page.keyboard.press('Escape');
await expect(page.locator('.mobile-menu')).not.toBeVisible();
});
Audit report per clienti
Documenta ogni issue con:
- Screenshot del problema
- Pagina e selettore CSS specifico
- WCAG criterion violato (es. 2.1.1 Keyboard)
- Severità (Critical/High/Medium/Low)
- Fix proposto con stima ore
Usa Pa11y per generare report automatici:
npx pa11y-ci --sitemap https://example.com/sitemap.xml \
--json > accessibility-report.json
Test con utenti reali
Se il budget lo permette, coinvolgi utenti con disabilità reali per testing. Servizi come Fable (fable.io) connettono con tester professionisti.
Costa 150-300€ per sessione, ma identifica problemi che nessun tool automatico trova.
Plugin WordPress per accessibilità
Questi plugin aiutano, ma non sostituiscono sviluppo accessibile:
- WP Accessibility: aggiunge skip links, outline fix, toolbar accessibilità
- One Click Accessibility: widget per utenti (ingrandimento testo, contrasto, etc.)
- AccessiBe/UserWay: overlay accessibility (controversi, usare con cautela)
Gli overlay JS sono dibattuti nella community. Non risolvono problemi strutturali e alcuni screen reader li considerano fastidiosi. Preferisci sviluppo nativo accessibile.
Checklist finale pre-lancio
Prima di consegnare un sito cliente, verifica:
- Tutti gli elementi interattivi sono raggiungibili con Tab
- Focus indicator visibile su tutti gli elementi
- Ordine di focus logico e coerente
- Skip link funzionante all’inizio della pagina
- Menu navigabili con tastiera e Escape chiude dropdown
- Form con label corretti e messaggi di errore accessibili
- Modal trappano focus e si chiudono con Escape
- Slider controllabili con arrow keys
- Nessun keyboard trap (focus non può rimanere bloccato)
- Test con almeno NVDA o VoiceOver completato
Documenta nel README del progetto le feature di accessibilità implementate. Questo ti protegge legalmente e aiuta developer futuri.
Risorse e strumenti
Mantieni questi bookmark:
- WebAIM (webaim.org): guide pratiche e WCAG spiegato bene
- A11y Project (a11yproject.com): checklist e pattern pronti
- ARIA Authoring Practices (w3.org/WAI/ARIA): pattern ufficiali W3C
- WordPress Accessibility Handbook: standard ufficiali WordPress
- Inclusive Components di Heydon Pickering: pattern avanzati
Per formazione team, Deque University offre corsi certificati (paid, ma eccellenti).
FAQ
Quanto tempo serve per rendere accessibile un sito WordPress esistente?
Dipende dalla complessità. Per un sito standard con tema custom e 3-5 plugin, stima 16-24 ore: 4-6 ore per audit completo, 8-12 ore per fix development, 4-6 ore per testing e documentazione. Temi costruiti con page builder possono richiedere 40+ ore se la struttura HTML è molto problematica.
I temi WordPress dichiarati “accessibility-ready” sono davvero accessibili?
Il tag “accessibility-ready” su WordPress.org significa che il tema passa test base, ma non garantisce accessibilità completa. Copre principalmente: skip link, focus indicator, form label, e landmark HTML5. Non copre: JavaScript interaction, plugin compatibility, o contenuto inserito dall’utente. Testa sempre anche temi certified.
Posso usare tabindex positivo per correggere ordine di focus rotto?
No. Tabindex positivo (1, 2, 3…) crea più problemi di quanti ne risolva. Rompe il flusso naturale e diventa impossibile da mantenere. Se l’ordine di focus è sbagliato, il problema è nella struttura HTML o nel CSS che riordina elementi visualmente. Correggi quello, non usare tabindex come patch.
Come testo keyboard navigation su WordPress multilingua?
Testa in ogni lingua attiva. WPML e Polylang possono generare HTML diverso per lingua. Verifica che: label form siano tradotti correttamente, attributi aria-label abbiano traduzioni, screen reader announcements funzionino in ogni lingua, e skip link text sia localizzato. Usa Language Switcher accessibile (preferibilmente select con label, non solo flag icon).
Gli overlay di accessibilità come AccessiBe rispettano WCAG?
Gli overlay JavaScript non possono risolvere problemi strutturali del codice sottostante. Nel 2024, oltre 400 organizzazioni di advocacy per disabilità hanno firmato una lettera contro gli overlay, definendoli “falsa accessibilità”. Alcuni screen reader user li bloccano attivamente. Usali solo come supplemento temporaneo, mai come unica soluzione. L’unico approccio WCAG-compliant è codice nativo accessibile.