Skip to content

Commit 0acb754

Browse files
authored
Fix nbsphinx color outputs, suppress other notebook output Axe errors (#1905)
1 parent 9371608 commit 0acb754

File tree

2 files changed

+71
-2
lines changed

2 files changed

+71
-2
lines changed

src/pydata_sphinx_theme/assets/styles/extensions/_notebooks.scss

+32
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,38 @@ div.nblast.container {
5252
margin-bottom: 1rem;
5353
}
5454

55+
// Override nbsphinx's colors for notebook cell prompts because they do not have
56+
// sufficient contrast. Colors chosen from accessible-pygments
57+
// a11y-high-contrast-{light,dark} themes.
58+
59+
// Notebook cell input line number. Replace nbsphinx's low contrast blue with
60+
// higher contrast blues.
61+
.nbinput.container .prompt pre {
62+
html[data-theme="light"] & {
63+
// Copied from accessible-pygments [a11y-high-contrast-light](https://github.com/Quansight-Labs/accessible-pygments/tree/main/a11y_pygments/a11y_high_contrast_light)
64+
color: #005b82;
65+
}
66+
67+
html[data-theme="dark"] & {
68+
// Copied from accessible-pygments [a11y-high-contrast-dark](https://github.com/Quansight-Labs/accessible-pygments/tree/main/a11y_pygments/a11y_high_contrast_dark)
69+
color: #00e0e0;
70+
}
71+
}
72+
73+
// Notebook cell output line number. Replace nbsphinx's low contrast red with
74+
// higher contrast red / orange.
75+
.nboutput.container .prompt pre {
76+
html[data-theme="light"] & {
77+
// Copied from accessible-pygments [a11y-high-contrast-light](https://github.com/Quansight-Labs/accessible-pygments/tree/main/a11y_pygments/a11y_high_contrast_light)
78+
color: #a12236;
79+
}
80+
81+
html[data-theme="dark"] & {
82+
// Copied from accessible-pygments [a11y-high-contrast-dark](https://github.com/Quansight-Labs/accessible-pygments/tree/main/a11y_pygments/a11y_high_contrast_dark)
83+
color: #ffa07a;
84+
}
85+
}
86+
5587
/*******************************************************************************
5688
* myst NB
5789
*/

tests/test_a11y.py

+39-2
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ def filter_ignored_violations(violations, url_pathname):
3838
]:
3939
filtered = []
4040
for violation in violations:
41-
# TODO: eventually fix this rule violation. See
42-
# https://github.com/pydata/pydata-sphinx-theme/issues/1479.
41+
# TODO: remove this exclusion once the following update to Axe is
42+
# released and we upgrade:
43+
# https://github.com/dequelabs/axe-core/pull/4469
4344
if violation["id"] == "landmark-unique":
4445
# Ignore landmark-unique only for .sidebar targets. Don't ignore
4546
# it for other targets because then the test might fail to catch
@@ -167,6 +168,13 @@ def test_axe_core(
167168
# Wait for CSS transitions (Bootstrap's transitions are 300 ms)
168169
page.wait_for_timeout(301)
169170

171+
# On the PyData Library Styles page, wait for ipywidget to load and for our
172+
# JavaScript to apply tabindex="0" before running Axe checker (to avoid
173+
# false positives for scrollable-region-focusable).
174+
if url_pathname == "/examples/pydata.html":
175+
ipywidgets_pandas_table = page.locator("css=.jp-RenderedHTMLCommon").first
176+
expect(ipywidgets_pandas_table).to_have_attribute("tabindex", "0")
177+
170178
# Inject the Axe-core JavaScript library into the page
171179
page.add_script_tag(path="node_modules/axe-core/axe.min.js")
172180

@@ -176,6 +184,35 @@ def test_axe_core(
176184

177185
# Check found violations against known violations that we do not plan to fix
178186
filtered_violations = filter_ignored_violations(results["violations"], url_pathname)
187+
188+
# We expect notebook outputs on the PyData Library Styles page to have color
189+
# contrast failures.
190+
if url_pathname == "/examples/pydata.html":
191+
# All violations should be color contrast violations
192+
for violation in filtered_violations:
193+
assert (
194+
violation["id"] == "color-contrast"
195+
), f"Found {violation['id']} violation (expected color-contrast): {format_violations([violation])}"
196+
197+
# Now check that when we exclude notebook outputs, the page has no violations
198+
199+
results_sans_nbout = page.evaluate(
200+
f"axe.run({{ include: '{selector}', exclude: '.nboutput > .output_area' }})"
201+
)
202+
violations_sans_nbout = filter_ignored_violations(
203+
results_sans_nbout["violations"], url_pathname
204+
)
205+
206+
# No violations on page when excluding notebook outputs
207+
assert len(violations_sans_nbout) == 0, format_violations(violations_sans_nbout)
208+
209+
# TODO: for color contrast issues with common notebook outputs
210+
# (ipywidget tabbed panels, Xarray, etc.), should we override
211+
# third-party CSS with our own CSS or/and work with NbSphinx, MyST-NB,
212+
# ipywidgets, and other third parties to use higher contrast colors in
213+
# their CSS?
214+
pytest.xfail("notebook outputs have color contrast violations")
215+
179216
assert len(filtered_violations) == 0, format_violations(filtered_violations)
180217

181218

0 commit comments

Comments
 (0)