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
This commit is contained in:
Dylan DPC 2020-03-06 01:11:37 +01:00 committed by GitHub
parent ca4b85b815
commit fd56a53e76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 105 additions and 65 deletions

View File

@ -580,26 +580,60 @@ function playpen_text(playpen) {
}); });
})(); })();
(function autoHideMenu() { (function controllMenu() {
var menu = document.getElementById('menu-bar'); var menu = document.getElementById('menu-bar');
var previousScrollTop = document.scrollingElement.scrollTop; (function controllPosition() {
var scrollTop = document.scrollingElement.scrollTop;
document.addEventListener('scroll', function () { var prevScrollTop = scrollTop;
if (menu.classList.contains('folded') && document.scrollingElement.scrollTop < previousScrollTop) { var minMenuY = -menu.clientHeight - 50;
menu.classList.remove('folded'); // When the script loads, the page can be at any scroll (e.g. if you reforesh it).
} else if (!menu.classList.contains('folded') && document.scrollingElement.scrollTop > previousScrollTop) { menu.style.top = scrollTop + 'px';
menu.classList.add('folded'); // Same as parseInt(menu.style.top.slice(0, -2), but faster
} var topCache = menu.style.top.slice(0, -2);
menu.classList.remove('sticky');
if (!menu.classList.contains('bordered') && document.scrollingElement.scrollTop > 0) { var stickyCache = false; // Same as menu.classList.contains('sticky'), but faster
menu.classList.add('bordered'); document.addEventListener('scroll', function () {
} scrollTop = Math.max(document.scrollingElement.scrollTop, 0);
// `null` means that it doesn't need to be updated
if (menu.classList.contains('bordered') && document.scrollingElement.scrollTop === 0) { var nextSticky = null;
menu.classList.remove('bordered'); var nextTop = null;
} var scrollDown = scrollTop > prevScrollTop;
var menuPosAbsoluteY = topCache - scrollTop;
previousScrollTop = Math.max(document.scrollingElement.scrollTop, 0); if (scrollDown) {
}, { passive: true }); 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 });
})();
})(); })();

View File

@ -20,14 +20,13 @@ a > .hljs {
/* Menu Bar */ /* Menu Bar */
#menu-bar { #menu-bar,
position: -webkit-sticky; #menu-bar-hover-placeholder {
position: sticky;
top: 0;
z-index: 101; z-index: 101;
margin: auto calc(0px - var(--page-padding)); margin: auto calc(0px - var(--page-padding));
} }
#menu-bar > #menu-bar-sticky-container { #menu-bar {
position: relative;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
background-color: var(--bg); background-color: var(--bg);
@ -35,10 +34,21 @@ a > .hljs {
border-bottom-width: 1px; border-bottom-width: 1px;
border-bottom-style: solid; border-bottom-style: solid;
} }
.js #menu-bar > #menu-bar-sticky-container { #menu-bar.sticky,
transition: transform 0.3s; .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.bordered > #menu-bar-sticky-container { #menu-bar-hover-placeholder {
position: sticky;
position: -webkit-sticky;
top: 0;
height: var(--menu-bar-height);
}
#menu-bar.bordered {
border-bottom-color: var(--table-border-color); border-bottom-color: var(--table-border-color);
} }
#menu-bar i, #menu-bar .icon-button { #menu-bar i, #menu-bar .icon-button {
@ -72,10 +82,6 @@ a > .hljs {
text-decoration: none; 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 { .left-buttons {
display: flex; display: flex;
margin: 0 5px; margin: 0 5px;

View File

@ -60,6 +60,7 @@ h4 a.header:target {
.page { .page {
outline: 0; outline: 0;
padding: 0 var(--page-padding); padding: 0 var(--page-padding);
margin-top: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */
} }
.page-wrapper { .page-wrapper {
box-sizing: border-box; box-sizing: border-box;

View File

@ -97,41 +97,40 @@
<div class="page"> <div class="page">
{{> header}} {{> header}}
<div id="menu-bar" class="menu-bar"> <div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar-sticky-container"> <div id="menu-bar" class="menu-bar sticky bordered">
<div class="left-buttons"> <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"> <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> <i class="fa fa-bars"></i>
</button> </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"> <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> <i class="fa fa-paint-brush"></i>
</button> </button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu"> <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="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="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="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="navy">{{ theme_option "Navy" }}</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">{{ theme_option "Ayu" }}</button></li> <li role="none"><button role="menuitem" class="theme" id="ayu">{{ theme_option "Ayu" }}</button></li>
</ul> </ul>
{{#if search_enabled}} {{#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"> <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> <i class="fa fa-search"></i>
</button> </button>
{{/if}} {{/if}}
</div> </div>
<h1 class="menu-title">{{ book_title }}</h1> <h1 class="menu-title">{{ book_title }}</h1>
<div class="right-buttons"> <div class="right-buttons">
<a href="{{ path_to_root }}print.html" title="Print this book" aria-label="Print this book"> <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> <i id="print-button" class="fa fa-print"></i>
</a> </a>
{{#if git_repository_url}} {{#if git_repository_url}}
<a href="{{git_repository_url}}" title="Git repository" aria-label="Git repository"> <a href="{{git_repository_url}}" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa {{git_repository_icon}}"></i> <i id="git-repository-button" class="fa {{git_repository_icon}}"></i>
</a> </a>
{{/if}} {{/if}}
</div>
</div> </div>
</div> </div>