Skip to content

Commit fd56a53

Browse files
authored
ui: improve menu folding (#989)
* ui: improve menu folding Fold/unfold the menu bar just by the amount of scroll, not by its full width * refactor: use a variable for the menu bar height * Fix menu scroll jittering, remove hover folding smoothness Rewrite it to use `position:` `sticky` and `relative` instead of continuous programmatic position changes On-hover folding-unfolding transition removal is a side-effect
1 parent ca4b85b commit fd56a53

File tree

4 files changed

+107
-67
lines changed

4 files changed

+107
-67
lines changed

src/theme/book.js

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -580,26 +580,60 @@ function playpen_text(playpen) {
580580
});
581581
})();
582582

583-
(function autoHideMenu() {
583+
(function controllMenu() {
584584
var menu = document.getElementById('menu-bar');
585585

586-
var previousScrollTop = document.scrollingElement.scrollTop;
587-
588-
document.addEventListener('scroll', function () {
589-
if (menu.classList.contains('folded') && document.scrollingElement.scrollTop < previousScrollTop) {
590-
menu.classList.remove('folded');
591-
} else if (!menu.classList.contains('folded') && document.scrollingElement.scrollTop > previousScrollTop) {
592-
menu.classList.add('folded');
593-
}
594-
595-
if (!menu.classList.contains('bordered') && document.scrollingElement.scrollTop > 0) {
596-
menu.classList.add('bordered');
597-
}
598-
599-
if (menu.classList.contains('bordered') && document.scrollingElement.scrollTop === 0) {
600-
menu.classList.remove('bordered');
601-
}
602-
603-
previousScrollTop = Math.max(document.scrollingElement.scrollTop, 0);
604-
}, { passive: true });
586+
(function controllPosition() {
587+
var scrollTop = document.scrollingElement.scrollTop;
588+
var prevScrollTop = scrollTop;
589+
var minMenuY = -menu.clientHeight - 50;
590+
// When the script loads, the page can be at any scroll (e.g. if you reforesh it).
591+
menu.style.top = scrollTop + 'px';
592+
// Same as parseInt(menu.style.top.slice(0, -2), but faster
593+
var topCache = menu.style.top.slice(0, -2);
594+
menu.classList.remove('sticky');
595+
var stickyCache = false; // Same as menu.classList.contains('sticky'), but faster
596+
document.addEventListener('scroll', function () {
597+
scrollTop = Math.max(document.scrollingElement.scrollTop, 0);
598+
// `null` means that it doesn't need to be updated
599+
var nextSticky = null;
600+
var nextTop = null;
601+
var scrollDown = scrollTop > prevScrollTop;
602+
var menuPosAbsoluteY = topCache - scrollTop;
603+
if (scrollDown) {
604+
nextSticky = false;
605+
if (menuPosAbsoluteY > 0) {
606+
nextTop = prevScrollTop;
607+
}
608+
} else {
609+
if (menuPosAbsoluteY > 0) {
610+
nextSticky = true;
611+
} else if (menuPosAbsoluteY < minMenuY) {
612+
nextTop = prevScrollTop + minMenuY;
613+
}
614+
}
615+
if (nextSticky === true && stickyCache === false) {
616+
menu.classList.add('sticky');
617+
stickyCache = true;
618+
} else if (nextSticky === false && stickyCache === true) {
619+
menu.classList.remove('sticky');
620+
stickyCache = false;
621+
}
622+
if (nextTop !== null) {
623+
menu.style.top = nextTop + 'px';
624+
topCache = nextTop;
625+
}
626+
prevScrollTop = scrollTop;
627+
}, { passive: true });
628+
})();
629+
(function controllBorder() {
630+
menu.classList.remove('bordered');
631+
document.addEventListener('scroll', function () {
632+
if (menu.offsetTop === 0) {
633+
menu.classList.remove('bordered');
634+
} else {
635+
menu.classList.add('bordered');
636+
}
637+
}, { passive: true });
638+
})();
605639
})();

src/theme/css/chrome.css

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,35 @@ a > .hljs {
2020

2121
/* Menu Bar */
2222

23-
#menu-bar {
24-
position: -webkit-sticky;
25-
position: sticky;
26-
top: 0;
23+
#menu-bar,
24+
#menu-bar-hover-placeholder {
2725
z-index: 101;
2826
margin: auto calc(0px - var(--page-padding));
2927
}
30-
#menu-bar > #menu-bar-sticky-container {
28+
#menu-bar {
29+
position: relative;
3130
display: flex;
3231
flex-wrap: wrap;
3332
background-color: var(--bg);
3433
border-bottom-color: var(--bg);
3534
border-bottom-width: 1px;
3635
border-bottom-style: solid;
3736
}
38-
.js #menu-bar > #menu-bar-sticky-container {
39-
transition: transform 0.3s;
37+
#menu-bar.sticky,
38+
.js #menu-bar-hover-placeholder:hover + #menu-bar,
39+
.js #menu-bar:hover,
40+
.js.sidebar-visible #menu-bar {
41+
position: -webkit-sticky;
42+
position: sticky;
43+
top: 0 !important;
44+
}
45+
#menu-bar-hover-placeholder {
46+
position: sticky;
47+
position: -webkit-sticky;
48+
top: 0;
49+
height: var(--menu-bar-height);
4050
}
41-
#menu-bar.bordered > #menu-bar-sticky-container {
51+
#menu-bar.bordered {
4252
border-bottom-color: var(--table-border-color);
4353
}
4454
#menu-bar i, #menu-bar .icon-button {
@@ -72,10 +82,6 @@ a > .hljs {
7282
text-decoration: none;
7383
}
7484

