🎨 Palette: Add skip-to-content link for keyboard accessibility (#169)
💡 What: Added a "Skip to content" link that is visually hidden by default but appears when focused via keyboard. Pointed it to the main content area using `id="main-content"` and `tabIndex={-1}`. 🎯 Why: Keyboard users and screen readers must otherwise tab through the entire navigation menu on every page load before reaching the actual page content. This is tedious and a poor UX. 📸 Before/After: Before, keyboard focus started on "Home" in the header. After, the first tab press shows the "Skip to content" link at the top left of the screen. ♿ Accessibility: Massively improves WCAG compliance (Bypass Blocks) and keyboard navigation efficiency. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: ralksta <ralksta@users.noreply.github.com>
This commit is contained in:
@@ -10,6 +10,10 @@
|
||||
**Learning:** When building interactive card components that contain multiple pieces of text or badges (like titles and photo counts), screen readers may announce them in a fragmented or confusing way.
|
||||
**Action:** Always apply a comprehensive `aria-label` to the parent link/container that encompasses all meaningful visual data (e.g., titles and item counts). Use `aria-hidden="true"` on redundant text or visual child elements, and set `alt=""` on decorative images to consolidate screen reader announcements into a single, accurate interaction point.
|
||||
|
||||
## 2025-05-07 - Skip-to-Content Navigation
|
||||
**Learning:** Keyboard users and screen readers need a way to bypass repetitive header navigation links. Without a visually hidden skip link that becomes visible on focus, these users must tab through every nav item before reaching the main content on every page load.
|
||||
**Action:** Always include a "Skip to content" link as the first focusable element in the DOM, anchored to the main content container. Ensure the main container has `tabIndex={-1}` so it can programmatically receive focus without interrupting normal tab flow.
|
||||
|
||||
## 2024-06-18 - Dynamic Numeric Counters ARIA
|
||||
**Learning:** When displaying dynamic numeric text changes during navigation (like a lightbox image counter), the visual presentation (e.g., "1 / 5") does not provide sufficient context for screen reader users and might not be announced automatically.
|
||||
**Action:** Wrap the counter container with `aria-live="polite"` and `aria-atomic="true"`. Use `.sr-only` to provide a context-rich screen reader string (e.g., "Photo 1 of 5") and hide the visual short-hand using `aria-hidden="true"`.
|
||||
|
||||
@@ -7,6 +7,27 @@
|
||||
|
||||
@import url('./tokens.css');
|
||||
|
||||
/* ── Skip to content link ─────────────────────────── */
|
||||
.skip-link {
|
||||
position: absolute;
|
||||
top: -40px;
|
||||
left: 0;
|
||||
background: var(--bg-card);
|
||||
color: var(--text-primary);
|
||||
padding: 8px 16px;
|
||||
z-index: 1000;
|
||||
transition: top 0.2s ease;
|
||||
border-bottom-right-radius: var(--radius-sm);
|
||||
font-family: var(--font-sans);
|
||||
font-weight: 500;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.skip-link:focus {
|
||||
top: 0;
|
||||
outline: 2px solid var(--text-primary);
|
||||
}
|
||||
|
||||
/* ── Header / Navigation ──────────────────────────── */
|
||||
.header {
|
||||
position: fixed;
|
||||
|
||||
@@ -90,6 +90,9 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
||||
<link rel="stylesheet" href={fontsUrl} />
|
||||
</head>
|
||||
<body>
|
||||
<a href="#main-content" className="skip-link">
|
||||
Skip to content
|
||||
</a>
|
||||
<header className="header">
|
||||
<nav className="header__nav">
|
||||
<Link href="/" className="header__nav-link">
|
||||
@@ -107,7 +110,9 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
||||
<ThemeToggle />
|
||||
</nav>
|
||||
</header>
|
||||
<main className="main">{children}</main>
|
||||
<main id="main-content" tabIndex={-1} className="main">
|
||||
{children}
|
||||
</main>
|
||||
<Footer />
|
||||
<ScrollToTop />
|
||||
{process.env.NODE_ENV === 'development' && <DevToolbarLoader />}
|
||||
|
||||
Reference in New Issue
Block a user