Frontend akadálymentesség billentyűzet navigációval HTML-ben.

Webes akadálymentesség javítása billentyűzetes navigációval

Sziasztok!

Ma arról fogok beszélni, hogy miért fontos a billentyűzetes navigáció a webes akadálymentességben, és hogyan implementálhatod hatékonyan a projektedben. Talán már hallottad az accessibility kifejezést, és tudod, hogy fontos – de a gyakorlatban sokszor meglepően elhanyagolt terület. Pedig a billentyűzet használata nem csak a mozgáskorlátozott felhasználók számára kritikus, hanem számos más felhasználói csoport (például ismétlődő terhelési sérülések miatt egérhasználatot kerülők, vagy akár power userek) is gyakran támaszkodik rá.

Miért nem elég az egér?

Amikor csak az egérre tervezünk, automatikusan kizárunk olyan felhasználókat, akik fizikailag nem tudnak (vagy nem szeretnek) egeret használni. Ők a Tab billentyűvel navigálnak a fókuszolható elemek között (linkek, gombok, űrlapmezők). Ha ez a navigáció nem működik logikusan, vagy egyes elemek egyáltalán nem elérhetőek, akkor a weboldalunk gyakorlatilag használhatatlan számukra.

A HTML alapok: a fókusz sorrend és szemantika

A legnagyobb hiba, amit elkövethetünk, a nem szemantikus HTML használata. Egy

-et CSS-szel és JavaScript-tel átalakítunk gombná – de a böngésző és a segédtechnológiák számára az csak egy div marad. Nem fogja a Tab gomb figyelni, nem kapja meg a gomb ARIA szerepkört, és a felhasználó nem fogja tudni „rákattintani”.

<!-- ROSSZ -->
<div onclick="submitForm()">Küldés</div>

<!-- JÓ -->
<button onclick="submitForm()">Küldés</button>
<!-- Vagy ha muszáj div: -->
<div tabindex="0" role="button" onclick="submitForm()">Küldés</div>

A tabindex attribútum kulcsfontosságú: – tabindex="0": Az elem kerüljön be a természetes fókuszsorrendbe. – tabindex="-1": Az elem kivehető a sorrendből, de programozottan fókuszálható. – Pozitív érték: Kerüljön! Megbontja a természetes sorrendet, nagyon ritkán kell.

Gyakori buktatók a gyakorlatban

1. CSS: outline: none; önkényesen: A fókusz körvonala (amit a Tab nyomogatásakor látsz) vizuális jelzés. Ne vedd el globálisan! Inkább stilizáld szépen.

    button:focus {
        outline: 3px solid #005fcc;
        outline-offset: 2px;
    }
    

2. Modális ablakok és billentyűzet csapdája: Amikor egy felugró ablak nyílik, a fókusznak azonnal oda kell ugrania, és csak a modális elemei között kell tudni tabolni. A bezárás után a fókusznak vissza kell ugrania a megnyitó elemre.

3. Egyedi widget-ek (pl. legördülők, kártyák): Ezeket nem lehet csak CSS-szel megoldani. JavaScript kell a nyíl billentyűk, Enter, Escape kezeléséhez.

Egy összetett példa: Fókuszkezelés PHP backenddel és jQuery frontenddel

Képzelj el egy admin felületet, ahol felhasználókat lehet törölni. A backend PHP generálja a listát.

<?php
// users.php - A lista generálása
$users = fetchUsersFromDatabase(); // Tételezzük fel, hogy ez létezik
foreach ($users as $user) {
    echo '
    <div class="user-card card mb-3" data-user-id="' . htmlspecialchars($user['id']) . '">
        <div class="card-body">
            <h5 class="card-title">' . htmlspecialchars($user['name']) . '</h5>
            <button class="btn btn-danger btn-delete-user" 
                    data-user-name="' . htmlspecialchars($user['name']) . '">
                Felhasználó törlése
            </button>
        </div>
    </div>';
}
?>

Most a frontenden, jQuery és Bootstrap segítségével, implementálunk egy modális megerősítést, ami teljesen billentyűzet-barát.

// main.js - A fókuszkezelés implementálása jQuery-vel
$(document).ready(function() {
    let $deleteButton; // Elmentjük, melyik gomb nyitotta a modált
    let $lastFocusedElement; // Hol volt a fókusz a megnyitás előtt

    // Törlés gombra kattintás
    $(document).on('click', '.btn-delete-user', function(e) {
        e.preventDefault();
        $deleteButton = $(this);
        $lastFocusedElement = $(document.activeElement); // Aktív elem mentése
        
        const userName = $deleteButton.data('user-name');
        $('#confirmDeleteModal .user-name').text(userName);
        
        // Modal megjelenítése Bootstrap-tel
        const $modal = $('#confirmDeleteModal');
        $modal.modal('show');
        
        // A modál megjelenése után azonnal fókuszt adunk az "Igen" gombnak
        $modal.on('shown.bs.modal', function() {
            $('#confirmDeleteBtn').focus();
        });
    });

    // Törlés megerősítése
    $('#confirmDeleteBtn').on('click', function() {
        const userId = $deleteButton.closest('.user-card').data('user-id');
        // AJAX hívás a törléshez itt következne...
        console.log('Törlés indítása user ID:', userId);
        
        $('#confirmDeleteModal').modal('hide');
        // VISSZAFÓKUSZÁLÁS: A bezárás után visszaugrunk az eredeti gombra
        if ($lastFocusedElement) {
            $lastFocusedElement.focus();
        }
    });

    // ESC billentyű kezelése a modál bezárásához
    $(document).on('keydown', function(e) {
        if (e.key === 'Escape' && $('#confirmDeleteModal').hasClass('show')) {
            $('#confirmDeleteModal').modal('hide');
            if ($lastFocusedElement) {
                $lastFocusedElement.focus();
            }
        }
    });
});

A modál HTML-je (Bootstrap komponens) és a hozzá tartozó SCSS:

<!-- A Bootstrap modális szerkezete -->
<div class="modal fade" id="confirmDeleteModal" tabindex="-1" aria-labelledby="modalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="modalLabel">Megerősítés</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Bezárás"></button>
      </div>
      <div class="modal-body">
        Biztosan törölni szeretnéd a(z) "<span class="user-name"></span>" felhasználót?
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Mégse</button>
        <button type="button" class="btn btn-danger" id="confirmDeleteBtn">Igen, törlés</button>
      </div>
    </div>
  </div>
</div>
// _modals.scss - A fókusz vizuális stílusa SCSS-ben
#confirmDeleteModal {
    // A Bootstrap modal z-index-ét kezeljük, hogy biztosan legfelül legyen
    z-index: 1060;

    // A fókusz stílus a modál gombjain
    .btn:focus {
        @include button-focus-shadow(); // Bootstrap mixin
        border-color: #86b7fe;
    }

    // A modál bezáró gombjának saját stílusa fókusznál
    .btn-close:focus {
        box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.5); // Piás árnyék a veszélyes művelethez
    }
}

Mit tegyél ma?

1. Teszteld a Tab-ot: Nyisd meg a legújabb projekted, és próbáld végignavigálni csak a Tab billentyűvel. Meglepődsz, hol akadsz el. 2. Használj szemantikus elemeket: