๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Javascript Effect

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋งˆ์šฐ์Šค ํšจ๊ณผ : ๊ธฐ์šธ๊ธฐ ํšจ๊ณผ / ๋ฐ˜์ „ ํšจ๊ณผ

by ์ฝ”ํŒŒ์นด 2022. 9. 28.
728x90

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ : ๋งˆ์šฐ์Šค ํšจ๊ณผ : ๊ธฐ์šธ๊ธฐ ํšจ๊ณผ / ๋ฐ˜์ „ ํšจ๊ณผ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋‹ค์–‘ํ•œ ํšจ๊ณผ๋“ค ์ค‘, ๋งˆ์šฐ์Šค ํšจ๊ณผ์ž…๋‹ˆ๋‹ค. ์ด๋ฒˆ์—๋Š” ์ด๋ฏธ์ง€ ์œ„์— ๋งˆ์šฐ์Šค๋ฅผ ์˜ค๋ฒ„ํ•˜๋ฉด ์ด๋ฏธ์ง€๊ฐ€ ๊ธฐ์šธ์–ด์ง€๊ณ , ์ƒ‰์ƒ์ด ๋ฐ˜์ „๋˜๋Š” ํšจ๊ณผ๊ฐ€ ๋‚˜ํƒ€๋‚˜๋„๋ก ์ž‘์—…ํ•ด ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ์ดํŽ™ํŠธ์— ์˜ํ–ฅ์„ ์ฃผ๋Š” ์ฃผ์š” CSS ์†Œ์Šค๋ถ€ํ„ฐ ๋จผ์ € ์‚ดํŽด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


1. CSS ์†Œ์Šค

1-1) ์ด๋ฏธ์ง€

.mouse__img {
    transform: perspective(600px) rotateX(0deg) rotateY(0deg);
    transform-style: preserve-3d;
    will-change: transform;
    transition: all 0.3s;
}

๋งˆ์šฐ์Šค๋ฅผ ์˜ค๋ฒ„ํ–ˆ์„ ๋•Œ, ์›€์ง์ผ ์ด๋ฏธ์ง€์— transform ์†์„ฑ์„ ๋ถ€์—ฌํ•ด ์ค๋‹ˆ๋‹ค. perspective ์†์„ฑ์€ ์›๊ทผ๊ฐ์„ ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค. css๋กœ 3D ํšจ๊ณผ๋ฅผ ์ฃผ๊ธฐ ์œ„ํ•ด์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์†์„ฑ์ž…๋‹ˆ๋‹ค.
์šฐ๋ฆฌ๋Š” 3D ์ž‘์—…์„ ํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์—, transform-style: preserve-3d; ์†์„ฑ์œผ๋กœ 3D ์‚ฌ์šฉ์„ ์„ ์–ธํ•ด ์ค๋‹ˆ๋‹ค.
๊ทธ์™€ ๋น„์Šทํ•˜๊ฒŒ, ์•„๋ž˜์˜ will-change: transform; ์†์„ฑ์€ transform์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ž„์„ ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ๋ฏธ๋ฆฌ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฒ‰์œผ๋กœ ๋‚˜ํƒ€๋‚˜๋Š” ํšจ๊ณผ๋Š” ๋ฏธ๋ฏธํ•˜์ง€๋งŒ, ๋ถ€๋“œ๋Ÿฌ์šด ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1-2) ๋งˆ์šฐ์Šค ์ปค์„œ

.mouse__cursor {
    position: absolute;
    left: 0;
    top: 0;
    width: 100px;
    height: 100px;
    border-radius: 50%;
    background: white;
    z-index: 999;
    pointer-events: none;
    user-select: none;
    mix-blend-mode: difference;
}

