-
🤩 CSS Text Shadow Mouse Move Effect 😎Web/JS30 2020. 11. 18. 19:14반응형
오늘은 마우스 커서의 움직임에 따라 그림자의 위치가 변하는 효과를 구현해보자.
생각보다 새로 배우는 내용이 너무 많아서 나름 알찬 예제였다.
<div class="hero"> <h1 contenteditable>🔥WOAH!</h1> </div>
여기서 한 가지 신기했던 점은 바로 저 h1 태그에 붙어있는 'contenteditable'이라는 속성이다.
저런 속성이 존재한다는 사실을 이번 예제를 통해 처음 알게 되었다.
특정 태그에다가 contenteditable 속성을 붙여주면, 사용자가 해당 요소의 내용을 편집할 수 있다.
1. 우선, DOM 요소들을 담은 변수부터 살펴보자.
const hero = document.querySelector('.hero'); const text = hero.querySelector('h1');
hero가 한글로 변역했을 때 정확히 무엇을 의미하는지는 잘 모르겠지만
이 예제에서 대충 살펴보면 그냥 브라우저 화면 전체 영역을 의미하는 듯 하다.
그냥 특정 범위를 설정했다고 생각하면 될 듯.
이 예제에서는 그 범위를 브라우저 전체로 설정한거고.
text는 hero 안에 있는 텍스트 영역.
2. 그림자를 구현하는 함수를 만들어야 하는데, 일단 hero 영역의 가로, 세로 너비부터 잡아보자.
offsetWidth와 offsetHeight로 잡을 수 있는데, 여기서 ES6의 destructuring을 사용할 수 있다.
function shadow(e) { // ES6 destructuring X const width = hero.offsetWidth; const height = hero.offsetHegiht; // ES6 destructuring O const { offsetWidth : width, offsetHeight : height } = hero; } hero.addEventListener('mousemove', shadow);
객체에다가 destructuring을 사용하는 방법은 오늘 처음 알았다.
3. 이제 마우스의 위치를 변수로 잡아줘야 하는데, 이 또한 event 객체를 이용하여 destructuring을 해줄 수 있다.
let { offsetX : x, offsetY : y } = e; console.log(x, y);
여기서 한 가지 문제점이 발생하는데, x와 y를 콘솔에서 출력해보면
숫자가 급격하게 바뀌는 구간이 있다는 것을 알 수 있을 것이다.
이는 e.target을 찍어봄으로써 이유를 확인할 수 있는데,
console.log(this, e.target);
우리가 hero에 이벤트 리스너를 붙였기 때문에
hero 내부에 있는 h1 태그도 event의 대상이 될 수 있다.
그래서, hero를 기준으로 offsetX, offsetY를 잡다가 h1 태그의 영역으로 마우스가 들어가는 순간
h1 태그를 기준으로 offsetX, offsetY가 잡히게 되는 것이다.
이를 해결하기 위해서는, 현재 이벤트가 발생하는 영역이 hero 영역이 아닐 때
즉, h1 태그 영역에서 이벤트가 발생할 때 일정한 연산을 가해줘야 한다.
if(this !== e.target) { x = x + e.target.offsetLeft; y = y + e.target.offsetTop; }
h1 태그 영역일 때는 h1 태그의 맨 좌측을 기준으로 offsetX가 측정되기 때문에
hero 영역일 때와 동일하게 만들려면, h1 태그의 맨 좌측 x 좌표를 offsetX에다가 더해주면 된다.
y좌표도 마찬가지로, h1 태그의 최상단 y좌표를 offsetY에다가 더해준다.
그렇게 하면, 영역에 관계없이 일정한 offsetX, offsetY가 출력된다.
4. 그 다음에는 'walk'를 설정해 줄 차례이다.
이는 그림자가 해당 글자를 중심으로 마우스와 비례(혹은 반비례)하는 움직임을 갖게 하기 위해 설정하는 변수인데,
현재 상태에서 x, y를 출력해보면 hero 영역의 좌측 최상단이 (0, 0)이고,
우측 최하단이 (hero 영역 가로, hero영역 세로)이다.
이를 글자를 중심으로, 글자의 중심부가 (0, 0)이 되도록 하고
hero 영역의 좌측 최상단은 (- walk / 2, - walk / 2), 우측 최하단은 (walk / 2, walk / 2)가 되도록 만들어주는 것이다.
참고로 walk의 값은 우리가 설정해주고싶은대로 설정해주면 되는데,
walk 값이 작을수록 나중에 그림자의 움직임이 작아지고, walk 값이 클수록 그림자가 큼직큼직하게 움직인다.
const walk = 100; const xWalk = Math.round((x / width * walk) - (walk / 2)); const yWalk = Math.round((y / height * walk) - (walk / 2));
walk는 100으로 설정했고
xWalk은 마우스의 x좌표를 전체 영역의 너비로 나누고,
거기다가 다시 walk을 곱한 후 walk / 2만큼 빼준 값으로 설정했다.
우선, x좌표를 전체 영역의 너비로 나눈 x / width는, 그 값이 0과 1 사이로 좁혀진다.
x의 범위가 0 ~ width 까지이므로 width로 나누면 범위가 0 ~ 1이 되는 건 당연하다.
거기다가 우리가 원하는 만큼의 walk를 곱해주면, 범위가 0 ~ walk가 된다.
(이 때, walk가 커질수록 한 단위 당 간격이 커지므로 움직임이 큼직큼직해지는 것.)
그리고 마지막으로 walk / 2를 빼주면 전체 범위가 - walk / 2 ~ walk / 2가 되는 것이다.
Math.round를 해준 건, 그냥 안하면 숫자가 소수점이 너무 길게 나와서 그런 것.
5. 마지막으로 xWalk와 yWalk를 이용해서 textShadow를 조정해주면 다음과 같은 결과가 나온다.
text.style.textShadow = `${xWalk}px ${yWalk}px 0 red`;
반응형'Web > JS30' 카테고리의 다른 글
⌚Tally String Times with Reduce⏱ (0) 2020.11.20 📊 Sort Without Articles 🎢 (0) 2020.11.19 💿 LocalStorage & Event Delegation 📤 (0) 2020.11.17 🍴 References VS Copying 🎎 (0) 2020.11.13 Slide In on Scroll 💻 (0) 2020.11.12