From c25fab794c3f457bddda89f609de71d1f9aa3005 Mon Sep 17 00:00:00 2001 From: WofWca Date: Tue, 23 Jul 2019 23:51:52 +0800 Subject: [PATCH] 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 --- src/theme/book.js | 80 +++++++++++++++++++++++++++------------ src/theme/css/chrome.css | 25 +++++++----- src/theme/css/general.css | 1 + src/theme/index.hbs | 69 +++++++++++++++++---------------- 4 files changed, 106 insertions(+), 69 deletions(-) diff --git a/src/theme/book.js b/src/theme/book.js index d556c913db..778666bb65 100644 --- a/src/theme/book.js +++ b/src/theme/book.js @@ -595,30 +595,60 @@ function playpen_text(playpen) { }); })(); -(function autoHideMenu() { - var menuStickyContainer = document.getElementById('menu-bar-sticky-container'); - var previousScrollTop = document.scrollingElement.scrollTop; - menuStickyContainer.style.top = '0px'; - document.addEventListener('scroll', function () { - var scrollAmount = document.scrollingElement.scrollTop - previousScrollTop; - previousScrollTop = document.scrollingElement.scrollTop; - var newTopPx = parseInt(menuStickyContainer.style.top.slice(0, -2)) - scrollAmount; - if (newTopPx < -menuStickyContainer.clientHeight) { - newTopPx = -menuStickyContainer.clientHeight; - } else if (newTopPx > 0) { - newTopPx = 0; - } - menuStickyContainer.style.top = newTopPx + 'px'; - }, { passive: true }); -})(); - -(function controllMenuBorder() { +(function controllMenu() { var menu = document.getElementById('menu-bar'); - document.addEventListener('scroll', function () { - if (document.scrollingElement.scrollTop === 0) { - menu.classList.remove('bordered'); - } else { - menu.classList.add('bordered'); - } - }, { 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 = document.scrollingElement.scrollTop; + // `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 914bfbd8b9..65ba680f22 100644 --- a/src/theme/css/chrome.css +++ b/src/theme/css/chrome.css @@ -18,14 +18,12 @@ 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; @@ -34,12 +32,21 @@ a > .hljs { border-bottom-width: 1px; border-bottom-style: solid; } -.js #menu-bar:hover > #menu-bar-sticky-container, -html.sidebar-visible.js #menu-bar-sticky-container { +#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; - transition: top 0.2s; } -#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 { diff --git a/src/theme/css/general.css b/src/theme/css/general.css index 57d5d7a602..dc4e136c2e 100644 --- a/src/theme/css/general.css +++ b/src/theme/css/general.css @@ -47,6 +47,7 @@ h4 a.header:target::before { .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 4e29807c6f..8764df831f 100644 --- a/src/theme/index.hbs +++ b/src/theme/index.hbs @@ -94,41 +94,40 @@
{{> header}} -