diff options
author | Dylan DPC <dylan.dpc@gmail.com> | 2020-03-06 01:11:37 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-06 01:11:37 +0100 |
commit | fd56a53e76691b888e57e5986829c3636a8ecebc (patch) | |
tree | 56556872436af499d62c8f2513edf8a243a67385 | |
parent | ca4b85b8158dd39d005c0855ef0fa925821544aa (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.js | 74 | ||||
-rw-r--r-- | src/theme/css/chrome.css | 30 | ||||
-rw-r--r-- | src/theme/css/general.css | 1 | ||||
-rw-r--r-- | src/theme/index.hbs | 69 |
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> |