티스토리 뷰

이 포스팅은 tistory 스킨 #1을 기준으로 작성된 것입니다.

계기

현재 Tistory에서 제공하는 #1 스킨을 사용중입니다.

평소 모니터를 3대를 사용중인데 이 스킨을 사용하면서 피벗 모니터에서 블로그 글을 보았을 때는 세로가 길어 가독성이 괜찮아 보였다가 반대로 피벗이 아닌 평범한 16:9 비율의 환경에서 글을 보았을 때 글의 내용이 상단바에 가려져 가독성이 좋지 않아 글을 읽기가 불편한 것 같다라는 생각을 하게 되었습니다.

'글을 읽을 경우 상단바를 없애면 읽기 편하지 않을까?' 라는 호기심에 이 기능을 만들어보게 되었습니다. :)

github 저장소는 아래에 있습니다! :)

sukvvon/tistory-top-bar-visible

css

.hidden {
  animation: hide 0.1s linear forwards;
}

@keyframes hide {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
    visibility: hidden;
  }
}

.shown {
  animation: show 0.1s linear forwards;
}

@keyframes show {
  from {
    visibility: hidden;
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.hidden, .shown

.hidden {
  animation: hide 0.1s linear forwards;
}

.shown {
  animation: show 0.1s linear forwards;
}

숨김과 보임을 의미하는 hiddenshown 으로 class 이름을 지었습니다.

animation을 활용하였습니다. hidden에서는 hide라는 이름의 애니메이션을, shown에서는 show라는 이름의 애니메이션 효과를 주고,

hiddenshown에서 animation-duration은 0.1초로 설정하여 0.1초동안 애니메이션이 실행되도록 하고, animation-timing-funcionlinear로 설정하여 균일한 속도로 진행되게 하며, animation-fill-modeforwards로 설정하여 실행 된 애니메이션의 마지막 @keyframes에 의해 설정된 계산 된 값을 유지하도록 합니다.

@keyframe hide and show

@keyframes hide {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
    visibility: hidden;
  }
}

@keyframes show {
  from {
    visibility: hidden;
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes hide

@keyframes hide에서 전형적인 오프셋 fromto를 기준으로 opacity: 1로부터 opacity: 0visibiliy: hidden 속성으로 가게끔 하여,

opacity 즉 요소의 불투명도를 1에서 0으로 하여 완전히 불투명하였다가 완전히 투명하도록 하고,

visibility 즉 요소의 보임을 hidden 즉 숨겨지게 하여 opacity에 의해서 투명해졌지만 물리적으로 존재했던 요소를 숨김처리를 하여 물리적으로 존재하지 않고 레이아웃 상으로만 존재하게 합니다.

@keyframes show

@keyframes show에서는 @keyframes hide와 반대가 되도록 합니다.

js

const HIDDEN_CLASSNAME = "hidden";
const SHOWN_CLASSNAME = "shown";

const dkHead = document.getElementById("dkHead");
const areaMenu = document.querySelector(".area_menu");
const areaTitle = document.querySelector(".area_title");

let beforeScrollY = [];

const handleTopBar = (useClassName, unuseClassName) => {
  dkHead.classList.add(useClassName);
  dkHead.classList.remove(unuseClassName);
  areaMenu.classList.add(useClassName);
  areaMenu.classList.remove(unuseClassName);
};

window.addEventListener("scroll", () => {
  if (window.scrollY > areaTitle.offsetHeight) {
    if (beforeScrollY.pop() < window.scrollY) {
      handleTopBar(HIDDEN_CLASSNAME, SHOWN_CLASSNAME);
    } else {
      handleTopBar(SHOWN_CLASSNAME, HIDDEN_CLASSNAME);
    }
    beforeScrollY.push(window.scrollY);
  }
});

자주 쓰이는 변수 선언

const HIDDEN_CLASSNAME = "hidden";
const SHOWN_CLASSNAME = "shown";

2번 이상 쓰이는 String은 오타가 날 수 있기 때문에 변수 선언을 꼭 해주는 편입니다.

class의 역활을 가지고 있는 "hidden", "shown"HIDDEN_CLASSNAMESHOWN_CLASSNAME으로 대문자만으로 이름을 지어 변수를 선언해줍니다.

id 혹은 class 요소를 찾아 변수 선언

const dkHead = document.getElementById("dkHead");
const areaMenu = document.querySelector(".area_menu");
const areaTitle = document.querySelector(".area_title");

dkHead

const dkHead = document.getElementById("dkHead");

getElementById 메서드를 활용하여 상단바 전체를 의미하는 id 속성을 가진 요소 #dkHead를 찾아서 호출한 후 dkHead로 변수를 선언합니다.

areaMenu

const areaMenu = document.querySelector(".area_menu");

querySelector 메서드를 활용하여 상단바 전체를 의미하는 dkHead와 달리 상단바에 독립적으로 위치한 요소인 .area_menu를 호출한 후 areaMenu로 변수를 선언합니다.

areaTitle

const areaTitle = document.querySelector(".area_title");

querySelector 메서드를 활용하여
글의 제목을 의미하지만 여기서는 상단바를 숨기는 기준이 되는 요소인 .area_title을 호출한 후 areaTitle로 변수를 선언합니다.

handleTopBar()

const handleTopBar = (useClassName, unuseClassName) => {
  dkHead.classList.add(useClassName);
  dkHead.classList.remove(unuseClassName);
  areaMenu.classList.add(useClassName);
  areaMenu.classList.remove(unuseClassName);
};

상단바를 숨기고 보이게 하는 함수입니다.

추가하여 사용할 예정이라는 의미인 useClassName, 삭제하여 사용하지 않을 예정이라는 의미인 unuseClassName 라고 이름지은 두 개의 매개변수를 포함하는 함수로 구성합니다.

handelTopBar 함수가 실행되면 classList가 사용되며 addremove를 통해 dkHeadareaMenu의 class 목록에서 useClassName을 추가하고 unuseClassName를 삭제시킵니다.

beforeScrollY

let beforeScrollY = [];

언제든 새로운 값이 들어올 수 있도록 const가 아닌 let으로 이전의 window.scrollY 값을 받는다는 뜻의 beforeScrollY로 배열을 선언합니다.

addEventListener("scroll", () => {})

window.addEventListener("scroll", () => {
  if (window.scrollY > areaTitle.offsetHeight) {
    if (beforeScrollY.pop() < window.scrollY) {
      handleTopBar(HIDDEN_CLASSNAME, SHOWN_CLASSNAME);
    } else {
      handleTopBar(SHOWN_CLASSNAME, HIDDEN_CLASSNAME);
    }
    beforeScrollY.push(window.scrollY);
  }
});

addEventListener()

addEventListener()을 통해 scroll이벤트가 발생할 경우 화살표 함수가 실행되도록 합니다.

if else

window.scrollYareaTitle.offsetHeight보다 클 경우 즉 화면 전체의 세로 방향으로 스크롤된 값이 전체 글의 제목 높이보다 크다는 조건에서

beforeScrollY.pop()window.scrollY 보다 작을 경우 즉 페이지가 아래로 스크롤 되면서 beforeScrollY 배열의 마지막 값이 화면 전체의 높이보다 작을 경우 handleTopBar(HIDDEN_CLASSNAME, SHOWN_CLASSNAME) 함수가 실행되며 상단바를 보이지 않게 하고

아닐 경우 즉 반대로 페이지가 위로 스크롤 되면서 beforeScrollY 배열의 마지막 값이 화면 전체의 높이보다 클 경우 handleTopBar(SHOWN_CLASSNAME, HIDDEN_CLASSNAME) 함수가 실행되며 상단바를 보이게 합니다.

push()

위의 과정이 끝난 후 beforeScrollY.push(window.scrollY) 로 인하여 조건문에서 사용되었던 window.scrollY 값이 beforeScrollY 배열에 추가됩니다.

그리고 scroll 이벤트가 발생될 때마다 모든 과정이 반복됩니다.

'JavaScript' 카테고리의 다른 글

Tistory(#1) theme toggle 구현기  (0) 2022.02.22
댓글