코딩 일기

[TeamProject] 야놀자 홈페이지 팀프로젝트 작업 일기

FRDYtheme 2022. 12. 27. 17:02

처음 야놀자 홈페이지를 봤을 때 솔직히 이 정도로 오래 걸릴 거라고 생각하지 못했다.

이 모션에는 이런 코드를 쓰고 저 모션에는 저런 코드를 쓰면 되겠다고 쉽게 생각했는데

 

바디의 높이나, 콘텐츠의 레이아웃을 유지하면서 스크롤 이벤트를 적용하는 일은 HTML구조를 여러 번 수정하게 만들었고

overflow와 transition으로 만들면 되겠다고 생각한 페이지 전환 효과는 거의 이틀의 시간을 잡아먹었다.

단순한 화살표 애니메이션조차 디테일하게 구현하는 데에 애를 먹었기에 패스로 일일이 작업된 애니메이션들은 사실상 포기했었다.

 

하지만 시작이 어려웠던만큼 하나씩 차근차근 해나가는 과정에서 전혀 몰랐던 기능들도 알게 됐고 결국 해냈을 때는 약간의 쾌감도 느꼈던 것 같다.

 

또 팀원들과 공유하고 고민하며 완성도를 높이는 일이 작업하는 데 큰 원동력이 되었고 스스로 공부하는 데도 많은 도움이 됐다. 모두 각자 맡은 바 열심히 하면서 원활한 의사소통으로 큰 트러블 없이 프로젝트를 진행할 수 있어서 스스로에게도 값진 경험이 된 작업이었다. 

 

 

작업한 파트

  • ESG 페이지 작업
  • 코딩 컨벤션 및 github 워크플로우 작성
  • 웹페이지 공통 요소 (푸터, 페이지 전환 효과, TOP버튼 등) 작업
  • github 관리

 

 

Global R.E.S.T. Platform

야놀자는 누구나 마음 편히 놀 수 있게 여가의 패러다임을 전환합니다

3teamidkjs.github.io

 

 


 

 

조악하지만 처음으로 한 땀 한 땀 직접 작성한 자바스크립트 코드들이기에

팀 프로젝트 작업을 하며 사용한 코드들에 대해 정리해보려 한다.

 

일러스트 애니메이션

    일러스트로 작업한 파일을 svg로 저장했고 HTML에는 코드가 너무 지저분하게 보이지 않게 인라인이 아닌 object로 넣었다.

페이지 css가 이미 복잡했기 때문에 제어를 위한 css는 svg파일 내부에

<?xml-stylesheet type=”text/css”>로 외부 링크를 걸어 새로운 파일로 작업했다.

 

일러스트 작업할 때부터 id가 될 레이어 이름들을 수정해줬고 간단한 움직임만 사용하면 됐기 때문에

animation과 transform: rotate(), translate() 등을 사용했다.

 

object로 연결한 svg 노드를 검색하는데 인터넷에서 찾은 코드대로 작성했는데 계속 오류가 났다.찾아보니 DOM 구조를 찾지 못해 오류가 나는 것 같아서 window.onload 안에 코드들을 작성해줬다.

 

그렇게 잘 진행하다가 일러스트 패스를 회전해야하는데 레이어가 생각한 기준점으로 움직이지 않았다.

기준점을 바꾸기 위해 transform-origin으로 계속 새로고침을하면서 맞췄다.

굉장히 번거로운 작업이어서 효과적인 방법을 찾다가 로티 애니메이션을 알게 되었는데 추후 작업에는 공부해서 적용해보고 싶다.

 

window.onload = function () {
  // svg 태그 노드 검색
  const svgObjs = document.querySelectorAll("main .imgMask object");
  // svg의 내부 노드를 탐색하기 위한 속성을 적용해 새로운 배열로 전달.
  const svgDocs = [];
  svgObjs.forEach((svg) => {
    svgDocs.push(svg.contentDocument);
  });

  // 애니메이션을 적용할 요소들 탐색 후 선언
  const frontTree = svgDocs[0].getElementById("frontTree");
  const people = svgDocs[1].getElementById("peoples");
  const talking = svgDocs[2].getElementById("article3");
  // 애니메이션 스타트 기준이 될 스크롤값.
  const topLine = articles[0].offsetTop - 200;

  addEventListener("scroll", () => {
    scrollY > topLine ? frontTree.classList.add("svgControl") : false;
    scrollY > topLine * 2 ? people.classList.add("svgControl") : false;
    scrollY > topLine * 3 + 530 ? talking.classList.add("svgControl") : false;
  });
};

 


 

페이지 전환 효과

    처음에는 overflow , border-radius, transition으로 마스크 역할을 하는 레이어를 만들어서 작업했는데 기존 사이트와 움직임이 달라서 포기하고 방법을 찾다가 clip-path를 찾아냈다.

