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 previousScrollTop = document.scrollingElement.scrollTop;
(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 () {
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');
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;
}
if (!menu.classList.contains('bordered') && document.scrollingElement.scrollTop > 0) {
menu.classList.add('bordered');
} else {
if (menuPosAbsoluteY > 0) {
nextSticky = true;
} else if (menuPosAbsoluteY < minMenuY) {
nextTop = prevScrollTop + minMenuY;
}
if (menu.classList.contains('bordered') && document.scrollingElement.scrollTop === 0) {
menu.classList.remove('bordered');
}
previousScrollTop = Math.max(document.scrollingElement.scrollTop, 0);
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 {
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.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);
}
#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;

View file

@ -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;

View file

@ -97,8 +97,8 @@
<div class="page">
{{> header}}
<div id="menu-bar" class="menu-bar">
<div id="menu-bar-sticky-container">
<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>
@ -133,7 +133,6 @@
{{/if}}
</div>
</div>
</div>
{{#if search_enabled}}
<div id="search-wrapper" class="hidden">