初めまして。エンジニアのナベです。
前記事から連続とはなりますが、初回はJS関連の話をしたいと思います。
さて、Javascriptを用いたコーディングの現場では、実装効率を上げるためにライブラリを用いる場面が多くあるかと思います。
しかしながら、独創的な表現になってくると、ライブラリ頼りの開発には限界があり、ある程度自力でコードを書く作業が必要です。
個人的には、頭を使って実装イメージを考え、具現化するという作業はエンジニアとしてはやりがいがある一方で、実装方法を間違えるとサイトのパフォーマンス悪化したりと弊害が出てしまうので、実装前の検討が一番大事だと思っています。余計なライブラリの多用は避けたいところです。
そういったときに大きく助けてくれるものが、Javascriptの「Web API」です。
それでは、Web APIの中で、実際に弊社案件でgetBoundingClientRect()メソッドを使用しないと実装が難しい局面があったので、実装サンプルと合わせて紹介したいと思います!
Web API を使うメリット
JavascriptのWeb API(Application Programming Interfaces (APIs) )は標準でWebブラウザに組み込まれている仕組みです。
下記サイトを見ると、大量のAPIが存在していることがわかるかと思います。
例えば今、ブラウザ上でのあなたのカーソルの位置はブラウザのAPIで常に監視されています。(怖い仕組みではありません。)
また、APIの恩恵を受けることで少ないコード量で実装ができ、さらにはサイズ大きいライブラリなどを読み込む必要がなく、パフォーマンスの悪化も防ぐことができます。
例えば、スクロール系ではIntersection Observer APIというものがあり、パフォーマンスの悪化を起こさずに、複雑な条件を簡単に実装することができた経験もあります!
今回は、その中でもgetBoundingClientRect()というメソッドを使用した例を紹介します。
シンプルに説明すると、何らかの実装で要素の座標を取得する必要があるときには、ブラウザくんが常に情報を持っているので教えてもらおう!ということです。
実装サンプルの仕様について
カーソルに追従するサークルを表示させる、というサイトは最近増えてきたと感じていますが、
今回紹介する実装サンプルの仕様は、下記のように複雑なものでした。
- 特定のエリアにカーソルが入ったとき、サークルを表示させ追従させる
- 特定のエリアにカーソルが入ったときに、サークルを拡大させる
- 特定のエリアからカーソルが外れたときは、サークルを縮小させる
- サークルはCSSの「clip-path」で作成し、全面にある画像を切り抜くように表示させる
それでは次に、実装サンプルをご紹介します。
実装サンプル
See the Pen
mouse move clip-path by Mitsutoshi Watanabe (@gg_watanabe)
on CodePen.
写真にマウスホバーすると、犬の写真が円でトリミングされて表示されます。
今回は、写真のボックスの座標を取得する必要がありました。
下記は、とある状況でカーソルを写真の上に乗せてみたときのconsole.logです。
{
"x": 525,
"y": 67.5,
"width": 500,
"height": 303,
"top": 67.5,
"right": 1025,
"bottom": 370.5,
"left": 525,
}
ビューポート(表示領域)に対しての、写真ボックスの座標情報を取得することができます。 getBoundingClientRect()の仕様の詳細な説明は割愛させていただきますが、要点としては下記を覚えておくと良いと思います。
- ビューポートに対しての、指定要素の座標などを取得できる。(ウィンドウと画像の左側の余白がなければxは0となる)
- xとleft、yとtopは同じ値が返ってくる
- 例えば、スクロールして写真が半分しか見えない状況では、yとtopの値はマイナスで返ってくる
座標だけでなくwidthやheightまで取得することができるのは便利ですね!
そして、今回紹介したメソッドの使用箇所はonMouseMoveイベントの部分です。 サンプルではウィンドウの可変とスクロール移動にも対応するためにonMouseMoveイベントでgetBoundingClientRect()を毎回実行し、常に最新の座標を取得しています。
今回の実装サンプルでポイントとなるのは、onMouseMoveのeventで返ってくる座標と、ビューポート基準での写真ボックスの座標の扱い方です。
左上にカーソルを置いたとき
こちらは当たり前かと思いますが、写真ボックスの座標とonMouseMoveイベントの座標はほぼ一致した値が返ってきます。
さて、次は右下の場合を見てみましょう。
右下にカーソルを置いたとき
右下の場合は、異なる値が返ってきましたね。
実装サンプルではCSSのclip-pathを使用する必要があり、カーソルの位置(event.clientX)をそのまま使用するとサークルの位置がずれてしまうという課題があったので、サークルの中央にカーソルがある状態を実現するロジックを考える必要がありました。
話を戻すと、ここで要素の座標を求める必要性に気が付き、getBoundingClientRect()を使ってみることを決めた経緯があります。
結果、下記のコードで求めた変数targetXとtargetYをCSS変数に入れることでサークルの位置を中央に持っていくことに成功しました。
const thisRect = event.currentTarget.getBoundingClientRect();
const targetX = event.clientX - thisRect.left;
const targetY = event.clientY - thisRect.top;
skelton.style.setProperty("--block-loupeX", targetX);
skelton.style.setProperty("--block-loupeY", targetY);
まとめ
いかがでしたでしょうか?
今回ご紹介したメソッドは「要素の座標を取得する」、というシンプルなものだったので、そこまでのインパクトはなかったとは思いますが、利用することで何行も記述したり、jQueryのメソッドを使ったりする必要がなく、シンプルなコードで実装できるというメリットは大きいと思います!
まだまだ、スクロール系ではIntersection Observer、監視系ではMutation Observerという超便利なAPIもありますので、またご紹介できたらなと思います。
今回の実装サンプルと手法は少々特殊だったと思いますが、何らかのお役に立てれば幸いです!