3.3.4 - Hibamegelőzés (jogi, pénzügyi, adat)

Röviden a szabványpontról

A WCAG 2.2 Success Criterion 3.3.4 (Error Prevention – Legal, Financial, Data) megköveteli, hogy azokon a weboldalakon, ahol a felhasználói műveletek jogi kötelezettségekhez, pénzügyi tranzakciókhoz, adatmódosításokhoz vagy felhasználói tesztek beküldéséhez vezethetnek, a következők közül legalább egynek igaznak kell lennie: a beküldés visszavonható (a felhasználók visszavonhatják a műveletet), a bevitt adatokat ellenőrzik beviteli hibák szempontjából és a felhasználók lehetőséget kapnak a javításra, vagy mechanizmust biztosítanak az információk áttekintésére, megerősítésére és javítására a végső beküldés előtt.

Cél: Megelőzni a súlyos hibákat, amelyek negatívan befolyásolhatják a felhasználókat azzal, hogy biztosítják számukra az irányítást és áttekinthetőséget a kritikus műveletek végrehajtása előtt. Ez elsősorban űrlapokra, pénztári folyamatokra, jogi megállapodásokra és adatbeviteli felületekre vonatkozik.

Mire vonatkozik: Minden olyan webes tartalomra, ahol a felhasználói műveletek komoly következményekkel járhatnak, beleértve a vásárlási folyamatokat, regisztrációs űrlapokat, adatmódosító funkciókat, pénzügyi tranzakciókat és jogi dokumentumok aláírását.

Kiket érint

Elsődleges felhasználók: Kognitív fogyatékossággal, gyengénlátással, mozgásszervi akadályozottsággal élő emberek, vagy bárki, aki hibázhat a komplexitás vagy stressz miatt. Ezek a felhasználók különösen profitálnak a megerősítési lépésekből és a hibajavítási lehetőségekből.

Másodlagos előnyök: Minden felhasználó számára előnyös a kevesebb hiba és a világosabb folyamatok, javítva az oldal általános használhatóságát és megbízhatóságát. Különösen értékes stresszes helyzetekben, mint például online vásárlás vagy fontos űrlapok kitöltése.

Tesztelés

  1. Űrlap folyamatok áttekintése: Ellenőrizd, hogy a kritikus űrlapok rendelkeznek-e megerősítési lépéssel vagy hibák áttekintésével a végső beküldés előtt
  2. Érvénytelen beküldések tesztelése: Írj be helytelen vagy hiányos adatokat és nézd meg, hogy a rendszer észleli-e a hibákat és lehetővé teszi-e a javítást
  3. Visszavonás funkció tesztelése: Visszavonható műveletek esetén (pl. adatok törlése) ellenőrizd, hogy a felhasználók könnyen vissza tudják-e vonni a műveletet
  4. Billentyűzetes és képernyőolvasó tesztelés: Biztosítsd, hogy a hibaüzenetek és áttekintési lépések hozzáférhetőek és világosan kommunikálnak
  5. Felhasználói teszt: Figyeld meg a felhasználókat tranzakciók vagy jogi űrlapok kitöltése közben, hogy azonosítsd, képesek-e könnyen javítani az esetlegesen felmerülő hibákat

Jó gyakorlatok

1. Megerősítő oldal a végső beküldés előtt

