스크롤에 반응하는 콘텐츠와 원페이지 스크롤

SONU·2022년 3월 12일

JavaScript

목록 보기
1/2
post-thumbnail

결과물 미리보기🖥

동영상 보러가기👩🏻‍💻

일단 결과물부터 보고 시작하자👏

포트폴리오 재정비가 필요해서 만지다 보니 아예 새로 갈아엎게 되었다. 원페이지 스크롤 형식을 좋아해서 이전 버전의 사이트에서도 원페이지 가로 스크롤 방식을 사용했는데, 이번에도 원페이지 스크롤 형식으로 가기로 했다. 원페이지의 경우 사용자의 디바이스나 해상도 등 다양한 환경을 고려하여 작업하기에 다소 까다롭다는 애로사항이 있지만 데스크탑과 노트북 환경에서 깔끔한 맛이 있기에 포기할 수 없는 매력적인 인터랙션이다. 다만 이번 작업에서는 가로가 아닌 디폴트 방향 세로 스크롤로 가기로.

메인 페이지 디자인 래퍼런스를 참고하다가,스크롤을 하면 화면의 컨텐츠가 점점 커지고
일정 수준에 달하면 다음 페이지로 넘어가는 디자인을 보고 구현해보기로 정했다.
(그것이 멋이니까.)

인터랙션 구현에 사용할 메서드들

원하는 화면을 만들기 위해 필요한 것들은...

mousewheel (마우스 휠 이벤트)
DOMMouseScroll (마우스 스크롤 이벤트)
animation (애니메이션)
event.originalEvent.wheelDelta (마우스 스크롤 방향 감지 이벤트)
event.originalEvent.detail (마우스 스크롤 방향 감지 이벤트)

HTML 구조

<div id="contents">
    <div class="stn main">
        <div class="cont">
            <div class="main_tit01">
                <p>TITLE</p>
            </div>
            <div class="main_tit02">
                <p>TITLE</p>
            </div>
            <div class="photozone">
                <video src="" loop autoplay muted playsinline></video>
            </div>
        </div>
    </div>
    <div class="stn profile main-page"></div>
</div>

CSS 구조

.main{ 
    width:100vw; 
    height:100vh; 
    background:#fff; 
    overflow:hidden; 
}
.main .cont{ 
    position:relative; 
    height:100%; 
}
.main_tit01,.main_tit02{ 
    position:absolute; 
    left:0; top:50%; 
    transform: translateY(-50%); 
    font-size:250px; 
    line-height: 1; 
    transition: color 0.3s; 
    -webkit-text-stroke: 1px #fff; 
}
.main_tit01{ 
    width:100%; 
    mix-blend-mode:screen; 
    z-index: 3; 
 }
.main_tit02{ 
    width:100%; 
    color:#141150;
    z-index: 1; 
}
.photozone{ 
    position:absolute; 
    width:50vw; 
    height:50vh; 
    left:50%; top:50%; 
    transform: translate(-50%,-50%); 
    background:#fff; 
    background-size: 100vw; 
    transition:0.5s; overflow:hidden; 
    z-index: 2; 
}
.photozone.on{ 
    opacity:0.8; 
    transition:all 1s; 
}
.photozone.on::after{ 
    content:""; 
    display:inline-block; 
    width:100%; 
    height:100%; 
    position:absolute; 
    top:0; left:0; 
    backdrop-filter:blur(10px); 
}
.photozone video{ 
    position:absolute; 
    top:50%; left:50%; 
    transform:translate(-50%,-50%); 
}

자바스크립트 구조

let num = 0;
let idx = 0;
let delta;
const mainImg = document.querySelector(".photozone");
const mainTit = document.querySelector(".main_tit01");
const elMainCon = document.querySelectorAll(".main-page");

$(window).on('mousewheel DOMMouseScroll', function (e) {
    delta = e.originalEvent.wheelDelta || e.originalEvent.detail * -1;
    if (delta < 0) {
        if (!(num == 12)) {
            num++;
            if (num <= 11) {
                mainImg.style = `width:${(num * 5) + 50}vw; height:${(num * 5) + 50}vh;`;
            }
        }
        if ((num == 12) && (idx < elMainCon.length)) {
            idx++;
        }
    } else {
        if (!(idx == 0)) {
            idx--;
        }
        if ((num > 0) && (idx == 0)) {
            num--;
            mainImg.style = `width:${(num * 5) + 50}vw; height:${(num * 5) + 50}vh;`;
        }
    }
    
    if (num >= 10) {
        mainTit.style = `color:#fff;`;
        mainImg.classList.add("on");
    } else {
        mainTit.style = `color:#000;`;
        mainImg.classList.remove("on");
    }

    $('html,body').stop().animate({
        scrollTop: ($(window).height()) * idx
    }, 600)
})

스크립트 뜯어보기

let num = 0;
// 첫 페이지에서 스크롤 되는 횟수
// num으로 인해 첫 페이지의 동영상 크기가 변하게 하기 위함

