wheel イベント を見やすくしてみる - css custom variable を利用した 動的な色の変更アイディア

# 作成サンプル
css custom variable で数値を渡すことができます。

css には calc() という 数値を計算する関数があります。

css には min() max() clamp() という値の範囲を制限する為の関数があります。

つまり、こういうことができます。

<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="gONRWyp" data-pen-title="wheel event example" data-user="juner" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/juner/pen/gONRWyp">
  wheel event example</a> by juner clarinet (<a href="https://codepen.io/juner">@juner</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

※ code pen 領域でマウスのホイールや タッチパッドの スクロールジェスチャーを試してみてください。

<details>
<summary>ソース</summary>

```html
<input id=scale type="number" min=1 value=200 placeholder="--base-scale" />
<ul id="target">
  <template id="template">
    <li>
      <span class="property"><span class="title">deltaMode:</span><span class="delta-mode"></span></span>,
      <span class="property"><span class="title">deltaX:</span><span class="delta-x"></span></span>,
      <span class="property"><span class="title">deltaY:</span><span class="delta-y"></span></span>,
      <span class="property"><span class="title">deltaZ:</span><span class="delta-z"></span></span>,
      <span class="property"><span class="title">wheelDelta:</span><span class="wheel-delta"></span></span>,
      <span class="property"><span class="title">wheelDeltaX:</span><span class="wheel-delta-x"></span></span>,
      <span class="property"><span class="title">wheelDeltaY:</span><span class="wheel-delta-y"></span></span>
    </li>
  </template>
</ul>
<script type="module">
{
  // #region base scale
  scale.valueAsNumber = Number(
    getComputedStyle(document.body).getPropertyValue("--base-scale"),
  );
  scale.addEventListener("input", updateBaseScale);
  updateBaseScale();
  function updateBaseScale() {
    const scaleNum = scale.valueAsNumber;
    const body = document.body;
    if (isNaN(scaleNum)) body.style.removeProperty("--base-scale");
    else body.style.setProperty("--base-scale", scaleNum);
  }
  // #endregion

  // #region wheel event
  document
    .querySelector(":root")
    .addEventListener("wheel", wheel, { passive: false });

  function wheel(e) {
    e.preventDefault();
    e.stopPropagation();

    (async ({
      deltaMode,
      deltaX,
      deltaY,
      deltaZ,
      wheelDelta,
      wheelDeltaX,
      wheelDeltaY,
    }) => {
      await timeout();
      const $temp = template.content.cloneNode(true);
      const $li = $temp.querySelector("li");

      // #region deltaMode
      (($e, deltaMode) => {
        $e.innerText = ((deltaMode) => {
          if (WheelEvent.DOM_DELTA_PIXEL === deltaMode)
            return `DOM_DELTA_PIXEL(${deltaMode})`;
          if (WheelEvent.DOM_DELTA_LINE === deltaMode)
            return `DOM_DELTA_LINE(${deltaMode})`;
          if (WheelEvent.DOM_DELTA_PAGE === deltaMode)
            return `DOM_DELTA_PAGE(${deltaMode})`;
          return `${deltaMode}`;
        })(deltaMode);
        $e.classList.add(`delta-mode-${deltaMode}`);
      })($li.querySelector(".delta-mode"), deltaMode);
      // #endregion

      // #region other property
      [
        [$li.querySelector(".delta-x"), deltaX],
        [$li.querySelector(".delta-y"), deltaY],
        [$li.querySelector(".delta-z"), deltaZ],
        [$li.querySelector(".wheel-delta"), wheelDelta],
        [$li.querySelector(".wheel-delta-x"), wheelDeltaX],
        [$li.querySelector(".wheel-delta-y"), wheelDeltaY],
      ].forEach((v) => {
        const [$e, value] = v;
        $e.innerText = value;
        $e.style.setProperty("--value", value);
      });
      // #endregion

      target.insertAdjacentElement("afterbegin", $li);
      const removeTarget = target.querySelectorAll(":nth-child(1n+100 of li)");
      for (const rt of [...removeTarget]) rt.remove();
    })(e);
  }
  // #endregion
  function timeout(milliseconds) {
    return new Promise((resolve) => setTimeout(resolve, milliseconds));
  }
}
</script>
<style>
:root {
  /** delta の 色変換用スケール */
  --base-scale: 500;
  height: 100vh;
  width: 100vw;
  overflow: hidden;
  display: flex;
  flex-flow: column nowrap;
  container-type: size;

  body {
    display: contents;
    ul {
      flex: 1 1 auto;
      display: flex;
      flex-flow: column nowrap;
      padding: 0;
      margin: 0;
      overflow: hidden;
      gap: 2px;
      li {
        .delta-mode {
          color: var(--delta-mode-color, currentcolor);
          background-color: var(--delta-mode-background-color, transparent);
          &.delta-mode-0 {
            --delta-mode-color: white;
            --delta-mode-background-color: green;
          }
          &.delta-mode-1 {
            --delta-mode-background-color: yellow;
          }
          &.delta-mode-2 {
            --delta-mode-color: white;
            --delta-mode-background-color: blue;
          }
        }
        .property {
          display: inline flow-root;
        }
        .title {
          font-size: 0.5em;
        }
        .delta-x,
        .delta-y,
        .delta-z,
        .wheel-delta,
        .wheel-delta-x,
        .wheel-delta-y {
          background-color: oklab(
            100% 0 clamp(-0.5, calc(var(--value) / var(--base-scale)), 0.5)
          );
        }
      }
    }
    & > ul {
      pointer-events: none;
    }
  }
}
</style>
```
</details>

# ポイント
## 色の調整方法
色変換については次の様なコードで実現しています。

```css
.delta-x,
.delta-y,
.delta-z,
.wheel-delta,
.wheel-delta-x,
.wheel-delta-y {
  background-color: oklab(
    100% 0 clamp(-0.5, calc(var(--value) / var(--base-scale)), 0.5)
  );
}
```

`--base-scale` は :root で定義しており、 動作見た感じ 200 に設定してあります。そのうち js で変更できると面白いかもしれません。

`--value` は js から設定している各 delta の値です。 

oklab() は 色 関数の一つで今回の L a b の b ……つまり 青と黄色の色合いの値を 算出しています。

https://developer.mozilla.org/ja/docs/Web/CSS/color_value/oklab

値の範囲が外に出てしまうと不都合の場合は clamp() 関数で 最大と最小を範囲に収めるとよいです。

https://developer.mozilla.org/ja/docs/Web/CSS/clamp

## 要素数の制限

要素数の制限は次の様に実装してあります。

```js
const removeTarget = target.querySelectorAll(":nth-child(1n+100 of li)");
for (const rt of [...removeTarget]) rt.remove();
```

`:nth-child(1n+100 of li)` により `ul#target` 内にある 100 件目以降の li 要素を削除対象として逐次削除を行っております。

以上。