<!-- ONLINE VÁSÁRLÁS - Rendelés megerősítés -->
<form id="vasarlas-form" class="checkout-form" novalidate>
  <div class="form-section">
    <h2>Rendelési adatok</h2>
    
    <div class="form-group">
      <label for="szallitasi-nev">Szállítási név *</label>
      <input 
        type="text" 
        id="szallitasi-nev" 
        name="szallitasi_nev" 
        required
        aria-describedby="szallitasi-nev-error"
        autocomplete="name"
      >
      <div id="szallitasi-nev-error" class="error-message" role="alert" style="display: none;"></div>
    </div>
    
    <div class="form-group">
      <label for="szallitasi-cim">Szállítási cím *</label>
      <input 
        type="text" 
        id="szallitasi-cim" 
        name="szallitasi_cim" 
        required
        aria-describedby="szallitasi-cim-error"
        autocomplete="street-address"
      >
      <div id="szallitasi-cim-error" class="error-message" role="alert" style="display: none;"></div>
    </div>
    
    <div class="form-group">
      <label for="bankkartya-szam">Bankkártya szám *</label>
      <input 
        type="text" 
        id="bankkartya-szam" 
        name="bankkartya_szam" 
        required
        pattern="[0-9]{16}"
        aria-describedby="bankkartya-szam-help bankkartya-szam-error"
        autocomplete="cc-number"
      >
      <div id="bankkartya-szam-help" class="field-help">
        16 számjegyű bankkártya szám szóközök nélkül
      </div>
      <div id="bankkartya-szam-error" class="error-message" role="alert" style="display: none;"></div>
    </div>
    
    <div class="form-group">
      <label for="bankkartya-lej">Lejárat (HH/ÉÉ) *</label>
      <input 
        type="text" 
        id="bankkartya-lej" 
        name="bankkartya_lej" 
        required
        pattern="[0-9]{2}/[0-9]{2}"
        placeholder="12/25"
        aria-describedby="bankkartya-lej-error"
        autocomplete="cc-exp"
      >
      <div id="bankkartya-lej-error" class="error-message" role="alert" style="display: none;"></div>
    </div>
  </div>
  
  <div class="form-actions">
    <button type="submit" class="btn-primary">Rendelés áttekintése</button>
  </div>
</form>

<!-- MEGERŐSÍTŐ OLDAL -->
<div id="rendeles-megerosito" class="confirmation-page" style="display: none;">
  <h2>Rendelés áttekintése</h2>
  <p>Kérjük, ellenőrizze minden adatot a végleges rendelés leadása előtt.</p>
  
  <div class="rendeles-osszegzo">
    <h3>Szállítási adatok</h3>
    <div class="adat-sor">
      <strong>Név:</strong> <span id="confirm-nev"></span>
    </div>
    <div class="adat-sor">
      <strong>Cím:</strong> <span id="confirm-cim"></span>
    </div>
    
    <h3>Fizetési adatok</h3>
    <div class="adat-sor">
      <strong>Kártya:</strong> <span id="confirm-kartya"></span>
    </div>
    
    <h3>Összeg</h3>
    <div class="adat-sor vegosszeg">
      <strong>Végösszeg:</strong> <span id="confirm-osszeg"></span>
    </div>
  </div>
  
  <div class="confirmation-actions">
    <button type="button" id="rendeles-szerkesztes" class="btn-secondary">
      Adatok szerkesztése
    </button>
    <button type="button" id="rendeles-vegleges" class="btn-primary">
      Rendelés véglegesítése
    </button>
  </div>
</div>

