* 이 글은 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
에도 표시하게 된다. (정상임)
그림으로 나타내면 다음과 같다. 기하 프로퍼티 값은 숫자이며 단위는 픽셀이다.
요약을 먼저 보자면 다음과 같다.
offsetParent
: 위치 계산에 사용되는 가장 가까운 조상 요소나 td, th, table, body
offsetLeft와 offsetTop
: offsetParent 기준으로 요소가 각각 오른쪽, 아래쪽으로 얼마나 떨어져 있는지를 나타내는 값
offsetWidth와 offsetHeight
: 테두리를 포함 요소 '전체’가 차지하는 너비와 높이
clientLeft와 clientTop
: 요소 제일 밖을 감싸는 영역과 요소 안(콘텐츠 + 패딩)을 감싸는 영역 사이의 거리를 나타냄. 대부분의 경우 왼쪽, 위쪽 테두리 두께와 일치하지만, 오른쪽에서 왼쪽으로 글을 쓰는 언어가 세팅된 OS에선 clientLeft
에 스크롤바 두께가 포함됨
clientWidth와 clientHeight
: 콘텐츠와 패딩을 포함한 영역의 너비와 높이로, 스크롤바는 포함되지 않음
scrollWidth와 scrollHeight
: clientWidth, clientHeight
같이 콘텐츠와 패딩을 포함한 영역의 너비와 높이를 나타내는데, 스크롤바에 의해 숨겨진 콘텐츠 영역까지 포함됨
scrollLeft와 scrollTop
: 스크롤바가 오른쪽, 아래로 움직임에 따라 가려지게 되는 요소 콘텐츠의 너비와 높이
스크롤바를 움직일 수 있게 해주는
scrollLeft
와scrollTop
을 제외한 모든 프로퍼티는 읽기 전용이다.
(잘 쓰이는 프로퍼티는 아님)
offset은 요소가 화면에서 차지하는 영역 전체 크기를 나타낸다.
가장 가까운 조상 요소(position:static
이 아닌)의 참조를 반환한다.
위 조건의 요소가 없으면, 아래 중 하나를 반환
<td>나 <th>, 혹은 <table>
<body>
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>
❗ 다음과 같은 요소의
offsetParent
는null
이다.
1. 화면에 보이지 않는 요소(diplay:none
이거나 문서 내에 없는 요소)
2.<body>
와<html>
3.position: fixed
인 요소
각각 요소 '전체(테두리 포함)'가 차지하는 너비와 높이 정보를 제공한다.
❗ 참고
요소(혹은 이 요소의 조상 요소 중 어떤 것이든)의
display:none
이거나 문서 내에 해당 요소가 없는 경우,
모든 기하 프로퍼티 값은 0,offsetParent
는null
이 된다.이런 특징을 이용하면 요소의 숨김 상태 여부를 아래와 같은 방법을 이용해 확인할 수 있다.
function isHidden(elem){ return !elem.offsetWidth&&!elem.offsetHeight; }
화면에 요소가 있긴 하지만 사이즈가 0일 때(비어있는
<div>
등)도true
를 반환하므로 주의해서 사용하자.
요소 내엔 테두리가 있다. 테두리 두께는 clientTop
과 clientLeft
를 사용해 측정할 수 있다.
사실 정확히는, 테두리 바깥쪽을 기준으로 요소 안쪽의 상대 좌표를 나타내서 운영 체제 언어가 아랍어나 히브리어처럼 오른쪽에서 왼쪽으로 글이 전개되는 언어로 세팅되어 있을 때는 차이가 생긴다.
이때는 스크롤바가 오른쪽이 아닌 왼쪽에 나타나게 되서 clientLeft
에 스크롤바의 너비가 포함된다.
테두리(border) 안에 있는 영역의 사이즈를 나타낸다.
콘텐츠 너비엔 패딩은 포함되고 스크롤바는 포함되지 않는다.
clientWidth를 계산할 때 주의할 점은 수직 스크롤바가 차지하는 너비 16px 때문에 콘텐츠 너비는 300px이 아닌 284px이 된다는 점이다.
패딩이 없으면,
clientWidth
와clientHeight
는 테두리와 스크롤바 안쪽에 있는 콘텐츠 영역의 너비, 높이와 정확히 일치한다.
따라서 패딩이 없는 경우엔 clientWidth
와 clientHeight
를 사용해 콘텐츠 영역 크기를 구할 수 있다.
clientWidth
와 clientHeight
와 유사한데, 스크롤에 의해 감춰진 영역도 포함한다는 점에서 차이가 있다.
scrollWidth
와 scrollHeight
는 아래와 같이, 요소 크기를 콘텐츠가 차지하는 만큼 늘리고자 할 때 사용할 수 있다.
// 콘텐츠가 차지하는 높이만큼 요소 높이를 늘려준다.
element.style.height = `${element.scrollHeight}px`;
수평 스크롤이 오른쪽, 수직 스크롤이 아래로 움직임에 따라 가려진 영역의 너비와 높이를 나타낸다.
❗ 대부분의 기하 프로퍼티는 읽기 전용이지만
scrollLeft
와scrollTop
은 변경이 가능하다.스크립트를 사용해 프로퍼티를 수정하면 자동으로 요소 내 스크롤이 움직인다. 이런 특징을 이용하면
scrollTop
을 0이나 1e9같이 아주 큰 숫자로 설정해 스크롤 바를 최상단이나 최하단으로 옮길 수 있다.
getComputedStyle를 사용해 CSS가 적용된 요소의 높이와 너비를 구할 수 있다. 하지만 기하 프로퍼티를 사용해 너비와 높이 정보를 얻어야 하는 이유가 있다.
CSS width와 height는 다른 CSS 프로퍼티의 영향을 받는다. 요소의 너비와 높이 계산 방법을 '지정’하는 box-sizing이 이런 프로퍼티의 대표적인 예이다. 따라서 box-sizing을 변경하면 getComputedStyle로 구한 값이 부정확해 질 수 있다.
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
로 값을 얻고자 할 때만 발생한다. 눈으로 봤을 땐 전혀 문제가 없으니 이 점에 유의하자.