Opened 21 months ago
Last modified 9 days ago
#35874 assigned Bug
The console directive is not accessible for screenreaders.
| Reported by: | Sarah Boyce | Owned by: | Mike Edmunds |
|---|---|---|---|
| Component: | Documentation | Version: | dev |
| Severity: | Normal | Keywords: | accessibility, sphinx, sphinx-theme |
| Cc: | accessibility | Triage Stage: | Accepted |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description (last modified by )
docs._ext.djangodocs.visit_console_html generates the HTML for the console directive in docs and has buttons for Linux/MacOS and Windows
This is not very screen reader friendly.
The main issues are that the labels are not read out properly (it should read out the current title but is reading the content of /).
That these are clickable and what happens when you click them are also not clear.
I think it might be better to turn this into tabs: https://www.w3.org/WAI/ARIA/apg/patterns/tabs/examples/tabs-manual/
Some examples in docs: https://docs.djangoproject.com/en/5.1/intro/contributing/#getting-a-copy-of-django-s-development-version
Example html:
<div class="console-block" id="console-block-0"> <input class="c-tab-unix" id="c-tab-0-unix" type="radio" name="console-0" checked=""> <label for="c-tab-0-unix" title="Linux/macOS">/</label> <input class="c-tab-win" id="c-tab-0-win" type="radio" name="console-0"> <label for="c-tab-0-win" title="Windows"></label> <section class="c-content-unix" id="c-content-0-unix" style="display: block;"> <div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>git<span class="w"> </span>clone<span class="w"> </span>https://github.com/YourGitHubName/django.git </pre></div> </div> </section> <section class="c-content-win" id="c-content-0-win" style="display: none;"> <div class="highlight"><pre><span></span><span class="gp">...\></span> git clone https://github.com/YourGitHubName/django.git </pre></div> </section> </div>
Change History (13)
comment:1 by , 21 months ago
| Type: | Uncategorized → Bug |
|---|
comment:2 by , 21 months ago
| Keywords: | accessibility added |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
comment:3 by , 21 months ago
| Owner: | set to |
|---|---|
| Status: | new → assigned |
comment:4 by , 15 months ago
| Owner: | changed from to |
|---|
comment:5 by , 7 weeks ago
| Description: | modified (diff) |
|---|---|
| Owner: | changed from to |
Will make some improvements. Brief game plan:
- make the tabs look much more tab like
- make the generated HTML more screen reader friendly
- change the hover cursor to provide some visual feedback that tabs are clickable
- leave tabs as form inputs to retain css only presentation of the active block
- tidy up the layout of the block to match plain python pre-formatted code (padding on all sides, etc)
R.e. item 4, am going to assume if moving to something more semantic like <button> for the tabs required Javascript (think it might) we'd prefer not to do that.
comment:6 by , 6 weeks ago
| Keywords: | sphinx sphinx-theme added |
|---|
If any CSS changes are needed, note that docs.djangoproject.com uses its own _console-tabs.scss, not the CSS from django/docs/_theme/djangodocs/static. (In #37138 I'm creating an updated "djangoproject" Sphinx theme that shares the scss from djangoproject.)
follow-up: 8 comment:7 by , 2 weeks ago
I'd suggest dropping the icons altogether, and changing to text labels "Unix/macOS" and "Windows".
- Cleanly solves one of the accessibility issues
- Removes need to vendor the FontAwesome 5 Brands font into Django
- The current Linux penguin icon does not universally represent "Unix"
- The current Windows logo icon is outdated (applies to Windows 8-10 only; Windows 11 removed the perspective from the windowpanes)
I've implemented this in the first commit of PR https://github.com/django/django/pull/21585, along with some other fixes and portability improvements to the Sphinx console-tabs extension. Note that this is only a partial solution to the accessibility concerns in this issue.
follow-up: 9 comment:8 by , 2 weeks ago
Replying to Mike Edmunds:
I'd suggest dropping the icons altogether, and changing to text labels "Unix/macOS" and "Windows".
I'm +1 to this. Two extra notes/questions:
- Would replacing the FA glyph code points break the website? If not, would this allows us to drop FA from the website?
- if we want the icons, I would strongly advice to use the FA icons instead the fonts, see potential diff:
-
docs/_static/console-tabs.css
diff --git a/docs/_static/console-tabs.css b/docs/_static/console-tabs.css index 67fa0fcc502a..d24c0177f1ec 100644
a b 23 23 font-size: 0; /* Hide the directive's Font Awesome glyph placeholders. */ 24 24 } 25 25 26 .console-block > label:before { 27 content: attr(title); /* "Linux/macOS" or "Windows". */ 28 font-size: 0.8rem; 26 /* Tab icons (Font Awesome brand SVGs as background images). */ 27 .console-block > label[for$="-unix"]:before, 28 .console-block > label[for$="-unix"]:after, 29 .console-block > label[for$="-win"]:before { 30 content: ""; 31 display: inline-block; 32 width: 14px; 33 height: 14px; 34 vertical-align: middle; 35 background-position: center; 36 background-size: contain; 37 background-repeat: no-repeat; 38 } 39 40 .console-block > label[for$="-unix"]:before { 41 background-image: url("icons/linux.svg"); 42 } 43 44 .console-block > label[for$="-unix"]:after { 45 margin-left: 5px; 46 background-image: url("icons/apple.svg"); 47 } 48 49 .console-block > label[for$="-win"]:before { 50 background-image: url("icons/windows.svg"); 29 51 } 30 52 31 53 .console-block > input:checked + label { -
new file docs/_static/icons/apple.svg
diff --git a/docs/_static/icons/apple.svg b/docs/_static/icons/apple.svg new file mode 100644 index 000000000000..0481dd6d5768
- + 1 <svg fill="#888" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --><path d="M318.7 268.7c-.2-36.7 16.4-64.4 50-84.8-18.8-26.9-47.2-41.7-84.7-44.6-35.5-2.8-74.3 20.7-88.5 20.7-15 0-49.4-19.7-76.4-19.7C63.3 141.2 4 184.8 4 273.5q0 39.3 14.4 81.2c12.8 36.7 59 126.7 107.2 125.2 25.2-.6 43-17.9 75.8-17.9 31.8 0 48.3 17.9 76.4 17.9 48.6-.7 90.4-82.5 102.6-119.3-65.2-30.7-61.7-90-61.7-91.9zm-56.6-164.2c27.3-32.4 24.8-61.9 24-72.5-24.1 1.4-52 16.4-67.9 34.9-17.5 19.8-27.8 44.3-25.6 71.9 26.1 2 49.9-11.4 69.5-34.3z"/></svg> 2 No newline at end of file -
new file docs/_static/icons/linux.svg
diff --git a/docs/_static/icons/linux.svg b/docs/_static/icons/linux.svg new file mode 100644 index 000000000000..22d278a4754e
- + 1 <svg fill="#888" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --><path d="M220.8 123.3c1 .5 1.8 1.7 3 1.7 1.1 0 2.8-.4 2.9-1.5.2-1.4-1.9-2.3-3.2-2.9-1.7-.7-3.9-1-5.5-.1-.4.2-.8.7-.6 1.1.3 1.3 2.3 1.1 3.4 1.7zm-21.9 1.7c1.2 0 2-1.2 3-1.7 1.1-.6 3.1-.4 3.5-1.6.2-.4-.2-.9-.6-1.1-1.6-.9-3.8-.6-5.5.1-1.3.6-3.4 1.5-3.2 2.9.1 1 1.8 1.5 2.8 1.4zM420 403.8c-3.6-4-5.3-11.6-7.2-19.7-1.8-8.1-3.9-16.8-10.5-22.4-1.3-1.1-2.6-2.1-4-2.9-1.3-.8-2.7-1.5-4.1-2 9.2-27.3 5.6-54.5-3.7-79.1-11.4-30.1-31.3-56.4-46.5-74.4-17.1-21.5-33.7-41.9-33.4-72C311.1 85.4 315.7.1 234.8 0 132.4-.2 158 103.4 156.9 135.2c-1.7 23.4-6.4 41.8-22.5 64.7-18.9 22.5-45.5 58.8-58.1 96.7-6 17.9-8.8 36.1-6.2 53.3-6.5 5.8-11.4 14.7-16.6 20.2-4.2 4.3-10.3 5.9-17 8.3s-14 6-18.5 14.5c-2.1 3.9-2.8 8.1-2.8 12.4 0 3.9.6 7.9 1.2 11.8 1.2 8.1 2.5 15.7.8 20.8-5.2 14.4-5.9 24.4-2.2 31.7 3.8 7.3 11.4 10.5 20.1 12.3 17.3 3.6 40.8 2.7 59.3 12.5 19.8 10.4 39.9 14.1 55.9 10.4 11.6-2.6 21.1-9.6 25.9-20.2 12.5-.1 26.3-5.4 48.3-6.6 14.9-1.2 33.6 5.3 55.1 4.1.6 2.3 1.4 4.6 2.5 6.7v.1c8.3 16.7 23.8 24.3 40.3 23 16.6-1.3 34.1-11 48.3-27.9 13.6-16.4 36-23.2 50.9-32.2 7.4-4.5 13.4-10.1 13.9-18.3.4-8.2-4.4-17.3-15.5-29.7zM223.7 87.3c9.8-22.2 34.2-21.8 44-.4 6.5 14.2 3.6 30.9-4.3 40.4-1.6-.8-5.9-2.6-12.6-4.9 1.1-1.2 3.1-2.7 3.9-4.6 4.8-11.8-.2-27-9.1-27.3-7.3-.5-13.9 10.8-11.8 23-4.1-2-9.4-3.5-13-4.4-1-6.9-.3-14.6 2.9-21.8zM183 75.8c10.1 0 20.8 14.2 19.1 33.5-3.5 1-7.1 2.5-10.2 4.6 1.2-8.9-3.3-20.1-9.6-19.6-8.4.7-9.8 21.2-1.8 28.1 1 .8 1.9-.2-5.9 5.5-15.6-14.6-10.5-52.1 8.4-52.1zm-13.6 60.7c6.2-4.6 13.6-10 14.1-10.5 4.7-4.4 13.5-14.2 27.9-14.2 7.1 0 15.6 2.3 25.9 8.9 6.3 4.1 11.3 4.4 22.6 9.3 8.4 3.5 13.7 9.7 10.5 18.2-2.6 7.1-11 14.4-22.7 18.1-11.1 3.6-19.8 16-38.2 14.9-3.9-.2-7-1-9.6-2.1-8-3.5-12.2-10.4-20-15-8.6-4.8-13.2-10.4-14.7-15.3-1.4-4.9 0-9 4.2-12.3zm3.3 334c-2.7 35.1-43.9 34.4-75.3 18-29.9-15.8-68.6-6.5-76.5-21.9-2.4-4.7-2.4-12.7 2.6-26.4v-.2c2.4-7.6.6-16-.6-23.9-1.2-7.8-1.8-15 .9-20 3.5-6.7 8.5-9.1 14.8-11.3 10.3-3.7 11.8-3.4 19.6-9.9 5.5-5.7 9.5-12.9 14.3-18 5.1-5.5 10-8.1 17.7-6.9 8.1 1.2 15.1 6.8 21.9 16l19.6 35.6c9.5 19.9 43.1 48.4 41 68.9zm-1.4-25.9c-4.1-6.6-9.6-13.6-14.4-19.6 7.1 0 14.2-2.2 16.7-8.9 2.3-6.2 0-14.9-7.4-24.9-13.5-18.2-38.3-32.5-38.3-32.5-13.5-8.4-21.1-18.7-24.6-29.9s-3-23.3-.3-35.2c5.2-22.9 18.6-45.2 27.2-59.2 2.3-1.7.8 3.2-8.7 20.8-8.5 16.1-24.4 53.3-2.6 82.4.6-20.7 5.5-41.8 13.8-61.5 12-27.4 37.3-74.9 39.3-112.7 1.1.8 4.6 3.2 6.2 4.1 4.6 2.7 8.1 6.7 12.6 10.3 12.4 10 28.5 9.2 42.4 1.2 6.2-3.5 11.2-7.5 15.9-9 9.9-3.1 17.8-8.6 22.3-15 7.7 30.4 25.7 74.3 37.2 95.7 6.1 11.4 18.3 35.5 23.6 64.6 3.3-.1 7 .4 10.9 1.4 13.8-35.7-11.7-74.2-23.3-84.9-4.7-4.6-4.9-6.6-2.6-6.5 12.6 11.2 29.2 33.7 35.2 59 2.8 11.6 3.3 23.7.4 35.7 16.4 6.8 35.9 17.9 30.7 34.8-2.2-.1-3.2 0-4.2 0 3.2-10.1-3.9-17.6-22.8-26.1-19.6-8.6-36-8.6-38.3 12.5-12.1 4.2-18.3 14.7-21.4 27.3-2.8 11.2-3.6 24.7-4.4 39.9-.5 7.7-3.6 18-6.8 29-32.1 22.9-76.7 32.9-114.3 7.2zm257.4-11.5c-.9 16.8-41.2 19.9-63.2 46.5-13.2 15.7-29.4 24.4-43.6 25.5s-26.5-4.8-33.7-19.3c-4.7-11.1-2.4-23.1 1.1-36.3 3.7-14.2 9.2-28.8 9.9-40.6.8-15.2 1.7-28.5 4.2-38.7 2.6-10.3 6.6-17.2 13.7-21.1.3-.2.7-.3 1-.5.8 13.2 7.3 26.6 18.8 29.5 12.6 3.3 30.7-7.5 38.4-16.3 9-.3 15.7-.9 22.6 5.1 9.9 8.5 7.1 30.3 17.1 41.6 10.6 11.6 14 19.5 13.7 24.6zM173.3 148.7c2 1.9 4.7 4.5 8 7.1 6.6 5.2 15.8 10.6 27.3 10.6 11.6 0 22.5-5.9 31.8-10.8 4.9-2.6 10.9-7 14.8-10.4s5.9-6.3 3.1-6.6-2.6 2.6-6 5.1c-4.4 3.2-9.7 7.4-13.9 9.8-7.4 4.2-19.5 10.2-29.9 10.2s-18.7-4.8-24.9-9.7c-3.1-2.5-5.7-5-7.7-6.9-1.5-1.4-1.9-4.6-4.3-4.9-1.4-.1-1.8 3.7 1.7 6.5z"/></svg> 2 No newline at end of file -
new file docs/_static/icons/windows.svg
diff --git a/docs/_static/icons/windows.svg b/docs/_static/icons/windows.svg new file mode 100644 index 000000000000..da4cae6152ae
- + 1 <svg fill="#888" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --><path d="M0 93.7l183.6-25.3v177.4H0V93.7zm0 324.6l183.6 25.3V268.4H0v149.9zm203.8 28L448 480V268.4H203.8v177.9zm0-380.6v180.1H448V32L203.8 65.7z"/></svg> 2 No newline at end of file
-
comment:9 by , 2 weeks ago
Replying to Natalia Bidart:
- Would replacing the FA glyph code points break the website? If not, would this allows us to drop FA from the website?
Either option here (text or svg console-tabs labels) would allow us to drop the vendored fa-brands v5.0.4 fonts from the Django docs source. We'd remove the private-area FA glyphs from the rendered html.
djangoproject.com has its own vendored copy of the full FontAwesome v4.2.0 fonts. It uses those for icons throughout the site, including admonition icons on docs.djangoproject.com, so that wouldn't be affected. (djangoproject.com also has its own copy of the console-tabs stylesheet, which would need to be updated to track changes here—and I guess to somehow be simultaneously compatible with both old and new tabs html. 🤔)
[I'm tempted to suggest migrating to a third-party, generalized sphinx tabs package like sphinx-inline-tabs or sphinx-design. That would support, e.g., a third console tab for PowerShell, or breaking apart macOS and Unix if that's ever necessary, or even tabbed Jinja and Django template examples or sync+async examples. But that would be a separate discussion and ticket.]
follow-up: 11 comment:10 by , 2 weeks ago
Mike, thanks for the details! also, shall we assign this issue to you given your two PRs?
comment:11 by , 2 weeks ago
Replying to Natalia Bidart:
Mike, thanks for the details! also, shall we assign this issue to you given your two PRs?
Let's leave this ticket with James for now.
There are a bunch of accessibility issues with the console tabs:
- The FontAwesome glyphs as reported here
- Screen reader behavior in general (e.g., incorrect roles)
- No keyboard navigation support (selecting a tab currently requires a pointer device)
- Choice of tab is not synchronized/persistent (so Windows users have to activate their preferred tabs repeatedly on pages with multiple console examples, or after navigating; solution would require JS)
- The use of
text-align: rightandtext-align: leftprobably causes problems for rtl
My PRs for #37138 only solve the first problem right now, and only because I needed to get rid of the fa-brands fonts while adapting the djangodocs extension to the other Sphinx themes. I'd defer to any progress James has made on tab accessibility in general. (But if the scope of console-tabs changes in the other ticket starts to grow, I'll come back and claim this ticket too.)
Here are a couple of tab implementations that are meant to be accessible and work without JS enabled (though may be progressively enhanced when JS is available). The first one has a DOM structure pretty close to our own, so adapting it might be easier. But I'm not qualified to evaluate the screenreader support (and am mindful of "no ARIA is better than bad ARIA"):
- https://dfkaye.com/posts/2020/08/23/accessible-css-driven-tabs-without-javascript/
- https://css-tricks.com/html-web-components-make-progressive-enhancement-and-css-encapsulation-easier/#example-2-webui-tabs
One other thought: if we're making substantial changes to the DOM and CSS, we might want to change the class names at the same time (e.g., change to .dj-console-tabs). That would help djangoproject.com keep a single CSS file that supports old and new DOM across multiple Django versions.
comment:12 by , 12 days ago
| Owner: | changed from to |
|---|
After more investigation, I think we should handle this ticket in two stages. I'm claiming it to work on the first stage because that's also related to #37138.
There seems to be widespread agreement that fully accessible, screen-reader friendly tabs require JavaScript. We can make our CSS-only, hidden-radio-button tabs work better than they are now with keyboard nav and screen readers, but there's no way to make them truly behave correctly as tabs without using JS. (Attempts to assign ARIA tab roles to radio buttons and surrounding DOM—like the post I referenced in an earlier comment—fall into the "bad ARIA is worse than no ARIA" category. They claim to be tabs, but the behavior is not quite right.)
So my proposal is:
Stage 1: Make the current (CSS-only, hidden radio button) tabs support standard keyboard navigation for radio buttons and announce themselves as radio buttons in screen readers. Use text labels, eliminate the use of FontAwesome brand icons, and drop the vendored fa-brands font. (We might also try to follow the ARIA guidelines around high-contrast compatibility.)
Stage 2: Add JS that progressively enhances the console tabs to follow the ARIA tabs with automatic activation pattern, announce themselves as tabs, and implement all recommended keyboard navigation for tabs. While we're adding JS, also make the console tab selection synchronized within a page and persistent across pages.
I've started work on stage 1, but I'll leave the stage 2 JS for someone else later. That's a bigger project that requires either finding a tab component that's been extensively tested for accessibility¹ or developing our own JS and carefully testing it with a variety of screen readers and browsers. (Note that the WAI-ARIA example code says it shouldn't be used in production because it hasn't had that testing.)
Also, a big caveat on all of this is I'm not a screen reader user, so I can't speak to what regular users would or wouldn't find acceptable. And though I've done some exploration with macOS VoiceOver, Windows Narrator, and NVDA while researching this, I haven't fully tested all browser and screen reader combinations, or tried anything on mobile.
¹ Some possible, accessible tab components: Spectrum Web Components sp-tabs, GitHub tab-container-element, Web Awesome tab-group.
comment:13 by , 9 days ago
| Has patch: | set |
|---|
Here's "stage 1" that tries to improve accessibility on the current, CSS-only, hidden radio-button implementation: https://github.com/django/django/pull/21614 [for review].
And a proof-of-concept "stage 2" that uses JS to replace the CSS-only tabs with an ARIA-compliant tab component: https://github.com/django/django/pull/21615 [AI-generated, not intended for merge].
Due to the owner's inactivity. I will be happy to work on this ticket.