a11y: comprehensive WCAG 2.1 Level AA accessibility audit

- Add skip-to-main-content link and main content ID target
- Add prefers-reduced-motion media queries for all animations
- Enhance visible focus indicators (2px offset, high-contrast ring)
- Replace ~160 text-surface-500 instances with text-surface-600/dark:text-surface-400
  for 4.5:1+ contrast ratio compliance
- Add aria-hidden="true" to ~30+ decorative SVG icons across sidebars/widgets
- Convert facepile containers from div to semantic ul/li with role="list"
- Add aria-label to icon-only buttons (share, sort controls)
- Add sr-only labels to form inputs (webmention, search)
- Add aria-live="polite" to dynamically loaded webmentions
- Add aria-label with relative+absolute date to time-difference component
- Add keyboard handlers (Enter/Space) to custom interactive elements
- Add aria-label to nav landmarks (table of contents)
- Fix modal focus trap and dialog accessibility
- Fix lightbox keyboard navigation and screen reader announcements

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
This commit is contained in:
Ricardo
2026-03-07 18:58:08 +01:00
parent db75bd05ea
commit e236b4bf65
77 changed files with 638 additions and 505 deletions

View File

@@ -197,22 +197,26 @@
items.forEach((item) => {
const author = item.author || {};
const li = document.createElement('li');
li.className = 'inline';
const link = document.createElement('a');
link.href = author.url || '#';
link.className = 'facepile-avatar';
link.title = author.name || 'Anonymous';
link.setAttribute('aria-label', (author.name || 'Anonymous') + ' (opens in new tab)');
link.target = '_blank';
link.rel = 'noopener';
link.dataset.new = 'true';
const img = document.createElement('img');
img.src = author.photo || '/images/default-avatar.svg';
img.alt = author.name || 'Anonymous';
img.alt = '';
img.className = 'w-8 h-8 rounded-full ring-2 ring-white dark:ring-surface-900';
img.loading = 'lazy';
link.appendChild(img);
row.appendChild(link);
li.appendChild(link);
row.appendChild(li);
});
}
@@ -278,7 +282,7 @@
const dateLink = document.createElement('a');
dateLink.href = item.url || '#';
dateLink.className = 'text-xs text-surface-500 hover:underline';
dateLink.className = 'text-xs text-surface-600 dark:text-surface-400 hover:underline';
dateLink.target = '_blank';
dateLink.rel = 'noopener';
@@ -396,8 +400,9 @@
header.className = 'text-sm font-semibold text-surface-600 dark:text-surface-400 uppercase tracking-wide mb-3';
header.textContent = `0 ${type === 'likes' ? 'Likes' : 'Reposts'}`;
const row = document.createElement('div');
const row = document.createElement('ul');
row.className = 'facepile';
row.setAttribute('role', 'list');
section.appendChild(header);
section.appendChild(row);
@@ -446,6 +451,8 @@
const section = document.createElement('section');
section.className = 'webmentions mt-8 pt-8 border-t border-surface-200 dark:border-surface-700';
section.id = 'webmentions';
section.setAttribute('aria-live', 'polite');
section.setAttribute('aria-label', 'Webmentions');
const header = document.createElement('h2');
header.className = 'text-xl font-bold text-surface-900 dark:text-surface-100 mb-6';