View Transitions でテーマ切り替えの波紋を作る

クリック位置から広がる円で新しいテーマを現します。半径は最も遠い角まで届く必要があり、終了時にカスタムプロパティを消さないと次の切り替えに漏れます。

ダークモードの切り替えはサイトで唯一の「ページ全体の色が変わる」瞬間で、そのまま切り替わると唐突に見えます。使うのは View Transitions API です。新旧のスナップショットを重ね、クリック位置から広がる円形の clip-path で新しいテーマを現します。

半径は最も遠い角まで届かせる

中心はクリック位置、半径はビューポートの四隅までの最大距離です。

const dx = Math.max(x, innerWidth - x);
const dy = Math.max(y, innerHeight - y);
const radius = Math.hypot(dx, dy);

少しでも足りないと、画面の隅に古いテーマの欠片が残ります。「画面の対角線」で済ませたくなりますが、中心以外では常に過剰で、角に届く前にアニメーションが終わり同じ欠片が出ます。

幾何はカスタムプロパティへ

JS は中心と半径をルート要素に書くだけで、スタイル側は読むだけです。

document.documentElement.style.setProperty('--ripple-x', x + 'px');
document.documentElement.style.setProperty('--ripple-r', radius + 'px');
document.documentElement.dataset.ripple = '1';

終了時に必ず片付ける

アニメーションが終わったら data-ripple と --ripple-* を消します。残すと次の切り替えが前回の中心と半径で始まり、ちらついて見えます。二回目のクリックでしか出ない不具合なので、見逃しやすい種類です。

段階的な代替

View Transitions が無い場合、または prefers-reduced-motion が有効な場合は、アニメーションなしでテーマだけ切り替えます。テーマは機能、波紋は装飾で、両者を結びつけるべきではありません。

← 記事一覧に戻る

コメント

…