혼자서 진행하는 프로젝트를 진행하면서 중첩된 Navbar
를 작성해주는 중 어떻게 작성해야할지 막막하여 구글링과 다양한 시도를 하게되었다. 우선 처음 Navbar
는 최상단에 위치하여야 하며, 두번째 Navbar
는 css
의 속성 position
의 옵션중 하나인 fixed
로 스크롤을 내릴때마다 따라오게 해주는 방향으로 잡았었다.
문제는 이제부터였다. 우선 두가지 Navbar
를 작성하고, 각각의 스크롤 효과를 주기위해 window.scrollY
를 사용하여 주었는데, 두번째 Navbar
가 빌어먹게도 엉뚱한 위치에 가있거나 사라져 버리는 등 골치를 꽤나 썩였다. 자세한 원인을 파악하기 위해 구글링 중 컴포넌트가 한페이지에 여러개 붙어있기 때문에 두번째 Navbar
를 window.scrollY
로 기준을 잡았기 때문에 발생하는 문제였었다. 그렇게 postion
을 absolute
,stick
나 top:0
등 다양한 옵션을 수정하고 바꿔도 될리가 없었다. 어떻게든 찾은 구글링을 통해 DOM API를 활용하는 해답을 얻게되었다.
보통 웹페이지 개발을 할 경우 x축
의 좌표보다는 y축
좌표를 주로 사용한다. 내 개인 프로젝트도 마찬가지고.. 스크롤을 내리면서 효과를 구현한다거나 Child
요소의 y좌표
를 구할 경우를 가정해보자.
width: 100%;
height: 200VH;
width:100%
, height: 200vh
의 사이즈의 페이지안에 각각의 크기의 두 요소가 존재하는데 DOM API가 제공하는 명령어를 통해 좌표를 알아볼 생각이다.
element.getBoundingClientRect()
: 뷰포트(Viewport)를 이루는 가장자리와 요소(element)와의 거리 정보를 가지고 있는 객체를 리턴하는 메소드이다. 반환하는 객체로는 top, bottom, left, right 프로퍼티가 존재하며 뷰포트와의 방향별 거리를 의미한다.
window.pageYOffset
: 수직 방향으로 얼마나 스크롤했는지 픽셀 단위로 알려주는 window
객체의 속성으로, window.scrollY
와 같은 값을 가진다.
이 예제는 React
와 styled-components
로 작성되어있어서 useRef()
및 useEffect()
를 활용하여 작성해봤다.
import React, { useEffect, useState } from "react";
import { Redirect } from "react-router-dom";
import { useRef } from "react";
import { Target, TargetBox, Test } from "./styles/styeldGames";
export default function Games() {
const parentElement = useRef(null);
const childElement = useRef(null);
const distancePeFromTop = () => {
let peTop = parentElement.current.getBoundingClientRect().top;
console.log("HTML시작점으로부터의 거리(부모요소의 TOP):", peTop);
};
const distancePeFromBottom = () => {
let peBTM = parentElement.current.getBoundingClientRect().bottom;
console.log("HTML시작점으로부터의 거리(부모요소의 Bottom):", peBTM);
};
const distanceChildFromTop = () => {
let chTop = childElement.current.getBoundingClientRect().top;
let peTop = parentElement.current.getBoundingClientRect().top;
console.log("부모요소와의 거리(각 요소의 TOP),", chTop - peTop);
};
const distanceChildFromBottom = () => {
let chBTM = childElement.current.getBoundingClientRect().bottom;
let peBTM = parentElement.current.getBoundingClientRect().bottom;
console.log("부모요소와의 거리(각 요소의 Bottom),", chBTM - peBTM);
};
const distanceFromHTML = () => {
let chTop =
childElement.current.getBoundingClientRect().top + window.pageYOffset;
console.log("뷰포트 시작점으로부터의 거리:", chTop);
};
useEffect(() => {
window.addEventListener("scroll", distancePeFromTop);
window.addEventListener("scroll", distancePeFromBottom);
window.addEventListener("scroll", distanceChildFromTop);
window.addEventListener("scroll", distanceChildFromBottom);
window.addEventListener("scroll", distanceFromHTML);
}, []);
return (
<Test>
<TargetBox ref={parentElement}>
나는 네모의 부모요소
<Target ref={childElement}>나는 네모</Target>
</TargetBox>
</Test>
);
}
이제 대충 작성은 되었으니 스크롤을 내릴 경우 console.log()
로 아래의 이미지와 같이 출력된다.
스크롤을 내림에 따라 뷰포트, 부모요소와의 거리를 픽셀단위로 콘솔에 찍히는 모습을 볼 수 있다.
결과적으로 보면 이렇게 된다.
ref:maxkim-j블로그