JavaScript - Element Sizes & Scrolling

Noma·2021년 1월 28일
0

* 이 글은 javascript.info 자료를 정리한 내용이다.

자바스크립트는 요소의 너비, 높이와 같은 기하 정보를 알려주는 다양한 프로퍼티를 지원한다. 이런 프로퍼티들은 요소를 움직이거나 특정 좌표에 위치시킬 때 사용된다.

📜 샘플 요소

프로퍼티 사용법을 알아보기 위해 아래와 같은 샘플 요소를 사용할 예정이다.

<div id="example">
  ...텍스트...
</div>
<style>
  #example {
    width: 300px;
    height: 200px;
    border: 25px solid #E8C48F;
    padding: 20px;
    overflow: auto;
  }
</style>

example이라는 id가 붙은 이 요소는 border와 padding, 스크롤바 갖는다.

❗ margin은 요소 자체에 포함되지 않고, 관련 특수 프로퍼티가 없다.

샘플 요소의 생김새는 다음과 같다.

❗ 참고
몇몇 브라우저는 스크롤바를 콘텐츠 영역 너비(content width)의 일부를 빌려 위치시킨다. 즉, 원래 300px이어야 할 너비가 스크롤바(16px) 때문에 284px이 된다.

❗ 참고
padding-bottom영역으로 텍스트가 넘칠 수 있다. 대게 비어있으나 요소 내 텍스트가 넘치게 될 경우 브라우저가 이 텍스트들을 padding-bottom에도 표시하게 된다. (정상임)

기하(geometry) 프로퍼티

그림으로 나타내면 다음과 같다. 기하 프로퍼티 값은 숫자이며 단위는 픽셀이다.

요약을 먼저 보자면 다음과 같다.

  • offsetParent

    : 위치 계산에 사용되는 가장 가까운 조상 요소나 td, th, table, body

  • offsetLeft와 offsetTop

    : offsetParent 기준으로 요소가 각각 오른쪽, 아래쪽으로 얼마나 떨어져 있는지를 나타내는 값

  • offsetWidth와 offsetHeight

    : 테두리를 포함 요소 '전체’가 차지하는 너비와 높이

  • clientLeft와 clientTop

    : 요소 제일 밖을 감싸는 영역과 요소 안(콘텐츠 + 패딩)을 감싸는 영역 사이의 거리를 나타냄. 대부분의 경우 왼쪽, 위쪽 테두리 두께와 일치하지만, 오른쪽에서 왼쪽으로 글을 쓰는 언어가 세팅된 OS에선 clientLeft에 스크롤바 두께가 포함됨

  • clientWidth와 clientHeight

    : 콘텐츠와 패딩을 포함한 영역의 너비와 높이로, 스크롤바는 포함되지 않음

  • scrollWidth와 scrollHeight

    : clientWidth, clientHeight 같이 콘텐츠와 패딩을 포함한 영역의 너비와 높이를 나타내는데, 스크롤바에 의해 숨겨진 콘텐츠 영역까지 포함됨

  • scrollLeft와 scrollTop

    : 스크롤바가 오른쪽, 아래로 움직임에 따라 가려지게 되는 요소 콘텐츠의 너비와 높이

스크롤바를 움직일 수 있게 해주는 scrollLeftscrollTop을 제외한 모든 프로퍼티는 읽기 전용이다.

1.1 offsetParent와 offsetLeft, offsetTop

(잘 쓰이는 프로퍼티는 아님)
offset은 요소가 화면에서 차지하는 영역 전체 크기를 나타낸다.

1. offsetParent

가장 가까운 조상 요소(position:static이 아닌)의 참조를 반환한다.
위 조건의 요소가 없으면, 아래 중 하나를 반환

  • <td>나 <th>, 혹은 <table>
  • <body>

2. offsetLeft, offsetTop

offsetParent 기준으로 각각 요소가 오른쪽으로, 아래쪽으로 얼마나 떨어져 있는지를 나타낸다.

아래 예제를 보자.

<main style="position: relative" id="main">
  <article>
    <div id="example" style="position: absolute; left: 180px; top: 180px">...</div>
  </article>
</main>
<script>
  alert(example.offsetParent.id); // main
  alert(example.offsetLeft); // 180
  alert(example.offsetTop); // 180
</script>

❗ 다음과 같은 요소의 offsetParentnull이다.
1. 화면에 보이지 않는 요소(diplay:none이거나 문서 내에 없는 요소)
2. <body><html>
3. position: fixed인 요소

1.2 offsetWidth와 offsetHeight

각각 요소 '전체(테두리 포함)'가 차지하는 너비와 높이 정보를 제공한다.

❗ 참고

요소(혹은 이 요소의 조상 요소 중 어떤 것이든)의 display:none이거나 문서 내에 해당 요소가 없는 경우,
모든 기하 프로퍼티 값은 0, offsetParentnull이 된다.

