🍊

ボタンをホバーすると枠線が変化し、マウスの動きに追従するアニメーション

2023/03/09に公開


ホバーでボタンの枠線が変化して、マウスの動きに追従するアニメーションについて学びました。

サンプル

サンプルはこちら↓

コード抜粋

アニメーションに関する部分を抜粋しました↓

style.scss
.p-button  {
  position: relative;
  font-size:1.5rem;
  font-weight: bold;
  text-transform: uppercase;
  padding:1.5rem 3rem;
  --width:100%;
  --translateX:0;  
  &::before {
    content:"";
    position: absolute;
    inset:0;
    border:1px solid #000;
    pointer-events: none;
    border-radius:100vmax;
    width:var(--width);
    transform:translate(var(--translateX),0);    
  }
}
script.js

const $contactButton = $('.js-button')

const media = gsap.matchMedia()
media.add("(hover:hover) and (pointer:fine)",()=> {
  
$contactButton.addEventListener('mousemove', (e) => {
  const {left,width,height} =e.currentTarget.getBoundingClientRect();
  const posX = e.clientX - left;
  const controlPosX = posX - height /2;
  const interpolatePosX = gsap.utils.interpolate(height / 2 * -1, height / 2,posX /width );
  const calcPercent = height/ width * 100;
  gsap.to(e.currentTarget, {
     "--width":`${calcPercent}%`,
     "--translateX":`${controlPosX}px`,
     x:interpolatePosX,
     duration: .3,
     ease:"sine.out"
  })
})
$contactButton.addEventListener('mouseleave', (e) => {
  gsap.to(e.currentTarget, {
    "--width": "100%",
    "--translateX": `0`,
    x:0,
    duration: .3,
    ease:"sine.out"
  })
 })
})

実装ポイント

個人的に実装において大事だと思ったポイントを書きます。

擬似要素のスタイル変更にはCSS変数を使用

擬似要素はCSSによって追加されるため、DOMに存在しないようです。

But since this content was added with CSS, not HTML, it doesn’t exist in the DOM. This is why it's called a pseudo element; because it isn't technically part of the DOM like our hard-coded HTML is; it's added after-the-fact with style rules.

引用元サイト↓
https://www.learnhowtoprogram.com/user-interfaces/advanced-css-features/pseudo-elements

そのため、擬似要素のスタイルを変更する時はCSS変数を使いました。

値の単位を揃える

今回、アニメーションをGSAPで実装しました。
--widthの値を%で揃えないと、ボタンをホバーしたときに幅がビヨ~ンと伸びて意図した動きと異なるため、単位を揃えました。
--widthにボタンの高さをpxで指定した場合↓

テキスト移動距離の制御

「CONTACT ME」もボタンをホバーしたときに、移動させます。
単純にcontrolPosXgsap.to()xに指定すればいいと思ったのですが、
移動しすぎるので、gsap.utils.interpolate("開始値","終了値","割合")で移動距離を制御しました。

移動しすぎる動きはこちら↓

gsap.utils.interpolate()についてはこちら↓
https://greensock.com/docs/v3/GSAP/UtilityMethods/interpolate

border-radius:100vmax;を指定

今回のボタンは以下の特徴を持ちます。

  • ホバーされるまでピル(錠剤)型ボタン
  • ホバーされると枠線が円になる

要素の幅や高さが変わっても上記の特徴を維持したいので、50pxのような固定値を指定せず100vmaxを指定しました。

詳しくはこちら↓
https://eclair.blog/css-border-radius/

Chrome 99 と Safari 15 から無限大 infinity 値が使えるようになっているそうです↓
https://note.com/takamoso/n/n491ca96a619c

参考サイト

参考サイトではボタンの枠線用に空のdivを使用していましたが、今回は擬似要素で実装してみました↓
https://www.cultivatecommunications.com/

Discussion