Experience/[Javascript] JS 30

[Javascript] 16. Mouse Move Shadow

winCow 2021. 4. 28. 14:21

1. 배경

마우스의 움직임을 따라 문자에 그림자 효과를 추가한다.

 

 

2. HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Mouse Shadow</title>
</head>
<body>

  <div class="hero">
    <h1 contenteditable>🔥WOAH!</h1>
  </div>

 

 

3. CSS

  html {
    color: black;
    font-family: sans-serif;
  }

  body {
    margin: 0;
  }

  .hero {
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    color: black;
  }

  h1 {
    text-shadow: 10px 10px 0 rgba(0,0,0,1);
    font-size: 100px;
  }

 

 

4. Javascript

  const hero = document.querySelector('.hero');
  const text = hero.querySelector('h1');
  const walk = 500; //500px

  function shadow(e) {
    const { offsetWidth: width, offsetHeight: height } = hero;
    let { offsetX: x, offsetY: y } = e;

    if (this !== e.target) {
      x = x + e.target.offsetLeft;
      y = y + e.target.offsetTop;
    }

    const xWalk = (x / width * walk) - (walk / 2);
    const yWalk = (y / height * walk) - (walk / 2);

    text.style.textShadow = `
    ${xWalk}px ${yWalk * -1}px 0 rgba(255, 0, 255, 0.7),
    ${xWalk * -1}px ${yWalk}px 0 rgba(0, 255, 255, 0.7),
    ${yWalk}px ${xWalk * -1}px 0 rgba(0, 255, 0, 0.7),
    ${yWalk * -1}px ${xWalk}px 0 rgba(0, 0, 255, 0.7)
    `;
  }

  hero.addEventListener('mousemove', shadow);

🔥WOAH! 컨텐츠인 h1 태그를 text, 이를 담고 있는 부모 div를 hero라는 변수에 각각 할당한다. hero에 마우스 움직임에 반응하여 shadow 함수를 실행하는 이벤트 리스너를 건다.

shadow 함수를 구체적으로 살펴보면, width 변수에 hero.offsetWidth, height 변수에 hero.offsetHeight를 할당한다. 이는 객체 구조 분해로, const width = hero.offsetWidth, const height = hero.offsetHeight를 한 줄로 작성한 것과 같다. 같은 방식으로 할당된 x, y도 각각 전달된 이벤트의 offsetX, offsetY가 된다. 즉, width와 height는 div의 너비와 높이, x, y는 전달된 마우스의 좌표이다.

this 와 event.target이 다를 때, x, y에 e.target.offsetLeft와 e.target.offsetTop을 더해 주는데, this와 e.target이 다를 때는, 마우스가 글자 위를 지날 때로, 이 때 this는 부모인 div, e.target는 자식인 h1을 가리킨다. 마우스의 움직임에 따라 전달되는 offsetX값과 offsetY값에 계산식을 입력해야 하는데, 이 좌표 값은, 해당 요소의 내부에서 설정되므로, 뷰포트 전체를 차지하는 div를 기준으로 값이 정해져야 한다. 본 조건문이 없다면, h1 요소의 범위 안으로 마우스가 이동할 때, offsetX나 offsetY값이 초기화되므로, 그림자 효과가 부자연스럽게 끊기게 될 것이다. 그러므로, h1 범위 내부로 진입할 때도 offsetX, offsetY값이 연속적으로 설정되도록 만들기 위해, h1의 좌상단 꼭지점이 (0,0)이므로, x, y에 h1의 offsetLeft와 offsetTop을 각각 더해 준다.

그 후 xWalk와 yWalk를 정의해 주는데, x, y의 좌표를 각각 전체 너비와 높이로 나눈 뒤 1/2를 빼 주고 500px를 곱한 값이다. 전체 너비 분의 마우스 포인터의 x좌표 값이므로, 마우스의 움직임에 비례해 그림자가 움직이게 된다. 이는 0과 1 사이의 값이므로, 1/2을 빼면 이 값은 -1/2과 1/2 사이에서 움직이게 된다. walk인 500px를 곱하면, 결국 xWalk와 yWalk는 -250px과 250px 사이의 값이 된다.

이를 기반으로 CSS의 스타일 값을 바꿔 준다. textShadow 속성은 offset-x | offset-y | blur-radius | color 형태로 쓸 수 있다. xWalk와 yWalk를 사용해서 자유롭게 만들면 된다.