🔴 Correctness / Robustness
- Hero background URL should be root-relative
div#hero {
/* current: url("images/SciGov_hero_1920.webp") */
background: #fff url("/images/SciGov_hero_1920.webp");
background-size: cover;
}
Reason: relative "images/..." will 404 on nested routes (e.g., /about.html).
- Use GET for search (shareable/bookmarkable results) + semantics
<form id="search_form" action="https://www.science.gov/scigov/search.html" method="GET" role="search">
<label for="fullRecord" class="sr-only">Search</label>
<input type="search" id="fullRecord" name="fullRecord"
placeholder="Search for authoritative federal science information"
required autocomplete="on" inputmode="search" aria-label="Search Science.gov">
<button class="search-btn" type="submit" aria-label="Submit search">
<span class="material-symbols-outlined search" aria-hidden="true">search</span>
</button>
…
</form>
- Replace JS navigation button with a link (or add fallback)
<!-- Better semantics & graceful fallback: -->
<a class="btn learn-more" href="/about.html" role="button">Learn More</a>
(If you keep the <button onclick=…>, add a nested <a href="/about.html"> for non-JS environments.)
🟠 Accessibility (508/WCAG quick wins)
- “Here’s how you know” disclosure should expose state
<input id="how-you-know" type="checkbox" hidden>
<div id="official-site">
…
<label for="how-you-know"
role="button"
aria-controls="official-site-info"
aria-expanded="false">Here's how you know …</label>
</div>
<div id="official-site-info" hidden> … </div>
<script>
const box = document.getElementById('how-you-know');
const label = document.querySelector('label[for="how-you-know"]');
const panel = document.getElementById('official-site-info');
const sync = () => {
label.setAttribute('aria-expanded', String(box.checked));
panel.hidden = !box.checked;
};
box.addEventListener('change', sync);
sync();
</script>
- Don’t rely solely on the checkbox hack for screen readers—sync
aria-expandedandhidden.
- Mobile menu toggle should also expose state
<label for="hamburger" aria-controls="primary-menu" aria-expanded="false">
<span class="material-symbols-outlined menu" aria-hidden="true">menu</span>
<span class="sr-only">Menu</span>
</label>
<input type="checkbox" id="hamburger" hidden>
<ul id="primary-menu" class="menu" hidden>…</ul>
<script>
const ham = document.getElementById('hamburger');
const trigger = document.querySelector('label[for="hamburger"]');
const menu = document.getElementById('primary-menu');
const syncMenu = () => {
trigger.setAttribute('aria-expanded', String(ham.checked));
menu.hidden = !ham.checked;
};
ham.addEventListener('change', syncMenu);
syncMenu();
</script>
- Logos used as links: enrich alt text
- Current alt values are abbreviations only (e.g.,
alt="USDA"). Prefer full names:
<img src="/images/agencies/USDA.webp" alt="U.S. Department of Agriculture (USDA)">
- Decorative icons should be silent
- Add
alt="" aria-hidden="true"to purely decorative images/icons (e.g., caret glyphs) or render as CSS background.
- Back-to-top link: label & keyboard visibility
<a id="backToTop" href="#top" aria-label="Back to top">Top</a>
- When hidden off-screen, also set
aria-hidden="true"so tab order is clean.
- Section headings for banner info
- Inside
#official-site-info, add headings oraria-labelledbyfor the two sections so SR users get structure.
⚡ Performance
- Lazy-load non-critical images
<img src="/images/agencies/USDA.webp" alt="…" loading="lazy" width="100" height="84">
(Also set width/height to reduce CLS.)
- Preconnect for GA
<link rel="preconnect" href="https://www.googletagmanager.com" crossorigin>
<link rel="dns-prefetch" href="https://www.googletagmanager.com">
- Throttle scroll handler
- Inline
onscrollruns every frame; switch toIntersectionObserveror throttle:
<script>
(function(){
const btn = document.getElementById('backToTop');
const onScroll = () => {
const show = window.scrollY > 200;
btn.style.setProperty('right', show ? '0px' : '-100px');
btn.setAttribute('aria-hidden', String(!show));
};
let ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
requestAnimationFrame(() => { onScroll(); ticking = false; });
ticking = true;
}
}, { passive: true });
onScroll();
}());
</script>
- Respect reduced motion
@media (prefers-reduced-motion: reduce) {
#backToTop { transition: none !important; }
* { scroll-behavior: auto; }
}
🔐 Security / Privacy
- External links with
target="_blank"
- Add
rel="noopener noreferrer"to everytarget="_blank"(CENDI and all agency links, Vulnerability Disclosure Program).
<a href="https://www.cendi.gov/" target="_blank" rel="noopener noreferrer">…</a>
- GA4 IP privacy
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-PL8SK8Q34R', { anonymize_ip: true });
</script>
- Content Security Policy (next step)
- If you plan a CSP, move inline scripts to external files or adopt a nonce across all inline
<script>blocks.
🧼 Semantics & UX
- Landmarks
- You already have
<header>,<main>,<footer>. Addrole="navigation"to the nav if you keep multiple navs:
<nav role="navigation" aria-label="Primary">
…
</nav>
- Page title & alignment
<title>Science.gov</title>and<h1>Science.gov</h1>match—good. Keep unique, descriptive titles for secondary pages.
- Hero CTA contrast
- Ensure the “Learn More” button meets contrast with its background; if it’s the browser default, style it to at least a 3:1 contrast for large text or 4.5:1 for normal.
- Fallbacks for WebP
- If you need to support older browsers, wrap hero/logo in
<picture>with a JPEG/PNG fallback:
<picture>
<source srcset="/images/SciGov_hero_1920.webp" type="image/webp">
<img src="/images/SciGov_hero_1920.jpg" alt="" aria-hidden="true">
</picture>
Quick diff summary
- ✅ Root-relative hero image URL
- ✅ Search form
method="GET",role="search", accessible labels - ✅
aria-expanded/hiddensync for banner + mobile menu - ✅ Enrich alt text for agency logos; silence decorative icons
- ✅ Lazy-load images + add
width/height - ✅ Throttled scroll handler / passive listener; back-to-top
aria-hidden - ✅
rel="noopener noreferrer"ontarget="_blank" - ✅ GA
anonymize_ip, preconnect for GTM - ✅ prefers-reduced-motion CSS
If you want, I can roll these into a minimal PR (one JS file for toggles + scroll, one CSS patch, and small HTML tweaks) without changing layout or design.