프론트엔드/Javascript 연습과제 해답

브라우저 창 사이즈와 스크롤

syleemomo 2024. 2. 25. 21:17
728x90

 

* 브라우저 창의 너비와 높이 - document.documentElement.clientWidth, document.documentElement.clientHeight

브라우저 창의 너비와 높이 구하기

 

console.log(document.documentElement.clientHeight)
console.log(document.documentElement.clientWidth)

현재 브라우저의 너비와 높이를 조회할 수 있다. 

 

* window 객체가 아닌 document.documentElement 를 사용하는 이유 

console.log( window.innerWidth ); // 전체 창 너비
console.log( document.documentElement.clientWidth ); // 스크롤바가 차지하는 영역을 제외한 창 너비

브라우저의 window 객체도 innerWidth 와 innerHeiht 프로퍼티를 이용하여 브라우저의 너비와 높이를 알 수 있다. 브라우저에 스크롤바가 있는 경우 document.documentElement 로 구한 브라우저의 사이즈는 스크롤바를 제외하고, 실제 컨텐츠가 포함되어 있는 영역만 계산한다. 하지만 window 의 innerWidth 와 innerHeight 프로퍼티는 스크롤바 영역을 포함한다. 브라우저 사이즈가 필요한 경우는 대부분 스크롤바를 제외한 영역에 뭔가를 위치시키거나 그리기 위함이므로 document.documentElement 를 사용하는 것이 좋다. 

 

* 문서 너비와 높이 

이론상 문서 전체 너비와 높이는 document.documentElement 의 scrollWidth 와 scrollHeight 프로퍼티를 사용하면 될 것이라고 생각한다. 왜냐하면 document.documentElement 는 문서의 루트요소에 상응하기 때문이고, 루트 요소에는 문서 전체의 컨텐츠가 전부 들어가기 때문이다. 하지만 크롬, 사파리, 오페라와 같은 브라우저에서 해당 값으로 문서 전체 너비나 높이를 구하면 예상한 대로 계산되지 않는다. 

const scrollHeight = Math.max(
  document.body.scrollHeight, document.documentElement.scrollHeight,
  document.body.offsetHeight, document.documentElement.offsetHeight,
  document.body.clientHeight, document.documentElement.clientHeight
)

console.log('스크롤에 의해 가려진 부분을 포함한 전체 문서의 높이: ' + scrollHeight)

정확한 문서 전체 높이를 구하려면 해당 코드를 사용하여 6가지 값중 최대값을 골라야 한다. 

 

* 스크롤바의 위치 정보 구하기 

브라우저의 스크롤 위치는 document.documentElement 의 scrollLeft 나 scrollTop 을 이용하여 구할 수 있다. 하지만 구버전 Webkit 을 기반으로 하는 브라우저에서는 버그로 인해 document.documentElement 가 아닌 document.body 를 사용해야 스크롤 위치를 구할 수 있다. 즉, 브라우저 호환성이 떨어진다. 

console.log('세로 스크롤에 의해 가려진 위쪽 영역 높이: ' + window.pageYOffset)
console.log('가로 스크롤에 의해 가려진 왼쪽 영역 너비: ' + window.pageXOffset)

window 객체의 pageYOffset, pageXOffset 을 사용하면 브라우저 상관없이 스크롤 위치정보를 구할수 있어서 브라우저마다 신경써주지 않아도 된다. 다만 pageYOffset, pageXOffset 값은 읽기전용이므로 변경할 수 없다. 

 

* scrollTo, scrollBy 로 스크롤 상태 변경하기 

