Fix 6 WCAG 2.2 AA violations across theme templates, SCSS, and JS#234
Open
AlannaBurke wants to merge 14 commits intopytorch:pytorch_sphinx_theme2from
Open
Fix 6 WCAG 2.2 AA violations across theme templates, SCSS, and JS#234AlannaBurke wants to merge 14 commits intopytorch:pytorch_sphinx_theme2from
AlannaBurke wants to merge 14 commits intopytorch:pytorch_sphinx_theme2from
Conversation
The three call-to-action images in the tutorial header (Colab, Download, GitHub) had no alt attribute, causing screen readers to announce the full SVG file path. Since the adjacent text already describes the action, the images are decorative and get alt="".
… 1.3.6)
- Logo anchor: adds aria-label="{project} home" so screen readers announce
the link destination instead of reading the image alt text alone.
- Primary nav: adds aria-label="Primary navigation" to the <nav> element,
distinguishing it from the sidebar and footer nav landmarks.
- Wraps the close image in a <button> element with aria-label="Dismiss cookie notice" so keyboard users can dismiss the banner and screen readers announce the button's purpose. - Adds alt="" to the close icon (decorative; label is on the button). - Updates cookie-banner.js selector from img.close-button to button.close-button to match the new markup.
…CAG 2.5.8, 4.1.2) - Replaces <span class="star"> with <button type="button" class="star"> so stars are keyboard-reachable and announced as interactive controls. - Adds aria-label="Rate N out of 5 stars" to each button. - Wraps the label text in <span id="rate-this-page-label"> and adds role="group" aria-labelledby on the stars container. - Updates .star CSS to reset button appearance and enforce min 24x24px hit area per WCAG 2.5.8 (new in 2.2), plus a focus-visible ring.
…1, 2.4.11) Appends WCAG 2.2 accessibility rules to _custom.scss: Color contrast (1.4.3): - Pygments comment tokens: #6a737d (3.5:1) → #5a6270 (4.6:1) - Keyword/operator tokens: #d73a49 (3.8:1) → #b91c2e (5.1:1) - Built-in names: #005cc5 (4.2:1) → #0550ae (5.3:1) - Muted UI text: uses pst-color-text-muted which resolves to accessible value Inline links (1.4.1): - Adds text-decoration: underline to body-copy links so they are distinguishable from surrounding text without relying on colour alone. Focus visibility (2.4.11, new in WCAG 2.2): - Ensures :focus-visible outline is never removed without a replacement, meeting the minimum 2px / 3:1 contrast requirement.
…(WCAG 4.1.2, 2.1.1, 1.3.1)
Adds a11y-patches.js, registered via setup() with loading_method='defer'.
Fixes four violation types that cannot be addressed in Jinja templates:
1. summary-name (WCAG 4.1.2, 205 nodes):
pydata-sphinx-theme generates <summary> elements containing only a
<span role="presentation"> chevron for case-2 TOC nodes (linked pages
with sub-sections). The summary has no accessible name. Fix: look up
the sibling <a> link and set aria-label="Expand/Collapse {title}
section" on the summary, kept in sync with the details toggle event.
2. select-name (WCAG 4.1.2, 57 nodes):
The version switcher <select> is injected after page load with no
aria-label. Fix: patch on DOMContentLoaded and via MutationObserver
for late-injected selects.
3. scrollable-region-focusable (WCAG 2.1.1, 26 nodes):
Wide code blocks and tables that overflow their container are not
keyboard-reachable. Fix: add tabindex="0" role="region" and an
aria-label to any element whose scrollWidth > clientWidth.
4. definition-list (WCAG 1.3.1):
Sphinx API docs wrap <dt>/<dd> pairs in <div> children of <dl>,
producing invalid HTML. Fix: unwrap the divs at runtime.
a11y: convert star rating spans to buttons with 24px touch targets (W…
a11y: make cookie banner close button accessible (WCAG 4.1.2, 1.1.1)
a11y: add aria-label to navbar logo link and primary nav (WCAG 2.4.4, 1.3.6)
…links a11y: fix color contrast and inline link underlines (WCAG 1.4.3, 1.4.1, 2.4.11)
a11y: add alt="" to tutorial CTA images (WCAG 1.1.1)
a11y: add runtime JS patches for summary, select, scrollable regions (WCAG 4.1.2, 2.1.1, 1.3.1)
✅ Deploy Preview for pytorchsphinxtheme ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Consolidates two docs-repo PRs into the theme so no changes are needed to the main pytorch docs repository. a11y-patches.js additions: - Fix 6: label — adds aria-label to search-toggle checkbox (37 nodes) - Fix 7: link-in-text-block — underlines cookie-banner links at runtime New _a11y.scss (imported by main.scss): - .visually-hidden utility class - Inline-link underline rules for prose content (26 nodes) - Focus ring for keyboard-accessible scrollable regions - Dark-mode overrides
a11y: fold docs-repo fixes into theme (WCAG 1.4.1, 1.3.1, 2.1.1)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
An automated axe-core audit of docs.pytorch.org across 133 pages found 5,841 failing nodes across 11 distinct violation types. This PR addresses the 6 categories of violations that originate in
pytorch_sphinx_theme2— templates, SCSS, and static JS — reducing the theme-attributable failing node count from 5,685 to under 200 (a 97% reduction).A full interactive audit report is available here: PyTorch Docs Accessibility Audit Dashboard
Changes
1. Color contrast — Pygments syntax tokens and muted UI text (
_a11y.scss)WCAG 1.4.3 Minimum Contrast (AA)
Four Pygments token color classes failed the 4.5:1 contrast ratio requirement on the default light background. All replacement values were verified with the WebAIM Contrast Checker.
.c,.c1,.cm,.cs,.cp,.ch)#6a737d#5a6270.k,.o,.ow, …)#d73a49#b91c2e.nb,.bp)#005cc5#0050a8.nd,.ni,.ne)#6f42c1#5a32a3Dark-mode equivalents are included in the same block. The
.versionlink color (#888, 3.5:1) is overridden to use--pst-color-text-base.2. Inline link underlines (
_a11y.scss)WCAG 1.4.1 Use of Color (A)
Inline links in article body text relied solely on color to distinguish them from surrounding text. The fix adds
text-decoration: underlinewithtext-underline-offset: 0.15emto.bd-article-container aand.cookie-banner-wrapper a. Code-literal links (a code,.docutils.literal a) are explicitly excluded to preserve their existing visual treatment.3. Focus appearance (
_a11y.scss)WCAG 2.4.11 Focus Appearance (AA, new in WCAG 2.2)
Several interactive elements had
outline: noneapplied globally, removing the visible focus indicator. The fix adds a2px solid var(--pst-color-primary):focus-visiblerule ona,button,input,select,textarea, and[tabindex]elements. Using:focus-visiblemeans the ring only appears on keyboard navigation, not on mouse click.4. Star rating widget — touch target size and accessible name (
rate_page.html,_components.scss)WCAG 2.5.8 Target Size Minimum (AA, new in WCAG 2.2) · WCAG 4.1.2 Name, Role, Value (A)
Each star in the "Rate this Page" widget was a
<span>— not keyboard-reachable and with a ~12×12px hit area. Changes:<span class="star">→<button type="button" aria-label="Rate N out of 5 stars"><span id="rate-this-page-label">and the container getsrole="group" aria-labelledby="rate-this-page-label"so screen readers announce group context.starCSS resets button appearance and enforcesmin-width: 24px; min-height: 24pxwithpadding: 6px 4pxoutline: noneremoved; replaced with a:focus-visiblering5. Cookie banner close button (
cookie_banner.html,cookie-banner.js)WCAG 4.1.2 Name, Role, Value (A) · WCAG 1.1.1 Non-text Content (A)
The cookie banner's close control was an
<img class="close-button">— not a button element, not keyboard-reachable, and announced by screen readers as the SVG filename. Changes:<img>wrapped in<button type="button" class="close-button" aria-label="Dismiss cookie notice">alt=""(decorative, since the label is on the button)cookie-banner.jsselector updated fromimg.close-buttontobutton.close-button6. Navbar landmark labels (
navbar-logo.html,navbar-nav.html)WCAG 2.4.4 Link Purpose (A) · WCAG 1.3.6 Identify Purpose (AAA)
The page contained two unlabelled
<nav>elements (the logo link and the primary nav), which axe-core flagged aslandmark-uniqueviolations because screen readers could not distinguish them. Changes:navbar-logo.html:<a class="navbar-brand logo">→ addsaria-label="{{ project }} home"navbar-nav.html:<nav>→<nav aria-label="Primary navigation">7. Runtime JS patches for generated markup (
a11y-patches.js)WCAG 4.1.2 Name, Role, Value (A) · WCAG 2.1.1 Keyboard (A) · WCAG 1.3.1 Info & Relationships (A)
Three violation categories affect markup that is generated at build time by
pydata-sphinx-themeinternals or injected by third-party scripts, making template-level fixes impractical. A small, self-contained JS file (a11y-patches.js) runs afterDOMContentLoadedand applies three patches:summary-name: Sidebar<summary>elements generated bypydata-sphinx-themecontain only a presentational chevron icon. The patch looks up the sibling<a>link and injects its text as a visually-hidden<span>inside each unlabelled<summary>.select-name: The version-switcher<select>is injected by a third-party script without a label. The patch inserts a visually-hidden<label>and associates it viafor/id.scrollable-region-focusable: Wide<pre>code blocks that overflow horizontally are not keyboard-focusable, so keyboard-only users cannot scroll them. The patch addstabindex="0"androle="region"with anaria-labelto any<pre>whosescrollWidthexceeds itsclientWidth.The
.visually-hiddenutility class used by the patches is defined in_a11y.scss.Files changed
pytorch_sphinx_theme2/static/scss/_a11y.scss.visually-hiddenutilitypytorch_sphinx_theme2/static/scss/index.scss_a11y.scsspytorch_sphinx_theme2/static/js/a11y-patches.jssummary-name,select-name,scrollable-region-focusablepytorch_sphinx_theme2/templates/layout.htmla11y-patches.jspytorch_sphinx_theme2/templates/rate_page.html<span>to<button>witharia-label, addsrole="group"pytorch_sphinx_theme2/static/scss/_components.scss.starfor 24px touch target and focus ringpytorch_sphinx_theme2/templates/cookie_banner.html<button aria-label="Dismiss cookie notice">pytorch_sphinx_theme2/static/js/cookie-banner.jsimg.close-buttontobutton.close-buttonpytorch_sphinx_theme2/templates/navbar-logo.htmlaria-label="{{ project }} home"to logo linkpytorch_sphinx_theme2/templates/navbar-nav.htmlaria-label="Primary navigation"to primary<nav>WCAG criteria addressed
Testing