let idx = 0;
// 첫 페이지에서 다음 페이지로 넘어갈 때 부터 카운트 되는 스크롤 횟수
// 페이지 이동을 작동시키기 위한 변수

let delta;
// 스크롤의 방향(상,하)을 판별하기 위한 변수

const mainImg = document.querySelector(".photozone");
// 첫 페이지의 비주얼 요소를 감싸고 있는 태그(img or video 여기서는 비디오)

const mainTit = document.querySelector(".main_tit01");
// 첫 페이지 타이틀 (스타일을 주기 위한 변수로 크게 신경쓰지 않으셔도 됩니다.)

const elMainCon = document.querySelectorAll(".main-page");
// 두번째 페이지

여기서 신경써야 할 것은 아래의 변수 3개이다.

let num = 0;
let idx = 0;
let delta;

num은 첫 페이지에서 스크롤 할때마다 증가하며 그에 따라서 비디오의 크기가 변한다.
num이 일정 숫자에 달하면 (= 비디오가 화면을 꽉 채우게 되는 수치) 증가가 멈추며, idx가 증가하게 된다.
delta는 스크롤 방향(상,하)를 판별하기 위한 변수이며, 할당은 스크롤 이벤트 안에서 해준다.

// mousewheel DOMMouseScroll 스크롤 이벤트
$(window).on('mousewheel DOMMouseScroll', function (e) {

    delta = e.originalEvent.wheelDelta || e.originalEvent.detail * -1;
    // e.originalEvent.wheelDelta || e.originalEvent.detail는 스크롤을 했을때 페이지가 아래로 이동하면 양수가, 위로 이동하면 음수가 나온다. 여기서는 편의를 위해 -1을 곱해서 음수와 양수를 역으로 만들어주었다.
    
    if (delta < 0) { // 스크롤을 아래로 내렸을 때
    
        if (!(num == 12)) { // num이 12가 아닐 때
        // num의 증가범위를 12로 잡은 이유는, 비주얼 컨텐츠의 동작 횟수를 12회 내로 잡았기 때문.
        
            num++; // num 증가
            
            if (num <= 11) { // num이 11과 같거나 작다면
            
                mainImg.style = `width:${(num * 5) + 50}vw; height:${(num * 5) + 50}vh;`;
                // 비주얼 컨텐츠 영역의 넓이가 변하도록 스타일 조정(커짐)
            }
        }
        if ((num == 12) && (idx < elMainCon.length)) {
        // num이 12와 같고(비주얼 컨텐츠가 변하고 다음 페이지로 넘어갈 준비가 된 순간),
        // idx(초기값0)가 첫 페이지 다음으로 오는 페이지들의 수보다 적을 때
        
            idx++; // idx를 증가시킴
        }
        
    } else { // 스크롤을 위로 올렸을 때
    
        if (!(idx == 0)) { // idx가 0이 아니라면
            idx--; // idx를 감소시켜라
        }
        if ((num > 0) && (idx == 0)) {
        // num이 0보다 크고 idx가 0일때
        
            num--; // num을 감소시키고
            
            mainImg.style = `width:${(num * 5) + 50}vw; height:${(num * 5) + 50}vh;`;
            // 비주얼 컨텐츠 영역의 넓이가 변하도록 스타일 조정(작아짐)
        }
    }
    
    $('html,body').stop().animate({
        scrollTop: ($(window).height()) * idx
        // 화면의 높이값에 스크롤에 따라 변하는 idx값을 곱해서 페이지 단위로 이동시킨다.
        // idx가 1이라면 첫 페이지에서 다음 페이지로, idx가 2라면 두 번 째 페이지에서 세 번 째 페이지로 이동하는 식으로 작동한다.
    }, 600)
    
})

완성...!👏 (마치며...)

동영상 보러가기👩🏻‍💻

원하는대로 비주얼 컨텐츠도 잘 변하고, 이후의 스크롤 이벤트도 잘 작동하고 있다.
다만 스크롤 제어 이벤트는 트랙패드 환경에서는 다소 의도하지 않은 움직임을 보일 수 있다는 점이 문제. 그래서 이번 포트폴리오 사이트에서는 페이지가 2페이지를 초과하지 않도록 최대 페이지 수를 제한했다. 마우스를 쓰지 않는 랩탑 환경에 최적화 하는 것이 추후의 과제 아닌 과제라고나 할까......

그런 의미에서 보다 더 좋은 방법이 있다면 피드백은 언제나 환영합니다!
(부디 초짜 퍼블리셔를 살려주세요!!! 🙇‍♀️🙇‍♀️🙇‍♀️🙇‍♀️)

profile
FE개발자를 꿈꾸는 SONU 입니다.

1개의 댓글

comment-user-thumbnail
2023년 3월 18일

2번째 페이지가 아주 멋지네요. 잘 보고 갑니다.

답글 달기