75-
html:not(.sidebar-visible) #menu-bar:not(:hover).folded > #menu-bar-sticky-container {
76-
transform: translateY(calc(-10px - var(--menu-bar-height)));
77-
}
78-
7985
.left-buttons {
8086
display: flex;
8187
margin: 0 5px;

src/theme/css/general.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ h4 a.header:target {
6060
.page {
6161
outline: 0;
6262
padding: 0 var(--page-padding);
63+
margin-top: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */
6364
}
6465
.page-wrapper {
6566
box-sizing: border-box;

src/theme/index.hbs

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -97,41 +97,40 @@
9797

9898
<div class="page">
9999
{{> header}}
100-
<div id="menu-bar" class="menu-bar">
101-
<div id="menu-bar-sticky-container">
102-
<div class="left-buttons">
103-
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
104-
<i class="fa fa-bars"></i>
105-
</button>
106-
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
107-
<i class="fa fa-paint-brush"></i>
108-
</button>
109-
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
110-
<li role="none"><button role="menuitem" class="theme" id="light">{{ theme_option "Light" }}</button></li>
111-
<li role="none"><button role="menuitem" class="theme" id="rust">{{ theme_option "Rust" }}</button></li>
112-
<li role="none"><button role="menuitem" class="theme" id="coal">{{ theme_option "Coal" }}</button></li>
113-
<li role="none"><button role="menuitem" class="theme" id="navy">{{ theme_option "Navy" }}</button></li>
114-
<li role="none"><button role="menuitem" class="theme" id="ayu">{{ theme_option "Ayu" }}</button></li>
115-
</ul>
116-
{{#if search_enabled}}
117-
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
118-
<i class="fa fa-search"></i>
119-
</button>
120-
{{/if}}
121-
</div>
122-
123-
<h1 class="menu-title">{{ book_title }}</h1>
124-
125-
<div class="right-buttons">
126-
<a href="{{ path_to_root }}print.html" title="Print this book" aria-label="Print this book">
127-
<i id="print-button" class="fa fa-print"></i>
128-
</a>
129-
{{#if git_repository_url}}
130-
<a href="{{git_repository_url}}" title="Git repository" aria-label="Git repository">
131-
<i id="git-repository-button" class="fa {{git_repository_icon}}"></i>
132-
</a>
133-
{{/if}}
134-
</div>
100+
<div id="menu-bar-hover-placeholder"></div>
101+
<div id="menu-bar" class="menu-bar sticky bordered">
102+
<div class="left-buttons">
103+
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
104+
<i class="fa fa-bars"></i>
105+
</button>
106+
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
107+
<i class="fa fa-paint-brush"></i>
108+
</button>
109+
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
110+
<li role="none"><button role="menuitem" class="theme" id="light">{{ theme_option "Light" }}</button></li>
111+
<li role="none"><button role="menuitem" class="theme" id="rust">{{ theme_option "Rust" }}</button></li>
112+
<li role="none"><button role="menuitem" class="theme" id="coal">{{ theme_option "Coal" }}</button></li>
113+
<li role="none"><button role="menuitem" class="theme" id="navy">{{ theme_option "Navy" }}</button></li>
114+
<li role="none"><button role="menuitem" class="theme" id="ayu">{{ theme_option "Ayu" }}</button></li>
115+
</ul>
116+
{{#if search_enabled}}
117+
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
118+
<i class="fa fa-search"></i>
119+
</button>
120+
{{/if}}
121+
</div>
122+
123+
<h1 class="menu-title">{{ book_title }}</h1>
124+
125+
<div class="right-buttons">
126+
<a href="{{ path_to_root }}print.html" title="Print this book" aria-label="Print this book">
127+
<i id="print-button" class="fa fa-print"></i>
128+
</a>
129+
{{#if git_repository_url}}
130+
<a href="{{git_repository_url}}" title="Git repository" aria-label="Git repository">
131+
<i id="git-repository-button" class="fa {{git_repository_icon}}"></i>
132+
</a>
133+
{{/if}}
135134
</div>
136135
</div>
137136

0 commit comments

Comments
 (0)