スクロール監視で作られていたトップに戻るボタンの改修をしていた。Intersection Observer APIを使うと10行に満たないJavaScriptで実装できた。グローバル・ヘッダーが見えなくなったらボタンを出す、という条件でのみだが、実用性はありそう。
HTMLではbody
要素直下の最後にでもbutton
要素を置いておく。最後の方に置くのは重なり順のため。位置はCSSで行うので、あまり考える必要はない。イベントの発生までラグがあるかもしれないので、デフォルトでhidden
属性は追加しておく。
<body>
<header class="global-header">
...
</header>
...
<button id="to-top" hidden>↑ Back to Top</button>
</body>
ボタンをビューポートの右下に配置する。位置を固定するだけ。z-index
プロパティーが必要なら細心の注意を払う。
#to-top {
bottom: 1rem;
position: fixed;
right: 1rem;
}
ボタンを押すとスクロールするコードと、グローバル・ヘッダーが見えなくなったらボタンを表示するコードを書く。スクロールするコードはwindow.scrollTo(0, 0)
を使う。
IntersectionObserver
オブジェクトを作る時に渡すコールバック関数で、表示の切り替えを行う。引数から監視するグローバル・ヘッダーの位置情報が手に入るので、そのうちの見えるか見えないかだけを真偽値で返してくれるisIntersecting
プロパティーを利用する。ボタンのhidden
属性へコピーするだけで、グローバル・ヘッダーとボタンのどちらかのみが表示されるようになるはず。
var toTop = document.getElementById("to-top");
toTop.addEventListener("click", function () {
window.scrollTo(0, 0);
});
(new IntersectionObserver(function (entries) {
toTop.hidden = entries[0].isIntersecting;
})).observe(document.querySelector(".global-header"));
位置を計算して、見えなくなったかどうかを判定する必要がなくなると、これだけ簡単な実装になる。ボタンにアイコンを使いたい! とか、ボタンを徐々に表示したい! とか、スクロールをアニメーションしたい! とか、グローバル・ヘッダーが見えなくなってから半ページくらいスクロールしたらボタンを表示したい! とか、要件が増えると、ちょっとややこしくなる。
そういった要件も、様々な標準技術が実装されている現在なら、それぞれに最適な技術の選定さえできれば、基本を変えることなく追加できる。ボタンならインラインSVGの採用、表示のアニメーションならtransition
プロパティーの利用、スクロールのアニメーションならrequestAnimationFrame()
での制御、スクロール判定のあそびならrootMargin
やthreshold
の調節、それぞれで達成できるだろう。
コード・ハイライトを復活させた。highlight.jsを使って、HTMLファイルを作成する時にハイライトしている(RSSやデータでは生のまま)。カラー・スキームは、ダーク・モードで切り替えずに済むように、Solarizedのアクセント色を流用した。もうちょっと抑え気味でも良さそう。