Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 10f4349

Browse files
committed
Use css for opening/closing menu
- Menu is opened/closed using only css (invisible checkbox), works without js enabled - Accessibility added using javascript
1 parent 203b40a commit 10f4349

File tree

3 files changed

+124
-88
lines changed

3 files changed

+124
-88
lines changed

python_docs_theme/layout.html

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -34,35 +34,33 @@
3434
{%- endif %}
3535
{% endblock %}
3636

37-
{% block extrahead %}
37+
{%- block extrahead -%}
3838
<link rel="shortcut icon" type="image/png" href="{{ pathto('_static/' + theme_root_icon, 1) }}" />
39-
{% if builder != "htmlhelp" %}
40-
{% if not embedded %}
39+
{%- if builder != "htmlhelp" %}
40+
{%- if not embedded %}
4141
<script type="text/javascript" src="{{ pathto('_static/copybutton.js', 1) }}"></script>
4242
<script type="text/javascript" src="{{ pathto('_static/menu.js', 1) }}"></script>
43-
{% endif %}
44-
{% endif %}
43+
{%- endif -%}
44+
{%- endif -%}
4545
{{ super() }}
46-
{% endblock %}
46+
{%- endblock -%}
4747

48-
{%- block css %}
48+
{%- block css -%}
4949
<meta name="viewport" content="width=device-width, initial-scale=1.0">
5050
{{ super() }}
51-
{%- endblock %}
51+
{%- endblock -%}
5252

