From fe815a07bc2949bd10facc2006990c64aa41621b Mon Sep 17 00:00:00 2001 From: WofWca Date: Fri, 19 Jul 2019 23:54:49 +0800 Subject: [PATCH 1/3] ui: improve menu folding Fold/unfold the menu bar just by the amount of scroll, not by its full width --- src/theme/book.js | 32 ++++++++++++++++++-------------- src/theme/css/chrome.css | 11 +++++------ 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/theme/book.js b/src/theme/book.js index ca73ee14d0..d556c913db 100644 --- a/src/theme/book.js +++ b/src/theme/book.js @@ -596,25 +596,29 @@ function playpen_text(playpen) { })(); (function autoHideMenu() { - var menu = document.getElementById('menu-bar'); - + var menuStickyContainer = document.getElementById('menu-bar-sticky-container'); var previousScrollTop = document.scrollingElement.scrollTop; - + menuStickyContainer.style.top = '0px'; 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'); + 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 }); +})(); - if (menu.classList.contains('bordered') && document.scrollingElement.scrollTop === 0) { +(function controllMenuBorder() { + var menu = document.getElementById('menu-bar'); + document.addEventListener('scroll', function () { + if (document.scrollingElement.scrollTop === 0) { menu.classList.remove('bordered'); + } else { + menu.classList.add('bordered'); } - - previousScrollTop = document.scrollingElement.scrollTop; }, { passive: true }); })(); diff --git a/src/theme/css/chrome.css b/src/theme/css/chrome.css index 94f86f7907..359cdb2b01 100644 --- a/src/theme/css/chrome.css +++ b/src/theme/css/chrome.css @@ -26,6 +26,7 @@ a > .hljs { margin: auto calc(0px - var(--page-padding)); } #menu-bar > #menu-bar-sticky-container { + position: relative; display: flex; flex-wrap: wrap; background-color: var(--bg); @@ -33,8 +34,10 @@ a > .hljs { border-bottom-width: 1px; border-bottom-style: solid; } -.js #menu-bar > #menu-bar-sticky-container { - transition: transform 0.3s; +.js #menu-bar:hover > #menu-bar-sticky-container, +html.sidebar-visible.js #menu-bar-sticky-container { + top: 0 !important; + transition: top 0.2s; } #menu-bar.bordered > #menu-bar-sticky-container { border-bottom-color: var(--table-border-color); @@ -70,10 +73,6 @@ a > .hljs { text-decoration: none; } -html:not(.sidebar-visible) #menu-bar:not(:hover).folded > #menu-bar-sticky-container { - transform: translateY(-60px); -} - .left-buttons { display: flex; margin: 0 5px; From c9f54262f61069829bf5e29c3ecd58790e7fcbd2 Mon Sep 17 00:00:00 2001 From: WofWca Date: Sat, 20 Jul 2019 14:44:56 +0800 Subject: [PATCH 2/3] refactor: use a variable for the menu bar height --- src/theme/css/chrome.css | 8 ++++---- src/theme/css/variables.css | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/theme/css/chrome.css b/src/theme/css/chrome.css index 359cdb2b01..914bfbd8b9 100644 --- a/src/theme/css/chrome.css +++ b/src/theme/css/chrome.css @@ -46,7 +46,7 @@ html.sidebar-visible.js #menu-bar-sticky-container { position: relative; padding: 0 8px; z-index: 10; - line-height: 50px; + line-height: var(--menu-bar-height); cursor: pointer; transition: color 0.5s; } @@ -85,7 +85,7 @@ html.sidebar-visible.js #menu-bar-sticky-container { display: inline-block; font-weight: 200; font-size: 20px; - line-height: 50px; + line-height: var(--menu-bar-height); text-align: center; margin: 0; flex: 1; @@ -123,7 +123,7 @@ html.sidebar-visible.js #menu-bar-sticky-container { text-decoration: none; position: fixed; - top: 50px; /* Height of menu-bar */ + top: var(--menu-bar-height); bottom: 0; margin: 0; max-width: 150px; @@ -412,7 +412,7 @@ ul#searchresults span.teaser em { .theme-popup { position: absolute; left: 10px; - top: 50px; + top: var(--menu-bar-height); z-index: 1000; border-radius: 4px; font-size: 0.7em; diff --git a/src/theme/css/variables.css b/src/theme/css/variables.css index 29daa07293..bfea1f9be1 100644 --- a/src/theme/css/variables.css +++ b/src/theme/css/variables.css @@ -5,6 +5,7 @@ --sidebar-width: 300px; --page-padding: 15px; --content-max-width: 750px; + --menu-bar-height: 50px; } /* Themes */ From c25fab794c3f457bddda89f609de71d1f9aa3005 Mon Sep 17 00:00:00 2001 From: WofWca Date: Tue, 23 Jul 2019 23:51:52 +0800 Subject: [PATCH 3/3] 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}} -