<!-- JAVASCRIPT A MEGERŐSÍTÉSHEZ -->
<script>
  const vasarlasForm = document.getElementById('vasarlas-form');
  const megerositoOldal = document.getElementById('rendeles-megerosito');
  const szerkesztesGomb = document.getElementById('rendeles-szerkesztes');
  const veglegesGomb = document.getElementById('rendeles-vegleges');
  
  // Űrlap beküldés - megerősítő oldal megjelenítése
  vasarlasForm.addEventListener('submit', function(esemeny) {
    esemeny.preventDefault();
    
    // Adatok validálása
    if (validalasRendeles()) {
      // Adatok betöltése a megerősítő oldalra
      document.getElementById('confirm-nev').textContent = 
        document.getElementById('szallitasi-nev').value;
      document.getElementById('confirm-cim').textContent = 
        document.getElementById('szallitasi-cim').value;
      document.getElementById('confirm-kartya').textContent = 
        '****' + document.getElementById('bankkartya-szam').value.slice(-4);
      document.getElementById('confirm-osszeg').textContent = '25.990 Ft';
      
      // Oldal váltás
      vasarlasForm.style.display = 'none';
      megerositoOldal.style.display = 'block';
      
      // Fókusz a megerősítő oldal címére
      megerositoOldal.querySelector('h2').focus();
    }
  });
  
  // Vissza az űrlaphoz
  szerkesztesGomb.addEventListener('click', function() {
    megerositoOldal.style.display = 'none';
    vasarlasForm.style.display = 'block';
    document.getElementById('szallitasi-nev').focus();
  });
  
  // Végleges rendelés
  veglegesGomb.addEventListener('click', function() {
    // Itt történik a tényleges rendelés beküldése
    alert('Rendelés sikeresen leadva!');
    // Átirányítás a köszönő oldalra
    window.location.href = '/koszonjuk';
  });
  
  // Validáció függvény
  function validalasRendeles() {
    let ervenyesForm = true;
    
    const szallitasiNev = document.getElementById('szallitasi-nev');
    const szallitasiCim = document.getElementById('szallitasi-cim');
    const bankkartya = document.getElementById('bankkartya-szam');
    const lejarat = document.getElementById('bankkartya-lej');
    
    // Név validálás
    if (szallitasiNev.value.trim() === '') {
      mutatHiba('szallitasi-nev-error', 'A szállítási név megadása kötelező.');
      ervenyesForm = false;
    } else {
      rejtsHiba('szallitasi-nev-error');
    }
    
    // Cím validálás
    if (szallitasiCim.value.trim() === '') {
      mutatHiba('szallitasi-cim-error', 'A szállítási cím megadása kötelező.');
      ervenyesForm = false;
    } else {
      rejtsHiba('szallitasi-cim-error');
    }
    
    // Bankkártya validálás
    if (!/^[0-9]{16}$/.test(bankkartya.value.replace(/\s/g, ''))) {
      mutatHiba('bankkartya-szam-error', 'Érvénytelen bankkártya szám. 16 számjegy szükséges.');
      ervenyesForm = false;
    } else {
      rejtsHiba('bankkartya-szam-error');
    }
    
    // Lejárat validálás
    if (!/^[0-9]{2}\/[0-9]{2}$/.test(lejarat.value)) {
      mutatHiba('bankkartya-lej-error', 'Érvénytelen lejárat formátum. HH/ÉÉ formában adja meg.');
      ervenyesForm = false;
    } else {
      rejtsHiba('bankkartya-lej-error');
    }
    
    return ervenyesForm;
  }
  
  function mutatHiba(hibaMezoId, hibaUzenet) {
    const hibaMezo = document.getElementById(hibaMezoId);
    hibaMezo.textContent = hibaUzenet;
    hibaMezo.style.display = 'block';
    hibaMezo.setAttribute('aria-live', 'assertive');
  }
  
  function rejtsHiba(hibaMezoId) {
    const hibaMezo = document.getElementById(hibaMezoId);
    hibaMezo.style.display = 'none';
    hibaMezo.removeAttribute('aria-live');
  }
</script>

2. Azonnali validálás és hibajavítási javaslatok

<!-- REGISZTRÁCIÓ - Azonnali validálással -->
<form id="reg-form" class="registration-form" novalidate>
  <div class="form-section">
    <h2>Új felhasználói fiók</h2>
    
    <div class="form-group">
      <label for="reg-email">E-mail cím *</label>
      <input 
        type="email" 
        id="reg-email" 
        name="email" 
        required
        aria-describedby="reg-email-help reg-email-error"
        autocomplete="email"
      >
      <div id="reg-email-help" class="field-help">
        Valós e-mail címét adja meg az aktiváláshoz
      </div>
      <div id="reg-email-error" class="error-message" role="alert" style="display: none;"></div>
    </div>
    
    <div class="form-group">
      <label for="reg-jelszo">Jelszó *</label>
      <input 
        type="password" 
        id="reg-jelszo" 
        name="jelszo" 
        required
        minlength="8"
        aria-describedby="reg-jelszo-help reg-jelszo-error"
        autocomplete="new-password"
      >
      <div id="reg-jelszo-help" class="field-help">
        Legalább 8 karakter, tartalmazzon számot és nagybetűt
      </div>
      <div id="reg-jelszo-error" class="error-message" role="alert" style="display: none;"></div>
    </div>
    
    <div class="form-group">
      <label for="reg-jelszo-meg">Jelszó megerősítése *</label>
      <input 
        type="password" 
        id="reg-jelszo-meg" 
        name="jelszo_megerosites" 
        required
        aria-describedby="reg-jelszo-meg-error"
        autocomplete="new-password"
      >
      <div id="reg-jelszo-meg-error" class="error-message" role="alert" style="display: none;"></div>
    </div>
    
    <div class="form-group">
      <label>
        <input type="checkbox" id="reg-feltetel" name="feltetel" required>
        Elfogadom a <a href="/feltetel" target="_blank">felhasználási feltételeket</a> *
      </label>
      <div id="reg-feltetel-error" class="error-message" role="alert" style="display: none;"></div>
    </div>
  </div>
  
  <div class="form-actions">
    <button type="submit" class="btn-primary">Regisztráció</button>
  </div>