์ฃผ๋ชฉํ•  ์ ์€ ๊ฐ€์žฅ ์•„๋ž˜์— ์žˆ๋Š” mix-blend-mode: difference; ์†์„ฑ์ž…๋‹ˆ๋‹ค. ์ด ์†์„ฑ์€ ์„œ๋กœ ๋‹ค๋ฅธ ์š”์†Œ๋ฅผ ๊ฒน์ณ์„œ ์ƒ‰์ƒ์— ๋Œ€ํ•œ ํšจ๊ณผ๋ฅผ ์ฃผ๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์ด๋ฏธ์ง€์— ๋งˆ์šฐ์Šค๋ฅผ ์˜ค๋ฒ„ํ–ˆ์„ ๋•Œ, ๋ฐ˜์ „ ํšจ๊ณผ๊ฐ€ ๋‚˜ํƒ€๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

2. JAVASCRIPT ์†Œ์Šค

2-1) mouseMove ์ด๋ฒคํŠธ ๋งŒ๋“ค์–ด ์ฃผ๊ธฐ

const mouseMove = (e) => {};
window.addEventListener("mousemove", mouseMove);

addEventListener๋กœ ๋งˆ์šฐ์Šค๊ฐ€ ์›€์ง์ผ ๋•Œ์˜ ์ด๋ฒคํŠธ๋ฅผ ๋จผ์ € ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค. ์•„๋ž˜์—์„œ ์ž‘์—…ํ•  ๋ชจ๋“  ์†Œ์Šค๋“ค์€, ๋ชจ๋‘ ํ•ด๋‹น ์ด๋ฒคํŠธ ์•ˆ์—์„œ ์ด๋ฃจ์–ด์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

2-2) ๋งˆ์šฐ์Šค ์ปค์„œ์˜ ์ขŒํ‘œ๊ฐ’ ๊ตฌํ•˜๊ธฐ

// ๋งˆ์šฐ์Šค ์ขŒํ‘œ๊ฐ’(๋ธŒ๋ผ์šฐ์ € ๊ธฐ์ค€)
let mousePageX = e.pageX;
let mousePageY = e.pageY;

// ์ปค์„œ ์›€์ง์ด๊ธฐ
gsap.to(".mouse__cursor", {
    duration: 0.3,
    left: mousePageX - 50,
    top: mousePageY - 50,
});

pageX, pageY๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ € ๊ธฐ์ค€ ๋งˆ์šฐ์Šค ์ขŒํ‘œ๊ฐ’์„ ๊ตฌํ•ด์ค๋‹ˆ๋‹ค.
๊ทธ ๋‹ค์Œ, gsap๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ์ปค์„œ๋ฅผ ์›€์ง์—ฌ ์ค๋‹ˆ๋‹ค. 50์„ ๋นผ์ฃผ๋Š” ์ด์œ ๋Š” ๋งˆ์šฐ์Šค ์ปค์„œ์˜ ๋„ˆ๋น„, ๋†’์ด๊ฐ€ 100px์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ ์ปค์„œ์˜ ์œ„์น˜๋ฅผ ๊ฐ€์šด๋ฐ๋กœ ์ž‘์—…ํ•ด์ฃผ๊ธฐ ์œ„ํ•จ์ž…๋‹ˆ๋‹ค.

// ๋งˆ์šฐ์Šค ์ขŒํ‘œ๊ฐ’(์ค‘์•™ ๊ธฐ์ค€)
let centerPageX = window.innerWidth / 2 - mousePageX;
let centerPageY = window.innerHeight / 2 - mousePageY;

๋ธŒ๋ผ์šฐ์ €์˜ ์ค‘์•™ ๊ธฐ์ค€ ๋งˆ์šฐ์Šค ์œ„์น˜๊ฐ’๋„ ๊ตฌํ•ด์ค๋‹ˆ๋‹ค. 2-2์—์„œ ๊ตฌํ•œ ์ขŒํ‘œ๊ฐ’๊ณผ๋Š” ๋ณ„๊ฐœ๋กœ, ์ด๋ฏธ์ง€๊ฐ€ ์›€์ง์ผ ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ๊ฐ’์ž…๋‹ˆ๋‹ค.
์ด ๊ฐ’์„ ๋ฐ”๋กœ ์ ์šฉํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์•„์ง์€ ๊ฐ’์ด ์ปค์„œ ์ด๋ฏธ์ง€๊ฐ€ ๊ณผํ•˜๊ฒŒ ์›€์ง์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ๊ฐ’์„ ์ค„์—ฌ์ฃผ๊ณ , ์ตœ๋Œ€ใ†์ตœ์†Œ๊ฐ’์„ ์ง€์ •ํ•˜๋Š” ์ž‘์—…์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