요소의 스크롤 상태는 앞서 scrollTop 이나 scrollLeft 값을 변경하면 된다고 배웟다. 문서 전체의 스크롤 상태는 document.documentElement 의 scrollTop 이나 scrollLeft 를 사용하면 변경할 수 있다. 다만 사파리는 document.body 의 scrollTop 이나 scrollLeft 를 사용해야 한다. 하지만 이보다 편하고 브라우저 상관없이 사용할 수 있는 함수가 scrollBy(x,x)와 scrollTo(pageX, pageY) 이다. 

  <!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <div id="example">
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores vitae est temporibus mollitia consequatur adipisci at, laboriosam necessitatibus facere sit maxime, nemo placeat dolore consectetur suscipit dignissimos ullam, exercitationem quo!
      Dolorum ipsum libero illum in. Consequuntur repellat ab nostrum consectetur. Repudiandae veniam eaque pariatur! Perspiciatis totam fugit natus repellendus dolor quae quis animi voluptatum. Qui dicta ab ipsam ex veniam!
      Aliquam neque vel amet libero harum cupiditate eaque, quasi eligendi sed? Ea, quisquam voluptatem vel eaque provident est minus vitae officia? Eligendi sequi assumenda nam unde molestiae provident quaerat quisquam!
    </div>
    <button>요소의 높이 키우기</button>
    <script src="app.js"></script>
  </body>
  </html>
#example {
  width: 300px;
  height: 200px;
  border: 25px solid #E8C48F;
  padding: 20px;
  overflow: auto;
}
const example = document.getElementById('example')
const button = document.querySelector('button')

function scroll(){
  example.scrollBy(0, 50)
}

button.addEventListener('click', scroll)

scrollBy(x, y) 메서드는 문서의 스크롤 상태를 현재 스크롤 위치를 기준으로 상대적으로 조정한다. 예를 들어 scrollBy(0, 50)은 현재 스크롤바 위치를 기준으로 50px 만큼 아래로 스크롤한다. 

const example = document.getElementById('example')
const button = document.querySelector('button')

function scroll(){
  example.scrollTo(0, 0)
}

button.addEventListener('click', scroll)

scrollTo(pageX, pageY) 메서드는 절대좌표를 기준으로 문서의 스크롤 상태를 변경한다. 문서의 좌측상단 꼭지점을 기준으로 pageX, pageY만큼 떨어진 위치로 스크롤한다. 마치 scrollLeft 나 scrollTop 값을 변경한것처럼 말이다. 예를 들어 scrollTo(0, 0)은 요소의 스크롤 위치를 초기화한다. 

 

* scrollIntoView 로 스크롤 상태 변경하기 

요소의 scrollIntoView 메서드는 전체 문서를 스크롤해서 해당 요소를 브라우저 화면에 보이도록 한다. scrollIntoView 메서드는 인자를 전달받는데 인자에 따라 다르게 동작한다. 만약 top 이 true 로 설정되면 해당 요소가 브라우저 상단으로 스크롤한다. 정확히 말하면 해당 요소의 위쪽 모서리가 브라우저의 위쪽 모서리에 닿도록 스크롤한다. 만약 top 이 false 이면 해당 요소가 브라우저 하단으로 스크롤한다. 정확히 말하면 해당 요소의 아래쪽 모서리가 브라우저의 아래쪽 모서리에 닿을때까지 스크롤한다. 

  <!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <div id="example">
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores vitae est temporibus mollitia consequatur adipisci at, laboriosam necessitatibus facere sit maxime, nemo placeat dolore consectetur suscipit dignissimos ullam, exercitationem quo!
      Dolorum ipsum libero illum in. Consequuntur repellat ab nostrum consectetur. Repudiandae veniam eaque pariatur! Perspiciatis totam fugit natus repellendus dolor quae quis animi voluptatum. Qui dicta ab ipsam ex veniam!
      Aliquam neque vel amet libero harum cupiditate eaque, quasi eligendi sed? Ea, quisquam voluptatem vel eaque provident est minus vitae officia? Eligendi sequi assumenda nam unde molestiae provident quaerat quisquam!
    </div>
    <button>스크롤하기</button>
    <script src="app.js"></script>
  </body>
  </html>
body{
  height: 200vh;
}
#example {
  width: 300px;
  height: 200px;
  border: 25px solid #E8C48F;
  padding: 20px;
  overflow: hidden;
}
const example = document.getElementById('example')
const button = document.querySelector('button')

function scroll(){
  console.log('스크롤')
  button.scrollIntoView(true)
}

button.addEventListener('click', scroll)

해당 코드는 버튼을 클릭할때 버튼을 브라우저 상단으로 스크롤한다. 

 

* 스크롤 방지하기 

