서브 픽셀 렌더링 및 CSS 개체 모델
Windows 8에서 웹 브라우징이 가능한 장치는 넓은 화면의 데스크톱에서 아담한 사이즈의 태블릿 PC에 이르기까지 다양하므로 선택의 폭이 그 어느 때보다 넓습니다. 브라우저가 이처럼 다양한 장치에서 구동하려면 다양한 화면 크기와 차원에 적합한 웹의 크기와 레이아웃을 지원해야 합니다. 이전 글에서 이러한 시나리오를 지원하는 IE의 일부 몇 가지 기능을 살펴본 바 있습니다. 텍스트와 레이아웃의 서브 픽셀 위치 지정 기술은 어떠한 화면 크기에서도 웹 페이지의 일관성과 멋진 스타일을 구현해 주는 핵심 플랫폼 기술 중 하나입니다.
이 글에서는 CSS-OM을 통해 서브 픽셀 위치 지정 기술을 더욱 강력하게 지원하는 IE10의 변화된 모습을 설명하겠습니다.
웹 개발자는 다양한 플랫폼 기술을 통해 멋진 레이아웃을 만들 수 있습니다. 일반적으로 개발자는 CSS 스타일 시트를 사용하여 웹 사이트 레이아웃을 구성합니다. 시나리오에 따라 웹 개발자는 pixel-perfect
(픽셀 완전) 정확도로 웹 페이지 요소를 측정, 정렬 또는 위치 지정하기 위해 JavaScript 코드를 사용합니다. 예를 들어, 어떤 온라인 에디터가 정확히 기존 콘텐츠 위에 편집 상자를 배치하여 기존 콘텐츠를 직접 편집할 때만 이 상자가 나타나게 하려고 합니다. 이러한 시나리오에서는 CSS 개체 모델(CSS-OM) API를 사용하여 요소 위치를 읽거나 설정할 수 있습니다. CSS-OM은 CSS를 프로그래밍 방식으로 다루기 위한 JavaScript API의 집합입니다.
CSS-OM API를 사용하여 레이아웃 요소를 측정, 정렬하는 방법은 이러한 API가 서브 픽셀로 위치 지정된 값을 반올림하거나 버림하여 정수 픽셀 숫자로 만드는 방식 때문에 문제가 될 수 있습니다.
픽셀 완전 레이아웃의 간략한 소개
일반적으로 웹에서 픽셀 완전 레이아웃은 콘텐츠의 접근성, 호환성, 적응성이라는 목표와 상충되기 쉽기 때문에 결과론적으로 보면 최상의 선택이 아닙니다. 아래 이미지들은 웹 디자이너가 픽셀 완전 디자인을 만들고자 했으나 예상치 못한 웹 플랫폼의 차이로 인해 버그가 발생하여 디자인이 엉망이 된 예입니다.
픽셀 완전 디자인이 잘못된 예
CSS-OM을 사용하여 레이아웃을 동적으로 생성할 때 웹 개발자는 몇몇 픽셀이 잠재적인 오류를 일으킬 수 있다는 사실을 받아들여야 합니다. 다행히도 IE10에서는 여러 가지 새로운 레이아웃 옵션이 제공되기 때문에 개발자는 CSS-OM을 사용하여 픽셀 완전 정렬을 하지 않고도 원하는 레이아웃을 구현할 수 있습니다.
예시
CSS-OM API가 어떻게 미묘한 배치 문제를 일으키는지 간단한 예를 통해 알아보겠습니다. 서브 픽셀 위치 지정 기능은 컨테이너의 크기가 균등하게 4등분될 수 없는데도 컨테이너 내에 4개의 상자를 똑같이 분배합니다.
다음과 같은 HTML 마크업 조각이 있습니다.
<footer>
<div>content 1</div><div>content 2</div><div>content 3</div><div>content 4</div>
</footer>
부분적인 CSS 마크업은 아래와 같습니다.
footer { width: 554px; border: 1px solid black; text-align: center; }
footer div { display: inline-block; width: 25%; }
footer div:nth-child(even) { background-color: Red; }
footer div:nth-child(odd) { background-color: Orange; }
이제 온로드로 실행되어 이 항목들의 너비를 보고하는 함수를 추가합니다.
onload = function () {
var footerBoxes = document.querySelectorAll("footer div");
var s = "";
var totalSize = 0;
for (var i = 0; i < footerBoxes.length; i++) {
// Reporting
var offsetWidth = footerBoxes[i].offsetWidth;
s += "content " + (i + 1) + " offsetWidth = " + offsetWidth + "px" + "<br />";
totalSize += offsetWidth;
}
s += "Total <i>calculated</i> offsetWidth = " + totalSize + "px" + "<br />";
s += "Container width = " + document.querySelector("footer").clientWidth + "px" + "<br />";
document.querySelector("#message").innerHTML = s;
}
IE9에서 이 마크업과 코드를 실행하면 결과는 다음과 같습니다.
content 1content 2content 3content 4 content 1 offsetWidth = 139content 2 offsetWidth = 139content 3 offsetWidth = 139content 4 offsetWidth = 139Total calculated offsetWidth = 556Actual container width = 554
Total calculated offsetWidth에서 CSS-OM API offsetWidth
에 의해 반환된 값을 합한 결과가 실제 컨테이너 너비와 2픽셀 차이가 난다는 것에 주목하시기 바랍니다. 이는 개별 div
요소의 offsetWidth
에서 반올림되었기 때문입니다.
총합이 실제보다 크거나 작을 수 있지만, 다른 브라우저에서도 결과에 유사한 차이가 나타납니다.
위 예시처럼 반올림/버림으로 인해 총합이 컨테이너 크기를 초과하면 콘텐츠가 줄 바꿈되거나 원치 않는 스크롤 막대가 나타납니다. 또한 다수의 컨테이너가 텍스트 및 텍스트를 렌더링하기 위해 사용된 글꼴에 따라 그 크기가 결정되며, 이러한 글꼴 메트릭은 브라우저마다 다르고 요청된 글꼴을 사용할 수 없을 때에는 대체 글꼴이 선택됩니다.
offsetWidth
API는 널리 사용되는 다른 CSS-OM 속성들(1997년 IE4부터 시작)과 함께 서로 다른 다양한 좌표 시스템에서 요소를 정수 픽셀 값으로 추출하기 위한 편리하고 빠른 방식을 제공합니다. 모든 주요 브라우저는 호환성을 위해 이러한 API를 거의 모두 사용하며 이는 W3C 초안 표준, CSS-OM View 모듈의 일부이기도 합니다.
새로운 브라우저 기능은 CSS-OM 속성이 정수 값 픽셀로 제한됨에 따른 부족 값을 계속 보여줍니다. 예를 들어, SVG 및 CSS 2D/3D 변환과 같은 기능은 요소를 픽셀 사이의 크기로 쉽게 지정할 수 있도록 합니다.
문제 해결
이러한 제약을 어느 정도 인식하여 W3C CSS-OM View 명세는 getBoundingClientRect()
API를 통해 반환된 좌표가 floats
(부동 소수점 수)가 되도록 만듭니다. 즉, 서브 픽셀 정확도를 나타낼 수 있는 값입니다. getBoundingClientRect()
는 또 다른 CSS-OM API이며 offsetWidth
API와 같은 근원을 사용하여 요소의 경계 상자 위치와 크기를 제공합니다.
IE10에서 우리는 getBoundingClientRect()
API를 업데이트하여 IE10 표준 모드에서 기본적으로 서브 픽셀 해상도를 반환하도록 함으로써 다른 브라우저와 상호 운용 가능하고 W3C 표준에 부합되게 하였습니다.
위의 예를 업데이트하여 getBoundingClientRect()
에서 직사각형의 width
요소가 반환되도록 하였으며 IE10은 이제 다음과 같은 소수 값을 보고합니다.
content 1content 2content 3content 4 content 1 offsetWidth = 139, getBoundingClientRect().width = 138.5 content 2 offsetWidth = 139, getBoundingClientRect().width = 138.5 content 3 offsetWidth = 139, getBoundingClientRect().width = 138.5 content 4 offsetWidth = 139, getBoundingClientRect().width = 138.5 Total calculated offsetWidth = 556 Total calculated getBoundingClientRect().width = 554 Actual container width = 554
모든 곳에서 서브 픽셀 값 사용
getBoundingClientRect
외에도, IE10 표준 모드에서 마우스/포인터 이벤트에 대해서도 서브 픽셀 위치를 기본적으로 보고합니다. 확대/축소 요소가 100%가 아닌 값으로 설정되어 있을 때 마우스/포인터를 between
픽셀로만 지정할 수 있습니다. 구체적으로, 영향을 받는 마우스/포인터 API는 다음과 같습니다.
MouseEvent.offsetX/Y
MouseEvent.layerX/Y
MouseEvent.clientX/Y
MouseEvent.pageX/Y
MouseEvent.x/y
일반적으로 CSS-OM의 서브 픽셀 값을 처리할 준비가 되어 있지 않은 기존 웹 페이지와의 호환성을 유지하기 위해 IE10은 다른 CSS-OM 속성에 대해 기본적으로 정수 값 픽셀 단위를 계속 보고합니다. 이러한 API는 다음과 같습니다.
Element.clientHeight
Element.clientWidth
Element.clientLeft
Element.clientTop
Element.scrollTop
Element.scrollLeft
Element.scrollWidth
Element.scrollHeight
HTMLElement.offsetWidth
HTMLElement.offsetHeight
HTMLElement.offsetTop
HTMLElement.offsetLeft
TextRange.offsetLeft
TextRange.offsetTop
하지만 이제 IE10에서는 필요한 경우 웹 개발자가 위에 있는 CSS-OM 속성에서 서브 픽셀로 배치된 값을 사용할 수도 있습니다. 이 특별한 기능을 사용하려면 IE10 표준 모드가 필요하며 문서 개체에서 다음 속성을 설정하여 사이트가 옵트인되어야 합니다.
document.msCSSOMElementFloatMetrics = true;
document.msCSSOMElementFloatMetrics
를 true
로 설정하여 활성화하면 이전 목록의 모든 CSS-OM API는 값을 서브 픽셀 정확도로 보고하며, 레이아웃과 렌더링 엔진에서 내부적으로 사용된 계산을 정확하게 반영합니다. JavaScript는 1.00을 1로 변환합니다. 따라서 반환된 값에 소수점이 없을 수도 있습니다.
예시로 돌아가 이 IE10에서 document.msCSSOMElementFloatMetrics
를 true
값으로 설정해 봅니다.
content 1content 2content 3content 4 content 1 offsetWidth = 138.5, getBoundingClientRect().width = 138.5 content 2 offsetWidth = 138.5, getBoundingClientRect().width = 138.5 content 3 offsetWidth = 138.5, getBoundingClientRect().width = 138.5 content 4 offsetWidth = 138.5, getBoundingClientRect().width = 138.5 Total calculated offsetWidth = 554 Total calculated getBoundingClientRect().width = 554 Actual container width = 554
offsetWidth
에서 반환한 소수 값을 눈여겨 보시기 바랍니다. 이제 총합이 일치합니다.
요약
픽셀 완전 레이아웃 계산을 위해 CSS-OM 속성을 사용할 수 있다는 것은 유용할 때가 많으며 반드시 필요한 경우도 있습니다. CSS-OM을 사용할 경우 이러한 API의 완전 픽셀 보고 특성을 기억하시기 바랍니다. CSS 또는 CSS-OM API로 레이아웃을 디자인할 때에는 다양한 브라우저와 장치에서 사이트가 제대로 표시되도록 몇 픽셀의 오차 여유 공간을 두는 것이 좋습니다.
- Internet Explorer 프로그램 관리자, Travis Leithead