2-3) ์„ธ๋ถ€ ์ž‘์—…ํ•˜๊ธฐ

// ์ตœ์†Œ๊ฐ’์€ -100, ์ตœ๋Œ€๊ฐ’์€ 100 ์„ค์ •
let maxPageX = Math.max(-100, Math.min(100, centerPageX));
let maxPageY = Math.max(-100, Math.min(100, centerPageY));

Math.max ํ•จ์ˆ˜๋Š” ์ž…๋ ฅ๊ฐ’์œผ๋กœ ๋ฐ›์€ ์ˆซ์ž ์ค‘ ๊ฐ€์žฅ ํฐ ์ˆซ์ž๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋Œ€๋กœ Math.min ํ•จ์ˆ˜๋Š” ๊ฐ€์žฅ ์ž‘์€ ์ˆซ์ž๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
์ฆ‰, Math.min(100, centerPageX)์—์„œ, centerPageX๊ฐ€ 100๋ณด๋‹ค ์ปค์ง€๋ฉด ํ•จ์ˆ˜๋Š” 100์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ดํ›„, Math.max(-100, 100)์—์„œ, 100์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋˜๋ฏ€๋กœ, ์ตœ๋Œ€๊ฐ’์€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ 100์œผ๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.
ํ•œํŽธ, Math.min(100, centerPageX)์—์„œ, centerPageX๊ฐ€ 100๋ณด๋‹ค ์ž‘์œผ๋ฉด ํ•จ์ˆ˜๋Š” centerPageX์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ดํ›„, Math.max(-100, centerPageX)์—์„œ, centerPageX์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋˜๊ณ , ๊ฐ’์ด ๋” ์ž‘์•„์ง€๋ฉด -100์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ตœ์†Œ๊ฐ’์€ -100์œผ๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

// ๊ฐ๋„ ์ค„์ด๊ธฐ
let anglePageX = maxPageX * 0.1;
let anglePageY = maxPageY * 0.1;
    
// ๋ถ€๋“œ๋Ÿฌ์šด ์„ค์ •
let softPageX = 0,
    softPageY = 0;
softPageX += (anglePageX - softPageX) * 0.4;
softPageY += (anglePageY - softPageY) * 0.4;

maxPageX, maxPageY๋ฅผ ๊ตฌํ–ˆ์ง€๋งŒ, ์•„์ง๋„ ์›€์ง์ž„์ด ํด ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ 0.1์”ฉ ๊ณฑํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
๋˜, ์›€์ง์ž„์„ ๋” ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ์ž‘์—…ํ•ด ์ฃผ๊ธฐ ์œ„ํ•ด softPage ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. anglePage์™€ softPage์˜ ๊ฐ’์€ 0์œผ๋กœ ๊ฐ™์ง€๋งŒ, ์˜ค์ฐจ๋Š” ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

2-4) ์ด๋ฏธ์ง€ ์›€์ง์ด๊ธฐ

const imgMove = document.querySelector(".mouse__img");
imgMove.style.transform = "perspective(600px) rotateX(" + softPageX + "deg) rotateY(" + softPageY + "deg)";

์ด์ œ ์ด๋ฏธ์ง€์— ์›€์ง์ž„ ํšจ๊ณผ๋ฅผ ์ฃผ๋ฉด ๋ชจ๋“  ์ž‘์—…์ด ๋๋‚ฉ๋‹ˆ๋‹ค.


๊ฒฐ๊ณผ

728x90

๋Œ“๊ธ€

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๐Ÿฆ™

CSS
๊ด‘๊ณ  ์ค€๋น„์ค‘