Skip to content

Commit 61fad27

Browse files
sorin-davidoiMichael-F-Bryan
authored andcommitted
Improve accessibility (#535)
* fix(theme/index): Use nav element for Table of Content * fix(renderer/html_handlebars/helpers/toc): Use ol instead of ul Chapters and sections are ordered, so we should use the appropriate HTML tag. * fix(renderer/html_handlebars/helpers/toc): Hide section number from screen readers Screen readers have this functionality build-in, no need to present this. Ideally, this should not even be in the DOM tree, since the numbers can be shown by using CSS. * fix(theme/index): Remove tabIndex="-1" from .page Divs are not focusable by default * fix(theme): Make sidebar accessible Using aria-hidden (together with tabIndex) takes the links out of the tab order. http://heydonworks.com/practical_aria_examples/#progressive-collapsibles * fix(theme/index): Wrap content inside main tag The main tag helps users skip additional content on the page. * fix(theme/book): Don't focus .page on page load The main content is identified by the main tag, not by auto-focusing it on page load. * fix(theme/index): Make page controls accessible * fix: Make theme selector accessible - Use ul and li (since it is a list) - Add aria-expanded and aria-haspopup to the toggle button - Use button instead of div (buttons are accessible by default) - Handle Esc key (close popup) - Adjust CSS to keep same visual style * fix(theme/stylus/sidebar): Make link clickable area wider Links now expand to fill the entire row. * fix(theme): Wrap header buttons and improve animation performance Previously, the header had a fixed height, which meant that sometimes the print button was not visible. Animating the left property is expensive, which lead to laggy animations - transform is much cheaper and has the same effect. * fix(theme/stylus/theme-popup): Theme button inherits color Bug introduced while making the popup accessible * fix(theme/book): Handle edge case when toggling sidebar Bug introduced when switching from animating left to using transform.
1 parent 9ab5441 commit 61fad27

File tree

10 files changed

+162
-88
lines changed

10 files changed

+162
-88
lines changed

src/renderer/html_handlebars/helpers/toc.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl HelperDef for RenderToc {
2525
.ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
2626
.replace("\"", "");
2727

28-
rc.writer.write_all(b"<ul class=\"chapter\">")?;
28+
rc.writer.write_all(b"<ol class=\"chapter\">")?;
2929

3030
let mut current_level = 1;
3131

@@ -45,13 +45,13 @@ impl HelperDef for RenderToc {
4545
if level > current_level {
4646
while level > current_level {
4747
rc.writer.write_all(b"<li>")?;
48-
rc.writer.write_all(b"<ul class=\"section\">")?;
48+
rc.writer.write_all(b"<ol class=\"section\">")?;
4949
current_level += 1;
5050
}
5151
rc.writer.write_all(b"<li>")?;
5252
} else if level < current_level {
5353
while level < current_level {
54-
rc.writer.write_all(b"</ul>")?;
54+
rc.writer.write_all(b"</ol>")?;
5555
rc.writer.write_all(b"</li>")?;
5656
current_level -= 1;
5757
}
@@ -96,7 +96,7 @@ impl HelperDef for RenderToc {
9696
if !self.no_section_label {
9797
// Section does not necessarily exist
9898
if let Some(section) = item.get("section") {
99-
rc.writer.write_all(b"<strong>")?;
99+
rc.writer.write_all(b"<strong aria-hidden=\"true\">")?;
100100
rc.writer.write_all(section.as_bytes())?;
101101
rc.writer.write_all(b"</strong> ")?;
102102
}
@@ -129,12 +129,12 @@ impl HelperDef for RenderToc {
129129
rc.writer.write_all(b"</li>")?;
130130
}
131131
while current_level > 1 {
132-
rc.writer.write_all(b"</ul>")?;
132+
rc.writer.write_all(b"</ol>")?;
133133
rc.writer.write_all(b"</li>")?;
134134
current_level -= 1;
135135
}
136136

137-
rc.writer.write_all(b"</ul>")?;
137+
rc.writer.write_all(b"</ol>")?;
138138
Ok(())
139139
}
140140
}

src/theme/book.css

Lines changed: 63 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -61,24 +61,29 @@ table thead td {
6161
-moz-box-sizing: border-box;
6262
box-sizing: border-box;
6363
-webkit-overflow-scrolling: touch;
64-
-webkit-transition: left 0.5s;
65-
-moz-transition: left 0.5s;
66-
-o-transition: left 0.5s;
67-
-ms-transition: left 0.5s;
68-
transition: left 0.5s;
64+
-webkit-transition: -webkit-transform 0.5s;
65+
-moz-transition: -moz-transform 0.5s;
66+
-o-transition: -o-transform 0.5s;
67+
-ms-transition: -ms-transform 0.5s;
68+
transition: transform 0.5s;
6969
}
7070
.sidebar code {
7171
line-height: 2em;
7272
}
7373
.sidebar-hidden .sidebar {
74-
left: -300px;
74+
-webkit-transform: translateX(-300px);
75+
-moz-transform: translateX(-300px);
76+
-o-transform: translateX(-300px);
77+
-ms-transform: translateX(-300px);
78+
transform: translateX(-300px);
7579
}
7680
.chapter {
7781
list-style: none outside none;
7882
padding-left: 0;
7983
line-height: 2.2em;
8084
}
8185
.chapter li a {
86+
display: block;
8287
padding: 5px 0;
8388
text-decoration: none;
8489
}
@@ -105,8 +110,6 @@ table thead td {
105110
-webkit-box-sizing: border-box;
106111
-moz-box-sizing: border-box;
107112
box-sizing: border-box;
108-
min-height: 100%;
109-
width: 100%;
110113
-webkit-transition: padding-left 0.5s, margin-left 0.5s;
111114
-moz-transition: padding-left 0.5s, margin-left 0.5s;
112115
-o-transition: padding-left 0.5s, margin-left 0.5s;
@@ -143,7 +146,18 @@ table thead td {
143146
}
144147
.menu-bar {
145148
position: relative;
146-
height: 50px;
149+
display: -webkit-box;
150+
display: -moz-box;
151+
display: -webkit-flex;
152+
display: -ms-flexbox;
153+
display: box;
154+
display: flex;
155+
-webkit-box-lines: multiple;
156+
-moz-box-lines: multiple;
157+
-o-box-lines: multiple;
158+
-webkit-flex-wrap: wrap;
159+
-ms-flex-wrap: wrap;
160+
flex-wrap: wrap;
147161
}
148162
.menu-bar i,
149163
.menu-bar .icon-button {
@@ -161,24 +175,24 @@ table thead td {
161175
.menu-bar .icon-button:hover {
162176
cursor: pointer;
163177
}
164-
.menu-bar .left-buttons {
165-
float: left;
166-
}
167-
.menu-bar .right-buttons {
168-
float: right;
169-
}
170178
.menu-title {
171179
display: inline-block;
172180
font-weight: 200;
173181
font-size: 20px;
174182
line-height: 50px;
175-
position: absolute;
176-
top: 0;
177-
left: 0;
178-
right: 0;
179-
bottom: 0;
180183
text-align: center;
181184
margin: 0;
185+
-webkit-box-flex: 1;
186+
-moz-box-flex: 1;
187+
-o-box-flex: 1;
188+
box-flex: 1;
189+
-webkit-flex: 1;
190+
-ms-flex: 1;
191+
flex: 1;
192+
white-space: nowrap;
193+
overflow: hidden;
194+
-o-text-overflow: ellipsis;
195+
text-overflow: ellipsis;
182196
opacity: 0;
183197
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
184198
filter: alpha(opacity=0);
@@ -252,15 +266,15 @@ table thead td {
252266
right: 15px;
253267
}
254268
@media only screen and (max-width: 1080px) {
255-
.nav-chapters {
269+
.nav-wide-wrapper {
256270
display: none;
257271
}
258272
.nav-wrapper {
259273
display: block;
260274
}
261275
}
262276
@media only screen and (max-width: 1380px) {
263-
.sidebar-visible .nav-chapters {
277+
.sidebar-visible .nav-wide-wrapper {
264278
display: none;
265279
}
266280
.sidebar-visible .nav-wrapper {
@@ -275,11 +289,18 @@ table thead td {
275289
font-size: 0.7em;
276290
}
277291
.theme-popup .theme {
292+
display: inline;
293+
border: 0;
278294
margin: 0;
279295
padding: 2px 10px;
280296
line-height: 25px;
297+
width: 100%;
281298
white-space: nowrap;
299+
text-align: left;
282300
cursor: pointer;
301+
color: inherit;
302+
background: inherit;
303+
font-size: inherit;
283304
}
284305
.theme-popup .theme:hover:first-child,
285306
.theme-popup .theme:hover:last-child {
@@ -349,6 +370,10 @@ table thead td {
349370
color: #333;
350371
background: #fafafa;
351372
border: 1px solid #ccc;
373+
margin: 0;
374+
padding: 0;
375+
list-style: none;
376+
display: none;
352377
}
353378
.light .theme-popup .theme:hover {
354379
background-color: #e6e6e6;
@@ -481,6 +506,10 @@ table thead td {
481506
color: #98a3ad;
482507
background: #141617;
483508
border: 1px solid #43484d;
509+
margin: 0;
510+
padding: 0;
511+
list-style: none;
512+
display: none;
484513
}
485514
.coal .theme-popup .theme:hover {
486515
background-color: #1f2124;
@@ -613,6 +642,10 @@ table thead td {
613642
color: #bcbdd0;
614643
background: #161923;
615644
border: 1px solid #737480;
645+
margin: 0;
646+
padding: 0;
647+
list-style: none;
648+
display: none;
616649
}
617650
.navy .theme-popup .theme:hover {
618651
background-color: #282e40;
@@ -745,6 +778,10 @@ table thead td {
745778
color: #262625;
746779
background: #e1e1db;
747780
border: 1px solid #b38f6b;
781+
margin: 0;
782+
padding: 0;
783+
list-style: none;
784+
display: none;
748785
}
749786
.rust .theme-popup .theme:hover {
750787
background-color: #99908a;
@@ -877,6 +914,10 @@ table thead td {
877914
color: #c5c5c5;
878915
background: #14191f;
879916
border: 1px solid #5c6773;
917+
margin: 0;
918+
padding: 0;
919+
list-style: none;
920+
display: none;
880921
}
881922
.ayu .theme-popup .theme:hover {
882923
background-color: #191f26;

src/theme/book.js

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ $( document ).ready(function() {
3838

3939
var KEY_CODES = {
4040
PREVIOUS_KEY: 37,
41-
NEXT_KEY: 39
41+
NEXT_KEY: 39,
42+
ESCAPE_KEY: 27,
4243
};
4344

4445
$(document).on('keydown', function (e) {
@@ -56,15 +57,16 @@ $( document ).ready(function() {
5657
window.location.href = $('.nav-chapters.previous').attr('href');
5758
}
5859
break;
60+
case KEY_CODES.ESCAPE_KEY:
61+
e.preventDefault();
62+
hideThemes();
63+
break;
5964
}
6065
});
6166

6267
// Interesting DOM Elements
6368
var sidebar = $("#sidebar");
6469

65-
// Help keyboard navigation by always focusing on page content
66-
$(".page").focus();
67-
6870
// Toggle sidebar
6971
$("#sidebar-toggle").click(sidebarToggle);
7072

@@ -101,36 +103,37 @@ $( document ).ready(function() {
101103
}
102104
});
103105

106+
function showThemes() {
107+
$('.theme-popup').css('display', 'block');
108+
$('#theme-toggle').attr('aria-expanded', true);
109+
}
110+
111+
function hideThemes() {
112+
$('.theme-popup').css('display', 'none');
113+
$('#theme-toggle').attr('aria-expanded', false);
114+
}
104115

105116
// Theme button
106117
$("#theme-toggle").click(function(){
107-
if($('.theme-popup').length) {
108-
$('.theme-popup').remove();
118+
if ($('.theme-popup').css('display') === 'block') {
119+
hideThemes();
109120
} else {
110-
var popup = $('<div class="theme-popup"></div>')
111-
.append($('<div class="theme" id="light">Light <span class="default">(default)</span><div>'))
112-
.append($('<div class="theme" id="rust">Rust</div>'))
113-
.append($('<div class="theme" id="coal">Coal</div>'))
114-
.append($('<div class="theme" id="navy">Navy</div>'))
115-
.append($('<div class="theme" id="ayu">Ayu</div>'));
116-
117-
118-
popup.insertAfter(this);
119-
120-
$('.theme').click(function(){
121-
var theme = $(this).attr('id');
122-
set_theme(theme);
123-
});
121+
showThemes();
124122
}
125123
});
126124

125+
$('.theme').click(function(){
126+
var theme = $(this).attr('id');
127+
set_theme(theme);
128+
});
129+
127130
// Hide theme selector popup when clicking outside of it
128131
$(document).click(function(event){
129132
var popup = $('.theme-popup');
130-
if(popup.length) {
133+
if(popup.css('display') === 'block') {
131134
var target = $(event.target);
132135
if(!target.closest('.theme').length && !target.closest('#theme-toggle').length) {
133-
popup.remove();
136+
hideThemes();
134137
}
135138
}
136139
});
@@ -375,7 +378,7 @@ function sidebarToggle() {
375378
} else if (html.hasClass("sidebar-visible")) {
376379
hideSidebar();
377380
} else {
378-
if ($("#sidebar").position().left === 0){
381+
if (getComputedStyle($('#sidebar')[0])['transform'] === 'none'){
379382
hideSidebar();
380383
} else {
381384
showSidebar();
@@ -385,11 +388,17 @@ function sidebarToggle() {
385388

386389
function showSidebar() {
387390
$('html').removeClass('sidebar-hidden').addClass('sidebar-visible');
391+
$('#sidebar a').attr('tabIndex', 0);
392+
$('#sidebar-toggle').attr('aria-expanded', true);
393+
$('#sidebar').attr('aria-hidden', false);
388394
store.set('mdbook-sidebar', 'visible');
389395
}
390396

391397
function hideSidebar() {
392398
$('html').removeClass('sidebar-visible').addClass('sidebar-hidden');
399+
$('#sidebar a').attr('tabIndex', -1);
400+
$('#sidebar-toggle').attr('aria-expanded', false);
401+
$('#sidebar').attr('aria-hidden', true);
393402
store.set('mdbook-sidebar', 'hidden');
394403
}
395404

0 commit comments

Comments
 (0)