이런 특징을 이용하면 요소의 숨김 상태 여부를 아래와 같은 방법을 이용해 확인할 수 있다.

function isHidden(elem){
	return !elem.offsetWidth&&!elem.offsetHeight;
}

화면에 요소가 있긴 하지만 사이즈가 0일 때(비어있는 <div>등)도 true를 반환하므로 주의해서 사용하자.

2.1 clientTop과 clientLeft

요소 내엔 테두리가 있다. 테두리 두께는 clientTopclientLeft를 사용해 측정할 수 있다.

사실 정확히는, 테두리 바깥쪽을 기준으로 요소 안쪽의 상대 좌표를 나타내서 운영 체제 언어가 아랍어나 히브리어처럼 오른쪽에서 왼쪽으로 글이 전개되는 언어로 세팅되어 있을 때는 차이가 생긴다.

이때는 스크롤바가 오른쪽이 아닌 왼쪽에 나타나게 되서 clientLeft에 스크롤바의 너비가 포함된다.

2.2 clientWidth와 clientHeight

테두리(border) 안에 있는 영역의 사이즈를 나타낸다.
콘텐츠 너비엔 패딩은 포함되고 스크롤바는 포함되지 않는다.

clientWidth를 계산할 때 주의할 점은 수직 스크롤바가 차지하는 너비 16px 때문에 콘텐츠 너비는 300px이 아닌 284px이 된다는 점이다.

패딩이 없으면, clientWidthclientHeight는 테두리와 스크롤바 안쪽에 있는 콘텐츠 영역의 너비, 높이와 정확히 일치한다.

따라서 패딩이 없는 경우엔 clientWidthclientHeight를 사용해 콘텐츠 영역 크기를 구할 수 있다.

3.1 scrollWidth와 scrollHeight

clientWidthclientHeight와 유사한데, 스크롤에 의해 감춰진 영역도 포함한다는 점에서 차이가 있다.

scrollWidthscrollHeight는 아래와 같이, 요소 크기를 콘텐츠가 차지하는 만큼 늘리고자 할 때 사용할 수 있다.

// 콘텐츠가 차지하는 높이만큼 요소 높이를 늘려준다.
element.style.height = `${element.scrollHeight}px`;

3.2 scrollLeft와 scrollTop

수평 스크롤이 오른쪽, 수직 스크롤이 아래로 움직임에 따라 가려진 영역의 너비와 높이를 나타낸다.

❗ 대부분의 기하 프로퍼티는 읽기 전용이지만 scrollLeftscrollTop은 변경이 가능하다.

스크립트를 사용해 프로퍼티를 수정하면 자동으로 요소 내 스크롤이 움직인다. 이런 특징을 이용하면 scrollTop을 0이나 1e9같이 아주 큰 숫자로 설정해 스크롤 바를 최상단이나 최하단으로 옮길 수 있다.

4. Don't use getComputedStyle

getComputedStyle를 사용해 CSS가 적용된 요소의 높이와 너비를 구할 수 있다. 하지만 기하 프로퍼티를 사용해 너비와 높이 정보를 얻어야 하는 이유가 있다.

  1. CSS width와 height는 다른 CSS 프로퍼티의 영향을 받는다. 요소의 너비와 높이 계산 방법을 '지정’하는 box-sizing이 이런 프로퍼티의 대표적인 예이다. 따라서 box-sizing을 변경하면 getComputedStyle로 구한 값이 부정확해 질 수 있다.

  2. CSS width와 height는 auto일 수 있다. 인라인 요소(inline element)가 이런 경우에 속한다. 자바스크립트 입장에선 정확한 px값이 있어야 계산을 할 수 있기 때문에 auto라는 값은 쓸모가 없다.

<span id="elem">안녕하세요!</span>

<script>
  alert( getComputedStyle(elem).width ); // auto
</script>

이 외에도 스크롤바 문제가 있다. getComputedStyle(elem).width를 사용하면, Chrome 같은 브라우저는 스크롤바 너비를 제외한 진짜 내부 너비를 반환하는데 (Windows 이외의 OS가 설치된 PC의)Firefox 에서는 스크롤바를 무시하고 CSS로 설정한 너비를 반환한다.

따라서, 이러한 이유로 getComputedStyle이 아닌 기하 프로퍼티를 사용해야 한다.

getComputedStyle과 기하 프로퍼티의 차이는 자바스크립트를 사용해 getComputedStyle(...).width로 값을 얻고자 할 때만 발생한다. 눈으로 봤을 땐 전혀 문제가 없으니 이 점에 유의하자.

❗ 출처
https://ko.javascript.info/size-and-scroll#ref-661

profile
Frontend Web/App Engineer

0개의 댓글