În cadrul proiectului Tiflo, accesibilitatea nu este un „feature” opțional, ci fundamentul pe care construim. Provocarea a fost clară: cum oferim o experiență de navigare impecabilă pentru utilizatorii de screen readers și tastatură, păstrând în același timp flexibilitatea WordPress? Am testat trei abordări, iar astăzi le analizăm tehnic.
1. Cele trei arhitecturi
- Kadence Minimalist (v1): Un child theme simplu care suprascrie template-urile
header.php. Rapid, dar limitat în controlul DOM-ului. - Kadence Avansat (v3): Utilizarea modulelor PHP pentru a injecta logica ARIA direct în
Walker_Nav_Menu. - Tiflo Story (Custom): Temă standalone bazată pe Material Design 3, fără framework-uri CSS, folosind 134 de design tokens.
2. Navigație Disclosure și WAI-ARIA
Pentru a respecta WAI-ARIA, nu putem folosi link-uri standard pentru submeniuri. Injectăm butoane de toggle:
// Injectare buton pentru submeniuri
const items = document.querySelectorAll('.menu-item-has-children');
items.forEach(item => {
const link = item.querySelector('a');
const btn = document.createElement('button');
btn.setAttribute('aria-expanded', 'false');
btn.innerHTML = '<span class="sr-only">Extinde</span>';
item.insertBefore(btn, item.querySelector('.sub-menu'));
});
3. Focus Trap pentru Mobile Drawer
Într-un overlay mobil, focusul nu trebuie să scape în restul paginii. Implementarea vanilla JS este esențială pentru performanță:
function trapFocus(modal) {
const focusables = modal.querySelectorAll('button, [href], input, select, textarea');
const first = focusables[0];
const last = focusables[focusables.length - 1];
modal.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === first) {
e.preventDefault(); last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault(); first.focus();
}
}
});
}
4. Toggle Contrast și Prevenirea FOUC
Pentru a evita Flash of Unstyled Content, rulăm un script inline cu prioritate 1 în wp_head:
add_action('wp_head', function() {
echo "<script>const c = localStorage.getItem('contrast') || 'default'; document.documentElement.dataset.contrast = c;</script>";
}, 1);
CSS-ul aferent asigură contrastul necesar:
html[data-contrast='yellow-black'] {
--surface: #000;
--on-surface: #FFFF00;
/* Contrast ratio 19.56:1 */
}
5. Manipularea Tag-urilor cu WP_HTML_Tag_Processor
Folosim noul API din WordPress 6.2+ pentru a curăța link-urile externe:
$processor = new WP_HTML_Tag_Processor($content);
while ($processor->next_tag('a')) {
if (is_external($processor->get_attribute('href'))) {
$processor->set_attribute('aria-label', $processor->get_content() . ' (se deschide în tab nou)');
$processor->set_attribute('target', '_blank');
$processor->set_attribute('rel', 'noopener');
}
}
6. Fix Viewport prin Output Buffering
Unele teme blochează zoom-ul. Corectăm acest aspect fără să modificăm fișierele sursă ale temei părinte:
add_action('wp_head', 'start_viewport_buffer', 0);
add_action('wp_head', 'end_viewport_buffer', 999);
function start_viewport_buffer() { ob_start(); }
function end_viewport_buffer() {
$html = ob_get_clean();
echo preg_replace('/user-scalable=no/', 'user-scalable=yes', $html);
}
Concluzie: Pentru proiecte cu cerințe severe de accesibilitate, abordarea Tiflo Story (Custom Theme) oferă cel mai mare control. Totuși, dacă ești blocat într-un child theme, tehnici precum WP_HTML_Tag_Processor și Output Buffering îți pot salva proiectul fără a compromite structura temei părinte.