</form>

<script>
  const regForm = document.getElementById('reg-form');
  const emailMezo = document.getElementById('reg-email');
  const jelszоMezo = document.getElementById('reg-jelszo');
  const jelszоMegMezo = document.getElementById('reg-jelszo-meg');
  const feltetelMezo = document.getElementById('reg-feltetel');
  
  // E-mail validálás gépelés közben
  emailMezo.addEventListener('input', function() {
    const emailErtek = this.value.trim();
    const emailError = document.getElementById('reg-email-error');
    
    if (emailErtek === '') {
      rejtsHiba('reg-email-error');
    } else if (!emailValidacio(emailErtek)) {
      mutatHiba('reg-email-error', 'Kérjük, érvényes e-mail címet adjon meg (pl. nev@domain.hu).');
    } else {
      rejtsHiba('reg-email-error');
    }
  });
  
  // Jelszó validálás
  jelszоMezo.addEventListener('input', function() {
    const jelszоErtek = this.value;
    const jelszоError = document.getElementById('reg-jelszo-error');
    
    if (jelszоErtek.length === 0) {
      rejtsHiba('reg-jelszo-error');
    } else if (jelszоErtek.length < 8) {
      mutatHiba('reg-jelszo-error', 'A jelszó legalább 8 karakter legyen.');
    } else if (!/[A-Z]/.test(jelszоErtek)) {
      mutatHiba('reg-jelszo-error', 'A jelszó tartalmazzon legalább egy nagybetűt.');
    } else if (!/[0-9]/.test(jelszоErtek)) {
      mutatHiba('reg-jelszo-error', 'A jelszó tartalmazzon legalább egy számot.');
    } else {
      rejtsHiba('reg-jelszo-error');
    }
    
    // Jelszó megerősítés ellenőrzése ha van érték
    if (jelszоMegMezo.value.length > 0) {
      jelszоMegerositesValidacio();
    }
  });
  
  // Jelszó megerősítés validálás
  jelszоMegMezo.addEventListener('input', jelszоMegerositesValidacio);
  
  function jelszоMegerositesValidacio() {
    const jelszо = jelszоMezo.value;
    const jelszоMeg = jelszоMegMezo.value;
    const jelszоMegError = document.getElementById('reg-jelszo-meg-error');
    
    if (jelszоMeg.length === 0) {
      rejtsHiba('reg-jelszo-meg-error');
    } else if (jelszо !== jelszоMeg) {
      mutatHiba('reg-jelszo-meg-error', 'A két jelszó nem egyezik meg.');
    } else {
      rejtsHiba('reg-jelszo-meg-error');
    }
  }
  
  // Űrlap beküldés validálása
  regForm.addEventListener('submit', function(esemeny) {
    esemeny.preventDefault();
    
    if (teljesValidacio()) {
      // Sikeres regisztráció
      alert('Regisztráció sikeres! Aktiváló e-mail elküldve.');
      // Itt történne a tényleges regisztráció
    }
  });
  
  function teljesValidacio() {
    let ervenyesForm = true;
    
    // E-mail ellenőrzés
    if (!emailValidacio(emailMezo.value.trim())) {
      mutatHiba('reg-email-error', 'Érvényes e-mail cím megadása kötelező.');
      ervenyesForm = false;
    }
    
    // Jelszó ellenőrzés
    if (jelszоMezo.value.length < 8) {
      mutatHiba('reg-jelszo-error', 'A jelszó legalább 8 karakter legyen.');
      ervenyesForm = false;
    }
    
    // Jelszó megerősítés
    if (jelszоMezo.value !== jelszоMegMezo.value) {
      mutatHiba('reg-jelszo-meg-error', 'A két jelszó nem egyezik meg.');
      ervenyesForm = false;
    }
    
    // Feltételek elfogadása
    if (!feltetelMezo.checked) {
      mutatHiba('reg-feltetel-error', 'A regisztrációhoz el kell fogadnia a felhasználási feltételeket.');
      ervenyesForm = false;
    }
    
    return ervenyesForm;
  }
  
  function emailValidacio(email) {
    const emailMinta = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailMinta.test(email);
  }
  
  function mutatHiba(hibaMezoId, hibaUzenet) {
    const hibaMezo = document.getElementById(hibaMezoId);
    hibaMezo.textContent = hibaUzenet;
    hibaMezo.style.display = 'block';
    hibaMezo.setAttribute('aria-live', 'assertive');
  }
  
  function rejtsHiba(hibaMezoId) {
    const hibaMezo = document.getElementById(hibaMezoId);
    hibaMezo.style.display = 'none';
    hibaMezo.removeAttribute('aria-live');
  }
