3.2.6 - Következetes segítségnyújtás
Röviden a szabványpontról
A WCAG 2.2 Success Criterion 3.3.1 (Error Identification) megköveteli, hogy amikor beviteli hibát észlelünk, a hibát azonosítsuk és szöveges formában ismertessük a felhasználóval. Ez vonatkozik minden felhasználói beviteli űrlapra, interaktív vezérlőre és adatbeviteli pontra a webes tartalomban. A cél annak biztosítása, hogy azok a felhasználók, akik hibákat ejtenek űrlapok kitöltése, vagy a bevitelek használata során, világosan tájékoztatva legyenek arról, hogy mi ment rosszul, így ki tudják javítani azt.
Cél: Segíteni a felhasználókat abban, hogy elkerüljék a zavart és frusztrációt azáltal, hogy világos és érthető hibaüzeneteket kapnak, amelyek pontosan megmondják, mit kell javítaniuk. Ez különösen fontos a kisegítő technológiákat használó felhasználók számára.
Mire vonatkozik: Minden olyan webes tartalomra, amely felhasználói adatbevitelt fogad, beleértve az űrlapokat, interaktív vezérlőket, keresőmezőket és bármilyen adatvalidációt igénylő elemet.
Kiket érint
Elsődleges felhasználók: Kognitív fogyatékossággal, tanulási nehézségekkel, gyengénlátással élő emberek vagy azok, akik képernyőolvasóra támaszkodnak, nagy hasznot húznak a világos hibaazonosításból. Segít nekik megérteni, hogy melyik bevitelt kell javítaniuk.
Másodlagos előnyök: Minden felhasználó számára előnyös a világos hibaüzenetek, javítva az általános használhatóságot és csökkentve a hibákat űrlap beküldése vagy interakció során.
Tesztelés
- Manuális űrlap tesztelés: Szándékosan érvénytelen adatokat írj be vagy hagyd ki a kötelező mezőket és ellenőrizd, hogy megjelennek-e a hibaüzenetek és világosan leírják-e a problémát
- Képernyőolvasó tesztelés: Használj képernyőolvasót (pl. NVDA, JAWS, VoiceOver) annak ellenőrzésére, hogy a hibaüzenetek programozottan kapcsolódnak a megfelelő beviteli mezőkhöz és felolvasásra kerülnek
- Kizárólag billentyűzetes navigáció: Küldj el hibás űrlapokat csak billentyűzet használatával és győződj meg róla, hogy a fókusz a hibaüzenetre vagy annak közelébe kerül
- Automatizált eszközök: Használj akadálymentességi tesztelő eszközöket, mint az axe DevTools a hiányzó vagy helytelenül kapcsolt hibaüzenetek észlelésére
- Kód vizsgálat: Ellenőrizd, hogy a hibaüzenetek kapcsolódnak a bevitelekhez ARIA attribútumok használatával, mint az aria-describedby vagy a hibaüzenet elhelyezésével a címkékben vagy bevitelek közelében
Jó gyakorlatok
1. Explicit hibaüzenetek beviteli mezőkhöz kapcsolva
<!-- REGISZTRÁCIÓS ŰRLAP - Teljes hibakezeléssel -->
<form class="registration-form" novalidate>
<div class="form-section">
<h2>Új fiók regisztrációja</h2>
<!-- Általános hibák megjelenítése -->
<div id="form-errors" class="form-errors" role="alert" aria-live="polite" style="display: none;">
<h3>Hibák történtek az űrlap kitöltése során:</h3>
<ul id="error-list"></ul>
</div>
</div>
<div class="form-group">
<label for="username">Felhasználónév *</label>
<input
type="text"
id="username"
name="username"
required
minlength="3"
maxlength="20"
pattern="[a-zA-Z0-9]+"
aria-describedby="username-help username-error"
autocomplete="username"
>
<div id="username-help" class="field-help">
3-20 karakter, csak betűk és számok használhatók
</div>
<div id="username-error" class="error-message" role="alert" style="display: none;"></div>
</div>
<div class="form-group">
<label for="email">E-mail cím *</label>
<input
type="email"
id="email"
name="email"
required
aria-describedby="email-help email-error"
autocomplete="email"
>
<div id="email-help" class="field-help">
Valós e-mail címet adjon meg (pl. nev@domain.hu)
</div>
<div id="email-error" class="error-message" role="alert" style="display: none;"></div>
</div>
<div class="form-group">
<label for="password">Jelszó *</label>
<input
type="password"
id="password"
name="password"
required
minlength="8"
aria-describedby="password-help password-error"
autocomplete="new-password"
>
<div id="password-help" class="field-help">
Minimum 8 karakter, tartalmazzon legalább egy számot és egy nagybetűt
</div>
<div id="password-error" class="error-message" role="alert" style="display: none;"></div>
</div>
<div class="form-group">
<label for="password-confirm">Jelszó megerősítése *</label>
<input
type="password"
id="password-confirm"
name="password-confirm"
required
aria-describedby="password-confirm-help password-confirm-error"
autocomplete="new-password"
>
<div id="password-confirm-help" class="field-help">
Írja be újra a jelszót a megerősítéshez
</div>
<div id="password-confirm-error" class="error-message" role="alert" style="display: none;"></div>
</div>
<div class="form-group">
<label for="birth-date">Születési dátum *</label>
<input
type="date"
id="birth-date"
name="birth-date"
required
max="2006-01-01"
aria-describedby="birth-date-help birth-date-error"
>
<div id="birth-date-help" class="field-help">
Legalább 18 évesnek kell lennie a regisztrációhoz
</div>
<div id="birth-date-error" class="error-message" role="alert" style="display: none;"></div>
</div>
<div class="form-group">
<fieldset>
<legend>Értesítési beállítások</legend>
<div class="checkbox-group">
<input type="checkbox" id="newsletter" name="newsletter" value="yes">
<label for="newsletter">Szeretnék hírlevelet kapni</label>
</div>
<div class="checkbox-group">
<input
type="checkbox"
id="terms"
name="terms"
required
aria-describedby="terms-error"
>
<label for="terms">
Elfogadom a <a href="/felhasznalasi-feltetelek" target="_blank">felhasználási feltételeket</a> *
</label>
</div>
<div id="terms-error" class="error-message" role="alert" style="display: none;"></div>
</fieldset>
</div>
<div class="form-actions">
<button type="submit" class="btn-submit">Fiók létrehozása</button>
<button type="reset" class="btn-reset">Űrlap törlése</button>
</div>
</form>
<script>
document.addEventListener('DOMContentLoaded', function() {
const form = document.querySelector('.registration-form');
const inputs = form.querySelectorAll('input[required]');
// Valós idejű validáció (opcionális)
inputs.forEach(input => {
input.addEventListener('blur', function() {
validateField(input);
});
// Jelszó megerősítés speciális kezelése
if (input.id === 'password-confirm') {
input.addEventListener('input', function() {
validatePasswordMatch();
});
}
});
// Űrlap beküldési validáció
form.addEventListener('submit', function(event) {
event.preventDefault();
let isValid = true;
const errors = [];
// Minden kötelező mező ellenőrzése
inputs.forEach(input => {
const fieldValid = validateField(input);
if (!fieldValid) {
isValid = false;
const label = form.querySelector(`label[for="${input.id}"]`);
const fieldName = label ? label.textContent.replace(' *', '') : input.name;
errors.push({
field: input.id,
fieldName: fieldName,
message: getErrorMessage(input)
});
}
});
// Jelszó egyezés ellenőrzése
if (!validatePasswordMatch()) {
isValid = false;
}
if (isValid) {
// Sikeres validáció - űrlap elküldése
submitForm();
} else {
// Hibák megjelenítése
displayFormErrors(errors);
// Fókusz az első hibás mezőre
const firstErrorField = form.querySelector('input[aria-invalid="true"]');
if (firstErrorField) {
firstErrorField.focus();
firstErrorField.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
}
});
function validateField(input) {
const errorElement = document.getElementById(input.id + '-error');
let isValid = true;
let errorMessage = '';
// Kötelező mező ellenőrzése
if (input.hasAttribute('required') && !input.value.trim()) {
isValid = false;
errorMessage = `A ${getFieldLabel(input)} megadása kötelező.`;
}
// E-mail formátum ellenőrzése
else if (input.type === 'email' && input.value && !isValidEmail(input.value)) {
isValid = false;
errorMessage = 'Kérjük, adjon meg egy érvényes e-mail címet (pl. nev@domain.hu).';
}
// Jelszó erősség ellenőrzése
else if (input.id === 'password' && input.value && !isStrongPassword(input.value)) {
isValid = false;
errorMessage = 'A jelszónak legalább 8 karakter hosszúnak kell lennie, és tartalmaznia kell legalább egy számot és egy nagybetűt.';
}
// Felhasználónév formátum ellenőrzése
else if (input.id === 'username' && input.value && !isValidUsername(input.value)) {
isValid = false;
if (input.value.length < 3) {
errorMessage = 'A felhasználónév legalább 3 karakter hosszú legyen.';
} else if (input.value.length > 20) {
errorMessage = 'A felhasználónév legfeljebb 20 karakter hosszú lehet.';
} else {
errorMessage = 'A felhasználónév csak betűket és számokat tartalmazhat.';
}
}
// Születési dátum ellenőrzése
else if (input.id === 'birth-date' && input.value && !isValidAge(input.value)) {
isValid = false;
errorMessage = 'Legalább 18 évesnek kell lennie a regisztrációhoz.';
}
// Checkbox ellenőrzése
else if (input.type === 'checkbox' && input.hasAttribute('required') && !input.checked) {
isValid = false;
errorMessage = 'El kell fogadnia a felhasználási feltételeket a folytatáshoz.';
}
// Hibaállapot beállítása
input.setAttribute('aria-invalid', isValid ? 'false' : 'true');
if (isValid) {
errorElement.style.display = 'none';
errorElement.textContent = '';
input.classList.remove('field-error');
} else {
errorElement.style.display = 'block';
errorElement.textContent = errorMessage;
input.classList.add('field-error');
}
return isValid;
}
function validatePasswordMatch() {
const password = document.getElementById('password');
const passwordConfirm = document.getElementById('password-confirm');
const errorElement = document.getElementById('password-confirm-error');
if (passwordConfirm.value && password.value !== passwordConfirm.value) {
passwordConfirm.setAttribute('aria-invalid', 'true');
passwordConfirm.classList.add('field-error');
errorElement.style.display = 'block';
errorElement.textContent = 'A két jelszó nem egyezik meg.';
return false;
} else if (passwordConfirm.value) {
passwordConfirm.setAttribute('aria-invalid', 'false');
passwordConfirm.classList.remove('field-error');
errorElement.style.display = 'none';
errorElement.textContent = '';
}
return true;
}
function displayFormErrors(errors) {
const formErrors = document.getElementById('form-errors');
const errorList = document.getElementById('error-list');
if (errors.length > 0) {
errorList.innerHTML = '';
errors.forEach(error => {
const li = document.createElement('li');
const link = document.createElement('a');
link.href = `#${error.field}`;
link.textContent = `${error.fieldName}: ${error.message}`;
link.addEventListener('click', function(e) {
e.preventDefault();
document.getElementById(error.field).focus();
});
li.appendChild(link);
errorList.appendChild(li);
});
formErrors.style.display = 'block';
formErrors.scrollIntoView({ behavior: 'smooth', block: 'center' });
// Képernyőolvasó értesítése
announceToScreenReader(`${errors.length} hibát találtunk az űrlapban. Kérjük, javítsa ki őket.`);
} else {
formErrors.style.display = 'none';
}
}
function getFieldLabel(input) {
const label = form.querySelector(`label[for="${input.id}"]`);
return label ? label.textContent.replace(' *', '').toLowerCase() : input.name;
}
function getErrorMessage(input) {
const errorElement = document.getElementById(input.id + '-error');
return errorElement ? errorElement.textContent : 'Érvénytelen érték.';
}
function isValidEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
function isStrongPassword(password) {
return password.length >= 8 &&
/[A-Z]/.test(password) &&
/[0-9]/.test(password);
}
function isValidUsername(username) {
return username.length >= 3 &&
username.length <= 20 &&
/^[a-zA-Z0-9]+$/.test(username);
}
function isValidAge(birthDate) {
const today = new Date();
const birth = new Date(birthDate);
const age = today.getFullYear() - birth.getFullYear();
const monthDiff = today.getMonth() - birth.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
return age - 1 >= 18;
}
return age >= 18;
}
function submitForm() {
announceToScreenReader('Űrlap sikeresen elküldve. Kérjük, várjon...');
// Itt történne a tényleges űrlap elküldése
console.log('Űrlap elküldése...');
// Siker üzenet megjelenítése
setTimeout(() => {
alert('Regisztráció sikeres! Ellenőrizze e-mail címét az aktiválási linkért.');
}, 1000);
}
function announceToScreenReader(message) {
const announcement = document.createElement('div');
announcement.setAttribute('role', 'status');
announcement.setAttribute('aria-live', 'polite');
announcement.className = 'visually-hidden';
announcement.textContent = message;
document.body.appendChild(announcement);
setTimeout(() => {
if (announcement.parentNode) {
document.body.removeChild(announcement);
}
}, 1000);
}
});
</script>
<style>
.registration-form {
max-width: 600px;
margin: 2rem auto;
padding: 2rem;
background: white;
border: 1px solid #e9ecef;
border-radius: 8px;
}
.form-section h2 {
margin: 0 0 1.5rem 0;
color: #495057;
}
.form-errors {
background: #f8d7da;
border: 1px solid #f5c6cb;
border-radius: 4px;
padding: 1rem;
margin-bottom: 1.5rem;
}
.form-errors h3 {
margin: 0 0 0.5rem 0;
color: #721c24;
font-size: 1.1em;
}
.form-errors ul {
margin: 0;
padding-left: 1.2rem;
}
.form-errors li {
margin-bottom: 0.25rem;
}
.form-errors a {
color: #721c24;
text-decoration: none;
}
.form-errors a:hover, .form-errors a:focus {
text-decoration: underline;
}
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
font-weight: 600;
margin-bottom: 0.5rem;
color: #495057;
}
.form-group input, .form-group select {
width: 100%;
padding: 0.75rem;
border: 2px solid #ced4da;
border-radius: 4px;
font-size: 1rem;
transition: border-color 0.2s ease;
}
.form-group input:focus, .form-group select:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
}
.form-group input.field-error {
border-color: #dc3545;
background-color: #fff5f5;
}
.form-group input.field-error:focus {
border-color: #dc3545;
box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.1);
}
.field-help {
margin-top: 0.5rem;
font-size: 0.9em;
color: #6c757d;
line-height: 1.4;
}
.error-message {
margin-top: 0.5rem;
padding: 0.5rem;
background: #f8d7da;
border: 1px solid #f5c6cb;
border-radius: 4px;
color: #721c24;
font-size: 0.9em;
font-weight: 500;
}
fieldset {
border: 1px solid #e9ecef;
border-radius: 4px;
padding: 1rem;
margin: 0;
}
legend {
font-weight: 600;
color: #495057;
padding: 0 0.5rem;
}
.checkbox-group {
display: flex;
align-items: flex-start;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.checkbox-group input[type="checkbox"] {
width: auto;
margin-top: 0.25rem;
}
.checkbox-group label {
margin-bottom: 0;
font-weight: normal;
cursor: pointer;
}
.form-actions {
display: flex;
gap: 1rem;
margin-top: 2rem;
}
.btn-submit, .btn-reset {
padding: 0.75rem 1.5rem;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
transition: all 0.2s ease;
}
.btn-submit {
background: #28a745;
color: white;
}
.btn-submit:hover, .btn-submit:focus {
background: #218838;
}
.btn-reset {
background: #6c757d;
color: white;
}
.btn-reset:hover, .btn-reset:focus {
background: #545b62;
}
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
@media (max-width: 768px) {
.registration-form {
margin: 1rem;
padding: 1rem;
}
.form-actions {
flex-direction: column;
}
}
</style>
Magyarázat: A hibaüzenetek az aria-describedby attribútummal kapcsolódnak a mezőkhöz, role=”alert” attribútummal dinamikusan bejelentésre kerülnek, és az aria-invalid attribútum jelzi a hibás állapotot a kisegítő technológiák számára.
2. Fókusz kezelése hiba után és programozott hibaazonosítás
<!-- KAPCSOLATFELVÉTELI ŰRLAP - Fejlett hibakezeléssel -->
<form class="contact-form" novalidate>
<div class="form-header">
<h2>Kapcsolatfelvételi űrlap</h2>
<!-- Hibák összesítő doboza -->
<div id="error-summary" class="error-summary" role="alert" aria-labelledby="error-summary-title" style="display: none;">
<h3 id="error-summary-title">Az űrlapban hibák találhatók</h3>
<p>Kérjük, javítsa ki az alábbi hibákat a folytatáshoz:</p>
<ul id="error-summary-list"></ul>
</div>
</div>
<div class="form-content">
<div class="form-group">
<label for="contact-name">
Teljes név
<span class="required-indicator" aria-label="kötelező">*</span>
</label>
<input
type="text"
id="contact-name"
name="name"
required
minlength="2"
aria-describedby="contact-name-help contact-name-error"
autocomplete="name"
>
<div id="contact-name-help" class="field-help">
Adja meg teljes nevét (vezetéknév és keresztnév)
</div>
<div id="contact-name-error" class="error-message" role="alert" style="display: none;"></div>
</div>
<div class="form-group">
<label for="contact-email">
E-mail cím
<span class="required-indicator" aria-label="kötelező">*</span>
</label>
<input
type="email"
id="contact-email"
name="email"
required
aria-describedby="contact-email-help contact-email-error"
autocomplete="email"
>
<div id="contact-email-help" class="field-help">
Érvényes e-mail címet adjon meg (pl. nev@domain.hu)
</div>
<div id="contact-email-error" class="error-message" role="alert" style="display: none;"></div>
</div>
<div class="form-group">
<label for="contact-phone">Telefonszám</label>
<input
type="tel"
id="contact-phone"
name="phone"
pattern="[\+]?[0-9\s\-\(\)]+"
aria-describedby="contact-phone-help contact-phone-error"
autocomplete="tel"
>
<div id="contact-phone-help" class="field-help">
Opcionális. Magyar vagy nemzetközi formátumban (pl. +36 1 234 5678)
</div>
<div id="contact-phone-error" class="error-message" role="alert" style="display: none;"></div>
</div>
<div class="form-group">
<label for="contact-subject">
Tárgy
<span class="required-indicator" aria-label="kötelező">*</span>
</label>
<select id="contact-subject" name="subject" required aria-describedby="contact-subject-help contact-subject-error">
<option value="">Válasszon témát</option>
<option value="general">Általános kérdés</option>
<option value="technical">Technikai probléma</option>
<option value="billing">Számlázási kérdés</option>
<option value="complaint">Panasz</option>
<option value="suggestion">Javaslat</option>
</select>
<div id="contact-subject-help" class="field-help">
Válassza ki a legmegfelelőbb kategóriát
</div>
<div id="contact-subject-error" class="error-message" role="alert" style="display: none;"></div>
</div>
<div class="form-group">
<label for="contact-message">
Üzenet
<span class="required-indicator" aria-label="kötelező">*</span>
</label>
<textarea
id="contact-message"
name="message"
required
minlength="10"
maxlength="1000"
rows="5"
aria-describedby="contact-message-help contact-message-error contact-message-count"
></textarea>
<div id="contact-message-help" class="field-help">
Részletesen írja le kérését vagy problémáját (minimum 10, maximum 1000 karakter)
</div>
<div id="contact-message-count" class="character-count" aria-live="polite">
0 / 1000 karakter
</div>
<div id="contact-message-error" class="error-message" role="alert" style="display: none;"></div>
</div>
<div class="form-group">
<fieldset>
<legend>Adatvédelmi hozzájárulás</legend>
<div class="checkbox-group">
<input
type="checkbox"
id="privacy-consent"
name="privacy"
required
aria-describedby="privacy-consent-error"
>
<label for="privacy-consent">
Elolvastam és elfogadom az
<a href="/adatvedelem" target="_blank" rel="noopener">adatvédelmi tájékoztatót</a>
<span class="required-indicator" aria-label="kötelező">*</span>
</label>
</div>
<div id="privacy-consent-error" class="error-message" role="alert" style="display: none;"></div>
</fieldset>
</div>
<div class="form-actions">
<button type="submit" class="btn-submit">
Üzenet küldése
<span id="submit-status" class="visually-hidden" aria-live="polite"></span>
</button>
<button type="reset" class="btn-reset">Mezők törlése</button>
</div>
</div>
</form>
<script>
document.addEventListener('DOMContentLoaded', function() {
const form = document.querySelector('.contact-form');
const messageTextarea = document.getElementById('contact-message');
const characterCount = document.getElementById('contact-message-count');
const submitButton = form.querySelector('.btn-submit');
const submitStatus = document.getElementById('submit-status');
let isSubmitting = false;
// Karakter számláló frissítése
messageTextarea.addEventListener('input', function() {
const length = this.value.length;
const maxLength = 1000;
characterCount.textContent = `${length} / ${maxLength} karakter`;
if (length > maxLength * 0.9) {
characterCount.classList.add('warning');
} else {
characterCount.classList.remove('warning');
}
});
// Valós idejű validáció
const inputs = form.querySelectorAll('input, select, textarea');
inputs.forEach(input => {
input.addEventListener('blur', function() {
validateField(this);
});
// Azonnali visszajelzés javítás után
input.addEventListener('input', function() {
if (this.getAttribute('aria-invalid') === 'true') {
clearFieldError(this);
}
});
});
// Űrlap beküldés kezelése
form.addEventListener('submit', function(event) {
event.preventDefault();
if (isSubmitting) return;
const validationResult = validateForm();
if (validationResult.isValid) {
submitForm();
} else {
handleFormErrors(validationResult.errors);
}
});
function validateForm() {
const errors = [];
let isValid = true;
inputs.forEach(input => {
const fieldValid = validateField(input);
if (!fieldValid.isValid) {
isValid = false;
errors.push({
field: input.id,
fieldName: getFieldLabel(input),
message: fieldValid.message,
element: input
});
}
});
return { isValid, errors };
}
function validateField(input) {
const errorElement = document.getElementById(input.id + '-error');
let isValid = true;
let message = '';
// Kötelező mezők ellenőrzése
if (input.hasAttribute('required')) {
if (input.type === 'checkbox' && !input.checked) {
isValid = false;
message = 'Az adatvédelmi tájékoztató elfogadása kötelező.';
} else if (input.type !== 'checkbox' && !input.value.trim()) {
isValid = false;
message = `A ${getFieldLabel(input).toLowerCase()} megadása kötelező.`;
}
}
// Specifikus validációk
if (isValid && input.value.trim()) {
switch (input.type) {
case 'email':
if (!isValidEmail(input.value)) {
isValid = false;
message = 'Kérjük, adjon meg egy érvényes e-mail címet.';
}
break;
case 'tel':
if (!isValidPhone(input.value)) {
isValid = false;
message = 'Kérjük, adjon meg egy érvényes telefonszámot.';
}
break;
}
// Hossz ellenőrzése
if (input.hasAttribute('minlength') && input.value.length < parseInt(input.getAttribute('minlength'))) {
isValid = false;
const minLength = input.getAttribute('minlength');
message = `Legalább ${minLength} karakter szükséges.`;
}
if (input.hasAttribute('maxlength') && input.value.length > parseInt(input.getAttribute('maxlength'))) {
isValid = false;
const maxLength = input.getAttribute('maxlength');
message = `Maximum ${maxLength} karakter engedélyezett.`;
}
}
// Select mező specifikus ellenőrzés
if (input.tagName === 'SELECT' && input.hasAttribute('required') && !input.value) {
isValid = false;
message = 'Kérjük, válasszon egy opciót.';
}
// Hibaállapot beállítása
updateFieldError(input, isValid, message);
return { isValid, message };
}
function updateFieldError(input, isValid, message) {
const errorElement = document.getElementById(input.id + '-error');
input.setAttribute('aria-invalid', isValid ? 'false' : 'true');
if (isValid) {
input.classList.remove('field-error');
if (errorElement) {
errorElement.style.display = 'none';
errorElement.textContent = '';
}
} else {
input.classList.add('field-error');
if (errorElement) {
errorElement.style.display = 'block';
errorElement.textContent = message;
}
}
}
function clearFieldError(input) {
updateFieldError(input, true, '');
}
function handleFormErrors(errors) {
// Hibák összesítő megjelenítése
displayErrorSummary(errors);
// Fókusz az első hibás mezőre
if (errors.length > 0) {
const firstErrorField = errors[0].element;
// Smooth scroll az első hibához
firstErrorField.scrollIntoView({
behavior: 'smooth',
block: 'center'
});
// Fókusz beállítása kis késleltetéssel
setTimeout(() => {
firstErrorField.focus();
}, 300);
// Képernyőolvasó értesítése
announceToScreenReader(`${errors.length} hibát találtunk az űrlapban. A kurzor az első hibás mezőre került.`);
}
}
function displayErrorSummary(errors) {
const errorSummary = document.getElementById('error-summary');
const errorList = document.getElementById('error-summary-list');
if (errors.length > 0) {
errorList.innerHTML = '';
errors.forEach(error => {
const li = document.createElement('li');
const link = document.createElement('a');
link.href = `#${error.field}`;
link.textContent = `${error.fieldName}: ${error.message}`;
link.addEventListener('click', function(e) {
e.preventDefault();
error.element.focus();
error.element.scrollIntoView({ behavior: 'smooth', block: 'center' });
});
li.appendChild(link);
errorList.appendChild(li);
});
errorSummary.style.display = 'block';
errorSummary.scrollIntoView({ behavior: 'smooth', block: 'start' });
// Fókusz az error summary-ra
setTimeout(() => {
errorSummary.focus();
}, 300);
} else {
errorSummary.style.display = 'none';
}
}
function submitForm() {
isSubmitting = true;
submitButton.disabled = true;
submitStatus.textContent = 'Üzenet küldése folyamatban...';
// Szimuláció: űrlap küldése
setTimeout(() => {
isSubmitting = false;
submitButton.disabled = false;
submitStatus.textContent = '';
// Sikeres küldés
announceToScreenReader('Üzenet sikeresen elküldve!');
// Success üzenet megjelenítése
const successMessage = document.createElement('div');
successMessage.className = 'success-message';
successMessage.setAttribute('role', 'alert');
successMessage.innerHTML = `
<h3>Üzenet sikeresen elküldve!</h3>
<p>Köszönjük megkeresését. Munkatársunk 24 órán belül válaszol.</p>
`;
form.parentNode.insertBefore(successMessage, form);
form.style.display = 'none';
successMessage.scrollIntoView({ behavior: 'smooth', block: 'center' });
successMessage.focus();
}, 2000);
}
function getFieldLabel(input) {
const label = form.querySelector(`label[for="${input.id}"]`);
if (label) {
return label.textContent.replace(/\s*\*\s*$/, '').trim();
}
return input.name || input.id;
}
function isValidEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
function isValidPhone(phone) {
const phoneRegex = /^[\+]?[0-9\s\-\(\)]{6,}$/;
return phoneRegex.test(phone);
}
function announceToScreenReader(message) {
const announcement = document.createElement('div');
announcement.setAttribute('role', 'status');
announcement.setAttribute('aria-live', 'polite');
announcement.className = 'visually-hidden';
announcement.textContent = message;
document.body.appendChild(announcement);
setTimeout(() => {
if (announcement.parentNode) {
document.body.removeChild(announcement);
}
}, 1000);
}
});
</script>
<style>
.contact-form {
max-width: 700px;
margin: 2rem auto;
padding: 2rem;
background: white;
border: 1px solid #e9ecef;
border-radius: 8px;
}
.form-header h2 {
margin: 0 0 1.5rem 0;
color: #495057;
}
.error-summary {
background: #f8d7da;
border: 2px solid #f5c6cb;
border-radius: 6px;
padding: 1.5rem;
margin-bottom: 2rem;
outline: none;
}
.error-summary:focus {
outline: 3px solid #dc3545;
outline-offset: 2px;
}
.error-summary h3 {
margin: 0 0 0.5rem 0;
color: #721c24;
font-size: 1.2em;
}
.error-summary p {
margin: 0.5rem 0;
color: #721c24;
}
.error-summary ul {
margin: 0.5rem 0 0 0;
padding-left: 1.5rem;
}
.error-summary li {
margin-bottom: 0.5rem;
}
.error-summary a {
color: #721c24;
font-weight: 500;
text-decoration: none;
}
.error-summary a:hover, .error-summary a:focus {
text-decoration: underline;
outline: 2px solid #721c24;
outline-offset: 1px;
}
.required-indicator {
color: #dc3545;
font-weight: bold;
}
.character-count {
font-size: 0.9em;
color: #6c757d;
text-align: right;
margin-top: 0.25rem;
}
.character-count.warning {
color: #856404;
font-weight: bold;
}
.success-message {
background: #d4edda;
border: 2px solid #c3e6cb;
border-radius: 6px;
padding: 1.5rem;
margin-bottom: 2rem;
outline: none;
}
.success-message:focus {
outline: 3px solid #28a745;
outline-offset: 2px;
}
.success-message h3 {
margin: 0 0 0.5rem 0;
color: #155724;
}
.success-message p {
margin: 0;
color: #155724;
}
/* További stílusok az előző példából... */
</style>
Magyarázat: A rendszer automatikusan az első hibás mezőre irányítja a fókuszt, hibák összesítőt jelenít meg, és programozott kapcsolatot biztosít az aria-invalid és aria-describedby attribútumokkal.
3. Világos és konkrét hibaüzenetek leírásokkal
<!-- BEJELENTKEZÉSI ŰRLAP - Specifikus hibaüzenetekkel -->
<form class="login-form" novalidate>
<div class="login-header">
<h2>Bejelentkezés</h2>
<p>Adja meg felhasználónevét és jelszavát a belépéshez.</p>
</div>
<div class="form-group">
<label for="login-username">Felhasználónév vagy e-mail cím</label>
<input
type="text"
id="login-username"
name="username"
required
autocomplete="username"
aria-describedby="login-username-error"
>
<div id="login-username-error" class="error-message" role="alert" style="display: none;"></div>
</div>
<div class="form-group">
<label for="login-password">Jelszó</label>
<div class="password-container">
<input
type="password"
id="login-password"
name="password"
required
autocomplete="current-password"
aria-describedby="login-password-error"
>
<button
type="button"
class="password-toggle"
aria-label="Jelszó megjelenítése"
onclick="togglePasswordVisibility('login-password')"
>
<span class="toggle-text">Mutat</span>
</button>
</div>
<div id="login-password-error" class="error-message" role="alert" style="display: none;"></div>
</div>
<div class="form-group">
<div class="checkbox-group">
<input type="checkbox" id="remember-me" name="remember">
<label for="remember-me">Emlékezzen rám ezen az eszközön</label>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn-login">Bejelentkezés</button>
<a href="/jelszo-visszaallitas" class="forgot-password">Elfelejtette jelszavát?</a>
</div>
<!-- Általános hiba üzenetek -->
<div id="login-general-error" class="general-error" role="alert" style="display: none;"></div>
</form>
<!-- FIZETÉSI ŰRLAP - Komplex validációval -->
<form class="payment-form" novalidate>
<div class="payment-header">
<h2>Fizetési adatok</h2>
<p>Minden mezőt pontosan töltsön ki a biztonságos fizetéshez.</p>
</div>
<div class="form-group">
<label for="card-number">Bankkártya száma</label>
<input
type="text"
id="card-number"
name="cardNumber"
required
maxlength="19"
pattern="[0-9\s]{13,19}"
autocomplete="cc-number"
aria-describedby="card-number-help card-number-error"
placeholder="1234 5678 9012 3456"
>
<div id="card-number-help" class="field-help">
16 számjegy, szóközökkel vagy anélkül
</div>
<div id="card-number-error" class="error-message" role="alert" style="display: none;"></div>
</div>
<div class="form-row">
<div class="form-group form-group-half">
<label for="expiry-date">Lejárati dátum</label>
<input
type="text"
id="expiry-date"
name="expiryDate"
required
maxlength="5"
pattern="[0-9]{2}/[0-9]{2}"
autocomplete="cc-exp"
aria-describedby="expiry-date-help expiry-date-error"
placeholder="MM/YY"
>
<div id="expiry-date-help" class="field-help">
HH/ÉÉ formátumban
</div>
<div id="expiry-date-error" class="error-message" role="alert" style="display: none;"></div>
</div>
<div class="form-group form-group-half">
<label for="cvv">CVC/CVV kód</label>
<input
type="text"
id="cvv"
name="cvv"
required
maxlength="4"
pattern="[0-9]{3,4}"
autocomplete="cc-csc"
aria-describedby="cvv-help cvv-error"
placeholder="123"
>
<div id="cvv-help" class="field-help">
3-4 számjegy a kártya hátulján
</div>
<div id="cvv-error" class="error-message" role="alert" style="display: none;"></div>
</div>
</div>
<div class="form-group">
<label for="cardholder-name">Kártyatulajdonos neve</label>
<input
type="text"
id="cardholder-name"
name="cardholderName"
required
autocomplete="cc-name"
aria-describedby="cardholder-name-help cardholder-name-error"
placeholder="Ahogy a kártyán szerepel"
>
<div id="cardholder-name-help" class="field-help">
Pontosan úgy, ahogy a bankkártyán szerepel
</div>
<div id="cardholder-name-error" class="error-message" role="alert" style="display: none;"></div>
</div>
<div class="form-actions">
<button type="submit" class="btn-pay">
Fizetés: <span class="amount">15.990 Ft</span>
</button>
</div>
</form>
<script>
// Specifikus hibaüzenetek definiálása
const ErrorMessages = {
// Bejelentkezési hibák
login: {
usernameRequired: 'Kérjük, adja meg felhasználónevét vagy e-mail címét.',
usernameInvalid: 'A felhasználónév vagy e-mail cím formátuma helytelen.',
passwordRequired: 'Kérjük, adja meg jelszavát.',
passwordTooShort: 'A jelszó túl rövid. Legalább 6 karakter szükséges.',
invalidCredentials: 'Hibás felhasználónév vagy jelszó. Kérjük, ellenőrizze adatait és próbálja újra.',
accountLocked: 'A fiók átmenetileg zárolva van túl sok sikertelen bejelentkezési kísérlet miatt. Próbálja újra 15 perc múlva.',
accountDisabled: 'Ez a fiók inaktív. Kérjük, vegye fel a kapcsolatot az ügyfélszolgálattal.',
},
// Fizetési hibák
payment: {
cardNumberRequired: 'Kérjük, adja meg bankkártyájának számát.',
cardNumberInvalid: 'A bankkártya száma érvénytelen. Kérjük, ellenőrizze és adja meg újra (16 számjegy).',
cardNumberUnsupported: 'Ez a kártyatípus nem támogatott. Kérjük, használjon Visa vagy Mastercard kártyát.',
expiryRequired: 'Kérjük, adja meg a kártya lejárati dátumát.',
expiryInvalid: 'A lejárati dátum formátuma helytelen. Használja a HH/ÉÉ formátumot (pl. 12/25).',
expiryExpired: 'Ez a bankkártya már lejárt. Kérjük, használjon érvényes kártyát.',
cvvRequired: 'Kérjük, adja meg a CVC/CVV kódot.',
cvvInvalid: 'A CVC/CVV kód érvénytelen. 3-4 számjegyű kód szükséges.',
cardholderRequired: 'Kérjük, adja meg a kártyatulajdonos nevét.',
cardholderInvalid: 'A kártyatulajdonos neve csak betűket és szóközöket tartalmazhat.',
processingError: 'Hiba történt a fizetés feldolgozása során. Kérjük, próbálja újra.'
}
};
// Bejelentkezési űrlap kezelése
document.querySelector('.login-form').addEventListener('submit', function(event) {
event.preventDefault();
const username = document.getElementById('login-username');
const password = document.getElementById('login-password');
const generalError = document.getElementById('login-general-error');
let hasErrors = false;
// Felhasználónév validáció
if (!username.value.trim()) {
showFieldError('login-username', ErrorMessages.login.usernameRequired);
hasErrors = true;
} else if (!isValidUsernameOrEmail(username.value)) {
showFieldError('login-username', ErrorMessages.login.usernameInvalid);
hasErrors = true;
} else {
clearFieldError('login-username');
}
// Jelszó validáció
if (!password.value) {
showFieldError('login-password', ErrorMessages.login.passwordRequired);
hasErrors = true;
} else if (password.value.length < 6) {
showFieldError('login-password', ErrorMessages.login.passwordTooShort);
hasErrors = true;
} else {
clearFieldError('login-password');
}
if (hasErrors) {
// Fókusz az első hibás mezőre
const firstError = this.querySelector('input[aria-invalid="true"]');
if (firstError) {
firstError.focus();
}
return;
}
// Szimulált bejelentkezési kísérlet
simulateLogin(username.value, password.value, generalError);
});
// Fizetési űrlap kezelése
document.querySelector('.payment-form').addEventListener('submit', function(event) {
event.preventDefault();
const fields = {
cardNumber: document.getElementById('card-number'),
expiryDate: document.getElementById('expiry-date'),
cvv: document.getElementById('cvv'),
cardholderName: document.getElementById('cardholder-name')
};
let hasErrors = false;
// Bankkártya szám validáció
const cardNumber = fields.cardNumber.value.replace(/\s/g, '');
if (!cardNumber) {
showFieldError('card-number', ErrorMessages.payment.cardNumberRequired);
hasErrors = true;
} else if (!isValidCardNumber(cardNumber)) {
showFieldError('card-number', ErrorMessages.payment.cardNumberInvalid);
hasErrors = true;
} else if (!isSupportedCardType(cardNumber)) {
showFieldError('card-number', ErrorMessages.payment.cardNumberUnsupported);
hasErrors = true;
} else {
clearFieldError('card-number');
}
// Lejárati dátum validáció
const expiry = fields.expiryDate.value;
if (!expiry) {
showFieldError('expiry-date', ErrorMessages.payment.expiryRequired);
hasErrors = true;
} else if (!isValidExpiryFormat(expiry)) {
showFieldError('expiry-date', ErrorMessages.payment.expiryInvalid);
hasErrors = true;
} else if (isCardExpired(expiry)) {
showFieldError('expiry-date', ErrorMessages.payment.expiryExpired);
hasErrors = true;
} else {
clearFieldError('expiry-date');
}
// CVV validáció
const cvv = fields.cvv.value;
if (!cvv) {
showFieldError('cvv', ErrorMessages.payment.cvvRequired);
hasErrors = true;
} else if (!isValidCVV(cvv)) {
showFieldError('cvv', ErrorMessages.payment.cvvInvalid);
hasErrors = true;
} else {
clearFieldError('cvv');
}
// Kártyatulajdonos validáció
const cardholderName = fields.cardholderName.value.trim();
if (!cardholderName) {
showFieldError('cardholder-name', ErrorMessages.payment.cardholderRequired);
hasErrors = true;
} else if (!isValidCardholderName(cardholderName)) {
showFieldError('cardholder-name', ErrorMessages.payment.cardholderInvalid);
hasErrors = true;
} else {
clearFieldError('cardholder-name');
}
if (hasErrors) {
const firstError = this.querySelector('input[aria-invalid="true"]');
if (firstError) {
firstError.focus();
}
return;
}
// Fizetés feldolgozása
processPayment();
});
// Segédfüggvények
function showFieldError(fieldId, message) {
const field = document.getElementById(fieldId);
const errorElement = document.getElementById(fieldId + '-error');
field.setAttribute('aria-invalid', 'true');
field.classList.add('field-error');
errorElement.style.display = 'block';
errorElement.textContent = message;
}
function clearFieldError(fieldId) {
const field = document.getElementById(fieldId);
const errorElement = document.getElementById(fieldId + '-error');
field.setAttribute('aria-invalid', 'false');
field.classList.remove('field-error');
errorElement.style.display = 'none';
errorElement.textContent = '';
}
function isValidUsernameOrEmail(value) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const usernameRegex = /^[a-zA-Z0-9_]{3,}$/;
return emailRegex.test(value) || usernameRegex.test(value);
}
function isValidCardNumber(cardNumber) {
return cardNumber.length === 16 && /^[0-9]+$/.test(cardNumber);
}
function isSupportedCardType(cardNumber) {
// Visa: 4-gyel kezdődik, Mastercard: 5-tel kezdődik
return cardNumber.startsWith('4') || cardNumber.startsWith('5');
}
function isValidExpiryFormat(expiry) {
return /^[0-9]{2}\/[0-9]{2}$/.test(expiry);
}
function isCardExpired(expiry) {
const [month, year] = expiry.split('/').map(Number);
const now = new Date();
const currentYear = now.getFullYear() % 100;
const currentMonth = now.getMonth() + 1;
return year < currentYear || (year === currentYear && month < currentMonth);
}
function isValidCVV(cvv) {
return /^[0-9]{3,4}$/.test(cvv);
}
function isValidCardholderName(name) {
return /^[a-zA-ZáéíóöőúüűÁÉÍÓÖŐÚÜŰ\s]{2,}$/.test(name);
}
function simulateLogin(username, password, generalErrorElement) {
// Szimulált bejelentkezési logika
setTimeout(() => {
const randomOutcome = Math.random();
if (randomOutcome < 0.3) {
// Sikertelen bejelentkezés
generalErrorElement.textContent = ErrorMessages.login.invalidCredentials;
generalErrorElement.style.display = 'block';
} else if (randomOutcome < 0.4) {
// Zárolt fiók
generalErrorElement.textContent = ErrorMessages.login.accountLocked;
generalErrorElement.style.display = 'block';
} else {
// Sikeres bejelentkezés
alert('Sikeres bejelentkezés!');
}
}, 1000);
}
function processPayment() {
alert('Fizetés feldolgozása... (szimulált)');
}
function togglePasswordVisibility(fieldId) {
const field = document.getElementById(fieldId);
const button = field.nextElementSibling;
const toggleText = button.querySelector('.toggle-text');
if (field.type === 'password') {
field.type = 'text';
button.setAttribute('aria-label', 'Jelszó elrejtése');
toggleText.textContent = 'Rejt';
} else {
field.type = 'password';
button.setAttribute('aria-label', 'Jelszó megjelenítése');
toggleText.textContent = 'Mutat';
}
}
</script>
<style>
.login-form, .payment-form {
max-width: 500px;
margin: 2rem auto;
padding: 2rem;
background: white;
border: 1px solid #e9ecef;
border-radius: 8px;
}
.password-container {
position: relative;
}
.password-toggle {
position: absolute;
right: 0.5rem;
top: 50%;
transform: translateY(-50%);
background: #f8f9fa;
border: 1px solid #ced4da;
border-radius: 4px;
padding: 0.25rem 0.5rem;
cursor: pointer;
font-size: 0.8em;
}
.form-row {
display: flex;
gap: 1rem;
}
.form-group-half {
flex: 1;
}
.general-error {
background: #f8d7da;
border: 1px solid #f5c6cb;
border-radius: 4px;
padding: 1rem;
margin-top: 1rem;
color: #721c24;
}
.btn-login, .btn-pay {
width: 100%;
padding: 0.75rem;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
}
.btn-pay {
background: #28a745;
font-size: 1.1em;
font-weight: bold;
}
.amount {
background: rgba(255, 255, 255, 0.2);
padding: 0.25rem 0.5rem;
border-radius: 4px;
}
.forgot-password {
display: block;
text-align: center;
margin-top: 1rem;
color: #007bff;
text-decoration: none;
}
</style>
Magyarázat: A hibaüzenetek konkrétak és konstruktívak, világosan megmondják, mi a probléma és hogyan javítható ki. Kerülik a homályos üzeneteket, mint „Érvénytelen bevitel”.
Rossz gyakorlatok
Hibaüzenetek nem kapcsolódnak a beviteli mezőkhöz
<!-- HIBÁS: A hibaüzenet nincs programozottan kapcsolva -->
<form>
<label for="phone">Telefonszám:</label>
<input id="phone" type="tel" required>
<!-- HIBA: Nincs aria-describedby vagy más kapcsolat -->
<span style="color: red;">Kérjük, adja meg telefonszámát.</span>
</form>
<!-- HIBÁS: Hibaüzenet távol a mezőtől -->
<form>
<div class="form-group">
<label for="email">E-mail:</label>
<input id="email" type="email" required>
</div>
<div class="form-group">
<label for="password">Jelszó:</label>
<input id="password" type="password" required>
</div>
<!-- HIBA: Hibaüzenetek messze a mezőktől, nincs kapcsolat -->
<div class="errors">
<p>Az e-mail cím érvénytelen.</p>
<p>A jelszó túl rövid.</p>
</div>
</form>
Probléma: A képernyőolvasók nem tudják azonosítani, hogy melyik hibaüzenet melyik mezőhöz tartozik, mert nincs programozott kapcsolat közöttük.
Csak szín használata hibák jelzésére
<!-- HIBÁS: Csak vizuális jelzés színnel -->
<form>
<label for="zip">Irányítószám:</label>
<!-- HIBA: Csak a piros szegély jelzi a hibát -->
<input id="zip" type="text" style="border: 2px solid red;" required>
<!-- Nincs szöveges hibaüzenet -->
</form>
<!-- HIBÁS: Ikonok szöveg nélkül -->
<form>
<label for="username">Felhasználónév:</label>
<div class="input-container">
<input id="username" type="text" required>
<!-- HIBA: Csak vizuális ikon, nincs szöveges információ -->
<span class="error-icon" style="color: red;">❌</span>
</div>
</form>
<!-- HIBÁS: Háttérszín változás szöveg nélkül -->
<form>
<label for="age">Életkor:</label>
<!-- HIBA: Csak a rózsaszín háttér jelzi a hibát -->
<input id="age" type="number" style="background-color: #ffcccc;" required>
</form>
Probléma: A színvak vagy gyengénlátó felhasználók nem érzékelik a színváltozásokat, és nincs alternatív módja a hibák azonosításának.
Nem jelenik meg hibaüzenet
<!-- HIBÁS: Néma validáció -->
<form>
<label for="required-field">Kötelező mező:</label>
<input id="required-field" type="text" required>
<button type="submit">Küldés</button>
<script>
// HIBA: Csak console.log, nincs felhasználói visszajelzés
document.querySelector('form').addEventListener('submit', function(e) {
const input = document.getElementById('required-field');
if (!input.value) {
e.preventDefault();
console.log('Hiba: Kötelező mező üres'); // Felhasználó nem látja!
}
});
</script>
</form>
<!-- HIBÁS: Alert popup-ok -->
<form>
<label for="email-bad">E-mail:</label>
<input id="email-bad" type="email" required>
<button type="submit">Küldés</button>
<script>
// HIBA: Alert popup nem akadálymentes és zavaró
document.querySelector('form').addEventListener('submit', function(e) {
const email = document.getElementById('email-bad');
if (!email.value) {
e.preventDefault();
alert('E-mail cím megadása kötelező!'); // Rossz UX
}
});
</script>
</form>
<!-- HIBÁS: Rejtett hibaüzenetek -->
<form>
<label for="password-bad">Jelszó:</label>
<input id="password-bad" type="password" required>
<!-- HIBA: Hibaüzenet létezik, de sosem válik láthatóvá -->
<div id="password-error" style="display: none; visibility: hidden;">
Jelszó szükséges
</div>
<button type="submit">Küldés</button>
</form>
Probléma: A felhasználók nem kapnak visszajelzést a hibákról, így nem tudják, mit javítsanak ki.
Fókusz a küldés gombon marad hiba után
<!-- HIBÁS: Rossz fókusz kezelés -->
<form id="bad-focus-form">
<div>
<label for="name-bad">Név:</label>
<input id="name-bad" type="text" required>
<div id="name-bad-error" style="display: none; color: red;"></div>
</div>
<div>
<label for="email-bad-focus">E-mail:</label>
<input id="email-bad-focus" type="email" required>
<div id="email-bad-focus-error" style="display: none; color: red;"></div>
</div>
<button type="submit" id="submit-bad">Küldés</button>
</form>
<script>
document.getElementById('bad-focus-form').addEventListener('submit', function(e) {
e.preventDefault();
const nameField = document.getElementById('name-bad');
const emailField = document.getElementById('email-bad-focus');
const submitButton = document.getElementById('submit-bad');
let hasErrors = false;
// Hibák ellenőrzése
if (!nameField.value) {
document.getElementById('name-bad-error').textContent = 'Név kötelező';
document.getElementById('name-bad-error').style.display = 'block';
hasErrors = true;
}
if (!emailField.value) {
document.getElementById('email-bad-focus-error').textContent = 'E-mail kötelező';
document.getElementById('email-bad-focus-error').style.display = 'block';
hasErrors = true;
}
if (hasErrors) {
// HIBA: Fókusz a küldés gombon marad
submitButton.focus(); // Rossz! Nem segít a hibák megtalálásában
// HIBA: Nincs scroll a hibákhoz
// A felhasználó nem tudja, hol vannak a hibák
}
});
</script>
<!-- HIBÁS: Nincs hibák összesítő -->
<form id="no-summary-form">
<!-- Sok mező... -->
<div>
<label for="field1">Mező 1:</label>
<input id="field1" type="text" required>
</div>
<div>
<label for="field2">Mező 2:</label>
<input id="field2" type="text" required>
</div>
<div>
<label for="field3">Mező 3:</label>
<input id="field3" type="text" required>
</div>
<div>
<label for="field4">Mező 4:</label>
<input id="field4" type="text" required>
</div>
<div>
<label for="field5">Mező 5:</label>
<input id="field5" type="text" required>
</div>
<button type="submit">Küldés</button>
<!-- HIBA: Nincs hibák összesítő a tetején -->
<!-- Hosszú űrlapnál a felhasználó nem látja az összes hibát -->
</form>
Probléma: A billentyűzetes felhasználók és képernyőolvasó használók nehezen találják meg és javítják ki a hibákat, ha a fókusz nem a hibás mezőre kerül.
Források
- WCAG 2.2 Understanding Document: Error Identification
- WCAG 2.2 Specification: Success Criterion 3.3.1 Error Identification
Röviden a szabványpontról
A WCAG 2.2 Success Criterion 3.2.6 (Consistent Help) megköveteli, hogy ha egy weboldal-sorozaton belül segítség mechanizmus áll rendelkezésre, akkor annak minden oldalon ugyanazon a relatív pozícióban kell megjelennie. Ez vonatkozik a kapcsolatfelvételi adatokra, humán kapcsolattartási lehetőségekre, önkiszolgáló opciókra és teljes automatizált kapcsolatfelvételi mechanizmusokra.
Cél: Biztosítani, hogy a felhasználók könnyen megtalálják a segítséget, amikor szükségük van rá, függetlenül attól, hogy a webhely melyik oldalán tartózkodnak. A konzisztens elhelyezés különösen fontos azoknak a felhasználóknak, akiknek nehézségeik vannak az új információk feldolgozásával vagy a komplex feladatok elvégzésével.
Mire vonatkozik: Minden olyan webhelyre, amely segítség mechanizmusokat biztosít több oldalon keresztül, beleértve a kapcsolatfelvételi információkat, chat funkciókat, telefonszámokat, e-mail címeket vagy önkiszolgáló súgó rendszereket.
Kiket érint
Elsődleges felhasználók: Kognitív fogyatékossággal élő emberek, akiknek nehézségeik vannak az információk megtalálásával és feldolgozásával. Azok a felhasználók, akik memória problémákkal küzdenek vagy nehezen tanulnak meg új dolgokat, különösen profitálnak a konzisztens segítség elhelyezésből.
Másodlagos előnyök: Minden felhasználó számára javítja a felhasználói élményt, különösen stresszes vagy sürgős helyzetekben, amikor gyors segítségre van szükség. Az idősebb felhasználók és a technológiai újdonságokkal kevésbé jártas emberek szintén előnyt húznak a kiszámítható segítség elhelyezésből.
Tesztelés
- Manuális navigációs teszt: Látogass meg több oldalt a webhelyen és ellenőrizd, hogy a segítség mechanizmusok ugyanazon a relatív pozícióban vannak-e (pl. minden oldal jobb felső sarkában)
- Képernyőolvasó teszt: Használj képernyőolvasót a segítség elemek megtalálásához különböző oldalakon, és győződj meg róla, hogy mindig ugyanazon a helyen találhatók
- Mobileszköz teszt: Ellenőrizd, hogy a segítség mechanizmusok mobil nézetben is konzisztens pozícióban vannak minden oldalon
- Felhasználói útvonal teszt: Kövesd végig tipikus felhasználói útvonalakat és dokumentáld, hogy minden oldalon elérhető-e segítség ugyanazon a helyen
- Automatizált ellenőrzés: Használj eszközöket a DOM struktúra elemzésére, hogy megbizonyosodj arról, hogy a segítség elemek konzisztens helyen vannak
Jó gyakorlatok
1. Konzisztens kapcsolatfelvételi információk minden oldalon
<!DOCTYPE html>
<html lang="hu">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Főoldal - Példa Weboldal</title>
</head>
<body>
<header>
<div class="logo">
<img src="logo.png" alt="Példa Weboldal logója">
</div>
<nav role="navigation" aria-label="Főnavigáció">
<ul class="main-nav">
<li><a href="/fooldal">Főoldal</a></li>
<li><a href="/termekek">Termékek</a></li>
<li><a href="/szolgaltatasok">Szolgáltatások</a></li>
</ul>
</nav>
<!-- KONZISZTENS segítség pozíció - header jobb szélén MINDEN oldalon -->
<div class="help-section" role="region" aria-label="Segítség és támogatás">
<div class="help-contact">
<h3 class="visually-hidden">Azonnali segítség</h3>
<!-- Telefonos segítség -->
<a href="tel:+36123456789" class="help-phone" aria-label="Segítség telefonon: +36 1 234 5678">
<svg aria-hidden="true" class="help-icon">
<use href="#phone-icon"></use>
</svg>
<span>+36 1 234 5678</span>
</a>
<!-- Email segítség -->
<a href="mailto:segitseg@peldaweboldal.hu" class="help-email" aria-label="E-mail segítség: segitseg@peldaweboldal.hu">
<svg aria-hidden="true" class="help-icon">
<use href="#email-icon"></use>
</svg>
<span>E-mail segítség</span>
</a>
<!-- Live chat -->
<button type="button" class="help-chat" aria-label="Élő chat megnyitása" onclick="openLiveChat()">
<svg aria-hidden="true" class="help-icon">
<use href="#chat-icon"></use>
</svg>
<span>Élő chat</span>
</button>
<!-- Önkiszolgáló súgó -->
<a href="/sugo" class="help-self-service" aria-label="Önkiszolgáló súgó megnyitása">
<svg aria-hidden="true" class="help-icon">
<use href="#help-icon"></use>
</svg>
<span>Súgó</span>
</a>
</div>
</div>
</header>
<main>
<h1>Üdvözöljük a főoldalon</h1>
<p>Itt a főoldal tartalma...</p>
</main>
<footer>
<!-- Kiegészítő segítség információk a footer-ben is konzisztensen -->
<div class="footer-help" role="contentinfo">
<h3>További segítség</h3>
<ul class="help-links">
<li><a href="/gyik">Gyakori kérdések</a></li>
<li><a href="/felhasznaloi-kezikonyv">Felhasználói kézikönyv</a></li>
<li><a href="/video-oktatoanyagok">Video oktatóanyagok</a></li>
<li><a href="/kapcsolat">Kapcsolatfelvétel</a></li>
</ul>
<div class="business-hours">
<h4>Telefonos segítség nyitvatartása</h4>
<p>Hétfő-Péntek: 8:00-18:00<br>
Szombat: 9:00-15:00<br>
Vasárnap: zárva</p>
</div>
</div>
</footer>
<!-- TERMÉKEK OLDAL - PONTOSAN UGYANAZ a segítség elhelyezés -->
<!DOCTYPE html>
<html lang="hu">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Termékek - Példa Weboldal</title>
</head>
<body>
<header>
<div class="logo">
<img src="logo.png" alt="Példa Weboldal logója">
</div>
<nav role="navigation" aria-label="Főnavigáció">
<ul class="main-nav">
<li><a href="/fooldal">Főoldal</a></li>
<li><a href="/termekek" aria-current="page">Termékek</a></li>
<li><a href="/szolgaltatasok">Szolgáltatások</a></li>
</ul>
</nav>
<!-- PONTOSAN UGYANAZ a segítség pozíció és tartalom -->
<div class="help-section" role="region" aria-label="Segítség és támogatás">
<div class="help-contact">
<h3 class="visually-hidden">Azonnali segítség</h3>
<a href="tel:+36123456789" class="help-phone" aria-label="Segítség telefonon: +36 1 234 5678">
<svg aria-hidden="true" class="help-icon">
<use href="#phone-icon"></use>
</svg>
<span>+36 1 234 5678</span>
</a>
<a href="mailto:segitseg@peldaweboldal.hu" class="help-email" aria-label="E-mail segítség: segitseg@peldaweboldal.hu">
<svg aria-hidden="true" class="help-icon">
<use href="#email-icon"></use>
</svg>
<span>E-mail segítség</span>
</a>
<button type="button" class="help-chat" aria-label="Élő chat megnyitása" onclick="openLiveChat()">
<svg aria-hidden="true" class="help-icon">
<use href="#chat-icon"></use>
</svg>
<span>Élő chat</span>
</button>
<a href="/sugo" class="help-self-service" aria-label="Önkiszolgáló súgó megnyitása">
<svg aria-hidden="true" class="help-icon">
<use href="#help-icon"></use>
</svg>
<span>Súgó</span>
</a>
</div>
</div>
</header>
<main>
<h1>Termékeink</h1>
<p>Itt a termékek oldal tartalma...</p>
</main>
<!-- Footer segítség is ugyanaz -->
<footer>
<div class="footer-help" role="contentinfo">
<h3>További segítség</h3>
<ul class="help-links">
<li><a href="/gyik">Gyakori kérdések</a></li>
<li><a href="/felhasznaloi-kezikonyv">Felhasználói kézikönyv</a></li>
<li><a href="/video-oktatoanyagok">Video oktatóanyagok</a></li>
<li><a href="/kapcsolat">Kapcsolatfelvétel</a></li>
</ul>
<div class="business-hours">
<h4>Telefonos segítség nyitvatartása</h4>
<p>Hétfő-Péntek: 8:00-18:00<br>
Szombat: 9:00-15:00<br>
Vasárnap: zárva</p>
</div>
</div>
</footer>
<!-- SVG ikonok -->
<svg style="display: none;">
<defs>
<symbol id="phone-icon" viewBox="0 0 24 24">
<path d="M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.67A2 2 0 014.11 2h3a2 2 0 012 1.72 12.84 12.84 0 00.7 2.81 2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45 12.84 12.84 0 002.81.7A2 2 0 0122 16.92z"/>
</symbol>
<symbol id="email-icon" viewBox="0 0 24 24">
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>
<polyline points="22,6 12,13 2,6"/>
</symbol>
<symbol id="chat-icon" viewBox="0 0 24 24">
<path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/>
</symbol>
<symbol id="help-icon" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10"/>
<path d="M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3"/>
<point cx="12" cy="17"/>
</symbol>
</defs>
</svg>
<script>
function openLiveChat() {
// Chat megnyitási logika
console.log('Chat ablak megnyitása...');
// Képernyőolvasó értesítése
const announcement = document.createElement('div');
announcement.setAttribute('role', 'status');
announcement.setAttribute('aria-live', 'polite');
announcement.className = 'visually-hidden';
announcement.textContent = 'Chat ablak megnyitva. Várjon egy pillanatot, amíg kapcsolódunk egy támogatási munkatárshoz.';
document.body.appendChild(announcement);
setTimeout(() => {
if (announcement.parentNode) {
document.body.removeChild(announcement);
}
}, 3000);
}
</script>
<style>
header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
background: white;
border-bottom: 1px solid #e9ecef;
}
.logo img {
height: 40px;
}
.main-nav {
list-style: none;
display: flex;
gap: 2rem;
margin: 0;
padding: 0;
}
.main-nav a {
text-decoration: none;
color: #495057;
font-weight: 500;
}
.main-nav a[aria-current="page"] {
color: #007bff;
font-weight: bold;
}
/* SEGÍTSÉG SZEKCIÓ - KONZISZTENS POZICIONÁLÁS */
.help-section {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 8px;
padding: 1rem;
min-width: 250px;
}
.help-contact {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
justify-content: center;
}
.help-phone, .help-email, .help-chat, .help-self-service {
display: flex;
align-items: center;
gap: 0.25rem;
padding: 0.5rem;
text-decoration: none;
color: #495057;
background: white;
border: 1px solid #dee2e6;
border-radius: 4px;
font-size: 0.9em;
transition: all 0.2s ease;
cursor: pointer;
}
.help-phone:hover, .help-email:hover,
.help-chat:hover, .help-self-service:hover,
.help-phone:focus, .help-email:focus,
.help-chat:focus, .help-self-service:focus {
background: #e9ecef;
border-color: #007bff;
color: #007bff;
text-decoration: none;
}
.help-icon {
width: 16px;
height: 16px;
fill: none;
stroke: currentColor;
stroke-width: 2;
}
.footer-help {
background: #f8f9fa;
padding: 2rem;
margin-top: 2rem;
}
.help-links {
list-style: none;
display: flex;
gap: 1rem;
flex-wrap: wrap;
padding: 0;
margin: 1rem 0;
}
.help-links a {
color: #007bff;
text-decoration: none;
}
.help-links a:hover, .help-links a:focus {
text-decoration: underline;
}
.business-hours {
margin-top: 1rem;
padding: 1rem;
background: white;
border-radius: 4px;
border: 1px solid #dee2e6;
}
.business-hours h4 {
margin: 0 0 0.5rem 0;
color: #495057;
}
.business-hours p {
margin: 0;
font-size: 0.9em;
line-height: 1.4;
}
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
/* Mobil reszponzivitás */
@media (max-width: 768px) {
header {
flex-direction: column;
gap: 1rem;
}
.help-section {
width: 100%;
min-width: auto;
}
.help-contact {
justify-content: space-around;
}
.help-phone span, .help-email span,
.help-self-service span {
display: none;
}
.help-links {
flex-direction: column;
gap: 0.5rem;
}
}
</style>
</body>
</html>
Magyarázat: A segítség mechanizmusok minden oldalon pontosan ugyanazon a helyen találhatók: a header jobb szélén és a footer-ben, biztosítva, hogy a felhasználók mindig tudják, hol találnak segítséget.
2. Konzisztens mobil segítség gomb
<!-- MOBIL NÉZET - Lebegő segítség gomb minden oldalon ugyanott -->
<div class="mobile-help-fab" role="region" aria-label="Mobil segítség menü">
<button
type="button"
class="help-fab-button"
aria-expanded="false"
aria-controls="mobile-help-menu"
aria-label="Segítség menü megnyitása"
onclick="toggleMobileHelp()"
>
<svg class="help-fab-icon" aria-hidden="true">
<use href="#help-icon"></use>
</svg>
<span class="help-fab-text">Segítség</span>
</button>
<div
id="mobile-help-menu"
class="help-fab-menu"
role="menu"
aria-hidden="true"
>
<div class="help-menu-header">
<h3>Hogyan segíthetünk?</h3>
<button
type="button"
class="help-menu-close"
aria-label="Segítség menü bezárása"
onclick="toggleMobileHelp()"
>
<svg aria-hidden="true">
<use href="#close-icon"></use>
</svg>
</button>
</div>
<ul class="help-menu-options" role="none">
<li role="none">
<a
href="tel:+36123456789"
class="help-menu-item"
role="menuitem"
aria-label="Telefonhívás: +36 1 234 5678"
>
<svg class="help-item-icon" aria-hidden="true">
<use href="#phone-icon"></use>
</svg>
<div class="help-item-content">
<span class="help-item-title">Hívjon minket</span>
<span class="help-item-desc">+36 1 234 5678</span>
</div>
</a>
</li>
<li role="none">
<button
type="button"
class="help-menu-item"
role="menuitem"
aria-label="Élő chat indítása"
onclick="openMobileLiveChat()"
>
<svg class="help-item-icon" aria-hidden="true">
<use href="#chat-icon"></use>
</svg>
<div class="help-item-content">
<span class="help-item-title">Élő chat</span>
<span class="help-item-desc">Azonnali segítség</span>
</div>
</button>
</li>
<li role="none">
<a
href="mailto:segitseg@peldaweboldal.hu"
class="help-menu-item"
role="menuitem"
aria-label="E-mail írása segítségkéréshez"
>
<svg class="help-item-icon" aria-hidden="true">
<use href="#email-icon"></use>
</svg>
<div class="help-item-content">
<span class="help-item-title">E-mail írása</span>
<span class="help-item-desc">segitseg@peldaweboldal.hu</span>
</div>
</a>
</li>
<li role="none">
<a
href="/sugo"
class="help-menu-item"
role="menuitem"
aria-label="Önkiszolgáló súgó megnyitása"
>
<svg class="help-item-icon" aria-hidden="true">
<use href="#help-icon"></use>
</svg>
<div class="help-item-content">
<span class="help-item-title">Súgó és GYIK</span>
<span class="help-item-desc">Önkiszolgáló megoldások</span>
</div>
</a>
</li>
<li role="none">
<a
href="/callback-keres"
class="help-menu-item"
role="menuitem"
aria-label="Visszahívás kérése"
>
<svg class="help-item-icon" aria-hidden="true">
<use href="#callback-icon"></use>
</svg>
<div class="help-item-content">
<span class="help-item-title">Visszahívás</span>
<span class="help-item-desc">Mi hívjuk Önt</span>
</div>
</a>
</li>
</ul>
<div class="help-menu-footer">
<p class="help-availability">
<strong>Telefonos elérhetőség:</strong><br>
H-P: 8:00-18:00, Szo: 9:00-15:00
</p>
</div>
</div>
</div>
<!-- Háttér overlay a menü mögött -->
<div id="help-menu-overlay" class="help-menu-overlay" onclick="toggleMobileHelp()"></div>
<script>
let helpMenuOpen = false;
function toggleMobileHelp() {
const button = document.querySelector('.help-fab-button');
const menu = document.getElementById('mobile-help-menu');
const overlay = document.getElementById('help-menu-overlay');
helpMenuOpen = !helpMenuOpen;
// Állapot frissítése
button.setAttribute('aria-expanded', helpMenuOpen.toString());
menu.setAttribute('aria-hidden', (!helpMenuOpen).toString());
// CSS osztályok kezelése
if (helpMenuOpen) {
menu.classList.add('help-menu-open');
overlay.classList.add('overlay-visible');
document.body.style.overflow = 'hidden'; // Scroll letiltása
// Első menüelemre fókusz
setTimeout(() => {
const firstMenuItem = menu.querySelector('.help-menu-item');
if (firstMenuItem) firstMenuItem.focus();
}, 100);
} else {
menu.classList.remove('help-menu-open');
overlay.classList.remove('overlay-visible');
document.body.style.overflow = '';
// Fókusz visszaadása a gombra
button.focus();
}
// Képernyőolvasó értesítése
announceToScreenReader(
helpMenuOpen ? 'Segítség menü megnyitva' : 'Segítség menü bezárva'
);
}
function openMobileLiveChat() {
toggleMobileHelp(); // Menü bezárása
console.log('Mobil chat megnyitása...');
announceToScreenReader('Chat ablak megnyitása. Kérjük, várjon.');
// Chat logika itt...
}
function announceToScreenReader(message) {
const announcement = document.createElement('div');
announcement.setAttribute('role', 'status');
announcement.setAttribute('aria-live', 'polite');
announcement.className = 'visually-hidden';
announcement.textContent = message;
document.body.appendChild(announcement);
setTimeout(() => {
if (announcement.parentNode) {
document.body.removeChild(announcement);
}
}, 1000);
}
// Escape billentyű kezelése
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && helpMenuOpen) {
toggleMobileHelp();
}
});
// Mobil gomb megjelenítése/elrejtése képernyő méret alapján
function handleMobileHelpVisibility() {
const helpFab = document.querySelector('.mobile-help-fab');
const desktopHelp = document.querySelector('.help-section');
if (window.innerWidth <= 768) {
helpFab.style.display = 'block';
if (desktopHelp) desktopHelp.style.display = 'none';
} else {
helpFab.style.display = 'none';
if (desktopHelp) desktopHelp.style.display = 'block';
// Ha nyitva volt mobil menü, bezárjuk
if (helpMenuOpen) {
toggleMobileHelp();
}
}
}
// Eseményfigyelők
window.addEventListener('resize', handleMobileHelpVisibility);
document.addEventListener('DOMContentLoaded', handleMobileHelpVisibility);
</script>
<style>
/* MOBIL SEGÍTSÉG LEBEGŐ GOMB */
.mobile-help-fab {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 1000;
display: none; /* Alapértelmezetten rejtett, JS-sel szabályozzuk */
}
.help-fab-button {
width: 60px;
height: 60px;
border-radius: 50%;
background: #007bff;
color: white;
border: none;
box-shadow: 0 4px 12px rgba(0, 123, 255, 0.3);
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.help-fab-button:hover, .help-fab-button:focus {
background: #0056b3;
transform: scale(1.05);
outline: 2px solid #fff;
outline-offset: 2px;
}
.help-fab-icon {
width: 24px;
height: 24px;
fill: none;
stroke: currentColor;
stroke-width: 2;
}
.help-fab-text {
font-size: 0.7em;
font-weight: bold;
margin-top: 2px;
}
/* SEGÍTSÉG MENÜ */
.help-fab-menu {
position: fixed;
bottom: 90px;
right: 20px;
width: 320px;
max-width: calc(100vw - 40px);
background: white;
border-radius: 12px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
transform: translateY(20px) scale(0.9);
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
max-height: 70vh;
overflow-y: auto;
}
.help-fab-menu.help-menu-open {
transform: translateY(0) scale(1);
opacity: 1;
visibility: visible;
}
.help-menu-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
border-bottom: 1px solid #e9ecef;
}
.help-menu-header h3 {
margin: 0;
font-size: 1.1em;
color: #495057;
}
.help-menu-close {
background: none;
border: none;
cursor: pointer;
padding: 0.25rem;
border-radius: 4px;
transition: background-color 0.2s ease;
}
.help-menu-close:hover, .help-menu-close:focus {
background: #f8f9fa;
}
.help-menu-close svg {
width: 20px;
height: 20px;
stroke: currentColor;
stroke-width: 2;
}
.help-menu-options {
list-style: none;
padding: 0;
margin: 0;
}
.help-menu-item {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
text-decoration: none;
color: #495057;
background: none;
border: none;
width: 100%;
text-align: left;
cursor: pointer;
transition: background-color 0.2s ease;
border-bottom: 1px solid #f8f9fa;
}
.help-menu-item:hover, .help-menu-item:focus {
background: #f8f9fa;
text-decoration: none;
outline: 2px solid #007bff;
outline-offset: -2px;
}
.help-item-icon {
width: 24px;
height: 24px;
fill: none;
stroke: #007bff;
stroke-width: 2;
flex-shrink: 0;
}
.help-item-content {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.help-item-title {
font-weight: 600;
color: #495057;
}
.help-item-desc {
font-size: 0.9em;
color: #6c757d;
}
.help-menu-footer {
padding: 1rem;
background: #f8f9fa;
border-top: 1px solid #e9ecef;
border-radius: 0 0 12px 12px;
}
.help-availability {
margin: 0;
font-size: 0.9em;
color: #6c757d;
text-align: center;
}
/* OVERLAY */
.help-menu-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.3);
z-index: 999;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
}
.help-menu-overlay.overlay-visible {
opacity: 1;
visibility: visible;
}
/* Reszponzív módosítások */
@media (max-width: 480px) {
.help-fab-menu {
bottom: 90px;
left: 20px;
right: 20px;
width: auto;
}
}
@media (min-width: 769px) {
.mobile-help-fab {
display: none !important;
}
}
</style>
Magyarázat: Mobil eszközökön a segítség mindig ugyanazon a helyen érhető el egy lebegő gomb formájában, amely konzisztens menüt nyit meg minden oldalon.
3. Kontextusspecifikus segítség konzisztens elhelyezéssel
<!-- ŰRLAP OLDAL - Kontextusspecifikus segítség -->
<form class="contact-form">
<div class="form-section">
<h2>Kapcsolatfelvételi űrlap</h2>
<!-- KONZISZTENS segítség pozíció minden űrlapnál - jobb felső sarokban -->
<div class="form-help-section" role="region" aria-label="Űrlap kitöltési segítség">
<details class="form-help-details">
<summary class="form-help-toggle" aria-expanded="false">
<svg class="help-icon" aria-hidden="true">
<use href="#help-icon"></use>
</svg>
Segítség az űrlap kitöltéséhez
</summary>
<div class="form-help-content">
<h3>Hogyan töltsem ki az űrlapot?</h3>
<ul>
<li>A * jelölt mezők kitöltése kötelező</li>
<li>Az e-mail címet érvényes formátumban adja meg</li>
<li>A telefonszám lehet hazai vagy nemzetközi formátumban</li>
<li>Az üzenet mezőben részletesen írja le kérését</li>
</ul>
<div class="form-help-contact">
<h4>További segítség szükséges?</h4>
<p>Hívja segélyvonalunkat: <a href="tel:+36123456789">+36 1 234 5678</a></p>
<p>Vagy írjon nekünk: <a href="mailto:urlapsegitech@peldaweboldal.hu">urlapsegitech@peldaweboldal.hu</a></p>
</div>
</div>
</details>
</div>
</div>
<div class="form-group">
<label for="contact-name">Teljes név *</label>
<input type="text" id="contact-name" name="name" required aria-describedby="name-help">
<div id="name-help" class="field-help">
Adja meg vezeték- és keresztnevét
</div>
</div>
<div class="form-group">
<label for="contact-email">E-mail cím *</label>
<input type="email" id="contact-email" name="email" required aria-describedby="email-help">
<div id="email-help" class="field-help">
Például: nev@domain.hu
</div>
</div>
<div class="form-group">
<label for="contact-phone">Telefonszám</label>
<input type="tel" id="contact-phone" name="phone" aria-describedby="phone-help">
<div id="phone-help" class="field-help">
Opcionális. Például: +36 1 234 5678 vagy 06 1 234 5678
</div>
</div>
<div class="form-group">
<label for="contact-subject">Tárgy *</label>
<select id="contact-subject" name="subject" required aria-describedby="subject-help">
<option value="">Válasszon témát</option>
<option value="info">Általános információ</option>
<option value="support">Technikai támogatás</option>
<option value="billing">Számlázási kérdés</option>
<option value="other">Egyéb</option>
</select>
<div id="subject-help" class="field-help">
Válassza ki a legmegfelelőbb kategóriát
</div>
</div>
<div class="form-group">
<label for="contact-message">Üzenet *</label>
<textarea id="contact-message" name="message" rows="5" required aria-describedby="message-help"></textarea>
<div id="message-help" class="field-help">
Részletesen írja le kérését vagy problémáját (minimum 10 karakter)
</div>
</div>
<div class="form-group">
<div class="checkbox-group">
<input type="checkbox" id="privacy-consent" name="privacy" required>
<label for="privacy-consent">
Elfogadom az <a href="/adatvedelem" target="_blank">adatvédelmi tájékoztatót</a> *
</label>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn-submit">Üzenet küldése</button>
<button type="reset" class="btn-reset">Űrlap törlése</button>
</div>
</form>
<!-- REGISZTRÁCIÓ OLDAL - UGYANEZ a segítség pozíció -->
<form class="registration-form">
<div class="form-section">
<h2>Új fiók regisztrációja</h2>
<!-- PONTOSAN UGYANAZ a segítség pozíció -->
<div class="form-help-section" role="region" aria-label="Regisztrációs segítség">
<details class="form-help-details">
<summary class="form-help-toggle" aria-expanded="false">
<svg class="help-icon" aria-hidden="true">
<use href="#help-icon"></use>
</svg>
Segítség a regisztrációhoz
</summary>
<div class="form-help-content">
<h3>Regisztrációs útmutató</h3>
<ul>
<li>Válasszon erős jelszót (min. 8 karakter, szám és betű)</li>
<li>A felhasználónév csak betűket és számokat tartalmazhat</li>
<li>Valós e-mail címet adjon meg az aktiváláshoz</li>
<li>A születési dátum a korhatár ellenőrzéshez szükséges</li>
</ul>
<div class="form-help-contact">
<h4>Problémák a regisztrációval?</h4>
<p>Segítség: <a href="tel:+36123456789">+36 1 234 5678</a></p>
<p>E-mail: <a href="mailto:regisztracio@peldaweboldal.hu">regisztracio@peldaweboldal.hu</a></p>
</div>
</div>
</details>
</div>
</div>
<!-- Regisztrációs mezők... -->
<div class="form-group">
<label for="reg-username">Felhasználónév *</label>
<input type="text" id="reg-username" name="username" required aria-describedby="username-help">
<div id="username-help" class="field-help">
3-20 karakter, csak betűk és számok
</div>
</div>
<!-- További mezők... -->
<div class="form-actions">
<button type="submit" class="btn-submit">Fiók létrehozása</button>
<button type="reset" class="btn-reset">Mezők törlése</button>
</div>
</form>
<style>
.form-section {
position: relative;
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.form-section h2 {
margin: 0 0 1rem 0;
color: #495057;
}
/* KONZISZTENS SEGÍTSÉG POZICIONÁLÁS */
.form-help-section {
position: absolute;
top: 1rem;
right: 1rem;
z-index: 10;
}
.form-help-details {
position: relative;
}
.form-help-toggle {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1rem;
background: #007bff;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 0.9em;
font-weight: 500;
transition: all 0.2s ease;
list-style: none;
}
.form-help-toggle:hover, .form-help-toggle:focus {
background: #0056b3;
outline: 2px solid #fff;
outline-offset: 2px;
}
.form-help-toggle::marker {
display: none;
}
.help-icon {
width: 18px;
height: 18px;
fill: none;
stroke: currentColor;
stroke-width: 2;
}
.form-help-content {
position: absolute;
top: 100%;
right: 0;
margin-top: 0.5rem;
width: 320px;
max-width: 90vw;
background: white;
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 1.5rem;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
z-index: 1000;
}
.form-help-content h3 {
margin: 0 0 1rem 0;
font-size: 1.1em;
color: #495057;
}
.form-help-content ul {
margin: 0 0 1rem 0;
padding-left: 1.2rem;
}
.form-help-content li {
margin-bottom: 0.5rem;
color: #6c757d;
line-height: 1.4;
}
.form-help-contact {
border-top: 1px solid #e9ecef;
padding-top: 1rem;
margin-top: 1rem;
}
.form-help-contact h4 {
margin: 0 0 0.5rem 0;
font-size: 1em;
color: #495057;
}
.form-help-contact p {
margin: 0.25rem 0;
font-size: 0.9em;
}
.form-help-contact a {
color: #007bff;
text-decoration: none;
}
.form-help-contact a:hover, .form-help-contact a:focus {
text-decoration: underline;
}
/* Űrlap stílusok */
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
font-weight: 600;
margin-bottom: 0.5rem;
color: #495057;
}
.form-group input, .form-group select, .form-group textarea {
width: 100%;
padding: 0.75rem;
border: 1px solid #ced4da;
border-radius: 4px;
font-size: 1rem;
transition: border-color 0.2s ease;
}
.form-group input:focus, .form-group select:focus, .form-group textarea:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
}
.field-help {
margin-top: 0.5rem;
font-size: 0.9em;
color: #6c757d;
line-height: 1.4;
}
.checkbox-group {
display: flex;
align-items: flex-start;
gap: 0.5rem;
}
.checkbox-group input[type="checkbox"] {
width: auto;
margin-top: 0.25rem;
}
.checkbox-group label {
margin-bottom: 0;
font-weight: normal;
cursor: pointer;
}
.form-actions {
display: flex;
gap: 1rem;
margin-top: 2rem;
}
.btn-submit, .btn-reset {
padding: 0.75rem 1.5rem;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
transition: all 0.2s ease;
}
.btn-submit {
background: #28a745;
color: white;
}
.btn-submit:hover, .btn-submit:focus {
background: #218838;
}
.btn-reset {
background: #6c757d;
color: white;
}
.btn-reset:hover, .btn-reset:focus {
background: #545b62;
}
/* Reszponzív */
@media (max-width: 768px) {
.form-help-section {
position: static;
margin-bottom: 1rem;
}
.form-help-content {
position: static;
width: 100%;
margin-top: 0.5rem;
}
.form-actions {
flex-direction: column;
}
}
</style>
Magyarázat: Minden űrlapnál a segítség konzisztensen a jobb felső sarokban jelenik meg, kontextusspecifikus információkkal és egységes kapcsolatfelvételi opciókkal.
Rossz gyakorlatok
Eltérő segítség pozíciók különböző oldalakon
<!-- FŐOLDAL - Segítség a header-ben -->
<header>
<nav>...</nav>
<div class="help-header">
<a href="/segitseg">Segítség</a>
</div>
</header>
<!-- TERMÉKEK OLDAL - HIBÁS: Segítség a sidebar-ban -->
<aside class="sidebar">
<div class="help-sidebar">
<h3>Segítség</h3>
<a href="/segitseg">Segítség</a>
</div>
</aside>
<!-- KAPCSOLAT OLDAL - HIBÁS: Segítség a footer-ben -->
<footer>
<div class="help-footer">
<a href="/segitseg">Segítség</a>
</div>
</footer>
<!-- ŰRLAP OLDAL - HIBÁS: Segítség a tartalom közepén -->
<main>
<h1>Kapcsolatfelvétel</h1>
<div class="help-middle">
<p>Segítségre van szüksége? <a href="/segitseg">Kattintson ide</a></p>
</div>
<form>...</form>
</main>
Probléma: A felhasználók nem tudják megjegyezni, hol találják a segítséget, mert minden oldalon más helyen van.
Hiányzó segítség mechanizmusok egyes oldalakon
<!-- FŐOLDAL - Van segítség -->
<div class="help-section">
<a href="tel:+36123456789">Hívjon minket</a>
<a href="mailto:help@example.com">E-mail</a>
</div>
<!-- FIZETÉS OLDAL - HIBÁS: Nincs segítség, pedig itt lenne a legfontosabb -->
<form class="payment-form">
<h1>Fizetési adatok</h1>
<!-- Nincs segítség elérhetőség! -->
<input type="text" placeholder="Kártyaszám">
<input type="text" placeholder="Lejárati dátum">
<button>Fizetés</button>
</form>
<!-- HIBA OLDAL - HIBÁS: Nincs segítség -->
<div class="error-page">
<h1>Hiba történt</h1>
<p>Valami rosszul sült el.</p>
<!-- Nincs segítség elérhetőség! -->
<a href="/">Vissza a főoldalra</a>
</div>
Probléma: A kritikus oldalakon (fizetés, hibák) nincs elérhető segítség, pedig ezekben a helyzetekben a leginkább szükséges lenne.
Inkonzisztens segítség tartalom és formátum
<!-- FŐOLDAL - Részletes segítség -->
<div class="help-detailed">
<h3>Segítség és támogatás</h3>
<p>Telefonos segítség: +36 1 234 5678</p>
<p>E-mail: help@example.com</p>
<p>Nyitvatartás: H-P 8-18</p>
</div>
<!-- TERMÉKEK OLDAL - HIBÁS: Minimalista segítség -->
<div class="help-minimal">
<a href="tel:+36123456789">📞</a> <!-- Csak ikon -->
</div>
<!-- SZOLGÁLTATÁSOK OLDAL - HIBÁS: Más formátum -->
<div class="help-different">
<button onclick="openChat()">Chat</button> <!-- Csak chat -->
</div>
<!-- KAPCSOLAT OLDAL - HIBÁS: Redundáns segítség -->
<div class="help-redundant">
<p>Itt már úgyis kapcsolatot vehet fel velünk.</p> <!-- Nem hasznos -->
</div>
Probléma: A különböző formátumú és részletezettségű segítség zavaró és nem biztosít konzisztens felhasználói élményt.
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!