5353
{%- block body_tag %}
54-
<body>
55-
<nav class="mobile-nav">
56-
<button class="toggler" aria-expanded="false" aria-label="{{ _('Menu') }}" aria-controls="navigation">
57-
<span class="hamburger">
58-
<span></span>
59-
</span>
60-
</button>
61-
<div class="nav-content" role="navigation">
54+
{{ super() }}
55+
<div class="mobile-nav">
56+
<input type="checkbox" id="menuToggler" class="toggler__input"
57+
aria-controls="navigation" aria-pressed="false" aria-expanded="false" />
58+
<label for="menuToggler" class="toggler__label" role="button" aria-label="{{ _('Menu')}}">
59+
<span></span>
60+
</label>
61+
<nav class="nav-content" role="navigation">
6262
<img src="{{ pathto('_static/' + theme_root_icon, 1) }}" alt="Logo"/>
63-
{%- if switchers is defined %}
6463
<div class="version_switcher_placeholder">{{ release }}</div>
65-
{% endif -%}
6664
{%- if pagename != "search" and builder != "singlehtml" %}
6765
<div id="searchbox" role="search">
6866
<form class="search" action="{{ pathto('search') }}" method="get">
@@ -76,28 +74,20 @@
7674
</form>
7775
</div>
7876
{%- endif %}
79-
</div>
80-
</nav>
81-
{% endblock %}
82-
83-
{% block sidebar1 %}
84-
<div class="menu-wrapper">
85-
<nav class="menu" role="navigation" aria-label="main navigation">
86-
{%- if switchers is defined %}
87-
<div class="language_switcher_placeholder">{{ language or 'en' }}</div>
88-
{% endif -%}
89-
{%- block sidebarlogo %}
77+
</nav>
78+
<div class="menu-wrapper">
79+
<nav class="menu" role="navigation" aria-label="main navigation">
80+
<div class="language_switcher_placeholder"></div>
9081
{%- if logo %}
9182
<p class="logo"><a href="{{ pathto(master_doc)|e }}">
9283
<img class="logo" src="{{ pathto('_static/' + logo, 1)|e }}" alt="Logo"/>
9384
</a></p>
9485
{%- endif %}
95-
{%- endblock %}
96-
{#- new style sidebar: explicitly include/exclude templates #}
97-
{%- for sidebartemplate in sidebars %}
98-
{%- include sidebartemplate %}
99-
{%- endfor %}
100-
</nav>
86+
{%- for sidebartemplate in sidebars %}
87+
{%- include sidebartemplate %}
88+
{%- endfor %}
89+
</nav>
90+
</div>
10191
</div>
10292
{% endblock %}
10393

python_docs_theme/static/menu.js

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,54 @@
1-
21
document.addEventListener('DOMContentLoaded', function () {
3-
const toggler = document.querySelector('.toggler');
2+
3+
// Make tables responsive by wrapping them in a div and making them scrollable
4+
const tables = document.querySelectorAll('table.docutils');
5+
tables.forEach(function(table){
6+
table.outerHTML = '<div class="responsive-table__container">' + table.outerHTML + '</div>'
7+
});
8+
9+
const togglerInput = document.querySelector('.toggler__input');
10+
const togglerLabel = document.querySelector('.toggler__label');
411
const sideMenu = document.querySelector('.menu-wrapper');
12+
const menuItems = document.querySelectorAll('.menu')
513
const doc = document.querySelector('.document');
14+
const body = document.querySelector('body');
615

716
function closeMenu() {
8-
sideMenu.classList.remove('open');
9-
toggler.classList.remove('active');
10-
toggler.setAttribute("aria-expanded", 'false');
17+
togglerInput.checked = false;
18+
sideMenu.setAttribute("aria-expanded", 'false');
19+
sideMenu.setAttribute('aria-hidden', 'true');
20+
togglerLabel.setAttribute('aria-pressed', 'false');
21+
body.style.overflow = 'visible';
1122
}
12-
function isMenuOpen(){
13-
return (' ' + sideMenu.className + ' ').indexOf(' open ') > -1;
23+
function openMenu() {
24+
togglerInput.checked = true;
25+
sideMenu.setAttribute("aria-expanded", 'true');
26+
sideMenu.setAttribute('aria-hidden', 'false');
27+
togglerLabel.setAttribute('aria-pressed', 'true');
28+
body.style.overflow = 'hidden';
1429
}
1530

31+
// Close menu when link on the sideMenu is clicked
1632
sideMenu.addEventListener('click', function (event) {
17-
// Close menu only if a link on the sideMenu is clicked
1833
let target = event.target;
19-
if (target.tagName !== 'a') return;
34+
if (target.tagName.toLowerCase() !== 'a') return;
2035
closeMenu();
2136
})
22-
toggler.addEventListener('click', function (e) {
23-
if (!isMenuOpen()) {
24-
sideMenu.classList.add('open');
25-
toggler.classList.add('active');
26-
toggler.setAttribute("aria-expanded", 'true');
37+
// Add accessibility data when sideMenu is opened/closed
38+
togglerInput.addEventListener('change', function (e) {
39+
togglerInput.checked ? openMenu() : closeMenu();
40+
});
41+
// Make sideMenu links tabbable only when visible
42+
for(let menuItem of menuItems) {
43+
if(togglerInput.checked) {
44+
menuItem.setAttribute('tabindex', '0');
2745
} else {
28-
closeMenu();
46+
menuItem.setAttribute('tabindex', '-1');
2947
}
30-
});
48+
}
49+
// Close sideMenu when document body is clicked
3150
doc.addEventListener('click', function () {
32-
if (isMenuOpen()) {
51+
if (togglerInput.checked) {
3352
closeMenu();
3453
}
3554
})

python_docs_theme/static/pydoctheme.css

Lines changed: 63 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@ body {
1414
div.related {
1515
margin-bottom: 1.2em;
1616
padding: 0.5em 0;
17-
border-top: 1px solid #ccc;
17+
border-bottom: 1px solid #ccc;
1818
margin-top: 0.5em;
1919
}
2020

2121
div.related a:hover {
2222
color: #0095C4;
2323
}
2424

25-
div.related:first-of-type {
26-
border-top: 0;
27-
border-bottom: 1px solid #ccc;
25+
div.related ~ div.related {
26+
border-top: 1px solid #ccc;
27+
border-bottom: none;
2828
}
2929

3030
.inline-search {
@@ -197,7 +197,7 @@ dl > dt span ~ em {
197197
font-family: monospace, sans-serif;
198198
}
199199

200-
@media (max-width: 900px) {
200+
@media (max-width: 1023px) {
201201
/* Body layout */
202202
div.body {
203203
min-width: 100%;
@@ -224,30 +224,44 @@ dl > dt span ~ em {
224224
div.related, .sphinxsidebar {
225225
display: none;
226226
}
227+
/* Anchorlinks are not hidden by fixed-positioned navbar when scrolled to */
228+
html {
229+
scroll-padding-top: 40px;
230+
}
231+
227232
/* Top navigation bar */
228233
.mobile-nav {
229234
display: block;
230-
padding: 0 1rem;
231235
height: 40px;
232-
width: calc(100% - 2rem);
236+
width: 100%;
233237
position: fixed;
234238
top: 0;
235239
left: 0;
236240
background-color: white;
237241
box-shadow: rgba(0, 0, 0, 0.25) 0 0 2px 0;
238-
z-index: 5;
242+
z-index: 1;
243+
}
244+
.mobile-nav * {
245+
box-sizing: border-box;
239246
}
240247
.nav-content {
241-
padding-left: 40px;
248+
position: absolute;
249+
z-index: 2;
250+
left: 0;
251+
top: 0;
242252
height: 40px;
253+
width: 100%;
254+
padding: 0 1rem 0 50px;
243255
display: flex;
244256
align-items: center;
257+
background-color: white;
245258
}
246259
.nav-content img {
247260
flex: 0 0 auto;
248261
margin-right: 0.7rem;
249262
}
250263
.version_switcher_placeholder {
264+
flex: 0 1 0;
251265
margin-right: 1rem;
252266
}
253267
.version_switcher_placeholder select {
@@ -286,46 +300,52 @@ dl > dt span ~ em {
286300
flex: 0 0 20px;
287301
fill: #333;
288302
}
289-
.toggler {
303+
.toggler__input {
304+
width: 40px;
305+
height: 40px;
306+
left: 0;
307+
opacity: 0;
308+
position: absolute;
309+
z-index: 3;
310+
margin: 0;
311+
}
312+
.toggler__label {
290313
width: 40px;
291314
height: 40px;
292315
margin: 0;
293316
position: absolute;
294317
cursor: pointer;
295318
top: 0;
296319
left: 0;
297-
z-index: 5;
298320
background-color: transparent;
299321
border: 1px solid white;
300-
box-shadow:none
322+
box-shadow:none;
323+
z-index: 3;
324+
display: flex;
325+
align-items: center;
326+
justify-content: center;
327+
padding: 0 8px;
301328
}
302-
.toggler:focus {
329+
.toggler__label:focus {
303330
background-color: #eee;
304331
border: 1px solid #ededed;
305332
box-shadow: rgba(0, 0, 0, 0.25) 1px 0 2px 0;
306333
}
307-
.hamburger {
308-
box-sizing: border-box;
309-
position: absolute;
310-
top: -1px;
311-
left: -1px;
312-
display: flex;
313-
align-items: center;
314-
justify-content: center;
315-
width: 40px;
316-
height: 40px;
317-
padding: 0 8px;
334+
.toggler__label:hover {
335+
background-color: #eee;
336+
border: 1px solid #ededed;
337+
box-shadow: rgba(0, 0, 0, 0.25) 1px 0 2px 0;
318338
}
319-
.hamburger > span {
339+
.toggler__label > span {
320340
position: relative;
321341
flex: none;
322342
height: 2px;
323343
width: 100%;
324344
background: black;
325345
transition: all 400ms ease;
326346
}
327-
.hamburger > span::before,
328-
.hamburger > span::after {
347+
.toggler__label > span::before,
348+
.toggler__label > span::after {
329349
content: '';
330350
height: 2px;
331351
width: 100%;
@@ -334,34 +354,36 @@ dl > dt span ~ em {
334354
left:0;
335355
top: -8px;
336356
}
337-
.hamburger > span::after {
357+
.toggler__label > span::after {
338358
top: 8px;
339359
}
340-
341-
.toggler.active > .hamburger span {
360+
.toggler__input:checked ~ .toggler__label span {
342361
transform: rotate(135deg);
343362
}
344-
.toggler.active > .hamburger span::before {
363+
.toggler__input:checked ~ .toggler__label span::before {
345364
transform: rotate(90deg);
346365
}
347-
.toggler.active > .hamburger span::before,
348-
.toggler.active > .hamburger span::after {
366+
.toggler__input:checked ~ .toggler__label span::before,
367+
.toggler__input:checked ~ .toggler__label span::after {
349368
top: 0;
350369
}
351-
.toggler.active:hover > .hamburger span {
370+
.toggler__input:checked:hover ~ .toggler__label span {
352371
transform: rotate(315deg);
353372
}
373+
.toggler__input:checked ~ .menu-wrapper {
374+
visibility: visible;
375+
left:0;
376+
}
354377

355378
/* Sliding side menu */
356379
.menu-wrapper {
357380
display: block;
358381
position: fixed;
359382
top: 0;
360-
z-index: 1;
383+
transition: left 400ms ease;
361384
left: -310px;
362385
width: 300px;
363386
height: 100%;
364-
transition: all 400ms ease;
365387
background-color: #eee;
366388
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
367389
overflow-y: auto;
@@ -419,4 +441,9 @@ dl > dt span ~ em {
419441
position: relative;
420442
z-index: 0;
421443
}
444+
/*Responsive tables*/
445+
.responsive-table__container {
446+
width: 100%;
447+
overflow-x: auto;
448+
}
422449
}

0 commit comments

Comments
 (0)