</script>

3. Visszavonás opció kritikus műveleteknél

<!-- ADAT TÖRLÉS - Visszavonási lehetőséggel -->
<div class="felhasznalo-beallitasok">
  <h2>Fiók beállítások</h2>
  
  <div class="beallitas-csoport">
    <h3>Fiók törlése</h3>
    <p>Figyelem: Ez a művelet törli az összes adatát és beállítását.</p>
    
    <button type="button" id="fiok-torles-gomb" class="btn-danger">
      Fiók törlése
    </button>
  </div>
</div>

<!-- MEGERŐSÍTŐ DIALÓGUS -->
<div id="torles-megersito" class="modal" style="display: none;" role="dialog" aria-labelledby="torles-cim" aria-modal="true">
  <div class="modal-content">
    <h3 id="torles-cim">Fiók törlésének megerősítése</h3>
    <p>Biztos, hogy törölni szeretné a fiókját? Ez a művelet nem vonható vissza!</p>
    <p>Az összes adata, beleértve a beállításokat, üzeneteket és dokumentumokat, véglegesen törlődik.</p>
    
    <div class="modal-actions">
      <button type="button" id="torles-megse" class="btn-secondary">Mégse</button>
      <button type="button" id="torles-megersites" class="btn-danger">Igen, törlöm a fiókot</button>
    </div>
  </div>
</div>

<!-- VISSZAVONÁSI ÜZENET -->
<div id="torles-visszavonasi" class="undo-message" style="display: none;" role="alert" aria-live="assertive">
  <div class="undo-content">
    <span>Fiók törlése elkezdődött. </span>
    <button type="button" id="torles-visszavon" class="btn-primary">Visszavonás</button>
    <span id="visszavon-ido" class="countdown">(30 másodperc)</span>
  </div>
</div>