때에 따라 문서가 스크롤되지 못하게 막아야 하는 경우가 있을수 있다. 가장 대표적인 예가 모달창이나 팝업창을 띄운 상황이다. 이때는 사용자가 모달창에 집중할 수 있도록 뒤쪽에 있는 문서가 스크롤되지 못하도록 고정하는 것이 좋다. 

  <!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <div id="example">
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores vitae est temporibus mollitia consequatur adipisci at, laboriosam necessitatibus facere sit maxime, nemo placeat dolore consectetur suscipit dignissimos ullam, exercitationem quo!
      Dolorum ipsum libero illum in. Consequuntur repellat ab nostrum consectetur. Repudiandae veniam eaque pariatur! Perspiciatis totam fugit natus repellendus dolor quae quis animi voluptatum. Qui dicta ab ipsam ex veniam!
      Aliquam neque vel amet libero harum cupiditate eaque, quasi eligendi sed? Ea, quisquam voluptatem vel eaque provident est minus vitae officia? Eligendi sequi assumenda nam unde molestiae provident quaerat quisquam!
    </div>
    <button class="fix-scrollbar">스크롤 고정하기</button>
    <button class="move-scrollbar">스크롤 이동하기</button>
    <script src="app.js"></script>
  </body>
  </html>
body{
  height: 200vh;
}
#example {
  width: 300px;
  height: 200px;
  border: 25px solid #E8C48F;
  padding: 20px;
  overflow: hidden;
}
const fixScrollbar = document.querySelector('.fix-scrollbar')
const moveScrollbar = document.querySelector('.move-scrollbar')

function fixScroll(){
  document.body.style.overflow = "hidden"
}
function moveScroll(){
  document.body.style.overflow = ""
}

fixScrollbar.addEventListener('click', fixScroll)
moveScrollbar.addEventListener('click', moveScroll)

해당 코드를 작성하여 스크롤을 고정하거나 해제해보자! 해당 방법은 document.body 뿐만 아니라 다른 요소의 스크롤을 고정시킬때 사용할 수 있다. 

해당 방법은 한가지 문제점이 존재한다. 스크롤바는 일정공간을 차지하는데 스크롤바가 사라지면 해당 공간을 채우기 위하여 컨텐츠가 갑자기 움직이면서 레이아웃이 깨질 수 있다. 이렇게 스크롤바가 사라지면 사용자 입장에서는 이상하게 볼 수 있기 때문에 개발자는 스크롤바가 사라지기 전후의 cilentWidth 값을 비교해서 스크롤바의 너비만큼 패딩이나 마진을 적용해서 레이아웃이 깨지지 않도록 하는 것이 좋다. 

 

* 연습과제 1

모달창 기능을 구현해보자! 웹 화면이 처음 로딩되면 스크롤바는 존재하고, 배경사진만 보인다. 로딩후 1초가 지나면 아래와 같이 모달창이 화면에 나타나면서 스크롤바는 사라진다. 물론 배경화면은 살짝 검은색으로 블러처리된다. 모달창에서 확인이나 취소 버튼을 클릭하면 모달창이 사라지고, 다시 처음 로딩화면으로 되돌아간다. 

웹화면 초기화면
모달창이 열린 화면

 

* 연습과제 2

웹 화면에 리스트 목록이 아래와 같이 한 행에 2개씩 배치되어 있다. 그리고 웹 화면의 우측하단에 버튼이 fixed 로 고정되어 있다. 여기서 다음 버튼을 클릭하면 2번째 행에 배치된 2개의 아이템의 상단 모서리가 브라우저 상단 모서리로 이동하고, 다음 버튼을 한번더 클릭하면 3번째 행에 배치된 2개의 아이템의 상단 모서리가 브라우저 상단 모서리로 이동한다. 

이런 식으로 다음 버튼을 클릭하면 다음 행이 브라우저 상단으로 스크롤되고, 이전 버튼을 클릭하면 이전 행이 브라우저 상단으로 스크롤되어 보여진다. 단, 더이상 이동할 행이 없으면 스크롤되지 않도록 한다. 

스크롤전 화면
스크롤시 화면

728x90