summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2020-03-06 01:11:37 +0100
committerGitHub <noreply@github.com>2020-03-06 01:11:37 +0100
commitfd56a53e76691b888e57e5986829c3636a8ecebc (patch)
tree56556872436af499d62c8f2513edf8a243a67385
parentca4b85b8158dd39d005c0855ef0fa925821544aa (diff)
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
-rw-r--r--src/theme/book.js74
-rw-r--r--src/theme/css/chrome.css30
-rw-r--r--src/theme/css/general.css1
-rw-r--r--src/theme/index.hbs69
4 files changed, 107 insertions, 67 deletions
diff --git a/src/theme/book.js b/src/theme/book.js
index 8ddd09d5..8fda7a6c 100644
--- a/src/theme/book.js
+++ b/src/theme/book.js
@@ -580,26 +580,60 @@ function playpen_text(playpen) {
});
})();
-(function autoHideMenu() {
+(function controllMenu() {
var menu = document.getElementById('menu-bar');
- var previousScrollTop = document.scrollingElement.scrollTop;
-
- document.addEventListener('scroll', function () {
- if (menu.classList.contains('folded') && document.scrollingElement.scrollTop < previousScrollTop) {
- menu.classList.remove('folded');
- } else if (!menu.classList.contains('folded') && document.scrollingElement.scrollTop > previousScrollTop) {
- menu.classList.add('folded');
- }
-
- if (!menu.classList.contains('bordered') && document.scrollingElement.scrollTop > 0) {
- menu.classList.add('bordered');
- }
-
- if (menu.classList.contains('bordered') && document.scrollingElement.scrollTop === 0) {
- menu.classList.remove('bordered');
- }
-
- previousScrollTop = Math.max(document.scrollingElement.scrollTop, 0);
- }, { passive: true });
+ (function controllPosition() {
+ var scrollTop = document.scrollingElement.scrollTop;
+ var prevScrollTop = scrollTop;
+ var minMenuY = -menu.clientHeight - 50;
+ // When the script loads, the page can be at any scroll (e.g. if you reforesh it).
+ menu.style.top = scrollTop + 'px';
+ // Same as parseInt(menu.style.top.slice(0, -2), but faster
+ var topCache = menu.style.top.slice(0, -2);
+ menu.classList.remove('sticky');
+ var stickyCache = false; // Same as menu.classList.contains('sticky'), but faster
+ document.addEventListener('scroll', function () {
+ scrollTop = Math.max(document.scrollingElement.scrollTop, 0);
+ // `null` means that it doesn't need to be updated
+ var nextSticky = null;
+ var nextTop = null;
+ var scrollDown = scrollTop > prevScrollTop;
+ var menuPosAbsoluteY = topCache - scrollTop;
+ if (scrollDown) {
+ nextSticky = false;
+ if (menuPosAbsoluteY > 0) {
+ nextTop = prevScrollTop;
+ }
+ } else {
+ if (menuPosAbsoluteY > 0) {
+ nextSticky = true;
+ } else if (menuPosAbsoluteY < minMenuY) {
+ nextTop = prevScrollTop + minMenuY;
+ }
+ }
+ if (nextSticky === true && stickyCache === false) {
+ menu.classList.add('sticky');
+ stickyCache = true;
+ } else if (nextSticky === false && stickyCache === true) {
+ menu.classList.remove('sticky');
+ stickyCache = false;
+ }
+ if (nextTop !== null) {
+ menu.style.top = nextTop + 'px';
+ topCache = nextTop;
+ }
+ prevScrollTop = scrollTop;
+ }, { passive: true });
+ })();
+ (function controllBorder() {
+ menu.classList.remove('bordered');
+ document.addEventListener('scroll', function () {
+ if (menu.offsetTop === 0) {
+ menu.classList.remove('bordered');
+ } else {
+ menu.classList.add('bordered');
+ }
+ }, { passive: true });
+ })();
})();
diff --git a/src/theme/css/chrome.css b/src/theme/css/chrome.css
index af4fd62c..33ca3ab5 100644
--- a/src/theme/css/chrome.css
+++ b/src/theme/css/chrome.css
@@ -20,14 +20,13 @@ a > .hljs {
/* Menu Bar */
-#menu-bar {
- position: -webkit-sticky;
- position: sticky;
- top: 0;
+#menu-bar,
+#menu-bar-hover-placeholder {
z-index: 101;
margin: auto calc(0px - var(--page-padding));
}
-#menu-bar > #menu-bar-sticky-container {
+#menu-bar {
+ position: relative;
display: flex;
flex-wrap: wrap;
background-color: var(--bg);
@@ -35,10 +34,21 @@ a > .hljs {
border-bottom-width: 1px;
border-bottom-style: solid;
}
-.js #menu-bar > #menu-bar-sticky-container {
- transition: transform 0.3s;
+#menu-bar.sticky,
+.js #menu-bar-hover-placeholder:hover + #menu-bar,
+.js #menu-bar:hover,
+.js.sidebar-visible #menu-bar {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0 !important;
+}
+#menu-bar-hover-placeholder {
+ position: sticky;
+ position: -webkit-sticky;
+ top: 0;
+ height: var(--menu-bar-height);
}
-#menu-bar.bordered > #menu-bar-sticky-container {
+#menu-bar.bordered {
border-bottom-color: var(--table-border-color);
}
#menu-bar i, #menu-bar .icon-button {
@@ -72,10 +82,6 @@ a > .hljs {
text-decoration: none;
}
-html:not(.sidebar-visible) #menu-bar:not(:hover).folded > #menu-bar-sticky-container {
- transform: translateY(calc(-10px - var(--menu-bar-height)));
-}
-
.left-buttons {
display: flex;
margin: 0 5px;
diff --git a/src/theme/css/general.css b/src/theme/css/general.css
index 747bda03..65c27776 100644
--- a/src/theme/css/general.css
+++ b/src/theme/css/general.css
@@ -60,6 +60,7 @@ h4 a.header:target {
.page {
outline: 0;
padding: 0 var(--page-padding);
+ margin-top: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */
}
.page-wrapper {
box-sizing: border-box;
diff --git a/src/theme/index.hbs b/src/theme/index.hbs
index 8b362342..8f586e01 100644
--- a/src/theme/index.hbs
+++ b/src/theme/index.hbs
@@ -97,41 +97,40 @@
<div class="page">
{{> header}}
- <div id="menu-bar" class="menu-bar">
- <div id="menu-bar-sticky-container">
- <div class="left-buttons">
- <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
- <i class="fa fa-bars"></i>
- </button>
- <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">
- <i class="fa fa-paint-brush"></i>
- </button>
- <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
- <li role="none"><button role="menuitem" class="theme" id="light">{{ theme_option "Light" }}</button></li>
- <li role="none"><button role="menuitem" class="theme" id="rust">{{ theme_option "Rust" }}</button></li>
- <li role="none"><button role="menuitem" class="theme" id="coal">{{ theme_option "Coal" }}</button></li>
- <li role="none"><button role="menuitem" class="theme" id="navy">{{ theme_option "Navy" }}</button></li>
- <li role="none"><button role="menuitem" class="theme" id="ayu">{{ theme_option "Ayu" }}</button></li>
- </ul>
- {{#if search_enabled}}
- <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">
- <i class="fa fa-search"></i>
- </button>
- {{/if}}
- </div>
-
- <h1 class="menu-title">{{ book_title }}</h1>
-
- <div class="right-buttons">
- <a href="{{ path_to_root }}print.html" title="Print this book" aria-label="Print this book">
- <i id="print-button" class="fa fa-print"></i>
- </a>
- {{#if git_repository_url}}
- <a href="{{git_repository_url}}" title="Git repository" aria-label="Git repository">
- <i id="git-repository-button" class="fa {{git_repository_icon}}"></i>
- </a>
- {{/if}}
- </div>
+ <div id="menu-bar-hover-placeholder"></div>
+ <div id="menu-bar" class="menu-bar sticky bordered">
+ <div class="left-buttons">
+ <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
+ <i class="fa fa-bars"></i>
+ </button>
+ <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">
+ <i class="fa fa-paint-brush"></i>
+ </button>
+ <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
+ <li role="none"><button role="menuitem" class="theme" id="light">{{ theme_option "Light" }}</button></li>
+ <li role="none"><button role="menuitem" class="theme" id="rust">{{ theme_option "Rust" }}</button></li>
+ <li role="none"><button role="menuitem" class="theme" id="coal">{{ theme_option "Coal" }}</button></li>
+ <li role="none"><button role="menuitem" class="theme" id="navy">{{ theme_option "Navy" }}</button></li>
+ <li role="none"><button role="menuitem" class="theme" id="ayu">{{ theme_option "Ayu" }}</button></li>
+ </ul>
+ {{#if search_enabled}}
+ <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">
+ <i class="fa fa-search"></i>
+ </button>
+ {{/if}}
+ </div>
+
+ <h1 class="menu-title">{{ book_title }}</h1>
+
+ <div class="right-buttons">
+ <a href="{{ path_to_root }}print.html" title="Print this book" aria-label="Print this book">
+ <i id="print-button" class="fa fa-print"></i>
+ </a>
+ {{#if git_repository_url}}
+ <a href="{{git_repository_url}}" title="Git repository" aria-label="Git repository">
+ <i id="git-repository-button" class="fa {{git_repository_icon}}"></i>
+ </a>
+ {{/if}}
</div>
</div>