<script>
  const fiokTorlesGomb = document.getElementById('fiok-torles-gomb');
  const torlesMegersito = document.getElementById('torles-megersito');
  const torlesMegse = document.getElementById('torles-megse');
  const torlesMegersites = document.getElementById('torles-megersites');
  const torlesVisszavonasi = document.getElementById('torles-visszavonasi');
  const torlesVisszavon = document.getElementById('torles-visszavon');
  const visszavonIdo = document.getElementById('visszavon-ido');
  
  let torlesTimeout;
  let visszavonTimeout;
  let visszavonIdoHatra = 30;
  
  // Törlés gomb megnyomása
  fiokTorlesGomb.addEventListener('click', function() {
    torlesMegersito.style.display = 'flex';
    torlesMegersito.focus();
  });
  
  // Törlés mégse
  torlesMegse.addEventListener('click', function() {
    torlesMegersito.style.display = 'none';
    fiokTorlesGomb.focus();
  });
  
  // Törlés megerősítése
  torlesMegersites.addEventListener('click', function() {
    torlesMegersito.style.display = 'none';
    
    // Törlés folyamat indítása 30 másodperces visszavonással
    inditsaTorlesVisszavonast();
  });
  
  // Törlés visszavonás indítása
  function inditsaTorlesVisszavonast() {
    // Visszavonási üzenet megjelenítése
    torlesVisszavonasi.style.display = 'block';
    torlesVisszavon.focus();
    
    // Visszavonási időzítő indítása
    visszavonTimeout = setInterval(function() {
      visszavonIdoHatra--;
      visszavonIdo.textContent = `(${visszavonIdoHatra} másodperc)`;
      
      if (visszavonIdoHatra <= 0) {
        // Idő lejárt, törlés véglegesítése
        clearInterval(visszavonTimeout);
        veglegesitesTorles();
      }
    }, 1000);
  }
  
  // Törlés visszavonása
  torlesVisszavon.addEventListener('click', function() {
    clearInterval(visszavonTimeout);
    torlesVisszavonasi.style.display = 'none';
    visszavonIdoHatra = 30;
    visszavonIdo.textContent = '(30 másodperc)';
    
    // Visszavonás megerősítése
    alert('Fiók törlése megszakítva. Adatai biztonságban vannak.');
    fiokTorlesGomb.focus();
  });
  
  // Törlés véglegesítése
  function veglegesitesTorles() {
    torlesVisszavonasi.style.display = 'none';
    
    // Itt történne a tényleges törlés
    alert('Fiók sikeresen törölve. Átirányítás a főoldalra...');
    
    // Átirányítás
    setTimeout(function() {
      window.location.href = '/';
    }, 2000);
  }
  
  // Dialógus bezárása ESC billentyűvel
  document.addEventListener('keydown', function(esemeny) {
    if (esemeny.key === 'Escape' && torlesMegersito.style.display === 'flex') {
      torlesMegse.click();
    }
  });
</script>

Rossz gyakorlatok

Kerülendő megoldások:

  • Hibaellenőrzés vagy megerősítés nélküli beküldés: Űrlapok beküldése a bevitelek validálása vagy fontos tranzakciók megerősítése nélkül
  • Rejtett vagy homályos hibaüzenetek: Hibák, amelyek nem világosan magyarázottak vagy nem hozzáférhetőek a képernyőolvasók számára
  • Visszavonás nélküli műveletek: Olyan műveletek, mint például egy adat azonnali és visszavonhatatlan törlése
  • Automatikus űrlap beküldés: Űrlapok automatikus beküldése felhasználói áttekintés nélkül, különösen kritikus érzékeny adatok esetében (pl. banki adatok fizetésnél stb.)
  • Félrevezető megerősítések: Olyan megerősítő üzenetek, amelyek nem tükrözik pontosan a végrehajtandó műveletet

Példa rossz gyakorlatra

<!-- ROSSZ GYAKORLAT - Validálás és megerősítés nélküli vásárlás -->
<form>
  <input type="text" name="bankkartya" placeholder="Bankkártya szám">
  <input type="text" name="nev" placeholder="Név">
  <input type="text" name="cim" placeholder="Cím">
  <button type="submit">Vásárlás most</button>
</form>
<!-- Nincs validálás, nincs megerősítés, nincsenek hibaüzenetek -->

<!-- ROSSZ GYAKORLAT - Azonnali törlés visszavonás nélkül -->
<button onclick="torlesAdat()" class="torles-gomb">
  Összes adat törlése
</button>
<script>
  function torlesAdat() {
    // Azonnal törli az adatokat megerősítés nélkül
    alert('Adatok törölve!');
    // Nincs visszavonási lehetőség
  }
</script>

<!-- ROSSZ GYAKORLAT - Automatikus form beküldés -->
<form>
  <input type="text" name="email" onchange="this.form.submit()">
  <input type="password" name="jelszo" onchange="this.form.submit()">
  <!-- Automatikusan beküldi a formot változás esetén -->
</form>

Források

Iratkozz fel hírlevelünkre!

Amennyiben szeretnél első kézből értesülni az új bejegyzésekről, iratkozz fel hírlevelünkre!

Ez a weboldal sütiket használ a böngészési élmény javítása és a webhely megfelelő működésének biztosítása érdekében. A webhely használatának folytatásával elismeri és elfogadja a sütik használatát.

Összes elfogadása Csak a szükségesek elfogadása