Skip to main content

sprezzature-accessibility

License Python

🇫🇷 LISEZMOI.md · 🇬🇧 README.md

logo

A web page is accessible when someone using a screen reader, a keyboard alone (no mouse), or a browser's reduced-motion setting can still use it. This tool checks HTML source code for the mistakes that most often break that: an <img> with no alt text is as invisible to a screen reader as if the image were simply missing from the page.

It is a static linter: twenty rules from WCAG (Web Content Accessibility Guidelines, the W3C standard that defines what "accessible" means for the web) and WAI-ARIA (the attribute vocabulary, role, aria-label and the like, that lets custom widgets describe themselves to assistive software), each one decidable by reading the HTML text alone. No browser opens, no page renders, no JavaScript runs, so there is no DOM (the tree of elements a browser builds while rendering a page) to inspect and nothing to install beyond Python itself. That is what makes it fast enough for a pre-commit hook or a CI step: a deterministic gate before any change lands in production.

The violations it covers account for the bulk of real-world accessibility failures: missing alt text, unlabelled inputs, empty buttons, clickable <div>s a keyboard cannot reach, dialogs with no way to close them by keyboard, missing lang attributes (which break screen-reader pronunciation), heading levels that jump around instead of nesting in order, status shown by color alone (a red/green pair that a colorblind reader cannot tell apart), and animations with no way to turn them down for someone sensitive to motion, and negative letter-spacing on running text (which slows reading for dyslexic readers). Six of those twenty rules also ship a mechanical auto-fix (--fix), so the gate can repair what it safely can instead of only reporting it.

This tool only ever reads source code, so it cannot catch what only shows up once a page actually renders in a browser: keyboard focus order, screen-reader announcement timing, color contrast against a real background. Pair it with axe-core, Pa11y, or Lighthouse, which drive a real browser, for that layer. The two are complementary, not interchangeable: this one is the fast, no-browser first gate; those are the slower, browser-accurate second pass.

Features

  • 20 rules covering img, a, button, div/span, input, dialog, html, tabindex, aria, heading order, color-only state, motion-reduce guards, body-text letter-spacing, and time-based media: video captions, audio transcripts, unmuted autoplay, keyboard controls, and caption-track language
  • Auto-fix for 6 rules: lang detection + insertion, redundant aria removal, tabindex demotion, aria-hidden strip, motion-reduce guard append, tight-tracking strip
  • text_spacing_preset.py: the make-side counterpart to the letter-spacing rule — emits an opt-in "comfortable reading" CSS block at the WCAG 1.4.12 Text Spacing minimums, for pages that want to ship the fix as a reader-facing toggle
  • Text and JSON output formats, composable with jq or any CI parser
  • Exit code 1 on any finding (exit 0 on clean), suitable as a pre-commit gate
  • Stdlib only at runtime: Python 3.10+, no pip install required for the core
  • Optional langdetect for the html-missing-lang auto-fixer (language detection)

Quick start

# Lint a single page
python scripts/lint_a11y.py public/index.html

# Lint a directory recursively, exit 1 on any finding
python scripts/lint_a11y.py public/

# JSON output for CI pipeline consumption
python scripts/lint_a11y.py --format json public/index.html

# Suppress two rules
python scripts/lint_a11y.py --ignore heading-skip,motion-no-reduce-guard public/

# Auto-fix what can be fixed mechanically
python scripts/lint_a11y.py --fix public/

# Preview what --fix would change, without writing
python scripts/lint_a11y.py --fix --dry-run public/

Install

pip install sprezzature-accessibility
# With language detection for the html-missing-lang fixer:
pip install "sprezzature-accessibility[lang]"

Or run directly without install:

python scripts/lint_a11y.py public/

Rules

Rule Severity Description
img-missing-alt error <img> without alt attribute
img-redundant-aria warning alt="" with redundant role/aria-hidden
a-missing-href error <a> without href (use <button>)
a-empty error <a> with no accessible name
button-empty error <button> with no accessible name
div-onclick error onclick div/span without role+tabindex
input-missing-label error <input> without associated label
dialog-missing-close error <dialog> without close affordance
html-missing-lang error <html> without lang attribute
tabindex-positive error tabindex >= 1 breaks DOM order
aria-hidden-interactive error aria-hidden on interactive element
heading-skip error headings skip levels downward
color-only-state warning red/green token with no icon or text
motion-no-reduce-guard warning animation without motion-reduce peer
video-missing-captions error <video> with audio and no <track kind="captions"> (WCAG 1.2.2)
audio-missing-transcript error <audio> with no text alternative (WCAG 1.2.1)
track-missing-srclang warning <track> without srclang: caption language unknown
media-missing-controls error <video>/<audio> with nothing to operate from the keyboard (WCAG 2.1.1)
media-autoplay-sound error unmuted autoplay masks a screen reader (WCAG 1.4.2)

License

BSD-3-Clause. Copyright 2026 Warith HARCHAOUI.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sprezzature_accessibility-1.0.2.tar.gz (42.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sprezzature_accessibility-1.0.2-py3-none-any.whl (35.4 kB view details)

Uploaded Python 3

File details

Details for the file sprezzature_accessibility-1.0.2.tar.gz.

File metadata

File hashes

Hashes for sprezzature_accessibility-1.0.2.tar.gz
Algorithm Hash digest
SHA256 5d2e0023c442c3009b301eb56671fd5e625e3f3040209c712da72cec40f0fda6
MD5 8fd23fb59ec511e6e1dc648407569dc2
BLAKE2b-256 158b14e60a1914c9844d4937aad61ef81baf786572c166e485efb954f96ad483

See more details on using hashes here.

File details

Details for the file sprezzature_accessibility-1.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for sprezzature_accessibility-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 a0273500949e83ebf3c603fe8b19e583450a23de96982d1437967b193531d972
MD5 e484c2cbba113c5d446d23810873098a
BLAKE2b-256 9c8bff4713baa13e0f1707cef3f9aab0905f88fc93b2201cbbf4384a17631618

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.0.2 This release

2 files

1.0.1

2 files

1.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page