Pattern
Scroll-up way back
On phones the way back appears after a short scroll up, and gets out of the way when the reader reads on.
01
Watch it
02
Rules
- Appears
- After 200px of scroll and a 40px move up from the lowest point since the last scroll down.
- Hides
- On any scroll down, and above 200px.
- Where
- Every page but the home. Phones always; tablets only without a rail; never on desktop.
- What
- The band’s own trail, rebuilt from its links: “← Index” or “← Index / Parent”.
- Motion
- 200ms opacity and 8px translate; instant under reduced motion.
- Without JavaScript
- Does not exist; the band carries the way back.
03
Code
From site/assets/js/site.js, lines 48 to 101.
// ------------------------------------------------------- scroll-up way back
const from = document.querySelector('main .crumbs ol, main a.band-back');
if (from) {
const up = document.createElement('nav');
up.className = 'up-index';
up.setAttribute('aria-label', 'Way back');
if (document.querySelector('main .rail')) up.classList.add('with-rail');
(from.matches('a') ? [from] : [...from.querySelectorAll('a')]).forEach((a, i) => {
if (i) {
const sep = document.createElement('span');
sep.className = 'up-index-sep';
sep.setAttribute('aria-hidden', 'true');
sep.textContent = '/';
up.append(sep);
}
const link = document.createElement('a');
link.href = a.getAttribute('href');
if (link.getAttribute('href') === '/') {
const arrow = document.createElement('span');
arrow.setAttribute('aria-hidden', 'true');
arrow.textContent = '\u2190\u00a0\u00a0';
link.append(arrow);
}
link.append(a.textContent.replace(/^\u2190\s*/, '').trim());
up.append(link);
});
(document.querySelector('.skip') || document.body.firstChild).after(up);
let last = scrollY;
let low = scrollY; // the lowest point since the reader last scrolled down
let on = false;
const show = (v) => {
if (v === on) return;
on = v;
up.classList.toggle('is-on', v);
};
addEventListener(
'scroll',
() => {
const y = scrollY;
if (y <= 200) {
show(false);
low = y;
} else if (y > last) {
show(false);
low = y;
} else if (low - y >= 40) {
show(true);
}
last = y;
},
{ passive: true }
);
}