fix(a11y): WCAG 2.1 AA compliance fixes for website

Contrast:
- Increase --text-muted from #64748B to #8494A7 (~5.3:1 on dark bg)
- Darken --docs-text-muted from #94A3B8 to #6B7B8D (~5.3:1 on white)
- Increase sidebar section title opacity from 0.5 to 0.7

Keyboard & focus:
- Add skip navigation link to both pages
- Make screenshot images keyboard-focusable (tabindex, role=button)
- Add visible lightbox close button with focus styles
- Fix search input focus: proper outline instead of outline:none

Structure:
- Fix heading hierarchy: single h1 per page, demote sections to h2/h3
- Replace sidebar h4 headings with p.sidebar-section-title
- Add aria-labels to all nav landmarks (main, sidebar, footer)
- Fix broken footer anchor links (#security-model, #api-endpoints)

Accessibility:
- Add sr-only label for docs search input
- Add aria-label to back-to-top button
- Change nav logo SVG from aria-label to aria-hidden (redundant)
- Add role=dialog and aria-label to lightbox
- Fix docs.html theme-color meta to #FAFBFC (matches light theme)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jason Staack
2026-03-15 20:53:50 -05:00
parent f96d561343
commit def4392c93
3 changed files with 226 additions and 144 deletions

View File

@@ -85,13 +85,15 @@
</head>
<body>
<a href="#main-content" class="skip-link">Skip to main content</a>
<!-- ═══════════════════════════════════════════ -->
<!-- Navigation -->
<!-- ═══════════════════════════════════════════ -->
<nav class="site-nav site-nav--dark">
<nav class="site-nav site-nav--dark" aria-label="Main navigation">
<div class="nav-inner container">
<a href="index.html" class="nav-logo">
<svg class="nav-logo-mark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="32" height="32" aria-label="The Other Dude logo">
<svg class="nav-logo-mark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="32" height="32" aria-hidden="true">
<rect x="2" y="2" width="60" height="60" rx="8" fill="none" stroke="#8B1A1A" stroke-width="2"/>
<rect x="6" y="6" width="52" height="52" rx="5" fill="none" stroke="#F5E6C8" stroke-width="1.5"/>
<rect x="8" y="8" width="48" height="48" rx="4" fill="#8B1A1A" opacity="0.15"/>
@@ -130,7 +132,7 @@
</div>
</div>
<main>
<main id="main-content">
<!-- ═══════════════════════════════════════════ -->
<!-- Hero -->
<!-- ═══════════════════════════════════════════ -->
@@ -410,7 +412,7 @@
</span>
<span class="footer-copy">&copy; 2026 The Other Dude. All rights reserved.</span>
</div>
<nav class="footer-links">
<nav class="footer-links" aria-label="Footer navigation">
<a href="docs.html">Docs</a>
<a href="blog/">Blog</a>
<a href="#what-it-does">Features</a>
@@ -424,7 +426,8 @@
</footer>
<!-- Lightbox -->
<div class="lightbox" id="lightbox">
<div class="lightbox" id="lightbox" role="dialog" aria-label="Image preview">
<button class="lightbox-close" aria-label="Close image preview">&times;</button>
<img src="" alt="The Other Dude dashboard managing multiple MikroTik routers">
<div class="lightbox-caption"></div>
</div>
@@ -436,23 +439,42 @@
var lb = document.getElementById('lightbox');
var lbImg = lb.querySelector('img');
var lbCap = lb.querySelector('.lightbox-caption');
var lbClose = lb.querySelector('.lightbox-close');
function openLightbox(img) {
lbImg.src = img.src;
lbImg.alt = img.alt;
var cap = img.closest('.screenshot-card').querySelector('figcaption');
lbCap.textContent = cap ? cap.textContent : '';
lb.classList.add('active');
lbClose.focus();
}
function closeLightbox() {
lb.classList.remove('active');
}
document.querySelectorAll('.screenshot-card img').forEach(function(img) {
img.addEventListener('click', function() {
lbImg.src = img.src;
lbImg.alt = img.alt;
var cap = img.closest('.screenshot-card').querySelector('figcaption');
lbCap.textContent = cap ? cap.textContent : '';
lb.classList.add('active');
img.setAttribute('tabindex', '0');
img.setAttribute('role', 'button');
img.addEventListener('click', function() { openLightbox(img); });
img.addEventListener('keydown', function(e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
openLightbox(img);
}
});
});
lb.addEventListener('click', function() {
lb.classList.remove('active');
lbClose.addEventListener('click', function(e) {
e.stopPropagation();
closeLightbox();
});
lb.addEventListener('click', closeLightbox);
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') lb.classList.remove('active');
if (e.key === 'Escape') closeLightbox();
});
})();
</script>