속성 중에 circle을 사용했는데 배경이 정사각형이 아니라서 움직임이 너무 달랐고,

직사각형으로 마스크를 제어할 수 있는 inset을 사용해 기존 웹사이트처럼 커지게 값을 맞춰줬다.

 

기존 배경은 브라우저 높이를 넘고 원에서 커지는 효과는 100vh에 맞춰져 있어서

setTimeout을 사용해서 마스크가 먼저 커지고 후에 풀사이즈의 배경이 나타나게 시간차를 줬다.

 

addEventListener("DOMContentLoaded") 를 사용했는데 사실 그냥 함수를 호출해도 동작에는 문제가 없지만 배운 걸 써먹어 보고 싶었다.

 

const pageLoad = () => {
  const clipImg = document.querySelector(".clipImg");
  const bgMask = document.querySelector(".bgMask");
  const bgTxt = document.querySelector(".menuWrapper .bgTxt");

  const bgEnd = () => (bgMask.style.clipPath = "inset(0% 0% 0% 0% round 0)");
  const bgScaleUp = () => (clipImg.style.transform = "scale(1)");
  const bgLoad = () => (bgBox.style.clipPath = "inset(0% 0% 0% 0%)");
  const bgOut = () => (bgMask.style.display = "none");
  const menuDown = () => (menu.style.top = 0);
  const txtUp = () => {
    bgTxt.classList.add("txtUp");
  };

  menu.style.top = `-${menu.offsetHeight}px`;

  setTimeout(() => {
    bgEnd();
    bgScaleUp();
    setTimeout(() => {
      txtUp();
      setTimeout(() => {
        bgLoad();
        menuDown();
        setTimeout(() => {
          bgOut();
        }, 1250);
      }, 250);
    }, 700);
  }, 500);
};
addEventListener("DOMContentLoaded", pageLoad);

 


 

스크롤 따라 움직이는 컨텐츠

    addEventListener(‘scroll’, 함수) 사용

하나의 세트가 되는 컨텐츠를 감싼 mainArticle을 기준으로 스크롤 값을 계산해서

이미지를 감싼 콘테이너를  style.top으로 조정했다.

값이 음수로 넘어가면 position:absolute가 적용되어 있어서 계속 올라가기 때문에

Math.max(값, 0)를 사용해 컨테이너 천장에 닿으면 멈추게 만들었다.

 

const followBox = () => {
  const imgBoxes = document.querySelectorAll(".mainArticle .followContainer");
  const imgCircle = document.querySelectorAll(".mainArticle .imgCircle");
  
  imgBoxes.forEach((box, idx) => {
    const getHt = (articles[idx].offsetTop - scrollY) / 4;
    box.style.top = `${Math.max(getHt, 0)}px`;
  });
  
  imgCircle.forEach((circle, idx) => {
    const getHt = (articles[idx].offsetTop - scrollY) / 2.5;
    circle.style.top = `${Math.max(getHt, 0)}px`;
  });
};
addEventListener("scroll", followBox);

 


 

Top 버튼

    top버튼 내부의 화살표 움직임은 css animation 속성을 사용했고 최상단 배경이미지를 넘어가면 화살표가 변하는 건  addEventListener(‘scroll’)을 사용했다.

scrollY가 배경이미지 높이를 넘겼는지를 boolean값으로 받을 수 있게 if 조건문에 classList.add와 classList.remove를 작성했고 class가 추가되면 버튼이 변할 수 있게 style css를 작성했다.

 

function changeBtn() {
  scrollY > 190
  ? topBtn.classList.add("scrolled")
  : topBtn.classList.remove("scrolled");
}
addEventListener("scroll", changeBtn);

topBtn.addEventListener("click", (e) => {
  e.preventDefault();
  scrollTo({
    top: 0,
    behavior: "smooth",
  });
});

 


 

로고 인트로

   css 스타일에 letter-spacing으로 자간을 조정하고 자바스크립트로 폰트 사이즈와 opacity를 조정해 사라진 후에

display: none으로 아예 삭제될 수 있게 setTimeOut으로 시간차를 줬다.

body에 overflowY 값을 줘서 스크롤을 없애고 로딩 이벤트가 사라지면 보일 수 있게 작성했다.

 

const introPlay = () => {
  const intro = document.querySelector(".introLogo");
  const introTxt = document.querySelector(".introLogo p");
  document.body.style.overflowY = 'hidden'
  intro.classList.add("play");
  setTimeout(function () {
    introTxt.style.fontSize = "20em";
    introTxt.style.opacity = "0";
    setTimeout(function() {
      intro.style.display = 'none'
      introTxt.style.display = 'none'
      document.body.style.overflowY = 'scroll'
    }, 1000)
  }, 1000);
};
addEventListener("DOMContentLoaded", introPlay);