47

CSSで作るインタラクティブなスポットライト

猫の中の犬を探せ!CSSとJavaScriptで実現したインタラクティブなエフェクト

猫の中に犬が紛れています。 ポインターに追従するスポットライト効果が実現されています。

使用技術

  • CSSのぼかし効果とマスク
  • JavaScriptによるインタラクション

制作意図

  • CSSとJavaScriptの連携方法を学ぶ
  • インタラクティブなエフェクトを実現する

こだわりポイント

  • ラジアルグラデーションマスクでスポットライト効果を実現
  • ポインター座標を取得しCSS変数を更新
  • カーソル非表示とドラッグ禁止で没入感を高める

HTML/CSS/JSそれぞれの役割が明確で、マウスインタラクションと視覚効果の連携がうまく実現されています。 エフェクトの仕組みとこだわりポイントが項目立ててわかりやすいです。

HTML

<!DOCTYPE html>
  <html lang="ja" >
    <head>
      <meta charset="UTF-8">
      <title>焦点フォーカス - Prodouga.com</title>
      <link rel="stylesheet" href="./style.css">
    </head>
    <body>
        <div id="bg"></div>
        <div id="bg_mask"></div>
      <main>
        <h3>Cat and Dog</h3>
      </main>
        <script  src="./script.js"></script>
    </body>
  </html>

HTMLの解説

<body>タグ内には以下の要素が配置されています。

<div id="bg"></div> 背景画像をぼかすためのdiv。

<div id="bg_mask"></div> ラジアルグラデーションのマスクを適用するdiv。ぼかした背景の一部を透過させる。

<main> コンテンツを囲うmain要素。

<h3>Cat and Dog</h3> 見出しのテキスト。

<script src="./script.js"></script> スポットライトを制御するJavaScriptコードを読み込む。

bgとbg_maskでぼかしとマスクを作成し、JavaScriptがポインター座標を検知してマスクの位置を変えることでインタラクティブなスポットライトが完成していることが分かります。

CSS

@import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@500&display=swap");
:root {
  --x: 50%;
  --y: 50%;
  --blur: 0.7vmax;
}
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
html,
body {
  background-color: black;
  overscroll-behavior-x: none;
  overscroll-behavior-y: none;
  overflow: hidden;
  /*
  cursor: none;
  */
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
}
body {
  width: 100vw;
  height: 100vh;
  font-family: "Montserrat", serif;
  text-align: center;
  line-height: 1;
  display: flex;
  justify-content: center;
  align-items: center;
}
main {
  z-index: 1;
}
h3 {
  font-size: max(5vw, 30px);
  color: #ddd;
}
#bg,
#bg_mask {
  /* ふちボケ対策 */
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  margin: calc(var(--blur) * -1);
 
  background: url(https://i.ibb.co/PNT0hL7/2-1.jpg) no-repeat center/cover;
}
#bg {
  filter: blur(var(--blur));
}
#bg_mask {
  -webkit-mask-image: radial-gradient(
    circle 50vmin at var(--x) var(--y),
    black 20vmin,
    transparent
  );
          mask-image: radial-gradient(
    circle 50vmin at var(--x) var(--y),
    black 20vmin,
    transparent
  );
}

CSSの解説

まず、カーソルに関しては以下のようになっています。

/* cursor: none; */
-webkit-user-select: none;   
-moz-user-select: none;
-ms-user-select: none;
user-select: none;

標準のカーソルを非表示にする/* cursor: none; */がコメントアウトされ、代わりにユーザー選択を禁止するスタイルが指定されています。これによりドラッグなどの操作が制限され、カーソルが表示されなくなっています。

次にボケ効果ですが、#bgと#bg_maskの2つの要素で実現されています。

#bgが背景画像にぼかしフィルターをかけることで全体のボケを作り出し、 #bg_maskがラジアルグラデーションのマスクを使って中央のみを透過させることでスポットライトの形を作っています。

この2つのレイヤーとCSS変数を組み合わせることで、インタラクティブなスポットライトとぼかし効果を実現しています。

JavaScript

"use strict";
console.clear();
 
var root = document.querySelector(":root");
function spotlight(e) {
  root.style.setProperty("--x", e.pageX + "px");
  root.style.setProperty("--y", e.pageY + "px");
}
window.addEventListener("pointermove", spotlight);
window.addEventListener("pointerdown", spotlight);

JavaScriptの解説

まず第一行の"use strict"は、コードをstrict modeで実行するための宣言です。エラーチェックが厳しくなります。

次にconsole.clear()でコンソールをクリアしています。

document.querySelector()を使って、:rootセレクターにマッチするdocumentElementを取得し、root変数に格納しています。

spotlight()関数が定義されています。この関数はマウスの移動イベント時に呼ばれ、

  • pageX、pageYでマウス座標を取得
  • rootのCSS変数"--x"と"--y"にその座標を設定しています。

最後に、pointermoveとpointerdownイベントが発生した時にspotlight()を呼び出すイベントリスナーが追加されています。

つまり、このコードはマウスの移動に合わせてCSS変数を更新し、スポットライトの座標を制御しているということです。 CSSのふちボケマスクと組み合わせることで、スポットライト効果を実現しています。