← back to Interiordesignershowroom
a11y: working skip-to-content link (focus-moving, tabindex=-1) + prefers-reduced-motion support (Cody-hardened)
3f3869c6f209127a3a0acee636680fb6f6b94656 · 2026-08-03 11:04:34 -0700 · Steve Abrams
Files touched
M lib/render.jsM public/css/site.css
Diff
commit 3f3869c6f209127a3a0acee636680fb6f6b94656
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Aug 3 11:04:34 2026 -0700
a11y: working skip-to-content link (focus-moving, tabindex=-1) + prefers-reduced-motion support (Cody-hardened)
---
lib/render.js | 3 ++-
public/css/site.css | 23 +++++++++++++++++++++++
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/lib/render.js b/lib/render.js
index e221944..d9404b0 100644
--- a/lib/render.js
+++ b/lib/render.js
@@ -257,6 +257,7 @@ function layout({ title, description, canonical, jsonld, image, body, activeNav
${(Array.isArray(jsonld) ? jsonld : [jsonld]).filter(Boolean).map((j) => `<script type="application/ld+json">${JSON.stringify(j)}</script>`).join('')}
</head>
<body>
+<a class="skip-link" href="#main-content">Skip to content</a>
${disclosureBar()}
<header class="site-header">
<a class="brand" href="/" aria-label="${esc(SITE.name)} — home">
@@ -266,7 +267,7 @@ ${disclosureBar()}
<nav class="site-nav" aria-label="Main navigation">${nav}</nav>
${roomMenu}
</header>
-<main id="main-content">${body}</main>
+<main id="main-content" tabindex="-1">${body}</main>
<footer class="site-footer">
<nav aria-label="Footer navigation">
<a href="/shop">Shop</a>
diff --git a/public/css/site.css b/public/css/site.css
index b52b118..6ab360f 100644
--- a/public/css/site.css
+++ b/public/css/site.css
@@ -1823,3 +1823,26 @@ body.admin-view .card{outline:2px solid #e6c98a;outline-offset:-2px}
.breadcrumbs a:hover { color: var(--accent); text-decoration: underline; }
.breadcrumbs [aria-current="page"] { color: var(--ink); font-weight: 500; }
.breadcrumbs .crumb-sep { color: var(--line); }
+
+/* ── a11y: skip-to-content link (visible only on keyboard focus) ─────────── */
+.skip-link {
+ position: absolute; left: 8px; top: -60px; z-index: 1000;
+ background: var(--ink); color: #fff; padding: 10px 16px; border-radius: 0 0 8px 8px;
+ text-decoration: none; font-size: .85rem; font-weight: 500;
+ transition: top .15s ease;
+}
+.skip-link:focus-visible, .skip-link:focus { top: 0; outline: 2px solid var(--accent); outline-offset: 2px; }
+/* the skip target is programmatically focused — no full-width ring around all of <main> */
+#main-content:focus { outline: none; }
+
+/* ── a11y: honor prefers-reduced-motion (vestibular safety) ──────────────── */
+/* Users who ask their OS to reduce motion get near-instant transitions and no
+ looping animations (spin, hotspotPulse, pulse-bg, the hamburger morph, etc.). */
+@media (prefers-reduced-motion: reduce) {
+ *, *::before, *::after {
+ animation-duration: .001ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: .001ms !important;
+ scroll-behavior: auto !important;
+ }
+}
← 85a3efa seo+integrity: per-page OG images + saved rooms/guides/catal
·
back to Interiordesignershowroom
·
refine: shared fmtStamp (storefront+admin, NaN/future-safe), 81d733e →