スクロールで色相を変化

6種類の色相でのプレビューを並べてみたもの。

秒数ごとに変えていた背景色を、スクロールするとランダムに変わるようにした。雑記ページスタイル・ガイドで、思う存分試せる。背景色の明るさは変わらないので、そんなに目に負担はかからないと想像しているが、本当のところはわからない。

スクロールに応じて変えるので、素直にやるならonscrollイベントを使うところだが、間引いても重いことがあるだろうし、Intersection Observerを利用した。トリガーをどうしようかと悩んだが、p要素ほど出てこず、たまに出てくる要素をすべて観察させると、どのページでもいい感じになった。

対象はこれらの要素だ。見出しやセクショニング要素でも良さそうだが、それだと雑記記事であまり変わらなくなってしまうので、これら挿入される何かを対象にした。つまり、このリストが画面外に消えると、色相が変わる。olul要素はネストを考慮したセレクターになっている。また最後のh2 + .metalineは、トップページや特集ページのため、特別に追加した。

const updateHueOnScroll = () => {
  const updateOnHide = (entries) => {
    if (entries[0].isIntersecting) {
      return;
    }

    /* global updateHue */
    updateHue();
  };

  const elements = document.querySelectorAll("hr, pre, blockquote, :not(li) > ol, :not(li) > ul, figure, table, h2 + .metaline");
  const observer = new IntersectionObserver(updateOnHide);

  for (const element of elements) {
    observer.observe(element);
  }
};

色々観察している関係上、entriesが複数あることが多いが、全部に反応する必要はないので最初だけを見ている。また、消えた時に色を変えるよう、isIntersectingfalseの時に色相を変更している。消えた時にすると、スクロールしすぎて戻るというありがちな行動パターンと、うまくなじむんじゃないかと考えた。

updateHue()模造紙風の背景色のコードを、少しだけ手直しし、秒数ではなくランダムにした。style属性にカスタム・プロパティーで色相(と明度)が仕込まれるところは同じだ。そのため、背景色他への反映はCSSがやってくれるので、呼ぶだけで済む。

あとは観察対象へ登録するだけだ。observe()はNodeListを受け取れないので、for..ofでばらまいた。forEach()を欲しがっていた割には、for...ofを好んで使うようになってしまった。breakしたい。