굉장히 좋은 자바스크립트 강좌가 있어 소개합니다. 영문이라는 한계가 있지만 “굉장히”라는 수식어가 모자랄 만큼 좋은 글입니다. 이렇게 좋은 글이 많이 알려지지 않은 건 글 제목이 자바스크립트가 아닌 “ECMAScript”여서가 아닐까 하는데요. ECMAScript는 자바스크립트의 기반이 되는 스크립트 언어로 ECMA International에서 표준화한 언어입니다.
소개하려는 글은 자바스크립트 프로그래머이자 ECMAScript 이론가라고 자신을 소개하고 있는 Dmitry A. Soshnikov가 블로그를 통해서 발표한 글입니다. 현재까지 발표한 글은 자바스크립트의 핵심을 한 페이지로 요약한 “JavaScript, The Core”와 ECMA-262의 세 번째 버전(edition)을 상세하게 설명하는 “ECMA-262-3 in detail”, 그리고 최신 버전을 다루는 “ECMA-262-5 in detail”, 마지막으로 네 개의 노트(note)로 구성되어 있습니다.
참고로 ECMA-262-3은 IE와 Adobe Flash 등에서 폭넓게 지원하는 버전이고, ECMA-262-5는 Google Chrome, Mozilla Firefox 등이 지원하고 있는 ECMAScript의 공식적인 최신 버전입니다.
자바스크립트를 깊이 이해하려면 스코프(scope)나 클로저(closure) 같은 핵심 개념을 이해해야 하는데 이런 개념은 직관적으로 이해하기가 쉽지 않았습니다. 지금껏 여러 번 시도해봐도 명확하지 않았는데 이 글을 보면서 비로서 이해를 할 수 있었습니다.
다시 강조하지만 정말 굉장한 글입니다. 하지만 영문이라는 한계가 있는데요. 글 중 일부는 러시아어를 기본으로(Dmitry 가 직접 쓴) 독일어, 아랍어, 중국어, 일본어 등으로 번역이 되어 있습니다. 여기에 한글 번역을 추가하려고 우선 “JavaScript, The Core” 번역을 시작했는데 생각보다 진도가 느리네요. 좋은 글을 번역해서 널리 알리는 데 많은 분들이 동참하셨으면 좋겠습니다.
미래의 HTML에서는 새로운 미디어 종류가 추가될 수 있고, 대상 미디어를 제한하는 기준이나 값(parameterized values)도 도입될 수 있다. 이런 확장에 대비해서 표준에 부합하는 사용자 에이전트(conforming user agent)는 media 속성을 반드시(MUST) 아래처럼 해석해야 한다.
결과 값은 미디어 종류를 쉼표(,)로 구분한 리스트이다. 예를 들어서,
media="screen, 3d-glasses, print and resolution > 90dpi"
이 속성 값은 아래처럼 변환된다.
"screen"
"3d-glasses"
"print and resolution > 90dpi"
각각의 항목은 영문 대소문자, 0~9까지의 숫자, 하이픈이 아닌 첫 번째 문자 바로 앞에서 끊는다. 위 항목은 아래처럼 정리된다.
"screen"
"3d-glasses"
"print"
각각의 항목은 대소문자를 구별해서 HTML 4.01에 정의된 미디어 종류인지 검사한다. 사용자 에이전트는 대소문자가 맞지 않는 항목을 무시할 수도 있다(MAY). 위 예에서는 screen과 print가 최종적인 대상 미디어가 된다.
두 번째 단계가 쉽게 와 닿지 않을 수도 있습니다. 왜 띄어쓰기 앞에서 정리할까 의아하게 생각할 수도 있는데요. 그 이유는 상위 호환성(forward compatibility)을 고려했기 때문입니다. 그럼 상위 호환성이란 무엇일까요?
상위 호환성이란 어떤 시스템이 미래 버전의 시스템을 위해 만들어진 입력을 적절하게(gracefully) 받아들이는 능력을 말한다. 상위 호환성을 갖는 기술의 도입은 오래된 장치가 새로운 장치에서 생성된 데이터의 일부를 인식할 수 있다는 의미를 내포한다. [중략] 상위 호환성을 지원하는 표준은 구 버전이 새로운 표준의 데이터를 받고(receive), 읽어들이고(read), 표현하고(view), 실행(play or execute)할 수 있다.
상위 호환성과 확장성(extensibility)은 비슷한 개념이지만 둘은 동일하지 않다. 상위 호환성을 갖는 시스템은 미래 버전 시스템의 데이트를 받아들일 수 있고, 받아들인 데이터 중에서 “현재 알고 있는” 부분만 골라낼 수 있다. 예를 들어서 텍스트만 인식하는 워드 프로세서는 미래 버전 문서로 만든 이미지 데이터를 무시한다. 확장성 있는 시스템은 새로운 입력 형식을 완전히 다룰 수 있도록 업그레이드 가능한 시스템을 말한다. 예를 들어서 확장성 있는 텍스트 기반 워드 프로세서는 이미지를 다룰 수 있도록 업그레이드가 가능하다.
여기서 말하는 상위 호환성의 핵심은 미래 버전의 데이터 중에서 자신이 이해하는 부분만 인식한다는 점입니다. 앞에서 설명한 예 중 "print and resolution > 90dpi"를 미래 버전의 데이터라고 생각해보면 그 중 자신이 이해하는 부분, 즉 "print" 부분만 인식한다는 점이지요.
† 지금은 미디어 쿼리가 일반화되어 있지 않아서 모든 장치에 적용할 스타일 시트를 지정하고, 미디어 쿼리는 선택적으로만 적용하는 경우가 많습니다. 하지만 미래에는 모든 외부 스타일 시트를 미디어 쿼리를 사용해서 불러올 수도 있습니다. 그런 상황에서 미디어 쿼리를 지원하지 않는 브라우저가 있다면 스타일 시트를 전혀 인식하지 못할 수도 있기 때문에 이렇게 해서 상위 호환성을 고려하는 것이 아닐까 하는 생각이 듭니다.
미디어 쿼리의 대응
이렇게 HTML 4.01의 media 속성 해석 방식이 상위 호환성을 갖기 때문에 우리가 일반적으로 의도하지 않은 문제가 생깁니다. 바로 미디어 쿼리를 지원하지 않는 브라우저의 문제이지요.
예를 들어서 아래처럼 미디어 쿼리를 사용했다고 생각해보겠습니다.
<link rel="stylesheet" type="text/css" media="all and (min-width:600px)" href="test_media_query.css" />
미디어 쿼리를 지원하는 브라우저라면 뷰포트 크기가 600px 이상인 미디어에서만 test_media_query.css 파일을 읽게 됩니다. 하지만 HTML 4.01은 지원하지만 미디어 쿼리라는 새로운 표준을 지원하지 않는 브라우저라면 어떨까요? CSS를 읽어 들일까요? 아니면 읽지 않을까요?
미디어 쿼리를 지원하지 않는 브라우저는 위에 설명한 방식의 결과 값, 즉 and 앞 띄어쓰기 앞까지만 읽어서 all로 적용 대상을 인식합니다. 따라서 all 뒤에 있는 조건과 상관 없이 CSS를 읽게 됩니다.
하지만 미디어 쿼리를 쓰는 경우 대부분은 미디어 쿼리를 지원하지 않는 브라우저에서는 인식하지 않기를 바랄 것입니다. 이런 상황을 고려해서 미디어 쿼리 표준은 only라는 키워드를 지원합니다.
only는 단어의 의미 그대로 미디어 쿼리를 지원하는 브라우저에서만 스타일 시트를 인식하게 한다는 뜻입니다. only는 두 가지 방식으로 처리됩니다. 먼저 미디어 쿼리를 지원하는 브라우저는 미디어 쿼리 표준에 따라서 only가 없는 것처럼 해석합니다. 말 그대로 대상 설정에는 아무 의미가 없는 것이죠.
그 다음으로 미디어 쿼리를 지원하지 않는 브라우저에서는 HTML 4.01 표준에 따라서 해석됩니다. 예를 들어서 아래처럼 지정했다면,
<link rel="stylesheet" type="text/css" media="only all and (min-width:600px)" href="test_media_query.css" />
대상 미디어의 결과 값은 첫 번째 띄어쓰기 앞인 only가 되고, 이 값은 HTML 4.01에 정의된 미디어 종류가 아니므로 무시됩니다.
브라우저의 지원
길게 설명했지만 제가 얘기하려는 의도는 하나입니다. 미디어 쿼리를 지원하는 브라우저만 고려한다면 반드시 only 키워드를 사용해야 한다는 점입니다. 그런데 미디어 쿼리를 설명하는 내용에 only 키워드는 빠지지 않고 들어가지만 막상 예제를 보면 사용하는 경우가 많지 않습니다. 왜 그럴까 궁금해서 테스트를 해봤습니다.
그러려면 먼저 미디어 쿼리를 지원하지 않는 브라우저를 확인해야 하는데요. 먼저 인터넷 익스플로러(이하 IE) 6, 7, 8은 위에서 설명한 HTML 4.01의 media 속성 해석 방식을 지키지 않았습니다. 그냥 전체를 인식해서 알고 있는 미디어 종류가 아니니 무시하는 것으로 생각합니다.
IE를 제외하면 미디어 쿼리를 지원하지 않는 브라우저 찾기가 정말 어렵습니다. 억지로 찾아낸 브라우저가 파이어폭스(이하 FF) 3.0.17 버전인데 IE와 달리 위에 설명한 방식대로 media 속성을 지원하는 것으로 판단했습니다.
그리고 크롬 브라우저도 확인을 해봤는데 2008년에 처음 발표된 1.0 버전도 제한적으로 미디어 쿼리를 지원하더군요. 그래서 제대로 해석하는지 확인을 못했습니다.
정리하자면 IE 8 이하 버전을 제외하면 대중적인 모든 브라우저가 미디어 쿼리를 지원합니다. 그리고 IE 8 이하 버전은 media 속성을 제대로 해석하지 않기 때문에 only 키워드를 사용하지 않아도 별다른 문제가 없습니다. 대부분의 미디어 쿼리 예제들이 only 키워드를 사용하지 않는 것도 현실적으로 문제가 없기 때문이라고 생각했습니다.
테스트 케이스
아래 소스의 렌더링 결과를 IE 8, FF 3.0.17, FF 4.0.1 버전에서 각각 확인해봤습니다.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>[Test] CSS media query</title>
<link rel="stylesheet" type="text/css" media="all and (min-width:9999px)" href="test_media_query.css">
<style type="text/css">
@media all and (min-width:600px) {
div {background:blue; color:#fff;}
}
</style>
</head>
<body>
<div style="width:600px; height:10px; background:maroon !important;"></div>
<div>
media query test!
</div>
</body>
</html>
test_media_query.css 파일에는 아래와 같은 스타일을 지정했습니다.
div {background:yellow; color:green; font-weight:bold;}
아래에 브라우저 각각의 렌더링 결과를 이미지로 볼 수 있습니다. 모든 결과는 뷰포트 width가 601px 이상, 9998px 이하인 상태로 캡처했습니다.
IE 8: 미디어 쿼리를 지원하지 않고 media 속성도 제대로 해석하지 않는 브라우저
외부 스타일 시트와 style 요소로 지정한 문서 스타일 시트 모두 해석하지 않아서 스타일이 아무 것도 적용되지 않습니다.
FF 3.0.17 : 미디어 쿼리를 지원하지 않지만 media 속성은 제대로 해석하는 브라우저
only 키워드가 없고 media 속성을 정확히 해석하기 때문에 min-width:9999px 조건과 상관 없이 외부 스타일 시트를 인식합니다. 하지만 문서 스타일 시트는 인식하지 않는 결과를 볼 수 있습니다. 그 이유는 문서 스타일 시트의 style 속성 내부는 HTML이 아닌 CSS의 영역이기 때문입니다. 미디어 쿼리를 지원하지 않는 브라우저라면 CSS 2를 기준으로 @media 규칙을 해석할 것이고, CSS 2에는 위에 설명한 방식을 정의하지 않고 있기 때문입니다.
FF 4.0.1 : 미디어 쿼리와 media 속성 모두를 제대로 해석하는 브라우저
min-width:9999px 조건을 만족하지 못하기 때문에 외부 스타일 시트는 인식하지 않습니다. 하지만 style 요소에 지정한 스타일은 min-width:600px 조건을 만족하기 때문에 정확하게 적용되는 것을 볼 수 있습니다(외부 스타일 시트를 인식하지 않는 것은 font-weight가 적용되지 않는 것으로 확인할 수 있습니다).
† 미디어 쿼리를 지원하지 않는 브라우저가 의외로 별로 없어서 다양한 환경에서 테스트해보지 못했습니다. 그러니 테스트 케이스를 바탕으로 내린 결론에는 오류가 있을 수 있습니다.
마치며
테스트 케이스에서 하나의 소스를 세 가지 브라우저가 전부 다르게 랜더링하는 것을 볼 수 있습니다. 만약 문서 제작자의 의도가 미디어 쿼리를 지원하는 브라우저에만 스타일을 적용하려는 것이어서 only 키워드를 사용했다면 의도했던 결과, 즉 FF 4.0.1에만 스타일이 적용됐을 것입니다. 새로 만들어질 브라우저가 HTML 4.01을 지원하면서 미디어 쿼리는 지원하지 않을 가능성을 100% 배제할 수는 없습니다. 그렇기 때문에 미디어 쿼리의 only 키워드가 중요합니다.
그리고 프로그래밍에 관한 격언 중 이런 것이 있습니다.
명시적인 것이 암시적인 것보다 낫다(Explicit is better than implicit).
명시적인 코드는 작정자의 의도를 분명히 표현하기 때문에 그 처리 결과도 분명합니다. 하지만 암시적인 코드는 내부의 처리 방식을 명확하게 이해하지 않고 사용하면 때때로 예상치 못한 결과를 가져올 수도 있습니다. 위에서 예로 든 media="only all and (min-width:600px)이 media="all and (min-width:600px)보다 명시적이고 좋은 방법이라고 생각합니다.
사실 only 키워드를 쓰지 않더라고 현실적으로 큰 문제는 없습니다. 하지만 미디어 쿼리에서 개인적으로 인상적인 부분이어서 포스팅했습니다. 표준은 당장의 현실뿐 아니라 미래까지도 고려해서 만들어지는 것이라고 생각해왔는데 이번에 HTML 4.01을 보면서 새삼 그렇다는 것을 느끼게 되었네요.
CSS의 관점에서, HTML 문서는 크고 작은 여러 개의 사각형 박스로 구성됩니다. 그 중에는 요소에 의해서 만들어지는 박스도 있고, 자동적으로 만들어지는 박스(익명(anonymous) 박스)도 있지만, 근본적으로 “박스”라는 것에는 차이가 없습니다.
CSS를 지원하는 사용자 에이전트는 이렇게 만들어진 박스를 배치함으로써 문서의 레이아웃을 표현합니다. 이 과정에서 각각의 박스는 어떤 방식으로 배치될 것인지에 따라 크게 다음과 같이 세 가지로 분류됩니다.
일반적인 흐름(normal flow)으로 배치되는 박스
떠있는(float) 상태로 배치되는 박스
절대적인 위치(absolute position)로 배치되는 박스
이 세 가지 배치 방식은 CSS의 근간인 시각적인 서식 모델의 핵심입니다. 이 글에서는 먼저 각각의 배치 방식을 간단히 알아보고, 배치 방식을 결정짓는 position. float 속성과 박스 유형을 결정짓는 display 속성이 어떻게 상호 작용하는지를 정리해보겠습니다.
† display 속성 값에 따라 만들어지는 block, inline, run-in 박스 등에 대해서는 이 글에서 다루지 않습니다.
일반적인 흐름(normal flow)으로 배치되는 박스
일반적인 흐름이란 순차적으로 박스가 배치되는 것을 말합니다. 예를 들어서 블록 박스의 경우에는 포함 블록(containing block) 상단부터 시작해서 순서대로 하나씩 수직으로 배치됩니다. 두 박스간의 간격은 margin 속성으로 조절되며, 두 마진이 닿을 경우에는 서로 병합됩니다.
이 배치 방식이 적용되려면 position 속성이 static(기본 값)이나 relative여야 하고, float 속성이 none(기본 값)이어야 합니다. 만약 position이 static이라면 해당 박스의 top, bottom, left, right 속성은 완전히 무시됩니다. relative가 지정된 박스도 일반적인 흐름에 따라 배치되지만, 배치된 위치를 기준으로 top 등의 속성에 따라 상대적으로 위치가 다시 조정됩니다(offset). 이렇게 박스에 offset이 발생하더라도 이어지는 박스는 offset이 없는 것처럼 배치되기 때문에 전체적인 흐름에는 영향을 주지 않습니다.
† CSS 2.1에서는 position:relative를 tbody, thead, tfoot, tr, colgroup, col, td, th, caption 요소에 지정했을 때의 효과에 대해서는 정의하지 않습니다. 따라서 td에 relative를 지정하면 사용자 에이전트에 따라서 서로 다른 결과가 발생할 수 있습니다.
떠있는(float) 상태로 배치되는 박스
float된 박스는 일반적인 흐름으로 배치되었을 때의 위치를 기준으로 포함 블록이나 float된 다른 박스에 닿을 때까지 오른쪽이나 왼쪽으로 이동합니다. 그리고 나서는 일반적인 흐름에서 벗어나서 말 그대로 “떠있는” 상태가 되기 때문에 구조상으로 해당 요소 앞, 뒤에 있는 블록 박스(normal flow)는 float된 박스가 존재하지 않는 것처럼 배치됩니다. 인라인 박스는 블록 박스와는 달리 float된 요소 주위로 흐르듯이 배치됩니다.
한 가지 예로, 아래 소스에서 빨간색 보더가 지정된 p 요소의 블록 박스는 float된 요소의 영향을 받지 않지만, 인라인 박스는 영향을 받아서 오른쪽으로 밀려나는 것을 볼 수 있습니다.
<div style="padding:10px; background:#eee;">
<p style="float:left; background:blue; color:#fff;">float 된 요소</p>
<p style="padding:10px; border:1px solid red;"><span style="background:orange;">주위를 흐르는 인라인 박스</span></p>
</div>
float 된 요소
주위를 흐르는 인라인 박스
이 배치 방식이 적용되려면 우선 position 속성이 absolute나 fixed가 아니고 float 속성이 none이 아니어야 합니다. absolute나 fixed 값은 float 보다 우선해서 박스를 다음에 설명할 절대적인 위치로 배치되도록 만들기 때문입니다. 또한, float된 박스는 display 속성을 inline으로 지정하더라도 실제 적용되는 산출 값(computed value)은 block이 됩니다.
† float된 요소에 display:inline을 지정하는 것은 흔히 발생하는 인터넷 익스플로러의 float 버그를 해결하는 CSS 핵(hack)입니다. 위와 같은 이유로 이 핵은 표준을 따르는 사용자 에이전트에는 아무런 영향도 미치지 않습니다.
절대적인 위치(absolute position)로 배치되는 박스
절대적인 위치로 배치되는 박스는 앞서 float된 박스가 일반적인 흐름에서의 위치를 기준으로 왼쪽이나 오른쪽으로 이동하는 것과는 달리 아예 일반적인 흐름에서 완전히 벗어나기 때문에 구조상의 앞, 뒤 요소에 아무런 영향을 미치지 않습니다. 절대 위치로 배치되는 박스에 유일하게 영향을 주는 것은 오직 그 자신의 포함 블록이며, 이 포함 블록을 기준으로 top, bottom, left, right 값에 따라 위치가 결정됩니다.
절대 위치로 배치되는 박스의 포함 블록은 일반적인 흐름에서의 포함 블록과는 다른 의미를 갖습니다. 즉, 일반적인 흐름에서는 가장 가까운 블록 레벨이나 inline-block, th, td 조상 요소 박스가 포함 블록를 형성하지만, 절대 위치 방식에서는 position이 지정된(positioned) 가장 가까운 조상 박스가 포함 블록이 되며 반드시 블록 레벨일 필요도 없습니다. 참고로 CSS 2.1에서 “위치가 지정된”이라는 표현은 position 속성 값이 static이 아닌 모든 경우에 해당합니다(absolute, fixed, relative).
이 배치 방식이 적용되려면 position 속성 값이 absolute나 fixed여야 합니다.
† 위에 설명한 “절대 위치 방식”에서의 포함 블록 정의는 position 속성이 absolute일 때에만 적용됩니다. position이 fixed일 때의 포함 블록은 “연속적인(continuous)” 미디어에서는 “뷰포트(viewport)”, 페이지로 구분되는(paged) 미디어에서는 “페이지 영역”을 기준으로 만들어집니다.
앞서 설명했던 내용을 정리해보겠습니다. 우선 요소의 배치 방식에 가장 큰 영향을 미치는 CSS 속성은 position입니다. display 속성은 요소가 어떻게 표현되는지를 결정하지만(심지어 보이거나 보이지 않게도 하지만) 근본적으로 배치 방식에는 영향을 주지 못합니다. position이 absolute나 fixed이면 절대 위치로 박스가 배치되고, static이나 relative이면 일반적인 배치나 떠있는 배치가 적용됩니다. 절대 위치로 배치되면 float 속성의 산출 값은 어떤 값을 지정하든 상관 없이 none으로 평가되고. display 속성은 아래 표에 따라 변환되어 적용됩니다.
일반적인 배치와 떠있는 배치 중 어느 쪽이 적용되는지는 float 속성에 따라 결정됩니다. float이 left나 right이면 떠있는 배치 방식이 적용되고, 이 때 display 속성 값은 위 표에 따라 변환되어 적용됩니다.
display 속성 값은 요소의 표현 방식을 결정합니다. block 요소를 inline 요소처럼 표현할 수도 있고, 그 반대도 가능합니다. 하지만 앞서 알아본 것처럼 absolute 속성이나 float 속성 값에 따라서 지정한 값과는 다르게 적용될 수도 있다는 점에 주의해야 합니다.
position과 float 속성이 display보다 우선하지만, 예외적으로 display가 none일 때에는 position과 float이 적용되지 않습니다. 당연한 얘기지만 박스 자체가 만들어지지 않기 때문입니다.
마치며
간단하게 position, float, display 속성이 어떻게 관련되어 있는지 정리하려고 했는데 또 글이 길어졌네요. 한동안 글을 쓰지 않다가 갑자기 뭔가를 쓰려고 하니 어색하기도 하고, 무엇보다 이렇게 마음 내키는대로 주제를 정해서 글을 쓰는 것에 한계를 느낍니다. 이 글만 해도 CSS의 박스 모델과 포함 블록, 블록 서식과 인라인 서식 등을 먼저 설명해야 하는데 그런 체계 없이 쓰려다 보니 설명을 많이 생략하게 되거든요.
예전에 float을 제거하는 방법이라는 글에서 overflow 속성을 이용하는 float 해제 방법을 다뤘습니다. 그 내용을 아래에 일부 인용하겠습니다.
“만약 width만 지정한 상태에서 overflow: hidden;을 적용하면 박스가 내용물의 크기만큼 아래로 늘어나니까요. 이 때 박스 안에 있는 float된 요소의 높이까지도 같이 계산됩니다. 결국 박스가 float된 요소를 포함할 만큼 커지기 때문에 float을 제거하는 효과가 나타나게 됩니다.”
글을 쓰던 당시에 overflow가 float된 요소를 포함하도록 박스 크기를 늘리는 명확한 이유는 몰랐습니다. CSS 2.1을 열심히 찾아봤는데 overflow 속성 설명에는 관련 내용이 전혀 없었거든요. 그래서 경험적인 추측일 뿐이었습니다.
그런데 어제 마진 병합에 관한 글을 쓰면서 그 원리가 CSS 2.1에 정확하게 명시되어 있다는 사실을 알게 되었습니다.
그 내용은 시각적인 서식 모델의 세부 사항(visual formatting model details)을 다루는 10장의 6.6, 6.7절입니다.
마진 병합을 다루면서 블록 레벨 요소의 height 결정 방식을 찾아봤는데 overflow가 visible일 때에만 적용되는 내용이었습니다. 그래서 visible이 아닌 경우를 찾아봤는데 6.6절에 있더군요.
6.6절은 일반적이지 않은 상황에서의 height 결정 방식을 다룹니다. 핵심적인 내용은 아래와 같습니다.
“일반적인 문서 흐름(normal flow)에서 블록 레벨 요소의 overflow 값이 visible이 아니고 height가 auto면 그 자손 요소에 따라서 6.7절에 명시된대로 높이가 결정된다.”
6.7절에서 실제 높이 결정 방식을 다루는데 float된 자식 요소과 관련된 부분은 다음과 같습니다.
“만약 요소가 float된 자손 요소를 갖고 이 자손 요소의 하단 마진 경계(bottom margin-edge)가 요소 박스 아래에 있으면 요소 박스의 높이는 자손 요소의 하단 마진 경계를 포함하도록 늘어난다.”
따라서 overflow를 이용한 float 해제는 CSS 2.1에 정의된 정확한 동작 방식입니다. 그동안 참 많이 궁금했었는데 결국은 궁금증이 풀렸네요. ^^
CSS를 이용해서 블록 레벨 요소를 배치하다보면 간혹 수직 방향으로 마진이 적용되지 않을 때가 있습니다. 이런 현상은 대부분 CSS의 중요한 레이아웃 모델 중 하나인 마진 병합(collapsing margins) 때문에 발생하는데 브라우저에 따라서 다르게 나타나는 경우가 많기 때문에 크로스 브라우징에 어려움을 주기도 합니다.
사실 마진 병합은 블록 레벨 요소의 height 결정 방식이나 float, overflow같은 다른 여러 가지 내용과 연결되어 있습니다. 이 글에서는 마진 병합의 정의와 계산 방법, 그리고 일반적인 문서 흐름(normal-flow)에서의 세 가지 마진 병합 패턴에 대해서만 알아보고 나머지 내용은 다음 글에서 이어가도록 하겠습니다.
† 기본적으로 마진 병합은 hasLayout 모델을 쓰는 IE 7 이하 브라우저에서는 정확하게 표현되지 않을 가능성이 큽니다. 관련된 버그도 상당히 많고요. 그러니 직접 테스트를 해보실 분들은 반드시 IE 8이나 파이어폭스, 오페라, 사파리 등의 브라우저를 사용하시기 바랍니다. ^^;
그리고 언제나 그렇듯이 설명에 오류가 있을 수도 있습니다. 오류를 알려주시면 즉시 반영하도록 하겠습니다.
마진 병합의 정의
먼저 마진 병합이 정확하게 무엇을 뜻하는지 알아봐야겠지요. CSS 2.1 박스 모델의 마진 병합 설명에는 이렇게 정의되어 있습니다(세부적인 조건은 뒤에서 따로 설명합니다).
“마진 병합은 인접한 두 개 이상의 수직 방향 박스 마진이 하나의 마진으로 합쳐지는 것을 의미한다.”
무엇보다 마진 병합은 수직 방향의 마진, 다시 말해서 margin-top과 margin-bottom에만 의미를 갖습니다. 따라서 margin-left와 margin-right는 전혀 그 고려 대상이 아닙니다.
또한, 두 개 이상의 마진이 인접했다는 것은 마진의 방향(top 또는 bottom)과 상관 없이 최소한 두 개의 마진이 서로 닿아있다는 의미입니다. 그렇다면 마진이 서로 닿으려면 어떻게 배치되어야 할까요? 크게 세 가지 경우가 있습니다.
두 요소가 형제(sibling) 관계일 때 위에 있는 요소의 margin-bottom과 아래 있는 요소의 margin-top이 서로 닿는 경우
두 요소가 부모, 자식 관계일 때 부모 요소의 margin-top과 자식 요소의 margin-top이 서로 닿는 경우(margin-bottom의 경우도 성립)
한 요소의 margin-top과 margin-bottom이 서로 닿는 경우
두 번째와 세 번째 경우를 생각해보면 한 가지 중요한 사실을 알 수 있습니다. CSS의 박스 모델에서 하나의 박스는 안에서 밖으로 봤을 때 “컨텐츠 영역” -> “패딩 영역” -> “보더 영역” -> “마진 영역”으로 구성됩니다. 그런데 일반적으로 부모와 자식 요소의 margin-top이 서로 닿으려면 부모 요소와 첫 번째 자식 요소 사이에 컨텐츠와 패딩, 보더 영역이 있어서는 안 됩니다. 한 요소 안에서 서로 닿으려면 해당 요소가 비어 있고 패딩, 보더가 없어야 하고요.
요소간의 관계로 미루어보면 두 요소(또는 한 요소)의 마진만 합쳐지는 것으로 생각할 수 있지만 실제로는 두 가지 이상의 패턴이 동시에 적용될 수 있습니다. 그래서 위의 정의에서도 “두 개 이상의 마진”이라고 표현하고 있지요.
여기에서는 최대한 간략하게 마진 병합을 정의했는데 실제로 마진이 합쳐지려면 여러 가지 조건을 만족해야 합니다. 이런 조건들은 나중에 설명하기로 하고 먼저 병합되는 마진 값이 어떻게 계산되는지 알아보겠습니다.
병합되는 마진 값 계산 방법
두 개 이상의 마진이 하나로 병합되어 만들어지는 단일 마진 값은 아래 규칙에 따라서 계산됩니다.
마진의 부호가 모두 같으면 절대값이 큰 쪽의 마진이 적용된다.
부호가 다른 마진이 있으면 양수 마진의 최대값에서 음수 마진의 절대값 중 최대값을 뺀다.
몇 가지 예를 들어보겠습니다.
조건
마진 A (절대값)
마진 B (절대값)
마진 C (절대값)
적용되는 마진 값
둘 다 양수
10px (10)
30px (30)
-
30px
둘 다 음수
-10px (10)
-30px (30)
-
-30px
셋 다 양수
10px (10)
20px (20)
30px (30)
30px
셋 다 음수
-10px (10)
-20px (20)
-30px (30)
-30px
양수와 음수 A
10px (10)
-30px (30)
-
10 – 30 = -20(px)
양수와 음수 B
-10px (10)
30px (30)
-
30 – 10 = 20(px)
양수와 음수 C
10px (10)
-20px (20)
30px (30)
30 – 20 = 10(px)
양수와 음수 D
-10px (10)
20px (20)
-30px (30)
20 – 30 = -10(px)
세 가지 마진 병합 패턴
마진이 서로 닿게 되는 세 가지 경우를 앞서 살펴봤습니다. 마진 병합은 그 각각의 경우에 대응되는 형제 요소간의 병합, 부모와 자식 요소간의 병합, 자체 병합의 세 가지 패턴으로 구분할 수 있습니다. 복잡한 상황은 미뤄두고 일단 가장 간단한 사례를 생각해보겠습니다.
블록 A의 margin-bottom과 블록 B의 margin-top이 하나로 합쳐져서 30px로 표현됩니다. 가장 흔히 발생하는 패턴으로 이해하기도 쉽습니다. 형제 요소(블록 B)가 clearance를 가질 때를 제외하면 언제나 성립하는데 이에 관해서는 나중에 설명하겠습니다.
패턴 2. 부모, 자식 요소간의 병합
일반적인 문서 흐름에서 부모, 자식 요소간의 마진 병합은 margin-top과 margin-top이 인접하는 경우와 margin-bottom과 margin-bottom이 인접하는 두 가지 경우에 발생하며 각각의 성립 조건이 약간 다릅니다. 먼저 조금 더 간단한 margin-top의 경우를 살펴보지요.
언듯 생각하면 부모 요소와 자식 요소에 margin-top이 따로 적용되어야 할 것 같지만 두 요소를 갈라 놓는 컨텐츠, 패딩, 보더, clearance가 없기 때문에 두 마진이 30px의 단일 마진으로 합쳐집니다. 그런데 합쳐진 마진은 왜 자식 요소가 아닌 부모 요소에 적용될까요?
사실 마진 병합은 블록 레벨 요소의 height 결정 방식과 밀접한 관계가 있습니다. 일반적인 문서 흐름에서 overflow의 산출 값이 visible인 블록 레벨 요소의 높이는 다음과 같이 정의됩니다(CSS 2.1 10.6.4 참고).
“overflow 속성의 산출 값이 visible인 블록 레벨 요소가 블록 레벨 자식을 가질 때 부모 요소의 height는 가장 위에 있는 블록 레벨 자식(자체적으로 마진이 병합되지 않는)의 상단 보더 경계(top border-edge)에서 가장 아래에 있는 블록 레벨 자식(자체적으로 마진이 병합되지 않는)의 하단 보더 경계(bottom border-edge)까지의 거리와 같다.”
“하지만 부모 요소에 top 패딩이나 보더가 있거나 부모 요소가 시조(root) 요소이면 컨텐츠 영역은 가장 위에 있는 블록 레벨 자식의 상단 마진 경계(top margin-edge)부터 시작된다. 비슷한 방식으로 마지막 자식 요소의 margin-bottom과 부모 요소의 margin-bottom이 병합되지 않으면 가장 아래에 있는 블록 레벨 자식의 하단 마진 경계(bottom margin-edge)에서 컨텐츠 영역이 끝난다.”
† 원문에서는 컨텐츠의 유무에 대해서 언급하지 않고, 대신 “익명 블록 박스(anonymous block box)도 자식 요소가 될 수 있다.”라고 명시하고 있습니다. 인라인 컨텐츠가 들어가면 자동으로 익명 블록 박스가 생성되어 자식 요소 박스처럼 동작한다는 의미입니다.
다시 말해서, 부모와 자식 요소간에 마진 병합이 발생하면 자식 요소의 margin-top이나 margin-bottom이 부모 요소의 높이 계산에 전혀 영향을 미치지 않는다는 얘기입니다. 따라서 부모와 자식 요소의 마진 영역이 같은 선(부모나 자식 요소의 보더 경계)에서 시작되고 그 두 마진이 하나로 합쳐지기 때문에 margin-top으로 병합되면 위쪽으로, margin-bottom으로 병합되면 아래쪽으로 마진이 적용됩니다.
부모, 자식 요소간의 margin-bottom이 합쳐지는 경우는 조건이 조금 더 복잡해지는데 우선 부모 요소의 height가 auto여야 하며 min-height는 요소의 실제 높이보다 작고 max-height는 요소의 실제 높이보다 커야 합니다. 여기에서 min-height와 max-height 조건에 따라서 첫 번째 조건인 height 산출 값(computed value)이 달라질 수 있기 때문에(CSS 2.1 10.7 참고) 첫 번째 조건이 핵심이라고 할 수 있습니다.
이런 조건이 필요한 이유는 height가 지정되면 자식 요소와 상관 없이 높이가 결정되고, 마진 영역은 투명하기 때문에 overflow가 visible인 상태에서는 가장 아래에 있는 자식 요소의 margin-bottom이 부모 요소의 렌더링에 영향을 미치지 않고, 만약 margin-bottom이 적용되면 부모 요소 다음에 배치되는 박스와의 관계에 혼란을 줄 수 있기 때문이 아닐까 생각합니다.
패턴 3. 요소의 자체 병합
마지막 세 번째 패턴입니다. 어떤 요소의 margin-top과 margin-bottom이 합쳐지려면 까다로운 조건을 만족시켜야 하지만 실제로는 아주 쉽게 발생하기도 합니다. 자체 병합이 이루어지려면 min-height 속성 값이 0이고, top, bottom 보더와 패딩이 없고, height 속성 값이 0 또는 auto이고, 어떤 라인 박스도 포함하지 않고, 해당 요소의 흐름 안에 있는 자식 요소들의 마진이(있다면) 모두 인접해야 합니다.
이런 조건은 문서에 수직 방향 보더와 패딩이 없는 빈 블록 레벨 요소가 들어가면 간단히 만족됩니다. min-height나 height를 지정하는 경우가 별로 없으니까요. 간단한 마크업 예는 다음과 같습니다.
만약에 빈 div의 마진이 먼저 합쳐지고, 이렇게 만들어진 단일 마진이 부모 요소와 블록 A의 마진과 합쳐진다면 최종 마진은 30 – 40 = -10(px), 50 – 10 = 40(px)이 됩니다. 하지만 네 마진이 한꺼번에 합쳐지면 앞서 설명한 계산 방법대로 50 – 40 = 10(px)이 됩니다.
파이어폭스 3, 사파리 3에서 테스트해보니 명세서대로 한꺼번에 합쳐져서 10px로 표현되었습니다. 오페라에서는 다른 결과가 나왔는데 버그일 가능성이 높다고 생각됩니다.
† 2010.06.22: 오페라 10에서 확인해보니 파이어폭스, 사파리와 동일하게 10px로 표현되네요. 이전에 테스트를 잘못했거나 아니면 버그가 수정되었나 봅니다. ^^;
요소의 마진이 자체적으로 병합될 때 마진이 top과 bottom 중 어느 방향으로 적용되는지에 관한 명확한 설명은 찾지 못했습니다. 그래서 나름대로 테스트를 해봤는데 방향 자체가 무의미하지 않을까 하는 생각이 듭니다. 최종 마진을 계산할 때 자체 병합되는 요소의 마진 값 두 개를 추가시키고, 그 결과 값을 문서 구조에 따라서 패턴 1, 2에 적용시키는 것이 아닐까 싶네요.
예를 들어서 바로 위 예제에서 최종 마진 값은 10px입니다. 이제 빈 요소를 무시하고 패턴 2에 따라서 부모 요소와 블록 A 사이에 10px의 마진이 있다고 가정하면 최종적으로 부모 요소에 10px의 margin-top이 적용됩니다.
물론 이것이 정확한 방식인지 확신할 수는 없습니다. 테스트를 더 하면서 추론과 위배되는 결과가 발생하거나 정확한 방식을 설명하는 자료를 찾으면 글을 업데이트하도록 하겠습니다.
마치며
다양한 조건에서 마진 병합이 발생하지만 일반적인 문서 흐름에서는 거의 대부분 위에 설명한 세 가지 패턴의 조합이라고 생각합니다. 하지만 float된 요소의 유무나 overflow, position 등의 속성 값에 따라서 마진 병합이 적용되지 않는 경우도 있는데 이런 상황에 대해서는 다음 글에서 알아보겠습니다.
현재 공식적인 CSS 최종 권고안은 1998년에 발표된 CSS 2이고, 이를 보완한 CSS 2 리비전 1(CSS 2.1)이 2007년 권고안 후보(CR: Candidated Recommendation)로서 발표되었습니다. 즉, CSS 2.1은 아직 최종 권고안이 아니고, 최종 권고안이 되기 위한 과정을 밟고 있는 단계지요.
그럼 한 가지 질문을 던져보겠습니다. 과연 CSS 2와 CSS 2.1 중 어떤 규격을 웹 브라우저 같은 사용자 에이전트가 더 잘 지원할까요? CR 단계에 있는 CSS 2.1일까요? 아니면 오래전에 만들어진 CSS 2일까요?
처음 CSS를 접했을 때 저는 당연히 CSS 2를 더 잘 지원할 것이라 믿었습니다. CSS 2.1은 불완전한 규격이라 생각했고, 무엇보다 인터넷 익스플로러 7, 파이어폭스 2, 오페라 9 등의 브라우저가 발표된 2006년 당시까지도 CSS 2.1은 초안(working draft) 단계에 머물고 있었으니까요.
하지만, 실제로 CSS 2 기능 중 상당수는 최신 브라우저에서도 아직 지원되지 않고 있습니다. 또한, W3C가 제공하는 CSS 검증 서비스 같은 경우 기본적으로 CSS 2.1을 기준으로 결과를 알려줍니다. 그렇다면 왜 이런 현상이 생겼을까요?
이런 의문에 대한 해답은 CSS 2.1 규격 소개에서 찾을 수 있습니다. 그 내용을 바탕으로 CSS 2.1이 왜 만들어졌고, 현재 어떠한 위치를 차지하고 있는지 알아보겠습니다.
CSS 2.1을 제정한 이유
먼저, 규격을 제정한 W3C가 밝힌 이유를 요약해봤습니다.
“CSS 2가 발표된 1998년 이후로 많은 사람들이 CSS를 이용하면서 CSS 2 규격에 포함된 다양한 오류가 밝혀졌다. 이런 오류는 정오표를 발표를 통해서 계속 수정되고 있지만, 이런 사항을 CSS 규격 자체에 반영할 기회는 지금까지 없었다.”
“문제들의 상당수는 새로 등장할 CSS 3 규격에서 처리되겠지만, 현재 상태가 CSS 2의 구현과 상호 운영성(interoperability)에 걸림돌이 되고 있다. CSS 2.1 규격은 이런 상황을 해결하기 위해 만들어졌다.”
즉, CSS 2.1은 CSS 2의 오류를 해결하려는 목적으로 만들어졌음을 알 수 있습니다. 하지만, XHTML 1.0에서처럼 오류를 반영한 새 버전(second edition)을 내놓는 대신 개정판(revision) 제정을 선택했는데 그만큼 규격 적용과 구현에 중대한 영향을 미치는 변화가 이루어졌다는 뜻입니다. W3C의 프로세스 문서에 따르면 이미 발표된 최종 권고안에 새로운 기능을 추가하기 위해서는 규격을 새로 만들 때와 동일한 일련의 과정을 거쳐야 합니다. 그래서 CSS 2.1을 초안(working draft) 단계부터 새로 시작한 것이지요.
“CSS 2.1의 가장 중요한 변화는 이상(W3C의)이 아닌 브라우저에 초점을 맞췄다는 사실이다. CSS 2의 일부 내용은 쓸모가 없거나 비합리적이고, 브라우저는 비합리적인 규격을 보다 합리적인 다른 방식으로 구현해왔다.”
그럼 CSS 2.1은 어떻게 사용자 에이전트에 초점을 맞췄을까요? W3C는 그 방향성을 다음과 같이 밝히고 있습니다.
CSS 2 내용 중에서 널리 받아들여지고 구현된 부분에 대한 호환성은 계속 유지한다.
발표된 모든 CSS 2 오류를 반영한다.
CSS 2 규격과 완전히 다른 방식으로 구현이 이루어진 경우에는 일반적인 방식을 따르도록 규격을 변경한다.
현재까지 구현되지 않아서 CSS 사용자들이 받아들이지 않은 CSS 2 기능은 제거한다.
CSS 3에서 폐기될 CSS 2 기능을 제거함으로써 CSS 3에 도입될 기능을 대신 받아들이도록 장려한다.
경험적으로 CSS 2를 구현하는데 필요하다고 여겨지는 속성 값은 새롭게 추가한다.
특히 세 번째와 네 번째 항목이 사용자 에이전트에 대한 존중을 잘 보여줍니다. 규격을 내놓고 따르기를 강요하는 것이 아니라 사용자 에이전트의 일반적인 구현 방식에 따라서 규격을 수정하겠다는 뜻이니까요.
다섯 번째 항목에 대해서는 앞서 언급한 Anne van Kesteren의 글에 좋은 예가 있습니다.
“CSS 3에서는 ::marker 가상 요소가 도입될 예정이므로 display 속성 값인 marker가 제거되었다. 마찬가지로 CSS 3 Speech 모듈과의 상위 호환성을 위해서 aural 미디어 타입 사용을 금지(deprecate)시키고 대신 speech 미디어 타입을 도입했다.”
위에 언급된 display: marker나 aural 미디어 타입을 제대로 지원하는 사용자 에이전트는 극히 드뭅니다(aural을 지원하는 Emacspeak같은 일부를 제외하고). 만약 CSS 3에 도입될 기능이라 해도 현재 사용자 에이전트가 폭넓게 지원하고 있다면 얘기는 달라졌을 것이라 생각합니다.
마지막 방식에 따라서 전부 다섯 가지 항목에 대한 속성 값이 추가되었는데 CSS 2.1 부록 C에 수록된 200가지가 넘는 변경 사항과 비교해보면 극히 미미한 변화라고 생각합니다.
CSS 2.1의 상위 호환성과 하위 호환성, 그리고 위치
CSS 2.1의 호환성에 대해서 W3C는 다음과 같이 설명하고 있습니다.
“CSS 2 스타일 시트는 CSS 2.1과의 상위 호환성을 완벽히 보장하지 못하지만, CSS 2.1 기능에 한정된 스타일 시트는 최신 사용자 에이전트의 지원과, 앞으로의 상위 호환성을 확보하기가 더 쉽다. 하위 호환성을 지키지 못한다는 점은 바람직하지 않지만, CSS 2.1 리비전을 통해 얻게 될 장점은 충분히 가치있다고 믿는다.”
“CSS 2.1은 CSS 2를 기반으로 만들어졌고, CSS 2를 대체하려는 목적을 갖고 있다. CSS 2의 일부는 CSS 2.1에도 그대로 유지되고, 일부는 변경되었으며 일부는 삭제되었는데 삭제된 부분이 미래의 CSS 3 규격에서 다시 사용될 수도 있다. 미래의 규격은 CSS 2.1을 참조해야 하지만 CSS 2.1에서 누락된 CSS 2 기능이 필요할 경우에는 CSS 2의 해당 기능을 참조하거나 이러한 기능을 포함하고 있는 CSS 3 모듈을 참조할 것이다.”
† 사실 “상위 호환성”이나 “하위 호환성”은 쉽게 설명할 수 있는 개념이 아닙니다. 처음에는 먼저 이 두 용어를 정의한 다음 설명할 생각이었는데 자료를 찾아보니 간단한 문제가 아니더군요. 그래서 이 글에서는 따로 설명하지 않겠습니다.
핵심은 CSS 2.1이 CSS 2의 추가 버전이 아니고, CSS 2를 완전히 대체할 규격이라는 사실입니다. 전례가 있는지 잘 모르겠지만 개인적으로는 CSS 2.1이 최종 권고안이 되면 CSS 2 규격은 폐기될 가능성도 있다고 생각합니다. 앞서 언급한 W3C의 프로세스 문서에는 특정 권고안에 심각한 오류가 있거나 특허권 문제가 있을 때 권고안 자체를 폐기시킬 수도 있다고 명시되어 있는데 그럴 경우에는 이후 발표되는 모든 기술 문서에서 해당 권고안을 참조할 수가 없기 때문에 CSS 2.1에서 삭제된 CSS 2 기능을 CSS 3에서 참조해야 할 경우를 생각하면 가능성이 크지는 않겠지만이요.
결론적으로, CSS 3로 넘어가기 전까지는 사실상 CSS 2.1이 최종 권고안이나 마찬가지라고 생각합니다. 웹 페이지를 제작하는 실무자가 신경써야 할 규격도 CSS 2.1이겠지요. 일례로 마이크로소프트사는 인터넷 익스플로러 8이 CSS 2.1을 완전히 지원할 것이라고 밝히고 있으며, 웹 표준 지원에 관한 오페라 기술 문서에는 오페라 9가 극히 일부를 제외한 모든 CSS 2.1 규격을 따른다고 명시되어 있습니다.
CSS 2.1의 미래
현 상태에서 CSS 2.1은 최종 권고안으로 채택될 날만을 기다리고 있습니다. CR 다음 단계인 PR(Proposed Recommendation)로 넘어가기 위해서 반드시 만족시켜야 할 조건 다섯 가지가 CSS 2.1 규격 서문에 나와 있는데 한 가지 요건인 최소한의 CR 기간(6개월)이 이미 지났기 때문에 사용자 에이전트의 지원이 확인되고 내부적인 테스트가 끝나면 머지 않아 PR 단계로 넘어갈 것이고, 최소한 4주간의 PR 단계를 거치면서 최종 검토를 한 후 자문 위원회의 승인을 거쳐 최종 권고안으로 발표될 것입니다.
한 가지 관심을 기울여야 할 부분이 있는데 바로 “위기에 처한 기능(features at risk)” 입니다. 위기에 처한 기능이란 W3C가 공개적으로 사용자 에이전트에게 구현을 재촉하는 기능을 말합니다. 다시 말해서 “빨리 이 기능을 구현하거나, 버그가 있는 구현을 바로잡지 않으면 CR이 끝나는대로 해당 기능을 제거하겠다.”라는 엄포입니다. 그러므로 변화의 가능성이 큰 기능이지요. 이렇게 CSS 2.1에서 위기에 처한 기능은 다음과 같습니다.
list-style-type에 사용되는 armenian, georgian, lower-greek 속성 값
† 관심을 기울여야 한다고 했는데 사실 실무적으로는 다섯 번째 항목을 제외하면 그리 중요하지 않다고 생각합니다.
다섯 번째 항목에서 XHTML과 HTML에서 body 요소의 overflow와 background 처리가 약간 다릅니다. overflow를 예로 들면 XHTML에서는 최상위 요소(html)에 지정된 overflow 속성 값을 뷰포트에 적용시켜야 하지만, HTML에서는 html 요소의 overflow 값이 visible일 경우에 한해서 body 요소의 속성 값을 뷰포트에 적용시키도록 규정되어 있는데 이런 예외 상황에 대한 처리가 XHTML에 그대로 이어졌다는 내용입니다.
마치며
참 긴 글이지만 결론은 한 줄로 요약할 수 있을만큼 간단합니다. ^^;
웹 제작자에게 중요한 규격은 CSS 2가 아닌 CSS 2.1이다.
나름대로 열심히 자료를 찾고, 해석해봤는데 과연 얼마나 정확한 내용을 담고 있을지 모르겠네요. 특히 CR에서 PR로, 다시 최종 권고안으로 진행되는 과정은 참고한 W3C의 프로세스 문서를 충분히 검토하지 않아서 오류가 있을 가능성이 다분합니다. 오류를 알려주시면 정오표에 수록한 다음 나중에 이 글의 리비전을 만들 때 반영하도록 하겠습니다. :)
W3C 권고안에서 자주 사용되는 용어 중 하나가 “규격을 따르는 사용자 에이전트(Conforming User Agent)”입니다. 이렇게 어떤 규격을 “따른다”거나 규격에 “부합한다”라는 의미로 사용되는 단어가 “conformance”인데 conformance에 대한 W3C의 정의는 다음과 같습니다.
conformance : 표준(standard)이나 지침(guideline), 규격(specification)의 모든 요구 사항을 만족함
다시 말해서 W3C가 제안한 각각의 규격에 부합하기 위한 요건들을 뜻하는데 그렇기 때문에 규격문에서 상당히 중요한 의미를 갖습니다. 일반적으로 각각의 규격문은 세부적인 설명(속성 설명 등)을 시작하기 전에 이런 요건들을 먼저 설명하는데 예를 들어서 HTML 4.01 권고안 4장, XHTML 1.0 권고안 3장, 그리고 이 글에서 다룰 CSS 2.1 권고안 3장에서 독립적으로 다루고 있습니다.
넓은 의미로 conformance는 규격문을 어떻게 해석하고 구현해야 하는지, 반드시 준수해야 하는 사항(requirements)과 권장 사항(recommandations)을 어떻게 구별해야 하는지를 알려줍니다. 사실 “어떤 사항을 지켜야 한다”라고 말하면 듣는 사람에 따라서 “반드시 지켜야 한다”고 생각할 수도 있고, “지키는 것이 좋다”라고 해석할 수도 있기 때문에 정확함이 필수인 규격문에서는 이런 구분을 명확히 할 필요가 있습니다. 또한, 규격문 전체가 핵심적인 준수 사항만을 다루지는 않습니다. 설명이나 예제도 있고 비공식적인 권장 사항도 있으니까요. 이런 부분에 대한 구분도 conformance에서 다루고 있습니다.
설명이 길었는데 그만큼 중요하다는 점을 강조하고 싶었기 때문입니다. 그러면 CSS 2.1의 conformance를 살펴볼까요?
† 기본적으로는 CSS 2.1의 관련 내용을 정리한 것이지만 자의적인 설명이나 해석도 일부 있습니다. 이 점 염두에 두시기 바랍니다.
용어와 표현 정의
CSS 2.1 conformance에서 처음 다루는 내용은 핵심적인 표현 정의입니다. 먼저 “필수 사항”과 “권장 사항”, “재량 사항”을 나타내는 단어를 정의하고 있는데 흥미로운 사실은 이런 용어 정의를 다루는 규격이 따로 있다는 점입니다. 이 규격은 RFC2119로 W3C 권고안을 포함한 다수의 규격문에서 인용되는데 하버드 대학의 보안 책임자(Security Officer)이자 다양한 네트워크 관련 기술 표준을 만드는 IETF의 공동 책임자(co-director)인 Scott Bradner가 1997년 발표한 규격입니다.
† RFC는 “Request for Comments”의 약자로 네트워크 엔지니어들이 새로운 기술이나 개념, 때로는 유머 등에 대해 자유롭게 올리는 메모 형식의 문서인데 그 중 일부를 IETF가 표준으로 채택하고 있습니다. RFC2119의 제목은 “RFC 문서에서 요구 조건을 명시하는데 사용할 키워드”입니다.
RFC2119의 핵심 내용은 아래 다섯 개의 키워드 정의입니다.
MUST(또는, REQUIRED, SHALL) : 반드시 지켜야 하는 사항
MUSTNOT(또는, SHALLNOT) : 절대적으로 금지되는 사항
SHOULD(또는, RECOMMENDED) : 상황에 따라서 지키지 않을 수도 있지만 그런 경우라 해도 신중하게 판단해야 하는 사항
SHOULDNOT(또는, NOTRECOMMENDED) : 어떤 방식이 적합하거나 때로는 더 유용할 수도 있는 상황에 한해 허용될 수도 있지만 그런 경우라 해도 신중하게 판단해야 하는 사항
MAY(또는, OPTIONAL) : 규격을 받아들이는 제작사(vendor)가 시장의 요구나 기능 향상을 위해 자유롭게 선택할 수 있는 사항
그런데 영문 규격문을 한글로 번역하면 “should”의 의미가 모호해지기도 합니다. 일반적으로 “~해야 한다”로 해석하기 때문에 “반드시 ~해야 한다”는 의미로 사용되는 “must”와 혼동될 수 있기 때문입니다. 그렇기 때문에 규격문을 올바르게 이해하려면 이 두 표현 차이를 정확히 구분해서 받아들여야 합니다.
또한, W3C가 사용자나 사용자 에이전트에게 권장하는 “좋은 방식(good practice)”을 제안할 때가 있는데 이런 경우에는 “우리는 ~하는 것을 권장한다(We recommand ~)”, 또는 “이 규격에서는 ~하는 것을 권장한다(This specification recommends ~)”라고 표현합니다. “should”와 비슷한 의미로 해석될 수 있지만 둘 사이에는 분명한 차이가 있습니다. 다시 말해서 좋은 방식에 대한 권고는 비공식적이기 때문에 사용자나 사용자 에이전트가 어떻게 받아들이든 상관없이 conformance에 아무런 영향을 주지 않습니다.
규범적인 내용과 그렇지 않은 내용
이렇게 규격문 내에서 conformance와 상관없는 내용을 “비 규범적(non-normative)”이라고 표현하는데 간단히 말해서 따르지 않아도 된다는 뜻입니다. 비슷한 표현으로 “informative”가 있는데 단순히 정보만을 제공할 때 사용됩니다. 이 두 표현 모두 conformance와는 관계가 없습니다. 예를 들어서 위에 설명한 좋은 방식에 대한 권고나 규격문에 포함된 각종 예제, 노트는 전부 규범적인 내용이 아닙니다.
규격문에서는 규범적인 내용과 그렇지 않은 내용을 엄격하게 구분하는데 일반적으로 특별히 언급하지 않는 한 규격문의 모든 단락(부록(appendix)을 포함해서)은 규범적이고, 따라서 사용자나 사용자 에이전트는 해당 단락이 요구하는 모든 사항을 지켜야 합니다. 지키지 않아도 되는 일부 사항에 대해서는 규격문에서 명시적으로 비 규범적이라고 밝히고 있습니다.
또한, 특정 기능 사용이 금지되거나(deprecated) CSS3에서 금지될 예정이라고 표현하는 경우가 있는데 이런 표현도 conformance와는 관계가 없습니다. 예를 들어서 CSS 2.1 부록 A에서 다루는 음성 스타일 시트에서는 aural 미디어 유형이 금지되었다고 밝히고 있는데 이 사실은 conformance에 영향을 주지 않습니다. 하지만 실제로 사용자 에이전트는 aural 미디어 유형을 반드시 지원하지 않아도 무방한데 그 이유는 부록 A 전체가 정보 제공만을 위한 내용이라고 명시되어 있기 때문입니다. 부록 A 목차 다음에 나오는 첫 번째 내용은 다음과 같습니다. “This chapter is informative”.
비슷하게 시스템 칼라도 CSS3에서 금지될 예정이라고 밝히고 있습니다. 하지만 여기에서는 명시적으로 informative나 non-normative라고 밝히지 않기 때문에 conformance를 만족하려면 사용자 에이전트가 반드시 구현해야 합니다.
† 특정 속성이나 요소가 금지(deprecated)되었더라도 사용자 에이전트는 이를 지원해야 합니다. 하위 호환성 때문이지요. 대조적으로 폐기된(obsolete) 속성이나 요소는 사용자 에이전트가 지원하지 않아도 무방합니다. 규격문에서도 기록을 위한 목적을 제외하고 완전히 삭제됩니다.
앞서 설명한 예제와 노트는 온라인 규격문에서 일반적인 내용과 구분되도록 독자적인 색으로 표현됩니다. 예제의 경우는 밤색 텍스트로, 노트의 경우에는 녹색 텍스트로 표현됩니다. 설명을 위한 이미지는 특별히 언급하지 않는 한 결과를 보여주기 위한 용도이기 때문에 사용자 에이전트가 실제로 동일하게 표현해야 하는 것은 아닙니다.
사용자 에이전트 Conformance
먼저 CSS 2.1에서 정의하는 사용자 에이전트란 무엇인지 W3C의 정의를 통해서 알아보겠습니다(다른 규격에서는 다른 의미로 사용될 수도 있습니다).
사용자 에이전트는 문서 언어(HTML, XHTML 같은)로 작성된 문서를 해석해서 이 규격에 명시된대로 스타일 시트를 적용하는 모든 프로그램을 말한다. 사용자 에이전트는 문서를 시각적으로 보여주거나, 음성으로 표현할 수도 있고, 인쇄할 수도 있으며, 문서를 다른 형식(format)으로 변환할 수도 있다. 추가적으로 스타일 시트를 만들어내는 제작 툴(authoring tool)도 사용자 에이전트에 속한다.
사용자 에이전트가 CSS 2.1 규격에 부합한다고(conformance) 말할 수 있으려면 아래의 여섯 가지 사항을 준수해야 합니다.
반드시 하나 이상의 CSS 미디어 유형(screen, print 등)을 인식할 수 있어야 한다.
각각의 문서에 대해서 인식한 미디어 유형에 해당하는 모든 스타일 시트를 최대한으로 가져와야 한다. 네트워크 오류 등으로 인해서 모든 스타일 시트를 가져오지 못할 경우에는 가져올 수 있는 스타일 시트만으로 문서를 표현해야 한다.
반드시 스타일 시트를 규격에 따라서 해석해야 한다. 특히 모든 @ 규칙과 선언 블록, 선택자를 반드시 인식해야 한다. 그런 다음 사용자 에이전트가 지원하는 미디어 유형에 적용되는 속성이 있으면 속성 값을 규격에 명시된 속성 정의에 따라 반드시 해석해야 한다. 다시 말해서 유효한 속성 값은 반드시 받아들이고, 유효하지 않은 속성 값이 지정된 선언은 반드시 무시해야 한다. 또한, 지원하지 않는 미디어 유형에 적용되는 규칙도 반드시 무시해야 한다.
문서 구조(document tree)에 있는 모든 요소에 대해서 속성 정의와 캐스케이딩, 상속 규칙에 따라 모든 속성 값을 반드시 지정해야 한다.
문서에 대체 스타일 시트가 포함되어 있을 경우에는 사용자 에이전트가 적용할 스타일 시트를 반드시 사용자가 선택할 수 있도록 해야 한다.
사용자 에이전트는 제작자가 작성한 스타일 시트의 효과를 사용자가 제거하는 것을 반드시 허용해야 한다.
하지만 사용자 에이전트의 목적과 기능이 전부 동일하지 않기 때문에 사용자 에이전트 유형에 따라서 지원해야 할 사항이 달라집니다. 아래 세 가지 조항이 이를 설명하고 있습니다.
문서 내용을 전혀 렌더링하지 않고 스타일 시트를 읽기만 하는 사용자 에이전트(CSS 2.1 validator 같은)는 1번부터 3번 항목을 반드시 준수해야 한다.
스타일 시트를 만들어내는 제작 툴은 유효한 스타일 시트를 만들어내기만 하면 된다.
스타일 시트를 이용해서 문서를 렌더링하는 사용자 에이전트는 1번부터 6번까지의 모든 조항을 준수해야 하며, 규격에 명시된 미디어 유형에 따른 요구사항에 따라서 문서를 렌더링해야 한다. 사용자 에이전트는 필요한 경우에 한해서 속성 값을 근사치로 계산할 수도 있다.
이외에도 몇 가지 항목을 더 설명하고 있는데 첫 번째는 장치의 제한에 대해서입니다. 예를 들어서 흑백 모니터에서는 사용자 에이전트가 칼라를 표현할 수 없는데 이런 장치의 한계 때문에 규격의 일부를 구현하지 못한다고 해서 규격을 준수하지 않는 것(non-conformance)은 아닙니다.
두 번째로 사용자 에이전트는 사용자가 자신만의 사용자 스타일 시트가 담긴 파일을 지정할 수 있도록 반드시 허용해야 합니다. 그렇지만 파일을 지정하거나 작성할 수 없는 장치에서 동작하는 사용자 에이전트는 이 요구 사항에 구속되지 않습니다. 또한, 사용자 에이전트는 그래픽 사용자 인터페이스(GUI) 같은 다른 방식으로 사용자가 자신이 선호하는 스타일을 선택하도록 할 수도 있습니다.
이제 중요한 마지막 항목이 남았습니다. CSS 2.1은 폼 컨트롤이나 프래임에 어떤 속성이 적용되고, 어떻게 스타일이 적용되는지를 정의하지 않습니다. 따라서 모든 요소에 적용된다고 정의된 속성이라도 폼 컨트롤이나 프레임에는 적용되지 않을 수 있습니다. 특히 폼 컨트롤 같은 경우에는 브라우저에 따라서 표현 방식과 적용되는 속성이 많이 다른데 CSS 2.1에서는 사용자 에이전트가 이런 요소에도 CSS 속성을 적용할 수 있다고만 밝히고 있습니다. 또한, W3C는 제작자가 이런 지원 방식을 시험적인 방식으로 받아들이기를 권고하고 있는데, 다시 말해서 현재의 규격을 따르기 위한 방식이 아니라는 뜻입니다. 그래서 차후 발표될 새로운 CSS 규격에서는 이런 부분을 명확히 할 수도 있다고 밝히고 있습니다.
† 폼 컨트롤을 시각적으로 표현하는 것은 전적으로 사용자 에이전트의 영역입니다. 따라서 select 같은 요소에 스타일이 적용되지 않는다고 해서 특정 사용자 에이전트가 CSS 규격을 어기는 것이 아닙니다. 또한, 동일한 사용자 에이전트라 해도 운영되는 플랫폼에 따라서 다르게 표현되기도 합니다. 대부분의 사용자는 자신이 사용하는 운영체제나 시스템이 제공하는 컨트롤에 익숙해져 있기 때문에 사용자 에이전트 대부분이 사용성(usability)을 높이기 위해서 제공되는 컨트롤을 그대로 이용하고 있습니다. 이런 이유로 현 시점, 그리고 앞으로도 CSS 규격이 폼 컨트롤 표현을 완벽하게 강제하기는 어렵다고 생각합니다.
운영체제, 사용자 에이전트에 따른 폼 컨트롤 렌더링 차이는 다양한 스크린샷을 제공하는 CSS로 폼 컨트롤 스타일 입히기 페이지를 참고하시기 바랍니다.
오류 처리와 MIME 타입
CSS 2.1 규격은 오류 처리에 관한 내용을 공식적으로 포함하고 있습니다. 이런 면에서 HTML 4.01과 대조되는데 HTML 4.01은 오류 처리에 대해서 공식적으로 규정하지 않기 때문입니다. 다만 어떤 방식으로 처리하는 것이 좋은지 노트 형식으로 권고는 하고 있는데 앞서 설명한 것처럼 informative한 항목입니다. CSS 2.1에서는 해석상의 오류 처리 방식처럼 필요할 경우에 명시적으로 오류 처리 방식을 제시하고 있습니다.
마지막으로 외부 스타일 시트가 전송될 때 text/css라는 content type이 외부 스타일 시트임을 나타낸다고 정의되어 있습니다. text/css 타입은 RFC2318에 등록되어 있습니댜.
† CSS 2.1 규격에서 정확한 content type을 명시하고 있기 때문에 다른 content type으로 전송되는 외부 스타일 시트는 사용자 에이전트가 무시할 수도 있습니다. 예를 들어서 파이어폭스 2.0 표준 렌더링 모드는 text/css로 전송되지 않는 외부 스타일 시트는 해석하지 않습니다.
마치며
상대적으로 최근에 제정된 XHTML 1.0이나 XHTML 1.1 규격에서는 규범적인(normative) 내용과 그렇지 않은 내용(non-normative)를 명확하게 구분합니다. 각각의 장(챕터) 첫 번째 단락에 normative인지 아니면 non-normative, 또는 informative인지를 분명하게 밝히고 있는데 그만큼 규격문을 해석하는데 중요하기 때문입니다.
W3C 규격문은 상당히 체계적으로 구성되어 있습니다. 물론, 모호한 일부 규격도 있지만 전체적으로 봤을 때 더 나은 웹을 위한 고심을 느낄 수 있을만큼 잘 정리되어 있다고 생각합니다. 웹이 제공할 무한한 가능성에 대한 기대도 이런 고심을 바탕으로 하는 것이겠지요.
normative와 non-normative에 대한 다양한 예를 소개하면서 설명하려고 했는데 처음 예상했던 것보다 글이 너무 길어졌네요. ^^; 다음 글에서는 CSS 2와 CSS 2.1의 관계에 대해서 알아보겠습니다.
사용자 에이전트는 CSS를 이용해서 스타일을 요소에 적용시킵니다. 이렇게 스타일이 최종적으로 적용될 때까지 속성 값은 최대 네 번 처리되는데 CSS 2.1 권고안은 그 과정을 값 지정, 캐스케이딩, 상속을 다루는 6장에서 설명하고 있습니다. 이 과정에서 핵심이 되는 것은 “지정된 값(specified values)”, “산출 값(computed values)”, “사용되는 값(used values)”, “실제 값(actual value)”인데 이 부분을 중심으로 CSS의 속성 처리 방식을 알아보겠습니다.
† 본문 내용에 제시된 설명의 상당 부분은 제가 권고안을 바탕으로 해석한 것입니다. 따라서 정확하지 않을 확률이 높으니 이 점을 감안하시기 바랍니다. ^^;
개요
사용자 에이전트는 문서를 해석해서 문서 구조(document tree)를 만든 다음 문서 구조상의 모든 요소에 media 유형이 지원하는 모든 속성에 대한 값을 지정해야 합니다. 최종적으로 속성에 적용되는 값은 네 단계의 계산을 거치는데 먼저 정확한 값을 확인하고(지정된 값) 이 값을 상속(inheritance)에 사용될 값(산출 값)으로 변환합니다. 그 다음 변환된 값을 필요에 따라 절대 값으로 바꾸고(실제 값) 마지막으로 주어진 환경에서 구현이 불가능한 값일 경우에 적당한 값으로 변환합니다(실제 값).
지정된 값
† “지정된 값”의 원문은 “specified values”인데 의미상으로 정확히 일치하지 않지만 마땅한 대치어가 생각나지 않네요. ^^;
사용자 에이전트는 먼저 아래 열거한 순서대로 지정된 값을 처리해서 각각의 속성 값으로 지정합니다.
캐스케이드로 값이 얻어지면 그 값을 사용한다.
상속이 되는 속성이고, 해당 요소가 문서 구조에서 최상위(root) 요소가 아닐 경우에는 부모 요소의 산출 값을 사용한다.
그 외의 경우에는 속성 정의에 지정되어 있는 해당 요소의 초기 값(initial value)을 사용한다.
첫 번째 캐스케이드 단계에서는 제작자(author) 스타일 시트 뿐 아니라 사용자 스타일 시트와 사용자 에이전트 스타일 시트가 전부 사용됩니다. 다시 말해서 직접 작성한 CSS에 값을 지정하지 않아도 브라우저의 기본 스타일 시트에 값이 지정되어 있으면 그 값을 사용한다는 뜻입니다. 일단 이 단계가 끝나고 남은 속성은 inherit 값을 갖거나 아니면 아예 값이 지정되지 않은 상태입니다.
두 번째 단계에서는 상속을 처리합니다. 속성 값이 명시적으로 inherit이거나 해당 속성이 부모 요소의 값을 상속한다고 정의되어 있을 경우에는 부모 요소의 산출 값을 사용합니다.
세 번째 단계에서는 속성 값이 없고 상속도 받지 않는 요소와 문서의 최상위 요소만 남습니다. 이럴 경우에는 모두 해당 속성의 초기값이 사용됩니다.
산출 값
캐스케이딩 과정에서 지정된 값이 할당되고 다시 산출 값으로 변환됩니다. 예를 들어서 상대 URI가 절대 URI로 변환되고, em이나 ex 단위가 픽셀이나 절대 길이로 변환되는데 이 과정까지도 사용자 에이전트는 문서를 렌더링하지 않습니다. 만약 사용자 에이전트가 URI를 절대 URI로 변환할 수 없는 경우에는 지정된 값을 그냥 사용합니다.
지정된 값이 inherit이 아닐 경우에 속성의 산출 값은 속성 정의에 명시된 “산출 값” 설명에 따라 변환됩니다. inherit일 경우에는 부모 요소의 산출 값을 상속받는데 앞서 설명한 “지정된 값” 계산 방식에 따라서 해당 요소의 지정된 값과 산출 값은 모두 부모 요소의 산출 값이 됩니다. 예를 들어서 다음과 같은 CSS와 마크업을 생각해보지요.
'font-size'
상속 여부: 상속됨
퍼센트 값: 부모 요소의 폰트 크기를 참조
산출 값: 절대 길이
h1 요소의 font-size가 퍼센트로 지정됐기 때문에 “퍼센트 값” 항목에 설명된대로 부모 요소(body)의 font-size 값을 기준으로 계산됩니다(10pt * 130% = 13pt). 따라서 최종 산출 값은 13pt인데 이 값을 em 요소가 상속받기 때문에 em 요소의 지정된 값과 산출 값은 모두 13pt가 됩니다. 이렇게 변환된 산출 값을 상속하는 이유는 불필요한 변환 과정을 줄이기 위해서라고 생각됩니다. 다시 말해서 부모 요소의 지정된 값을 상속받으면 다시 한 번 절대 단위나 절대 URI로 변환을 해야 하는데 산출 값을 상속받으면 이런 과정이 한 번만 이루어지니까요.
산출 값은 해당 요소에 해당 속성이 적용되지 않을 경우에도 계산됩니다. 하지만 일부 속성은 속성 적용 여부를 고려해서 요소에 적용될 변환 값을 정의할 수도 있습니다.
사용되는 값
산출 값은 문서를 서식화하지 않는 선에서(레이아웃을 신경쓰지 않고) 최대한 계산됩니다. 하지만 일부 속성 값은 문서 레이아웃이 만들어진 후에만 결정됩니다. 예를 들어서 width 속성 값이 퍼센트 값으로 지정될 경우에는 포함 블록(containing block)의 width가 결정되지 않으면 계산할 수가 없습니다. “사용되는 값”은 이렇게 의존성을 고려해서 산출 값을 절대 값으로 변환한 결과입니다.
실제 값
원칙적으로 실제 문서 렌더링에 사용되는 값은 “사용되는 값”입니다. 하지만 상황에 따라서 사용자 에이전트가 이 값을 제대로 처리하지 못하는 경우가 있습니다. 예를 들어서 사용자 에이전트가 보더 두께를 픽셀 값으로만 표현할 수 있는데 사용되는 값이 픽셀이 아닌 절대 길이(예: 2mm)라면 이 값을 다시 픽셀 값으로 변환해야 합니다. 또 색을 제대로 표현하지 못하는 사용자 에이전트는 색상 값을 그레이스케일 값으로 변환할 수도 있습니다. 이렇게 사용자 에이전트의 제한으로 사용되는 값을 제대로 표현할 수 없을 때 적당한 값으로 변환되는데 이 값이 최종적인 실제 값입니다.
변환 예
margin-left 속성을 예로 들어서 실제로(정확하다고 보장할 수는 없지만^^;) 계산을 해보겠습니다. 다음과 같은 마크업과 CSS가 있다고 생각해보지요.
<div>
<p>some text</p>
</div>
div { width: 300px; }
p { width: 100px; margin-left: 10%; }
margin-left의 속성 정의는 다음과 같습니다(필요한 부분만 가져왔습니다).
'margin-left'
퍼센트 값: 포함 블록의 width를 참조
산출 값: 지정된 퍼센트 값이나 절대 길이(the percentage as specified or the absolute length)
스타일 시트에 p 요소의 margin-left가 10%로 지정되어 있습니다. 값이 있고, 캐스케이딩에 영향을 주는 다른 규칙이 없으므로 “지정된 값”은 10%가 됩니다. 다음에 “산출 값”을 계산해야 하는데 속성에 지정된 퍼센트 값을 사용한다고 정의되어 있으므로 이 값도 10%가 됩니다. 앞서 확인했던 font-size 속성에는 산출 값이 절대 길이라고 정의되어 있는데 퍼센트 값도 부모 요소의 값을 이용해서 절대 길이로 바꿀 수 있었습니다. 하지만 margin-left 속성에 퍼센트 값이 사용될 경우에는 포함 블록의 width를 기준으로 해석되므로 산출 값을 “사용되는 값”으로 다시 변환해야 합니다. 결국 포함 블록 width의 10%인 30px이 얻어지는데 브라우저가 이 값을 그대로 표현할 수 있으면 “실제 값”으로 더 이상 변환되지 않고 그냥 최종 값으로 사용됩니다.
의문점
몇 가지 의문점이 있는데 그 중 가장 중요한 문제만 생각해보겠습니다. 바로 산출 값에서 “절대 길이(absolute length)”가 무엇을 의미하는가입니다. CSS에서는 길이 단위를 절대 길이 단위와 상대 길이 단위로 나누는데 px은 상대 길이 단위에 속합니다. 따라서 절대 길이가 절대 길이 단위로 표현된 모든 길이 값을 의미한다면 산출 값을 결정할 때 px 값도 인치(in)나 포인트(pt) 같은 절대 길이 단위로 변환되어야 합니다.
하지만 CSS 2.1의 길이 설명에 제시된 예제를 보면 절대 길이가 절대 길이 단위를 사용한 값을 의미하는 것 같지 않습니다. 예제는 다음과 같습니다.
p { font-size: 10px }
p { line-height: 120% } /* 120% of 'font-size' */
권고안에서는 p 요소의 line-height 산출 값이 12px이고, p 요소의 자식 요소도 이 값을 상속받는다고 명시하고 있습니다. 이 사실을 봤을 때 “절대 길이”라는 표현이 “확실한 길이”, 또는 “실제 길이” 등을 의미하는 것이 아닌가 하는 생각이 듭니다.
또한, W3C의 메일링 리스트와 WCAG 상대 단위와 절대 단위 페이지에는 웹 컨텐츠 접근성 지침(Web Content Accessibility Guidelines)에서 사용하는 “절대 길이 단위”라는 표현에 px도 포함시켜야 한다는 의견이 있습니다. 일반적인 웹 환경에서 픽셀이 대부분 절대 길이 단위처럼 취급되는 것이 한 가지 이유이고, 접근성 측면에서 WCAG가 텍스트 크기에 따라 길이가 늘어날 수 있도록 상대 단위 사용을 권장하는데 이 상대 길이 단위에 포함되는 픽셀을 사용하면 실제로 유동적인 길이를 표현하지 못하기 때문에 혼란이 있을 수 있다는 점이 다른 이유입니다. 이 부분은 WCAG 1.0의 체크포인트 3.4에 있는데 실제 내용은 다음과 같습니다.
마크업 언어와 스타일 시트의 속성 값에는 절대 단위(absolute units)보다 상대 단위(relative units)를 사용하라.
CSS를 예로 들면 절대 단위인 pt, cm 길이보다 em이나 퍼센트 길이를 사용하라. 절대 단위를 사용할 때에는 렌더링된 컨텐츠를 불편 없이 이용할 수 있는지 확인해야 한다.
WCAG 1.0이 오래된 권고안이기는 하지만 이런 점이 픽셀 단위에 대한 W3C의 모호함을 단적으로 보여주는 예라고 생각합니다.
마치며
간단히 정리하려고 했는데 잘 이해되지 않는 부분이 있어서 쉽지가 않네요. 그래도 이렇게 글을 작성하면서 속성 값이 처리되는 방식을 어느 정도 이해할 수 있게 되었습니다. 전에도 속성 정의에 제시된 산출 값이 정확히 무엇을 의미하는지 고민했던 적이 있었거든요.
서두에도 말씀드렸지만 이 글의 내용은 정확하지 않을 수 있습니다. 혹시 속성 값 산출 방식이나 절대 길이와 픽셀에 관한 정보나 의견이 있으면 꼭 알려주시기 바랍니다.
다음 글에서는 W3C 권고안에서 자주 사용되는 “CSS를 따르는 사용자 에이전트(conforming user agent)”가 무엇을 의미하는지 알아보겠습니다.
W3C가 제정한 CSS 권고안(규격)의 핵심이 바로 속성 정의와 그에 따른 설명입니다. 각각의 속성들이 어떻게 해석되고 적용되는지를 알기 위해서 속성 정의를 살펴볼 때가 많은데 CSS 권고안이 기본적으로 CSS를 작성하는 웹 제작자와 CSS를 구현하는 사용자 에이전트 제작자 모두를 대상으로 작성되었기 때문에 해석하기 까다로운 부분이 있습니다. CSS 2.1 권고안은 CSS 2.1을 소개하면서 속성 정의를 해석하는 방법을 설명하고 있는데 이 문서를 간략하게 설명해보겠습니다.
속성 정의 형식
속성 정의는 다음과 같은 형식으로 구성되어 있습니다.
'property-name'
Value: 허용되는 값이나 문법
Initial: 초기 값
Applies to: 적용 대상
Inherited: 상속 여부
Percentages: 퍼센트 값 해석 방식
Media: 속성이 적용되는 media 유형
Computed value: 산출 값
Value (허용되는 값이나 문법)
속성에 사용될 수 있는 유효한(valid) 값을 의미합니다. 아래처럼 값의 유형에 따라서 표기 형식이 약간씩 다릅니다.
키워드 값 (auto, disc 등)
기본 자료형 (<length>, <percentage> 등)
특정 속성과 동일한 허용 값을 갖고 이름도 같은 값 유형 (<'border-width'> 등)
특정 속성을 직접 나타내지 않고 적용되는 값만 정의하는 값 유형(<border-width> 등)
3번과 4번 유형은 비슷하게 표현되지만 차이가 있습니다. 즉, <border-width>는 특정한 속성 값(thin, medium, thick, <length>)만을 정의하는 독자적인 값 유형입니다. 반면에 <'border-width'>는 CSSborder-width 속성에 허용되는 값과 동일한 값을 나타내는 값 유형으로 <border-width>를 값으로 갖습니다(inherit는 포함되지 않습니다).
비슷한 값 유형을 이렇게 따로 정의한 이유는 속성 정의를 최대한 간단히 표현하기 위해서라고 생각합니다. XMLDTD에 사용되는 파라미터 엔티티(Parameter Entity) 선언처럼이요. 예를 들어서 CSS에는 border-width 뿐 아니라 border-top-width, border-right-width, border-bottom-width, border-left-width 속성이 따로 있습니다. 이 각각의 속성마다 앞서 열거한 값(thin 등) 대신 <border-width>를 쓰면 중복을 줄일 수 있고 각각의 값에 대한 설명도 반복할 필요가 없습니다. 또한, border-width 속성은 최소 1개부터 최대 4개까지의 값(각각 top, right, bottom, left를 의미)을 가질 수 있기 때문에 의미상으로도 <border-width>와 일치하지 않습니다.
온라인 CSS 권고안에서 <'border-width'>나 <border-width> 부분을 클릭해서 관련 속성이나 속성 값 유형을 직접 확인해보면 차이를 쉽게 알 수 있습니다.
값 나열 방식
값이 나열되는 방식에 따라서 허용되는 값이 달라집니다. 아래 네 가지 경우가 있습니다.
값을 공백으로 구분해서 나열하면 모든 값을 순서대로 지정해야 합니다.
값을 바(bar) 기호(|)로 구분해서 나열하면 나열된 값 중 한 개만 지정해야 합니다.
값을 더블 바(double bar) 기호(||)로 나열하며 순서와 상관 없이 한 개 이상의 값을 지정해야 합니다.
[ <border-width> || <border-style> || <'border-top-color'> ] 그룹과 inherit가 |로 구분되어 있으므로 그룹이나 inherit 중 하나를 지정해야 합니다. 그룹은 ||로 나열되었기 때문에 <border-width>, <border-style>, <'border-top-color'> 중 한 개 이상이 반드시 지정되어야 합니다. 또 <border-width>이 실제로는 [ thin | medium | thick | <length> ]을 의미하기 때문에 그룹을 다시 세 개의 그룹으로 나누어서 해석할 수도 있습니다.
빈도 표현
값이 몇 번 지정되어야 하는지도 확인할 수 있는데 역시 네 가지 형식이 있습니다.
별표(asterisk: *)는 값을 0번 이상 지정할 수 있음을 나타냅니다.
더하기(plus: +)는 값을 한 번 이상 지정할 수 있음을 나타냅니다.
물음표(question mark: ?)는 값이 선택 사항(0번이나 1번)이라는 것을 나타냅니다.
줄괄호에 숫자 두 개를 지정하면({A,B}) 최소 A번, 최대 B번 지정할 수 있음을 나타냅니다.
border-width 속성은 <border-width> 값을 최소 한 개에서 최대 네 개까지 가질 수 있습니다(네 개인 경우 각각 top, right, bottom, left). 그리고 font-family 속성에는 세 개의 그룹이 있는데 가장 바깥쪽 그룹은 inherit와 그룹 중에서 하나를 지정해야 한다는 의미이고, 내부의 두 그룹은 각각 <font-name>이나 <generic-family> 중 하나가 지정된다는 뜻입니다. 그런데 두 번째 그룹에는 쉼표(,)가 앞에 있고, 끝에는 별표(*)가 있습니다. 또한, 두 그룹은 |나 || 없이 공백으로만 연결되어 있습니다. 따라서 두 그룹이 반드시 순서대로 나열되어야 하는데 첫 번째 그룹은 한 번만, 두 번째 그룹은 0번 이상 나열된다는 의미입니다. 결국 다음과 같은 형식이 모두 가능하다는 얘기입니다.
p { font-family: serif; }
p { font-family: Arial, serif; }
p { font-family: Arial, serif, sans-serif; }
p { font-family: serif, Arial, sans-serif; }
마지막 CSS 규칙도 허용되기는 하지만 특정 폰트를 이용할 수 없을 경우의 대체 목적으로 범용 폰트 패밀리를 지정하기 때문에 좋은 방법은 아닙니다. CSS 권고안도 범용 폰트 패밀리(generic-family)를 마지막 대체 폰트로 제공할 것을 권장하고 있습니다.
Initial (초기 값)
속성에 적용되는 초기 값을 나타냅니다. 초기 값은 캐스케이드(Cascade)나 상속(Inheritance)에서 이용되는데 자세한 내용은 다음 글에서 다루겠습니다.
Applies to (적용 대상)
속성이 어떤 요소에 적용되는지를 알려줍니다. HTML에서는 요소마다 사용할 수 있는 속성이 정해져 있지만 CSS에서는 각각의 요소가 모든 속성을 가질 수 있습니다. 예를 들어서 span 요소에는 기본적으로 height 속성이 적용되지 않습니다. 하지만 height 속성을 지정했다고 해서 문법에 어긋나는 것은 아닙니다. CSS 2.1 권고안은 clear 속성을 예로 드는데 block 요소에만 적용됩니다.
Inherited (상속 여부)
속성 값이 없을 때 조상(ancestor) 요소의 속성 값을 상속받는지를 알려줍니다. 속성 값이 없고, 값을 상속받지도 않는 요소는 위에 설명한 초기 값이 지정됩니다. 여기서 속성 값이 없다는 표현은 캐스케이딩을 통해서 값이 지정되지 않았다는 의미입니다.
Percentage values (퍼센트 값 해석 방식)
퍼센트 값을 허용할 경우에 이 퍼센트 값이 어떻게 해석되는지를 알려줍니다. 예를 들어서 font-size 속성은 “부모 요소의 font-size를 기준으로 한다.”고 정의되어 있습니다. 퍼센트 값을 허용하지 않는 속성에는 “사용할 수 없음(N/A(Not Available))”으로 표시됩니다.
Media (속성이 적용되는 media 유형)
해당 속성이 적용될 media 유형을 알려줍니다. 대부분은 visual이지만, 문서를 프린트할 때 주로 사용하는 page-break-before 속성 같은 경우 visual, paged로 지정되어 있습니다.
Computed value (산출 값)
속성 값이 어떻게 변환되는지를 알려줍니다. 산출 값은 사용자 에이전트가 이용하는 최종 값이 아니고 중간 단계의 계산 값인데 캐스케이딩과 상속, 퍼센트 값 과의 상호 작용을 통해서 계산됩니다. 이 부분은 CSS 제작자보다는 CSS 구현자를 위한 정보라고 생각하는데 자세한 사항은 다음 글에서 알아보도록 하겠습니다.
단축 속성을 사용할 경우
추가로 단축 속성을 사용할 때 값이 어떻게 지정되는지도 설명하고 있습니다. 예를 들어서 font 속성은 font-style, font-variant, font-weight, font-size, line-height, font-family를 한꺼번에 지정할 때 사용하는 단축 속성입니다. 이런 단축 속성에서 속성을 모두 지정하지 않을 경우 누락된 속성에는 각 속성의 초기 값이 자동으로 지정됩니다. 예를 들어서 다음과 같은 규칙은
누락된 font-variant와 font-style의 초기 값이 normal이기 때문입니다.
마치며
CSS의 속성 정의는 속성에 대한 기본적인 설명을 요약적으로 담고 있습니다. 실제로 속성이 하는 역할을 알려면 속성 정의와 함께 설명을 확인해봐야 합니다. 그런데 이런 속성 설명은 여러 책에 수록되어 있습니다. 예를 들어서 “웹표준 교과서”에는 CSS 속성이 거의 완벽하게 정리되어 있습니다. 하지만 속성 정의 자체에 대해서는 특별한 설명이 없는데(혹시 있는지도 모르겠습니다. 좋은 책이지만 필요할 때만 조금씩 보거든요^^;) 그 이유가 “결정적으로 중요하지 않기 때문”이라고 생각합니다. 상세한 설명이 있고, 혹시 CSS 문법 오류가 있더라고 CSS Validator가 정확하게 찾아 주니까요.
하지만 바탕이 되는 개념이나 용어를 잘 알면 CSS를 더 잘 이해할 수 있으리라 생각합니다. 전에는 CSS 권고안의 속성 설명 부분, 특히 시각적인 서식 모델(Visual Formatting Model)을 중점적으로 봤는데 그 밖에도 중요한 내용이 많다는 것을 갈수록 느끼거든요. 앞으로는 이런 부분을 설명하는데 초점을 맞춰서 글을 쓰려고 합니다.
adobe사의 플래시는 웹 페이지에 강력한 멀티미디어 효과를 불어넣을 수 있게 해주는 강력한 도구입니다. 하지만 기본적으로 “시각”적인 인지를 바탕으로 하기 때문에 비시각적인 환경에서는 접근성을 떨어뜨리는 원인이 되기도 합니다.
물론, 플래시 자체적으로 접근성 향상을 위한 대체 텍스트를 제공하기는 합니다. 하지만 Window-Eyes나 JAWS 같은 일부 스크린 리더만이 이런 대체 텍스트를 읽을 수 있고, 플래시 플레이어 9가 지원하는 Microsoft Active Accessibility(MSAA) 기술은 윈도우즈 환경에 국한된 기술이기 때문에 윈도우즈 운영체제가 아닌 타 플랫폼에서는 제한적일 수 밖에 없다는 한계를 갖고 있습니다.
게다가 모든 사용자가 플래시 플러그인이 동작하는 환경에서 웹 페이지를 이용하지는 않습니다. 그렇기 때문에 페이지 네비게이션처럼 접근성이 중요한 컨텐츠에 대해서는 웹 페이지 제작자가 다양한 환경을 고려해서 최대한으로 대체 컨텐츠를 제공하는 것이 올바른 방법이라고 생각합니다. 그럼 어떤 방법이 있는지 알아볼까요?
예외적인 환경
대부분의 사용자는 일반적인 환경, 다시 말해서
브라우저가 자바스크립트를 지원하며,
브라우저가 지원하는 플래시 플러그인이 설치되어 있고,
브라우저가 CSS를 지원하는
환경에서 이 글을 보실 겁니다. 하지만 예외적인 환경에서 웹 서핑을 하는 분도 분명히 있겠지요. 각각의 환경에 따라서 대체 컨텐츠를 제공하는 방법이 달라집니다.
자바스크립트가 동작하지 않을 경우
자바스크립트와 플래시는 밀접한 관계를 갖고 있습니다. 특히 플래시에서 링크를 직접 처리하지 않고 자바스크립트 함수를 호출해서 페이지를 이동시키는 방법도 유지보수의 편의성 때문에 많이 사용되고 있는데 이런 경우에는 자바스크립트가 없으면 페이지 이동 자체가 불가능하게 됩니다.
또한, 마이크로소프트와 이올라스사와의 특허 분쟁 때문에(2007년 8월에 양사가 합의했지만) 외부 자바스크립트를 이용해서 플래시를 삽입하는 것이 일반화된 후로는 자바스크립트의 도움이 없으면 플래시 컨텐츠 자체를 볼 수 없는 경우도 많아졌습니다.
noscript 요소
이렇게 자바스크립트를 사용할 수 없는 환경을 고려해서 W3C는 noscript 요소를 HTML 권고안에 포함시켰습니다. HTML 4.01의 noscript관련 권고안 내용은 다음과 같습니다.
“noscript 요소는 스크립트가 실행되지 않는 환경에서의 대체 컨텐츠를 제공한다.”
“스크립트를 이해하는 사용자 에이전트는 스크립트가 실행되지 않도록 설정되었거나 script 요소에 지정된 스크립트 언어를 지원하지 않을 경우에 noscript 요소 안의 컨텐츠를 렌더링하고, 사용자 측(client-side) 스크립트를 지원하지 않는 사용자 에이전트는 항상 noscript 요소를 렌더링해야 한다.”
따라서, 자바스크립트로 플래시를 삽입할 경우에 noscript 요소에 대체 컨텐츠를 넣으면 스크립트를 지원하지 않는 환경에서도 컨텐츠를 이용할 수 있습니다.
하지만 브라우저가 noscript 요소를 처리하는 방식에 대해서 세부적인 권고안이 없기 때문에 noscript 요소 안의 컨텐츠를 재활용할 때에는 문제가 발생하기도 합니다. 이 부분에 대해서는 잠시 후에 알아보겠습니다.
플래시 플러그인이 설치되어 있지 않은 경우
플래시 플러그인이 없으면 브라우저는 해당 컨텐츠를 인식하지 못합니다. 그래서 플래시를 삽입할 때 대체 컨텐츠를 제공해줘야 합니다. 다행히도 플래시 삽입에 사용되는 object 요소는 param 요소를 제외한 요소 내의 모든 컨텐츠를 자동으로 대체 컨텐츠로 인식합니다.
하지만 일반적으로 사용되는(adobe사가 기본적으로 제공하는) 플래시 삽입 스크립트는 object와 embed 요소를 함께 이용하기 때문에 embed를 인식하는 넷스캐이프 계열 브라우저에서는 대체 컨텐츠를 인식하지 못합니다. 플래시 삽입 방법과 그에 따른 문제점들은 flash embed test suite 페이지를 참고하시기 바랍니다.
플래시 삽입 방법
대체 컨텐츠 제공을 위해서 플래시를 삽입하는 자바스크립트 함수를 약간 수정했습니다. 두 개의 object 요소를 인터넷 익스플로러만 인식하는 조건부 주석(conditional comment)과 함께 넣는 방법입니다.
† 2008년 3월 28일 업데이트: IE가 인식하는 외부 object에는 id를 주고, 내부 object에는 name을 준 이유는 자바스크립트로 플래시 무비를 직접 제어할 때 두 개의 object에 동일한 id를 부여하면 문제를 일으킬 수도 있기 때문입니다. object에 각각 id와 name을 준 다음 먼저 document.getElementsByNameDOM Level2 메소드로 내부 object를 찾고, object를 찾지 못했을 경우에는 다시 document.getElementById 메소드로 외부 object를 찾는 것이 안전한 방법이라고 하네요. Eionet의 Embedding Flash content에 자세한 설명과 자바스크립트 예제가 있으니 참고하시기 바랍니다.
이제 embedFlash 함수를 호출할 때 대체 컨텐츠를 문자열로 지정할 수 있습니다. 예를 한 번 들어보겠습니다.
두 개의 class가 지정된 div 요소를 앞서 설명한 noscript 요소 안에 넣으면 플래시 플러그인이 없거나 자바스크립트가 실행되지 않아도 동일한 대체 컨텐츠를 제공할 수 있고 CSS를 이용해서 스타일을 적용시킬 수도 있습니다.
효율적인 방법을 찾아서
자바스크립트로 플래시를 삽입할 때 대체 컨텐츠를 제공한다면 따로 문자열을 만들지 않고 이미 존재하는 noscript 요소 안의 컨텐츠를 이용할 수도 있지 않을까요? noscript 요소가 문서 구조 내에 있으면 innerHTML 같은 메소드를 이용해서 컨텐츠를 문자열로 가져올 수 있으니까요.
하지만, W3C의 권고안은 사용자 에이전트가 noscript 요소를 문서 구조 내에서 어떻게 이용하는지에 대해서는 다루지 않기 때문에 브라우저 제작사마다 처리 방식에 차이가 있습니다. 간단한 예를 들어볼까요?
인터넷 익스플로러 6에서는 noscript 요소 안에 있는 대체 컨텐츠를 올바른 HTML 컨텐츠로 인식하지만, 파이어폭스에서는 태그를 <와 >로 변환해서 일반 텍스트 형식으로 인식합니다. 자바스크립트 string 객체의 replace 메소드를 이용하면 일괄적으로 변환시킬 수 있지만 오페라에서는 더 큰 문제가 생깁니다. 자바스크립트가 활성화된 상태에서는 아예 noscript 요소를 인식하지 못한다는 점이지요. 다시 말해서 해당 요소가 없는 것과 마찬가지입니다.
† noscript 요소 안에 div를 넣고 여기에 id를 주면 파이어폭스에서는 해당 div 요소를 인식하지 못합니다. 요소 노드가 아닌 텍스트 노드로 인식하니까요.
그래서 noscript 요소의 컨텐츠를 재사용하는 것에는 한계가 있습니다.
첫 번째 대안
noscript 요소를 이용하기 어렵다면 대신 div 요소를 만들고 여기에 대체 컨텐츠를 넣은 다음 이용하면 어떨까요? 그러기 위해서는 해당 div 요소를 자바스크립트가 실행되는 환경에서는 숨겨야 합니다. 가장 간단한 방법은 CSS의 display 속성을 이용하는 것입니다. 예를 들어서 다음과 같은 자바스크립트를 이용할 수 있습니다.
그러면 페이지가 로드되면서 div를 숨기게 됩니다. 하지만 문서 구조 내에 포함되기 때문에 아래 소스처럼 요소의 컨텐츠를 재사용할 수 있습니다.
function embedFlash(id, url, width, height, flashVars, wmode) {
if (!flashVars) flashVars = '';
if (!wmode) wmode = 'window';
var altText = document.getElementById("alt-content-test").innerHTML;
...
}
CSS가 지원되지 않을 경우
그러면 앞서 열거했던 예외 상황 중 마지막 경우가 문제가 됩니다. 즉, CSS가 지원되지 않으면 요소가 숨겨지지 않기 때문에 자바스크립트가 실행되는 환경에서도 대체 컨텐츠가 표현됩니다.
또한, 파이어폭스(2, 3 베타)는 플래시를 object로 삽입하면 [보기]->[페이지 스타일]->[스타일 없음]을 선택할 경우에 플래시 컨텐츠를 보여주지 못합니다. 이 버그 관련 정보를 파이어폭스 버그 데이타베이스에서 찾아봤는데 결과가 없었고, A List Apart의 댓글에서만 정보를 찾을 수 있었습니다. 또한, 브라우저 자체 메뉴가 아닌 Web Developer Toolbar의 CSS 선택 메뉴를 이용하면 문제 없이 표현됩니다.
여러 방법을 살펴보면서 그래도 noscript 요소를 이용하는 것이 낫다고 판단했습니다. 자바스크립트로 어떤 조작을 하지 않아도 되고, 기본적으로 브라우저가 지원하는 대체 컨텐츠 제공 방법이니까요. 물론 일부 구형 브라우저에서는 호환성 문제가 있다는 보고도 있지만요.
그래서 서버 사이드 스크립트 언어(PHP)로 대체 컨텐츠를 변수화한 다음 object 요소와 noscript 요소에 동일하게 넣는 방법을 사용했습니다. 문서의 파일 크기가 약간 늘어나긴 했지만 큰 영향을 줄 정도는 아니었습니다.
참고로 자바스크립트에서 문자열의 최대 길이는 명확하게 정의되어 있지 않습니다. 다만, 일반적으로 문제없이 사용할 만큼 충분히 길다고 하네요.
마치며
플래시를 삽입하는 방식은 다양합니다. embed를 쓸 수도 있고, 표준 방식인 object를 사용할 수도 있습니다. 방법이 많다는 것은 그만큼 문제점도 많다는 뜻으로 해석할 수 있을겁니다.
개인적으로 플래시를 자바스크립트 이용 없이 마크업으로 직접 넣는 것이 좋다고 생각하지만, 이올라스사와의 특허 문제로 아직까지는 실무에 적용하기가 어렵네요. swfobject 2.0 버전에서는 DOM 노드를 조작하는 기존 방식과 함께 “static” 퍼블리싱이라는 새로운 방식을 도입했는데 플래시는 표준 마크업으로 삽입하고, 자바스크립트로는 플래시 플러그인 버전 확인 같은 부가 기능만을 처리하는 방식입니다.
어떤 방식이든 대체 컨텐츠를 제공하는 것은 접근성 측면에서 무척 중요합니다. 예를 들어서 서두에서 예로 들었던 네비게이션을 플래시로 제공하는 사이트는 대체 컨텐츠가 없으면 플래시 플레이어를 지원하지 않는 아이팟 터치 같은 일부 사용자 에이전트에서는 정상적인 이용이 불가능합니다.
웹의 영역은 PC 모니터를 넘어서 다양한 플랫폼으로 확장되고 있습니다. 이런 다양한 환경에서 사용자가 불편없이 컨텐츠를 이용하기 위해서는 접근성에 대한 고려가 필수적이라 생각합니다. 저도 일정이 부족하고, 기획 단계에서 접근성에 대한 고려가 없다는 핑계로 이런 부분을 게을리 했는데 이제부터는 조금씩 바꿔가려고 합니다. 접근성에 관해서는 기술보다 정성이 더 중요하다는 생각이 드네요.
마이크로소프트(이하 MS)가 인터넷 익스플로러(이하 IE) 8 베타1을 공개했다는 소식을 듣고 간단한 테스트를 해봤습니다. 웹 페이지 제작자의 입장에서 이전 버전과의 가장 큰 차이점은 달라진 레이아웃 모델(정확히는 CSS의 “시각적인 서식 모델(Visual Formatting Model)”)이라고 생각하는데 이 부분에 관한 얘기를 다뤄볼까 합니다.
† 이하 글에서는 IE8 베타1을 IE8로 표현합니다. 현재 베타 버전이지만 아래 설명할 내용은 정식 버전에 그대로 적용될 것으로 생각하기 때문입니다.
IE7 이하 버전의 hasLayout 문제
먼저, 이전 버전의 IE에 적용됐던 방법을 알아봐야 하는데 이 부분에 관해서는 이전에 작성했던 hasLayout 속성과 홀리 핵이라는 글에서 다뤘기 때문에 간단히 정리하겠습니다.
hasLayout 개념이 중요하게 여겨진 까닭은 IE가 W3C의 권고안과는 전혀 다른 방식으로 레이아웃, 즉 요소 박스의 위치와 크기를 해석했기 때문입니다. 따라서 표준 방식으로 CSS를 작성해도 예상했던 것과 다르게 레이아웃이 표현되는 경우가 많았습니다. 간단한 예를 들어보지요.
표준 레이아웃 모델에 따르면 float된 요소는 정상적인 문서의 흐름(normal flow)에서 벗어나 있기 때문에 id가 wrap인 div 요소는 높이가 계산되지 않습니다. 따라서 두 개의 회색 div만 표시되지요. 하지만, 독자적인 hasLayout 개념을 사용하는 IE에서는 width를 지정하는 것 만으로도 wrap 높이가 계산되기 때문에 빨간색 div까지 전부 세 개의 박스가 화면에 표현됩니다.
아래 결과를 IE7 이하 버전과 표준 레이아웃을 따르는 파이어폭스나 오페라 브라우저로 비교해보면 차이를 알 수 있습니다.
하지만, IE 8에서는 다른 주요 브라우저와 동일하게 표준 레이아웃 모델이 적용됩니다. 그러므로 두 개의 회색 박스만 표현되지요.
overflow 속성과 생성된 컨텐츠(generated content) 지원
IE 7은 이전 버전에서 Layout을 갖게 했던(hasLayout) width나 height 속성에 추가로 overflow 속성을 지원합니다. 즉, overflow 속성으로도 Layout을 갖게 만들 수 있습니다. 그런데 overflow 속성이 표준 레이아웃을 지원하는 브라우저에서 높이를 계산하도록 하는데(float 해제(clearing float)) 많이 사용되기 때문에 레이아웃 해석에 대한 실제 구현 방법은 다르지만 결과적으로는 같은 효과를 낼 수 있었지요. IE8에서의 overflow가 IE7 방식으로 해석되는지, 아니면 표준 방식을 사용하는지 확실하지는 않지만 적어도 제 생각으로는 기존 hasLayout 방식을 버리고 표준 방식을 받아들였을 것 같습니다.
또한, IE8은 생성된 컨텐츠를 만들 수 있는 가상 요소(Pseudo-element) 역시 지원합니다. 따라서 다음과 같은 class를 사용해서 float을 해제시킬 수도 있습니다.
† hasLayout은 CSS의 마짐 겹침 방식에 다양한 영향을 끼칩니다. 이 부분을 설명하려고 간단한 예제를 넣었는데 소스와 설명에 오류가 있었네요. ^^; 자료를 찾아 보니 간단히 다룰 문제가 아니어서 추후에 따로 포스팅을 하려고 합니다. 일단 관련 예제와 설명이 있는 웹 페이지를 알려드릴게요.
새로 발표된 IE8로 위 예제를 확인해보면 파이어폭스나 오페라, 사파리 등과 동일한 결과를 보여줍니다. 즉, 표준 레이아웃 모델을 지원한다는 얘기지요. 따라서 Layout을 갖게 만들기 위해서 사용되던 홀리 핵(Holly hack) 등을 적용할 필요가 없어졌고, 전체 IE에 적용되는 조건 주석문이나 핵은 오히려 문제를 일으킬 수도 있기 때문에 이런 부분은 IE7 이하에만 적용되도록 해야 합니다. 예를 들어서
blog_ie.css에 height: 1%; 같은 규칙을 지정해서 Layout을 갖게 만들었다면 주석문의 조건을 IE7 이하로 한정하고 IE8에서는 앞서 설명한 overflow나 layoutFix 같은 class를 사용해서 높이가 계산되도록 해야 합니다. 아래 조건 주석문은 IE 전용 CSS를 IE7 이하에만 적용시킵니다.
현재 IE8은 베타 버전인 만큼 많은 버그가 포함되어 있을 것입니다. 완성도 면에서 평가하기는 아직 이른 시점이지만 사용해보니 확실히 이전 버전보다 W3C의 권고안(표준) 지원 면에서 큰 향상을 확인할 수 있었습니다.
충분히 테스트해보지 않아서 확실히 말씀드릴 수는 없지만 다른 브라우저에서 잘 보이는 레이아웃이 IE8에서 어긋난다면 먼저 IE8에만 별도로 적용되는 핵이나 규칙을 사용하고 있는지를 의심해봐야 합니다. 그리고 나서 IE8의 버그 때문인지를 알아봐야 겠지요. 일반 사용자들이 IE8 테스트로 다음이나 네이버 등의 포탈 사이트를 확인하는데 이런 사이트는 아주 복잡하고 정교한 마크업과 CSS로 이루어져 있습니다. 그렇기 때문에 IE8의 표준 지원 여부를 렌더링되는 결과만으로 평가하는 것은 상당히 어렵다고 생각합니다. IE에만 적용되는 코드가 섞여 있을 수 있으니까요.
개인적으로는 IE8이 acid2 테스트를 통과했다는 사실 만으로도 이전 버전보다 훨씬 표준을 잘 따른다고 평가합니다. acid2 테스트가 간단해 보이지만 실제로는 다양한 position과 CSS 선택자(selector), 기타 CSS 개념들을 사용하기 때문에 제대로 표현된다는 것은 그만큼 많은 부분에서 표준을 따른다는 얘기거든요.
IE8의 등장으로 이제 모든 주요 브라우저가 표준 CSS 렌더링 방식을 지원하게 되었습니다. 향후 출시될 정식 버전과 IE8 등장으로 달궈진 브라우저 제조사들의 표준 지원 경쟁이 기대되네요.
scrollObj는 자바스크립트의 문서 객체 모델(DOM)을 이용해서 이미지나 텍스트에 스크롤 효과를 주는 오브젝트(객체)입니다. 비슷한 효과를 내는 함수나 오브젝트들이 자바스크립트 상의 소스를 document.write 메소드로 화면상에 출력하는 것과 달리 HTML 소스를 그대로 이용하므로 자바스크립트를 사용할 수 없는 환경에서도 스크롤될 내용을 확인할 수 있고, 문서의 소스도 간단해지는 장점을 갖습니다.
scrollObj는 이미지나 텍스트가 들어 있는 리스트(ul, ol)의 절대 위치(absolute position) 값을 바꾸는 것으로 스크롤 효과를 만듭니다. 즉, 리스트 요소 자체를 이동시키는 것이지요. 그러면서 리스트에 포함된 특정한 항목 요소(li)를 기준으로 하는 이동 거리를 계산합니다. 이 특정 요소의 너비(또는 높이)와 이동 거리가 같아질 때 리스트 항목의 순서를 바꾸어서 스크롤이 계속 이어지도록 하는 것이지요. 설명을 위해 간단한 예제를 만들어봤습니다.
11111
22222222222
3333
444444444444444
scrollObj 선언과 함게 먼저 리스트 요소의 순서가 바뀝니다. 예제에서 리스트의 마지막 요소였던 “444444444444444” 항목이 첫 번째 요소가 된 것처럼이요. 이 과정에서 앞으로 옮겨진 요소들의 너비(또는 높이)만큼 리스트의 절대 위치가 이동됩니다. 따라서 실제로는 리스트의 첫 번째 항목이 “11111” 요소인 것처럼 보이게 되지요.
“시작/정지” 버튼을 누르면 스크롤이 시작됩니다. “방향 전환” 버튼으로 스크롤 방향을 바꿀 수도 있고요. 리스트를 감싸는 div에 overflow: hidden; 속성을 주지 않았기 때문에 실제 요소의 이동을 눈으로 확인할 수 있습니다.
앞서 리스트의 순서가 바뀌는 시점을 특정 요소의 크기만큼 위치가 이동했을 때라고 했는데, 스크롤 방향에 따라서 기준이 되는 요소가 다르다는 점에 주의해야 합니다. 위 예제에서 일반적인 좌측 이동일 경우에는 리스트의 두 번째 요소가 기준이고, 오른쪽으로 이동할 때에는 첫 번째 요소가 기준이 되거든요. 이렇게 기준 요소를 달리 정한 것은 리스트 순서가 바뀔 때 정지 효과를 넣기 위해서입니다.
scrollObj 사용법
scrollObj는 오브젝트만 선언하면 자동으로 스크롤이 시작됩니다. 추가적인 전역 변수 선언은 필요하지 않고요. 선언 시 지정할 수 있는 인수는 많지만 대부분 생략 가능합니다. 먼저 scrollObj가 어떻게 선언되어야 하는지 실제 자바스크립트 소스를 적어보겠습니다.
하지만 이렇게 자유롭게 변경할 수 없는 인수들은 오브젝트 선언시 그 값을 정확히 지정해야 합니다. 예를 들어서 스크롤 거리를 2px로 지정하려면 다음과 같이 오브젝트가 선언되어야 합니다.
so1 = new scrollObj("scrollTest", false, 0, 2);
주의 사항
리스트 항목 요소들 사이에 마진(margin) 값이 존재할 경우에는 오브젝트 선언 시 이동 방향의 양쪽 마진을 합한 값을 sumMargin 인수에 넣어주여야 합니다. 만약 isVertical이 true이고(수직 스크롤) margin이 있을 경우에는 마진이 합쳐지는 현상(collapsing-margins)도 고려해야 합니다. 예를 들어서 아래와 같은 스타일이 적용될 경우에 sumMargin 값은 20이 아니라 10이 되어야 합니다.
#scrollTest li { margin: 10px 0; }
오브젝트 선언 시 사용되는 startNum 인수는 실제 보여질 화면 영역 왼쪽에 존재할 리스트 항목 요소의 수를 결정합니다. 예를 들어서 startNum이 기본값인 2라면 앞서 들었던 예처럼 리스트의 첫 번째 요소(“11111”)가 실제로는 두 번째 요소로 바뀐 상태에서 스크롤이 시작됩니다. 이 부분은 특히 역방향 스크롤에서 리스트 요소의 수가 적고 각각의 항목들 크기가 많이 차이날 때 중요한 역할을 합니다. 가급적이면 리스트 항목 요소들의 수를 충분히 확보한 상태에서 스크롤 효과를 주는 것이 좋습니다.
적용 예
scrollObj 데모 페이지에서 실제로 적용된 예를 보실 수 있습니다. 페이지 중앙에 있는 수평 텍스트 스크롤, 우측의 수직 텍스트 스크롤, 하단의 수평 이미지 스크롤이 모두 scrollObj로 구현되었습니다.
기존에 포스팅한 DOM 스크립트: 이미지 스크롤러를 다양한 용도로 사용할 수 있도록 수정하면서 내용이 많이 바뀌었습니다. 가장 큰 변화로는 기존 함수 기반의 소스를 오브젝트 기반으로 바꾼 것인데 그렇게 해서 전역 변수를 추가적으로 선언해야 하는 불편함을 없앴습니다. 범용성도 높이고요.
기존 소스에 비해서 오류 처리 부분이라든가 주석 처리가 많이 나아졌지만 충분한 테스트를 거치지 않았기 때문에 알 수 없는 문제가 있을 수도 있습니다. 혹시 이런 문제를 발견하시면 꼭 알려주세요.
앞서 CSS로 이미지 정렬하기라는 글에서 CSS의 clear 속성으로 float된 요소를 다루는 방법을 소개했습니다. 이렇게 float을 제거하는 방법(clearing float)은 그외에도 몇 가지가 더 있는데 그중에서 overflow 속성을 사용하는 방법과 CSS2에 새로 도입된 :after 가상 요소(pseudo-element)를 이용하는 방법을 알아보겠습니다.
overflow 속성을 사용하는 방법
overflow 속성은 박스(containing box)에 담긴 내용물이 박스 크기보다 클 때 브라우저가 어떻게 처리할 지 알려주는 역할을 하는 CSS 속성입니다. 기본값인 visible은 박스 밖으로 넘친(overflow) 내용물을 그대로 보여주고, hidden은 안보여주게 되지요.
† 인터넷 익스플로러(이하 IE)6에서는 visible 속성을 적용할 경우 박스가 내용물 높이만큼 늘어나는데 표준과는 어긋나는 방식입니다.
그런데 이런 효과는 박스의 크기(width, height)를 명확하게 지정했을 경우에만 나타납니다. 만약 width만 지정한 상태에서 overflow: hidden;을 적용하면 박스가 내용물의 크기만큼 아래로 늘어나니까요. 이 때 박스 안에 있는 float된 요소의 높이까지도 같이 계산됩니다. 결국 박스가 float된 요소를 포함할 만큼 커지기 때문에 float을 제거하는 효과가 나타나게 됩니다. 다시 말해서 앞서 설명한 clear 속성과 같은 효과를 내게 됩니다. 또한, 절대 위치(absolute positioning)가 지정되지 않은 박스의 높이(height)를 퍼센트 단위(%)로 지정하고, 높이를 참조할 상위 박스(containing box)의 높이가 명확하지 않을 경우(내용물에 따라 달라질 경우)에는 CSS 규격에 따라서 height가 auto로 간주된다는 점도 중요합니다.
아래 예는 이미지가 포함된 단락(paragraph)에 overflow 속성을 적용하지 않은 경우입니다.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean vel tellus nec massa cursus malesuada. Pellentesque metus.
Proin eu nisi eu tortor consectetuer varius. Curabitur magna nunc, pretium id, tincidunt a, tempus porttitor, nisi. Integer erat lacus, tempor non, varius sit amet, laoreet in, arcu. Pellentesque tempus mauris. Nulla ut ante ut massa suscipit euismod.
이미지와 텍스트 단락이 들어 있는 p 태그에 overflow: hidden; 속성을 적용하면 아래처럼 그 차이를 확인할 수 있습니다.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean vel tellus nec massa cursus malesuada. Pellentesque metus.
Proin eu nisi eu tortor consectetuer varius. Curabitur magna nunc, pretium id, tincidunt a, tempus porttitor, nisi. Integer erat lacus, tempor non, varius sit amet, laoreet in, arcu. Pellentesque tempus mauris. Nulla ut ante ut massa suscipit euismod.
하지만 IE에서는 overflow 속성이 조금 다르게 적용됩니다. 위 예를 IE6로 보면 IE7이나 파이어폭스 등의 브라우저와는 다른 결과가 나타나는데 그 이유는 앞서 hasLayout 속성과 홀리 핵(Holly hack)에서 소개했던 Layout 속성이 활성화되지 않았기 때문입니다. IE7은 overflow 속성이 박스가 Layout을 갖도록 하지만 IE6에서는 그렇지 않거든요. 따라서 IE6에서도 동일한 효과를 얻으려면 Holly hack을 사용하거나 Layout을 활성화시키는 추가적인 CSS 지정이 필요합니다.
정리하자면 파이어폭스, 오페라 등의 브라우저는 overflow: hidden;으로 float이 제거되고, IE7에서는 overflow가 Layout을 갖게 만들어서 같은 효과를 냅니다. 하지만 IE6 이하 버전에서는 overflow로 Layout을 갖게 할 수 없기 때문에 Holly hack이 필요한 것이지요.
† IE7이 overflow 속성을 CSS 표준대로 적용시키는지는 잘 모르겠습니다. 하지만 아무래도 CSS 표준보다는 Layout을 갖게 만드는 역할만 하는 것이 아닐까 생각되네요.
:afterCSS 가상 요소(pseudo-element)를 사용하는 방법
CSS2에 도입된 가상 요소(pseudo-element)는 말 그대로 HTML에 없는 요소를 CSS만으로 넣을 수 있도록 해주는 역할을 합니다. 가상 요소는 ‘생성된 컨텐츠(generated content)’를 만드는 방법의 하나인데 ‘생성된 컨텐츠(generated content)’의 가장 간단한 예는 순서있는 리스트(ordered list)를 만들 때 사용하는 ol 태그에서 list-style-type에 따라 자동으로 생기는 항목 번호를 들 수 있습니다. 즉, HTML에 없는 항목 번호가 CSS를 통해서 생기는 것이지요.
† 가상 요소는 링크 태그에 사용되는 :active 등의 가상 클래스(pseudo-class)와는 다른 개념입니다.
:after 가상 요소에 content 속성을 지정하면 해당 CSS가 적용된 요소 뒤에 content의 속성 값이 추가적으로 들어갑니다. 대표적인 예가 짧은 인라인 인용문에 쓰이는 q(quotation) 태그입니다. 한 번 써볼까요?
<q>짧은 인용문 테스트</q>
짧은 인용문 테스트
:before와 :after 가상 속성을 지원하는 파이어폭스에서는 “짧은 인용문 테스트” 같이 자동으로 큰 따옴표를 붙여서 보여줍니다. 하지만 안타깝게도 IE에서는 이 가상 요소를 지원하지 않으므로 큰 따옴표가 생기지 않습니다.
:after 속성을 사용해서 float을 제거하는 방법은 실질적으로는 clear 속성을 사용하는 것과 같습니다. 단지 clear용 div나 br을 사용하지 않고 CSS가 자동으로 생성하는 컨텐츠를 사용하는 것만 다를 뿐이지요. 일반적으로 사용되는 CSS 규칙은 아래와 같습니다.
layoutFix가 지정된 박스 끝부분에 마침표(.) 하나를 생성하고, 이 마침표에 clear 속성을 적용하게 됩니다. visiblity: hidden; 속성으로 보이지는 않지만 박스로서의 영역은 차지하도록 해주고요.
이 방법 역시 IE에서는 사용할 수가 없습니다. 마침표를 만들어주지 못하니까요. 따라서 Holly hack 등을 추가로 사용해야 합니다.
마치며
이밖에도 float된 요소가 포함된 박스 역시 float시켜서 float을 없애는 방법도 있지만 그렇게 의미 있는 방법은 아니라고 생각되네요. clear 속성을 사용하는 방법과 display 속성을 사용하는 방법, :after 가상 요소를 사용하는 방법을 알아봤는데 어느 한 가지가 최고의 방법이라고는 생각하지 않습니다. 상황에 따라서 적절한 방법을 골라서 쓰는 것이 가장 좋겠지요.
또한, float을 제거할 때 float된 요소의 마진이나 패딩(margin, padding)이 제대로 적용되지 않는 경우도 있습니다. 어떤 float 제거 방법을 쓰느냐에 따라서 달라지기도 하는데 관련된 정보가 잘 정리된 페이지가 CSS tests home 사이트의 Float containment에 있으니 참고하시고요.
이렇게 해서 이미지 정렬에 관한 글을 모두 마쳤습니다. ^^; 사실 float만 잘 사용하면 <br /> 태그를 반복해서 사용하지 않고도 이미지와 문단을 자유롭게 배치할 수 있거든요. 다음 글에서는 테이블(table) 태그 사용에 대해 알아볼게요.
CSS로 이미지 정렬하기에서 소개했던 CSS의 clear 속성을 이용하는 float 제거(clearing float)와 동일한 효과를 내는 방법은 몇 가지가 더 있습니다.
그 중 하나인 overflow 속성을 이용하는 방법을 설명하기 전에 인터넷 익스플로러(이하 IE)만의 독자적인 속성인 hasLayout에 대해서 먼저 알아보려고 하는데, 이 속성이 HTML 요소들의 레이아웃, 특히 float된 요소가 렌더링되는 방식에 크게 영향을 끼치기 때문입니다.
그러면 hasLayout 속성이란 무엇이고, 어떤 영향을 끼치는지, 그리고 어떤 방식으로 이 속성을 이용해야 하는지를 알아보도록 하겠습니다.
Layout은 각각의 요소가 어떻게 렌더링되고, 다른 요소들과 어떻게 상호작용 하는지를 결정하는 윈도우즈 버전 IE만의 독자적인 개념(concept)입니다. 이 layout이 적용되지 않으면 표준 규격을 따르는 브라우저와는 사뭇 다른 방식으로 각각의 요소들이 렌더링되므로 브라우저 호환성(cross browsing)을 위해서는 그 특성을 이해할 필요가 있습니다.
일부 HTML 요소는 아무런 설정 없이 기본적으로 Layout을 가지며, 일부 CSS 속성이 지정될 경우에는 Layout이 없는 요소도 Layout 속성을 갖게됩니다. 마이크로소프트의 개발자들은 객체 지향 프로그래밍(Object Oriented Programming) 방식에 기초해서 각각의 요소들이 hasLayout이라고 이름붙인 속성을 가질 수 있도록 해야 한다고 결정했는데 이 속성이 true로 설정된 요소만이 앞서 설명한 Layout 개념을 따르게 됩니다.
† 원문에서는 Layout이 개념(concept)을 가르키고, hasLayout은 이 개념의 적용 유무를 결정하는 속성(property)으로 표현되지만, 두 단어가 그렇게 엄격하게 구분된다고 느껴지지는 않습니다. 또한, hasLayout의 속성(property)은 CSS에서 사용되는 일반적인 속성과는 다른 개념이므로 구분을 위해서 스크립트 속성(script property)이라고 정의하고 있습니다. 사용자가 직접 지정할 수 없고 내부적으로만 처리되기 때문입니다. 이 글에서는 Layout과 hasLayout 두 단어를 혼용해서 사용하는 경우가 있으니 이 점 감안하시길 바랍니다.
hasLayout 속성이 영향을 미치는 경우들
많은 개발자들이 hasLayout과 관련된 문제를 경험합니다. Layout이 특정한 요소와 그 하위 요소들의 렌더링 방식에 예측하기 어려운 영향을 끼치기 때문입니다.
이렇게 Layout 유무에 따라 발생할 수 있는 일반적인 문제점은 다음과 같습니다.
흔히 발생하는 IE의 float 버그
기본 속성(width, height 등)이 표준과 다르게 적용되는 박스
요소와 컨테이너(container) 사이에 마진(margin)이 합쳐지는 현상
리스트(ul, ol 등)를 만들 때 나타나는 다양한 현상들
배경 이미지 위치를 다르게 해석하는 문제
스크립트를 사용할 때 발생하는 브라우저 호환성 문제
† 원문에서는 이 목록을 간단하고(brief) 완성되지 않았다고(incomplete) 표현하고 있습니다. 다시 말해서, 다른 문제들과도 관련이 있다는 얘기입니다.
hasLayout 속성은 어떻게 지정하는가?
Layout 속성은 특이하게도 CSS를 이용해서 직접 지정할 수가 없습니다. 따라서 CSS에서는 Layout이라는 속성 자체가 사용되지 않습니다. 다만 일부 요소들은 기본적으로 Layout을 갖고(hasLayout = true), 특정한 CSS 규칙이 적용될 경우에도 Layout을 가질 수 있습니다.
† IE7에서는 이밖에도 position: fixed, min-width, max-width, min-height, max-height 등이 Layout을 활성화시킵니다. 또한 IE6 이상의 표준 렌더링 모드(standards-compliance mode)에서는 인라인 요소의 width, height 속성이 무시되므로, 이 속성으로는 Layout을 갖도록 할 수 없습니다. 기타 자세한 정보는 원문인 On having layout을 참고하세요.
Layout 속성을 이용하는 방법
표준을 따르지 않는 Layout 속성 때문에 레이아웃과 관련된 많은 문제점이 발생합니다. 대표적인 예로는 앞서 CSS로 이미지 정렬하기에서 설명한 p 태그에 clear 속성이 다르게 적용되는 것을 들 수 있지요. 또한, 어떤 요소가 IE에서만 보이지 않는 문제도 hasLayout을 적용하면 해결됩니다.
이렇게 IE에서만 발생하는 Layout 문제를 해결하기 위해서 많은 핵(hack)이 고안되었는데 이들의 공통적인 목적은 Layout이 없는 요소가 Layout 속성을 갖게 만드는 것입니다. 따라서 위에 열거한 CSS 속성을 IE에만 적용시키는 것이지요. 그중에서 대표적으로 사용되는 Holly hack에 대해 알아보겠습니다.
Holly hack
2003년에 John Gallant와 Holly Bergevin이 발표한 Holly hack은 다음과 같은 CSS 규칙을 사용합니다.
/* Hides from IE5-mac \*/
* html .buggybox { height: 1%; }
/* End hide from IE5-mac */
이 핵은 Layout이 없는 요소에 height 속성을 주어서 문제를 해결하는 방법인데 IE가 아닌 표준을 따르는 브라우저에서는 height 속성이 문제를 일으킬 수 있으므로 이런 브라우저에게는 적용되지 않도록 하는 것이 이 방법의 핵심입니다.
사실 Holly hack은 두 개의 핵을 동시에 사용하고 있습니다. 먼저 가운데 줄에 있는 코드는 Tan hack으로 알려진 방법으로 CSS의 공용 선택자(universal selector: *)를 이용해서 IE7 표준 모드(standard mode)를 제외한 현재까지의 모든 IE 브라우저에 적용됩니다.
첫 번째와 세 번째 줄은 Layout 속성이 매킨토시 IE(이하 Mac IE)에는 적용되지 않기 때문에 Mac IE에서는 이 세 줄의 CSS 코드를 모두 주석으로 인식하도록 하는 역할을 합니다. Mac IE가 윈도우즈 IE와는 달리 보다 표준에 가까운 방법으로 렌더링을 하기 때문이지요. 이 방법은 Mac hack이나 comment-backslash 핵으로 불리는데 Mac IE가 주석문의 백슬래시(\) 문자 뒤에 있는 내용을 인식하지 못하고 세 번째 줄까지 주석이 이어진 것으로 인식하는 점을 이용합니다.
하지만 이 방법은 IE7 표준 모드(standard mode)에서는 적용되지 않는데 * html 선택자가 아무 것도 선택하지 않기 때문입니다. 또한, IE6의 표준 모드를 제외하면 overflow: hidden 속성과 함께 사용될 경우에 문제를 일으킵니다.
조건에 따른 주석(conditional comment) 이용하기
저는 개인적으로 크로스 브라우징 문제를 해결하기 위해서 핵보다는 조건에 따른 주석문를 주로 사용합니다. HTML 내에 IE에서만 인식되는 주석문을 넣는 방법으로 위의 Holly hack을 대체하려면 다음과 같은 코드를 사용하면 됩니다.
IE6 이하 버전에서는 Layout을 갖게 만드는 여러가지 CSS 속성 중에서 height 속성을 사용하는 것이 최선의 방법입니다. 물론 다른 CSS 속성과 충돌이 일어날 경우(예: overflow: hidden)에는 예외지만이요. height 속성으로 어떤 값(1%, 1px, 0 등)을 사용하는지 큰 차이는 없습니다. 하지만 일반적으로 많이 사용되는 1% 값은 극히 드문 경우지만 문제를 일으킬 수도 있다고 합니다. 이 문제에 관한 사항은 IE/Win: negative margins, position:relative, hasLayout를 참고하시기 바랍니다.
† IE6 이하 버전에서 height 지정이 최선의 방법인 이유는 IE5 때문입니다. IE5.5 이상의 브라우저에는 zoom 속성 같은 다른 대안이 있지만 IE5는 현실적으로 height가 최선의 방법이라는 설명입니다.
또한, height 속성은 이 속성을 지원하지 않는 인라인 요소에는 사용할 수 없습니다. IE7에서는 더욱 주의해야 하는데 먼저 height 속성 값은 반드시 퍼센트(%) 단위를 써야 하고, 속성이 적용될 요소의 상위 요소(parent element)에 고정적인 높이가 지정되지 않은 경우에만 또 다른 문제를 피할 수 있습니다. 이런 경우에는 display: inline-block이나 zoom: 1 속성을 사용하는 것이 혹시 모를 문제를 예방할 수 있습니다.
zoom 속성은 IE5를 제외한 IE5.5 이상의 모든 IE 브라우저에 적용되어 Layout을 만들고, 심지어 인라인 레벨 요소도 Layout을 갖게 만듭니다. 특별히 알려진 부작용도 없고요. 위의 예처럼 조건에 따른 주석(conditional comment)을 사용하면 CSS 검증(validation)도 문제없이 통과합니다. Mac IE는 conditional comment를 무시하므로 앞서 설명한 Mac hack도 필요하지 않습니다.
따라서 위 주석문은 height 속성이 필요한 IE6 이하 브라우저(특히 IE5)에게는 height를 0으로 지정하고, height 속성이 문제를 일으킬 수 있는 IE7에는 zoom 속성을 적용시켜서 Layout을 갖게 만듭니다. 또한, 앞으로 발표될 IE 브라우저에서 Layout 속성을 어떻게 처리할 지 모르기 때문에 가급적이면 IE만의 방법인 conditional comment와 zoom 속성을 사용하는 것이 보다 나은 방법이라고 설명하고 있습니다.
마치며
원문은 이 글보다 훨씬 많은 내용을 담고 있습니다. 내용을 요약하는 과정에서 오역이 있을 수도 있다는 점 감안하시길 바래요. 또한, 원문에 링크된 다양한 글은 제목만 봐도 유용한 정보라는 것이 느껴질 정도입니다. IE에서 레이아웃 문제로 어려움을 겪는다면 관련 글들이 큰 도움이 되리라 생각합니다.
제 경험으로는 Layout과 관련된 대부분의 문제가 Holly hack만으로도 간단히 해결되더군요. 그래서 Holly hack에 관한 내용을 중점적으로 다루었습니다. 다음 글에서 Layout 속성과 overflow 속성을 이용해서 float 효과를 제거하는 방법(clearing float)에 대해서 알아보지요.
엄격한(Strict) 문서 규격 정의(DTD)에서는 이미지 정렬에 흔히 사용되던 align 속성을 허용하지 않습니다. 따라서 img 태그만으로는 이미지의 위치를 자유롭게 조절할 수 없고, 반드시 CSS를 함께 사용해야만 합니다.
단순히 하나의 이미지만 넣어야 할 경우에는 text-align이라는 CSS 속성으로 간단히 해결할 수 있지만 현실적으로는 이보다 훨씬 복잡한 경우가 많습니다. 특히 이미지와 텍스트를 함께 배치하려면 어쩔 수 없이 float 속성을 사용해야 하는데 이 속성에 대한 해석이 브라우저에 따라 차이가 있으므로 브라우저 호환성 면에서 생각보다 훨씬 많은 위험성을 갖고 있습니다. 이렇게 까다로운 이미지 태그를 잘 사용하기 위해 알아두어야 할 점과 float 속성으로 이미지를 정렬하는 방법에 대해서 정리해봤습니다.
† 앞으로 제시할 모든 예는 noimgstyle class가 적용된 div 안에 넣었고, 기본적으로 적용된 속성은 아래와 같습니다. 그 외의 모든 CSS 규칙은 인라인 스타일로 정의했으므로 소스를 확인하면 각 예에 적용된 속성을 확인할 수 있습니다.
일반적으로 이미지는 직사각형의 영역을 갖고 있습니다. 따라서 div, p, blockquote 등의 태그처럼 블록(block) 레벨에 속한다고 착각하기 쉽지만 실제로는 일반 텍스트와 동일한 인라인 요소입니다. 따라서 특별한 처리 없이 사용될 경우 아래 예처럼 텍스트의 한 글자처럼 취급됩니다.
글자처럼취급되는image
그런데 동일한 인라인 요소임에도 줄이 제대로 맞지 않는 것을 볼 수 있습니다. 이것은 알파벳의 g, p, y 등의 문자에서 베이스라인 아래로 내려오는 꼬리(descender)를 위한 영역 때문입니다. 즉, 이미지를 꼬리가 없는 i 문자처럼 취급한다는 얘기지요.
이 사이 간격을 없애는 방법은 많이 알려져 있습니다. 첫 번째는 이미지를 감싸는 상위 요소(div 등)의 높이를 이미지와 같도록 해주는 것이고, 두 번째는 CSS의 vertical-align: text-bottom 속성을 지정하는 것입니다. 이미지를 블록(block) 요소로 보이도록 하는 세 번째 방법은 나중에 알아보고 일단 vertical-align: text-bottom 속성을 적용한 이미지를 보겠습니다. CSS를 인라인 스타일(inline stye)로 지정했으므로 소스를 확인하면 바뀐 부분을 확인할 수 있습니다.
글자처럼취급되는image
† 인라인 이미지와 텍스트의 배치를 결정해주는 vertical-align 속성에는 많은 브라우저 호환성 문제가 있습니다. 특히 line-height 속성과 결합되면 심각한 문제가 생길 수 있다고 하네요. 일반적으로 발생하는 문제가 아니기에 추가적으로 설명하지는 않겠습니다. 어떤 문제가 있는지 알아보려면 이미지 수직 정렬과 line-height와의 관계와 긴 이미지와 line-height와의 관계 페이지를 인터넷 익스플로러와 파이어폭스에서 비교해 보시기 바랍니다.
블록(block) 레벨 요소로 보이는 이미지
이미지를 인라인 요소가 아닌 블록 요소로 보여지도록 해야 할 경우가 있는데 이 때 사용되는 것이 CSS의 display 속성입니다. 먼저 알아두어야 할 것은 이 속성이 HTML 요소가 어떻게 보여질지만을 바꿀 수 있다는 점입니다. 다시 말해서 인라인 요소를 블록 요소로 바꾸어주는 것이 아니라는 것이지요. 간단한 예를 들자면 HTML 규격상 인라인 레벨 요소는 블록 레벨 요소를 포함할 수가 없습니다. 따라서 인라인 요소인 span 태그에 display: block; 속성을 지정한다고 해도 span 태그 안에 p 태그는 들어갈 수 없습니다.
하지만 인라인 요소를 블록 요소로 보이게(display) 하면 이미지 위, 아래에서 줄바꿈(line break)이 생깁니다. 아래 예는 이미지에 display: block; 속성이 적용되었을 때의 결과입니다.
블록으로취급되는image
† 이미지와 텍스트에 적용되는 line-height 속성 때문에 서로 다른 요소가 일부 겹치는 경우가 있습니다. line-height 속성 값을 바꾸어도 문제가 해결되지 않는다면 Designer kukie 님의 오늘의 문제는 line-height라는 글을 참고하시기 바랍니다. 이 문제로 한참을 헤매다가 kukie님이 잘 정리해두신 덕에 해결했습니다. :-)
인라인 이미지 정렬
인라인 이미지는 텍스트와 동일하게 취급되므로 텍스트 정렬에 사용되는 CSS의 text-align 속성이 그대로 적용됩니다. 따라서 중앙 정렬시키려면 이미지를 감싸고 있는 p 태그에 text-align: center;를 지정하고, 오른쪽으로 보내려면 text-align: right;를 사용할 수 있습니다. 아래는 가운데 정렬의 예입니다.
글자처럼취급되는image
† text-align 속성은 블록 레벨 요소와 테이블 셀(table cell: th, td), 인라인 블록(inline-block)에 적용되고, 해당 요소가 아닌 하위 요소에 영향을 미칩니다(예: 텍스트).
그런데 이미지가 이런 방식으로 텍스트와 함께 사용되는 경우는 드뭅니다. 보통은 이미지 아래에 텍스트가 들어가거나 이미지 옆 공간에 글 단락이 들어가니까요. 텍스트가 아래 배치될 경우에는 p 태그에 이미지만 넣거나 이미지를 블록 레벨로 보이게 하면 되지만 후자의 경우에는 문제가 복잡해집니다. 그럼 왜 문제가 복잡한지 알아볼까요?
이미지에 float 적용하기
이미지 옆에 텍스트 단락을 넣기 위해서는 이미지에 CSS의 float 속성을 주어야만 합니다. 과도적인(Transitional) HTML 문서 규격에서는 이미지에 align 속성을 사용할 수 있지만 엄격한(Strict) 문서 규격에서는 허용되지 않은 속성이기 때문입니다.
먼저 이미지에 float: left; 속성만 적용시킨 예를 보겠습니다. 단락 구분이 잘 보이도록 p 태그에 테두리선을 넣었습니다.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean vel tellus nec massa cursus malesuada. Pellentesque metus.
Proin eu nisi eu tortor consectetuer varius. Curabitur magna nunc, pretium id, tincidunt a, tempus porttitor, nisi. Integer erat lacus, tempor non, varius sit amet, laoreet in, arcu. Pellentesque tempus mauris. Nulla ut ante ut massa suscipit euismod.
이 상태로도 별 문제가 없지만 두 번째 단락을 이미지 옆이 아닌 새 줄에 넣으려는 의도였다면 원했던 결과는 아닐겁니다. float된 요소는 말 그대로 문서 내에서 떠 있는 상태이기 때문에 다른 요소들을 밀어낸 것처럼 보입니다. 또한, float된 요소는 순차적인 요소(box)들의 흐름(normal flow)을 따르지 않으므로 주의해서 사용해야만 합니다.
float 제거하기(clearing float)
float 속성을 적용시켜서 어떤 요소를 띄웠다면 적절한 곳에서 반드시 그 영향을 없애주는 것이 좋습니다. 기본적으로 float된 요소의 높이(height)는 해당 요소가 들어 있는 블록(containing block) 크기에 영향을 미치지 않는데 이런 특성을 없애서 바깥 블록이 float 요소의 높이만큼 늘어나도록 하면 float 특성을 제거할 수 있습니다. 이런 float 제거(clearing float) 방법에는 여러 가지가 있습니다.
clear 속성 사용
clear 속성을 이용해서 float을 제거하려면 두 가지 요건이 갖추어져야 합니다. 첫 번째는 float된 요소를 담고 있는 블록(containing block) 안에서 clear 속성이 사용되어야 한다는 것입니다. 아래 예가 이 요건을 갖춘 경우입니다.
두 번째 요건은 인터넷 익스플로러에만 해당되는 것으로 float 요소가 포함된 블록(containing block)이 화면상에서 레이아웃을 갖는 요소(haslayout = true)로 인식되어야 합니다. float 문제는 주로 페이지의 레이아웃을 잡을 때 나타나는데 대부분의 경우 float을 포함하는 div에 width나 height 속성을 지정하면서 자동으로 이런 요건을 갖춥니다. 하지만 아래 예처럼 이런 속성이 지정되지 않은 p 태그 안에서는 clear 속성이 인터넷 익스플로러에서만 다르게 적용됩니다. 즉, 인터넷 익스플로러에서는 파이어폭스에서와는 달리 p 태그 높이가 이미지 높이만큼 자동으로 늘어나지 않는 것을 볼 수 있지요.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean vel tellus nec massa cursus malesuada. Pellentesque metus.
Proin eu nisi eu tortor consectetuer varius. Curabitur magna nunc, pretium id, tincidunt a, tempus porttitor, nisi. Integer erat lacus, tempor non, varius sit amet, laoreet in, arcu. Pellentesque tempus mauris. Nulla ut ante ut massa suscipit euismod.
간단한 해결 방법은 Holly hack을 적용시키는 것입니다. float 이미지가 있는 p 태그에 다음과 같은 CSS를 적용시키면 문제가 해결됩니다. width나 height 중 어느 하나라도 정해지면 haslayout 속성이 적용되기 때문입니다.
p { height: 1%; }
float된 이미지의 옆 공간을 채우기 위해서 br 태그를 여러 개 이어서 사용하는 경우가 있는데 좋은 방법이 아닙니다. 그보다는 CSS에 clear를 담당하는 class를 지정해놓고 필요할 경우 적용시키는 것이 좋지요. 흔히 이용되는 코드는 다음과 같습니다.
한 가지 주의해야 할 점은 <div class="clearer"></div>가 만능은 아니라는 사실입니다. HTML의 컨텐츠 모델에 따라서 동일한 블록 레벨 요소라 해도 p 태그 안에는 div 태그가 들어갈 수 없으므로 상황에 따라서 적절한 태그를 골라서 적용시켜야 합니다.
간단한 방법이지만 float 제거만을 위한 마크업이 추가된다는 단점이 있습니다. 게다가 이미지 옆에 여러 개의 단락이 들어가야 할 경우에는 사용할 수가 없지요. 또한, 위 예처럼 두 개의 단락이 p 태그로 명확하게 구분되어 있을 경우에는 br 태그를 사용할 필요가 없으므로 ‘의미 있는’ 마크업도 아닙니다.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean vel tellus nec massa cursus malesuada. Pellentesque metus.
Proin eu nisi eu tortor consectetuer varius. Curabitur magna nunc, pretium id, tincidunt a, tempus porttitor, nisi. Integer erat lacus, tempor non, varius sit amet, laoreet in, arcu. Pellentesque tempus mauris. Nulla ut ante ut massa suscipit euismod.
먼저 앞서 설명한 float 제거(clearing float) 방법과는 달리 상위 블록이 자동으로 늘어나지가 않습니다. 또한, 인터넷 익스플로러(7 포함)와 기타 브라우저에서 서로 다른 결과가 나오는 것을 알 수 있습니다. 파이어폭스나 오페라 등의 브라우저에서는 이미지와 아래 p 요소 사이에 어떠한 공백도 생기지 않는데 이것이 그림이 나타내는 CSS의 표준 렌더링 방식입니다. 하지만 인터넷 익스플로러에서는 p 태그의 margin-bottom 속성이 float된 이미지에도 적용되기 때문에 이미지와 아래 p 요소 사이에 빈 공간이 들어가게 되지요.
모든 브라우저가 동일한 렌더링 결과를 보여준다면 굳이 float을 없애지(clearing float) 않아도(즉, containing block 길이를 늘리지 않고) 원하는 곳에서 clear 속성을 사용할 수도 있을겁니다. 이미지 아래로 p 태그와 같은 margin-bottom을 지정하면 되니까요. 하지만 현실적으로는 몇 가지 문제가 있는데 결정적으로 인터넷 익스플로러에서 이미지 하단과 p 단락 사이의 높이에 따라서 서로 다른 마진을 적용시키기 때문에 크로스 브라우징 면에서 사용하기는 어렵다고 생각됩니다.
† 이 문제에 대한 정보는 이상하게 찾을 수가 없더군요. 그래서 무언가 중요한 요소를 생각하지 못한게 아닌가 하는 생각도 듭니다. 하지만 최소한의 CSS만 적용한 상태에서도 같은 결과가 나오는 것을 보면 인터넷 익스플로러의 CSS 해석 문제라고 생각합니다. 관련 정보 아시는 분들의 제보를 기다립니다.
일단 마치며
간단히 이미지 정렬하는 방법에 대해 포스팅할 생각이었는데 p 태그에 테두리를 설정한 순간 이미 간단함은 멀리 사라졌습니다. 물론 이렇게 보여드리기 위한 예가 아니라면 흔히 발생하는 문제는 아닐겁니다. 하지만 글을 쓰는 입장에서는 가능하다면 왜 그런지 설명을 해야한다고 생각하기 때문에 간단하게 쓸 수가 없네요. 개인적으로 긴 글을 아주 싫어해서 나머지는 다음 글에서 이어나가기로 하겠습니다. ^^;
자료를 찾아보며 알게 된 분명한 사실은 인터넷 익스플로러가 표준을 따르는 오페라, 파이어폭스, 사파리(윈도우즈용으로 테스트)와는 다른 방식으로 float을 처리한다는 사실입니다. 이는 인터넷 익스플로러가 사용하는 자체 속성인 haslayout과 관련이 있는데 다음 글에서 좀 더 자세히 알아보도록 하겠습니다. 아울러 overflow를 사용하는 float 제거 방법과 그 외의 방법도 소개하겠습니다.
하지만 일부 태그에는 여전히 표현을 나타내는 속성이 남아있는데 그 중의 하나가 img와 object 태그에 사용되는 width, height 속성입니다. W3C가 이 속성들을 삭제하지 않은 이유를 이미지의 가로와 세로 크기를 지정하는 것이 페이지 로딩 속도 향상에 도움이 되기 때문이라고 설명하기도 합니다. 하지만 그런 효과는 부수적으로 얻어지는 것이고, 해당 속성이 필요한 근본적인 이유는 아니지요. 그럼 왜 img 태그에 width와 height 속성이 필요한지 알아볼까요?
브라우저가 HTML 문서를 해석하는 방식
브라우저가 HTML 문서를 어떻게 해석하는지에 대해서는 블로깅 툴간의 속도 차이라는 글에서 간단히 설명한 적이 있습니다. 중복을 피하기 위해서 일부를 인용하도록 하겠습니다.
“먼저 브라우저가 원하는 페이지를 전송해달라고 웹 서버에 요청하게 됩니다. 그러면 웹 서버가 이에 대한 응답으로 해당 페이지의 html 문서를 브라우저에게 전송합니다. 브라우저는 전송된 html 문서를 해석해서 페이지 출력(렌더링)에 필요한 CSS, 이미지, 스크립트 파일 등을 순차적으로 다시 웹 서버에 요청하고 그 결과를 받아옵니다. 그러면서 동시에 페이지를 그려나는데 이렇게 필요한 자원에 대한 요청과 전송, 렌더링이 동시에 이루어지기 때문에 이미지가 많이 포함된 페이지도 빠르게 화면에 표시됩니다.”
즉, HTML 문서를 해석하다가 img 태그를 발견하기 전까지는 이미지 파일이 브라우저에게 전송되지 않습니다. 하지만 이미 전송된(또는 전송중인) HTML 문서는 즉시 해석되고 화면에 출력되는데 이 과정에서 약간의 문제가 발생할 수 있지요.
페이지에서 이미지가 차지하는 영역
이미지가 많고 전송 회선이 느린 페이지를 열 경우에 이미지가 로딩되면서 페이지 길이가 계속 늘어나는 경우를 볼 수 있습니다. 스크롤바를 내려서 원하는 텍스트로 이동한 다음에도 계속 화면이 늘어나므로 불편함을 느낄 수도 있지요.
하지만, HTML 문서에 직접 이미지의 width와 height 속성을 지정했다면 얘기는 달라집니다. 브라우저가 HTML을 로딩하는 순간 이미 각각의 이미지가 차지하는 영역을 알고 있으니까요. 즉, 처음부터 문서의 길이를 모든 이미지를 수용할 수 있을 만큼 늘려서 렌더링한다는 얘기입니다.
또한, 브라우저가 이미지가 차지할 영역을 알고 있으면 문서 안에 책갈피(bookmark, anchor)를 넣을 경우 원하는 위치로 정확히 이동할 수 있습니다. 예를 들기 위해서 의미 없는 텍스트(dummy text) 사이에 이미지와 책갈피를 넣은 두 페이지를 준비했는데 실질적인 HTML 소스 상의 차이는 이미지의 width와 height 속성뿐입니다.
속성을 지정한 페이지와 지정하지 않은 페이지를 각각 클릭해보면 이동하는 위치에 차이가 있는 것을 알 수 있습니다. 일단 이미지가 로딩된 후에는 웹 서버에 있는 파일 대신 로컬 컴퓨터에 저장된 캐시(cache) 파일을 이용하므로 캐시를 비우지 않으면 처음과는 다른 결과나 나타납니다.
각각의 페이지 책갈피를 열였을 때 보여지는 브라우저 화면 맨 윗부분을 동일한 영역으로 캡처한 이미지는 아래와 같습니다.
왼쪽 이미지에서 볼 수 있듯이 가로와 세로 길이를 지정하면 책갈피로 이동하는 시점에서 이미지가 차지할 영역을 미리 계산하기 때문에 원했던 결과를 얻을 수 있습니다. id가 withdimension인 h4 태그로 정확하게 이동하지요.
오른쪽 이미지는 width와 height 속성을 지정하지 않았기 때문에 브라우저가 이미지의 크기를 알 수 없습니다. 이미지의 크기를 알 수 없어서 높이가 없다고 가정하고 페이지를 렌더링한 다음 실제로 이미지를 전송받고 화면에 표시하려다 보니 이미지 높이 만큼 아래로 밀려난 것이지요. 결과적으로 의도했던 withoutdimension 책갈피로 이동하지 못했습니다.
† 이 상태에서 페이지를 다시 읽으면(새로 고침) 이미지가 캐시 파일로 저장되었기 때문에 의도했던 곳으로 이동합니다. 또한, 이미지 상단의 테두리(border-top)가 표시되지 않는 것으로 봐서 이미지 크기가 지정되지 않으면 CSS의 border 속성이 적용되지 않는 것도 확인할 수 있습니다.
페이지 로딩 속도에 미치는 영향
이미지의 크기를 미리 알면 브라우저가 크기 정보를 파일에서 얻어 올 필요가 없어집니다. 하지만 이 과정에 소모되는 시간은 문서를 해석하고 렌더링하는데 걸리는 시간에 비교한다면 무시할 수 있을 정도라고 생각합니다. 실질적으로 로딩 속도 향상을 가져오는 것은 페이지에서 갱신되어야 하는 부분이 상대적으로 적기 때문이리라 판단됩니다.
페이지 렌더링은 먼저 컴퓨터의 메모리(RAM)에서 이루어집니다. 메모리에서 화면에 출력될 부분이 그려진 다음 이 부분이 그래픽 카드(VGA) 메모리에 복사되고 최종적으로 모니터 화면에 출력되는 것이지요. 이 과정에서 이미지 크기에 따라 화면이 계속 늘어나므로 갱신될 부분이 많아지고, 필연적으로 많은 연산이 필요하게 됩니다. 따라서 img 태그에 width와 height 속성을 지정하면 페이지 로딩 속도를 향상시킬 수 있는 것이지요.
† 이 부분은 정확한 정보가 아닌 추측입니다. 정확한 정보를 아시는 분들은 꼭 알려주세요.
마치며
W3C의 규격을 완벽하다고 할 수는 없지만 그렇다고 해서 아무렇게나 만들어진 것은 아닙니다. 나름대로 충분한 합리성을 갖고 있지요. img 태그에 width와 height 속성을 반드시 지정해야 하는 이유도 이런 합리성에 기초합니다. 비록 문서의 표현을 담당하는 속성이지만 현실적으로 꼭 필요하기 때문에 남겨둔 것이지요. 그러니 조금 불편하더라도 꼭 지정해 주는 것이 좋습니다.
또한, 현실적인 기능을 고려하지 않고 표현에 관한 속성이라는 이유만으로 ‘의미 있는’ 마크업에 반한다고 생각해서 사용하지 않는 것은 ‘웹 표준’의 진정한 의미를 잘못 해석하는 것이라 생각합니다. 각각의 태그와 속성이 갖고 있는 의미와 용도를 올바르게 이해하고 사용하는 것이 무엇보다 중요하니까요. 문서의 구조와 표현을 분리하려는 목적은 이 과정에서 자연스럽게 얻어지는 것이 아닐까요?
‘웹 표준’에 관한 흔한 오해 중의 하나는 HTML 대신에 XHTML을 사용하면 웹 표준을 더 잘 지킬 수 있다는 생각입니다. XHTML을 사용하면 문서의 ‘표현’과 ‘구조’를 분리할 수 있고, 그래서 보다 ‘의미 있는’ 마크업이 가능하다는 주장도 있는데 이것 역시 사실이 아닙니다.
실제로 ‘의미 있는’ 마크업을 위해서는 XHTML과 HTML 중 어느 것을 사용했느냐가 아니라 어떤 문서 타입 정의(DTD)을 사용하느냐가 절대적으로 중요합니다. (X)HTML 문서는 크게 ‘Transitional(과도적인)’ 타입과 ‘Stict(엄격한)’ 타입으로 나눌 수 있는데 이 두 DTD가 어떻게 다른지 그 차이점을 간단히 알아보고, 웹 표준을 위해서 왜 엄격한 문서 타입이 권장되는지를 알아보도록 하겠습니다.
† XHTML 1.0은 HTML 4.01 규격을 XML에 맞춰 재해석한 규격이므로 약간의 문법 차이를 제외하면 사실상 차이가 없습니다. 따라서 앞으로는 XHTML과 HTML의 문서 타입 정의(DTD)를 따로 구분하지 않겠습니다. XHTML과 HTML의 차이점에 대해서는 앞서 포스팅한 XHTML과 HTML의 차이를 참고하시기 바랍니다.
“Strict 타입은 W3C가 스타일시트 사용을 장려하기 위해 단계적으로 사라질 ‘표현’(presentation)에 관한 태그와 속성을 배제한 문서 타입이다. 웹 문서 제작자는 가능하다면 Strict 타입을 사용해야 하지만(should), 불가피하게 표현을 담당하는 속성이 필요할 경우에는 Transitional 타입을 사용할 수도 있다(may).”
즉, Strict DTD가 W3C가 의도했던 문서 타입이고, Transitional DTD는 ‘과도적인’이라는 단어의 의미 처럼 기존에 만들어진 문서들과의 호환성을 위해서 만들어진 것임을 알 수 있습니다. 과거의 모든 문서들을 Strict DTD에 맞게 바꾸려면 엄청난 변화가 필요하므로 그 중간 단계로 Transitional DTD를 설정한 것이지요.
Frameset DTD
Frameset 타입은 Transitional DTD 기반 위에 프레임 지원을 위한 태그와 속성을 추가한 문서 타입입니다. 그러므로 문서의 구조화에 있어서는 Transitional DTD와 동일하게 취급됩니다.
Strict DTD에서 달라진 점
Strict DTD에서는 Transitional DTD에서 허용되던 많은 태그와 속성이 금지되었습니다. 또한, 일부 태그의 쓰임(Content Model)에서도 차이가 있는데 두 DTD의 이런 차이점을 간단히 정리한 문서가 있어서 일부를 소개합니다. 원문은 24 ways에 포스팅된 Roger Johansson의 Transitional vs. Strict Markup입니다.
사라진 태그(element)들
center
font
iframe
strike
u
글꼴 설정과 각종 요소의 배치, 인라인 프레임, 밑줄 표시를 담당하는 태그가 사라졌고, 선을 긋는다는 의미의 strike 태그는 문서에서 삭제된 부분을 나타내는 del 태그로 대체되었습니다.
보시는 바와 같이 Strict DTD에서는 HTML 문서의 표현을 담당하는 대부분의 속성이 사라지고, 대신 CSS를 사용해서 같은 효과를 얻도록 요구하고 있습니다. 즉, Strict DTD를 사용하기 위해서는 문서의 구조와 표현을 엄격하게 분리시켜야 한다는 얘기지요.
하지만 table, image, object 태그에서는 일부 표현 속성들이 남아있는데 그 이유에 대해서는 다음 글에서 하나씩 다루기로 하지요.
바뀐 컨텐츠 모델(Content Model)
컨텐츠 모델이란 문서에 포함된 모든 요소(태그)와 속성들의 종합적인 관계를 나타냅니다. 이 컨텐츠 모델에 따라서 어떤 태그가 다른 태그를 하위 요소로 포함할 수 있는지가 결정되는데 이 부분에서 Transitional과 Strict DTD에 차이가 있지요.
모든 텍스트와 이미지는 body 태그 안에서 직접 사용될 수 없고, 반드시 div, p 태그와 같은 블록 레벨 요소로 감싸주어야 한다.
form 태그 안에서는 input 태그를 직접 사용할 수 없고, 반드시 div, p, fieldset 등의 태그로 감싸주어야 한다.
blockquote 태그 안의 모든 텍스트는 반드시 div, p 태그와 같은 블록 레벨 요소로 감싸주어야 한다.
Strict DTD를 사용해야 하는 이유
앞서 설명했듯이 Strict DTD는 문서의 구조와 표현을 엄격하게 분리시키기 위해 만들어졌습니다. 따라서 규격에 맞게 마크업하기만 하면 자연스럽게 그 목적을 달성할 수 있지요. 그에 반해서 Transitional DTD는 규격을 지킨다고 해서 ‘의미 있는’ 문서를 보장하지는 않습니다. 앞서 포스팅한 웹 표준에 대한 생각에서 ‘의미 있는’ 마크업의 장점을 다룬 바 있는데 그런 장점을 얻기 위해서는 Strict DTD를 사용하는 것이 최선의 방법입니다.
XHTML의 최종 권고안(규격)인 XHTML 1.1에서는 세 가지로 나뉘었던 DTD를 하나로 통합시켰는데 그 기반이 XHTML 1.0 Strict DTD라는 것을 생각해보면 앞으로의 웹 환경이 보다 구조적인 문서를 만드는 방향으로 나아가리라는 것을 짐작할 수 있습니다. 그러므로 새로 문서를 작성해야 한다면 Strict DTD를 도입하는 것이 미래의 웹 환경을 위해서도 바람직하리라 생각합니다.
마치며
Strict DTD를 사용하는 것은 그렇게 어려운 일이 아닙니다. Transitional DTD를 만족하는 문서를 작성할 수 있다면 약간의 연습만으로도 엄격한 마크업을 작성할 수 있으니까요. 이와 관련해서 몇 가지 HTML 태그의 사용법을 앞으로의 포스팅 주제로 삼을 생각입니다. 물론 자주 올리지는 않겠지만요. ^^;
‘웹 표준’에 관한 관심이 높아지면서 W3C가 제안한 HTML 권고안(Recommandation)을 지키는 블로거들도 많아졌습니다. 그런데 이렇게 웹 표준 마크업을 사용하는 블로그들을 살펴보면 대부분 태터툴즈가 아닌 워드프레스나 그 외의 블로깅 툴로 운영되는 것을 알 수 있는데 국내 설치형 블로그 사용자 대다수가 태터툴즈를 사용하는 것에 비추어보면 의외의 결과라고 할 수 있습니다.
이렇게 태터툴즈를 사용하면서 웹 표준을 지키는 블로그가 거의 없는 이유는 무엇일까요? 태터툴즈가 웹 표준을 제대로 지원하지 않기 때문일까요? 그 원인을 알아보고 어떻게 하면 태터툴즈로도 웹 표준에 맞는 블로그를 만들 수 있을지 알아보겠습니다.
태터툴즈 공식 홈페이지는 태터툴즈가 좋은 이유 페이지를 통해서 웹 표준 지원에 대해 다음과 같이 밝히고 있습니다.
“블로그, 관리자 화면에서 XHTML 1.1 을 준수하며, 여러 웹 브라우저 환경에서 무리 없이 쓸 수 있도록 제작되고 있습니다.”
일단 이것은 사실이 아닙니다. 추후에 XHTML 1.0 Transitional로 변경했다는 글을 어디에선가 봤는데 찾을 수가 없네요. 태터툴즈 배포 문서에서도 이에 관한 정보를 찾을 수 없었습니다.
† 태터툴즈의 문서화에 대한 문제는 Creorix님이 지적한 바 있는데 공식 홈페이지에서 잘못된 정보를 제공하는 점 역시 빨리 수정되어야 하리라고 생각합니다.
그러면 태터툴즈는 XHTML 1.0 Transitional 규격을 제대로 지킬까요? 자체적으로는 그렇습니다. 근본적으로 표준에 어긋나는 마크업을 만들어내지는 않으니까요. 그렇다면 어디에서 문제가 생기는지 하나씩 알아봐야겠지요?
표준을 지키지 않는 사용자 스킨
태터툴즈에 포함된 기본 스킨은 XHTML 1.0 Transitinal 규격에 맞는 마크업으로 작성되어 있습니다. 즉, 웹 표준을 지킨다는 얘기지요. 하지만 사용자들이 제작하는 스킨들 중 상당수는 표준 마크업을 지키지 않고 만들어지고 있습니다. 이것은 태터툴즈의 문제가 아니라 웹 표준에 대한 인식이 널리 확산되지 않은 국내 웹 환경의 문제 때문이라고 생각됩니다.
이와는 달리 방대한 양을 자랑하는 워드프레스는 테마(스킨)들 대부분은 웹 표준을 지켜서 만들어지고 있습니다. 블로깅 툴을 설치하고 새 스킨을 적용한 상태에서 기본적으로 마크업 검증을 통과한다는 얘기지요. 하지만 특별히 웹 표준을 준수하는 스킨을 골라서 사용하지 않는 한 태터툴즈 블로그는 시작부터 웹 표준에 어긋나게 됩니다.
† 내용 정정: 태터툴즈 기본 스킨에 들어 있는 a 태그의 name 속성은 금지된 속성이 아닙니다. 처음 글을 쓸 때 이 점을 잘못 알고서 기본 스킨이 표준 마크업을 지키지 않는다고 주장했는데 실제로는 그렇지 않습니다. 이와 관련해서 글 일부를 수정했음을 알려드립니다.
표준을 지키지 않는 플러그인
플러그인도 마찬가지입니다. 웹 표준에 대한 고려 없이 만들어지고 배포되고 있지요. 흔한 예는 다음과 같습니다.
<script language="javascript">
language 속성이 type 속성으로 대체되었기 때문에 아래와 같이 사용해야 하지요.
<script type="text/javascript">
표준에 어긋나는 마크업을 포함하는 플러그인을 사용하는 순간 웹 표준 준수와는 또 한 발자국 멀어집니다.
자체 문서 편집기의 한계
태터툴즈에 포함된 위지윅(WYSWYG) 에디터 역시 표준 마크업을 지키기 어렵게 만듭니다. 아무런 꾸밈 없이 글을 쓰면 표준 마크업에 위배되지는 않지만 문단 태그(paragraph) 대신 <br /> 태그를 사용하기 때문에 적절한 마크업은 아닙니다. 또한, 일부 텍스트 색을 바꾸거나 할 경우에는 금지된 font 태그가 들어가기 때문에 규격에서 벗어나게 되지요. 이런 문제들에 대한 자세한 사항은 이전에 포스팅한 실질적인 웹 표준을 참고하시기 바랍니다.
태터툴즈로 웹 표준을 지킬 수 있는가?
그렇다면 이런 문제들은 극복 가능할까요? 이미 힌트를 드렸으니 결론 먼저 말하겠습니다. 답은 ‘지킬 수 있다’입니다. 대표적인 예가(그리고 제가 아는 유일한 예가) 1up님이 운영하는 블로그와 티스토리 스킨 배포 사이트인 Tiskin인데 두 사이트 모두 엄격한 마크업 규격인 XHTML 1.0 Strict를 준수하고 있습니다.
웹 표준을 지키는 방법
앞서 설명한 문제점들을 피하면 됩니다. 먼저 웹 표준에 맞게 만들어진 스킨과 플러그인을 사용해야겠지요. 표준을 지키는지 여부를 확실히 알 수 없다면 W3C의 마크업 검증을 이용해서 확인해 보는 것이 좋습니다. 아무리 신경써서 글을 작성한다고 해도 기본적인 바탕이 어긋나면 의미가 없으니까요.
글을 작성할 때에는 가급적 위지윅 모드가 아닌 HTML 편집 모드를 사용해야 합니다. 쎄바님에 따르면 인터넷 익스플로러에서는 편집 모드 전환시에 태그가 자동으로 대문자로 바뀐다고 하니 익스플로러가 아닌 파이어폭스나 오페라 등의 브라우저를 이용하는 것이 좋겠지요.
마치며
마크업 검증을 통과했다고 해서 ‘웹 표준’을 완벽하게 준수했음을 의미하지는 않습니다. 다만 웹 표준 준수를 위한 첫걸음이라고 할 수 있기 때문에 중요한 것이지요. 쉽지는 않지만 충분한 가치가 있다고 생각합니다. 웹 표준을 지킴으로써 얻을 수 있는 장점에 대해서는 앞서 썼던 웹 표준에 관한 생각이라는 글을 참고하시기 바랍니다.
또한, 이 글은 모든 블로거들이 웹 표준을 지키기 바라는 마음으로 쓴 것이 아닙니다. HTML 태그를 잘 모르는 분들에게 웹 표준을 권하기는 현실적으로 어려우니까요. 단지 웹 표준에 대한 관심과 지식을 갖고 있는 분들 중에서 태터툴즈로는 웹 표준을 지킬 수 없다라고 오해하는 분들이 있지 않을까 싶어서 적어봤습니다. 사실 제가 얼마 전까지만 해도 그렇게 생각했었거든요. 1up님 블로그를 통해서 그 생각이 틀렸음을 알았답니다.
XHTML이 어떤 마크업 언어이고, 어떤 한계를 가지고 있는지를 앞선 글에서 알아봤습니다. 그렇다면 HTML 대신 XHTML을 사용하는 것은 과연 옳은 선택일까요? 이 주제에 관해서 포스팅하게 된 동기가 되었던 Tommy Olsson의 글에서는 이 문제에 대해서 부정적인 입장을 취하고 있습니다. XHTML이 실제로는 HTML과 거의 동일하게 취급되므로 구태여 XHTML을 사용할 필요가 없다는 주장이지요.
하지만 XHTML을 이용한 홈페이지와 블로그를 만들고 운영하는 제 생각은 그와는 다릅니다. XHTML이 HTML 대신 사용되는 것을 굳이 말릴 필요는 없다고 생각하거든요.
물론 이 문제에는 정답이 없습니다. 각자가 생각하고 판단해야 할 문제니까요. 그 판단을 돕기 위해서 각각의 주장에 대해서 자세히 설명하려는 것이 이 글의 목적입니다.
그리고 이 글은 XHTML 1.0과 HTML 4.01 규격을 비교하는데 중점을 두겠습니다. 하위 호환성을 보장할 수 없는 XHTML 1.1 규격을 특별한 목적 없이 사용해서 얻을 수 있는 것은 최신 규격을 지켰다는 심리적 만족 외에는 없다고 생각하므로 이 규격에 대해서는 언급하지 않겠습니다. 많은 사람들이 W3C의 권고안, 즉 표준을 완전무결한 기준으로 받아들이는데 그런 생각은 W3C의 권위가 불러오는 함정이 될 수 있습니다.
“XHTML과 HTML 중에서 어느 것을 선택해야 하는지에 관한 절대적 기준은 없으며, 이 문제에 관한 여러가지 기술적인 문제들을 생각했을때 간단히 답할 수 있는 문제가 아니다. 하지만 현실적으로 가장 호환성이 높은 W3C의 마지막 표준은 HTML 4.01이라 말할 수 있다. 당신이 실제로 HTML로는 불가능한 XHTML의 기능을 사용해야 하는 경우를 제외하면 기술적인 면에서 XHTML을 사용해야 할 이유는 전혀 없다.”
“XHTML을 사용해서 실익을 얻으려면 XHTML과 HTML의 근본적인 차이점을 이해해야 한다. 하지만 XHTML을 제대로 사용하는 사이트를 이용할 수 있는 것은 전체 웹 사용자들의 일부일 뿐이다.”
“일부 웹 디자이너와 개발자들은 XHTML의 문법 규칙을 선호한다. 특정한 지침을 따른다면, XHTML의 기술적인 면을 전혀 사용하지 않고서도 XHTML의 문법을 사용할 수 있다. 이런 접근 방식에는 잠재적인 문제점이 있지만, <br> 태그 대신 반드시 <br /> 태그를 사용하기를 원한다면 그 방식을 따르면 된다.”
“당신의 문서가 미래의 환경에서도 유효하려면(future-proofing) XHTML과 HTML에서 어느 것을 선택하느냐 보다 Transitional 대신 Strict DOCTYPE을 사용하는 것이 훨씬 중요하다.”
그의 주장의 바탕이 되는 이유는 앞선 글에서 설명했던 브라우저의 XHTML 호환성 문제 때문인데 이에 관한 설명은 브라우저가 XHTML을 해석하는 방식을 참고하시기 바랍니다.
마지막 문장에 대해서는 XHTML과 HTML의 차이에서 이미 다루었지만, 중요한 의미가 있어서 다시 한번 짚고 넘어가겠습니다.
많은 사람들이 XHTML을 사용하면 문서의 ‘구조’와 ‘표현’을 HTML보다 잘 분리해서 보다 ‘의미 있는’ 마크업을 할 수 있다고 생각하지만 이것은 사실이 아닙니다. 이런 면에서 두 규격은 서로 대등하니까요. 동일한 Strict DTD로 정의된 XHTML 1.0과 HTML 4.01 문서는 사용할 수 있는 요소(element)와 속성(attribute)에 차이가 거의 없습니다. 단지 <br> 태그 대신 <br /> 태그를 사용하는 것처럼 문법 규칙이 다를 뿐이지요.
CSS를 사용하는 것도 마찬가지입니다. XHTML과 HTML 모두 동일하게 적용되지요. 그러므로 XHTML로 가능한 문서의 ‘구조’와 ‘표현’의 분리는 HTML로도 똑같이 할 수 있습니다.
하지만 점점 더 많은 사람들이 HTML대신 XHTML을 사용해야 한다고 주장합니다. Tommy Olsson은 그 이유를 다음과 같이 밝히고 있지요.
“많은 웹 디자이너와 개발자들이 XHTML 1.0의 발표에 환호했다. XHTML은 당시에 크게 유행했던 XML이었고 HTML처럼 쉽게 사용할 수 있었으며 모든 브라우저에서 잘 동작했다. 사람들은 XHTML의 확장성에서 많은 가능성을 발견했고, W3C가 더 이상의 HTML 규격은 아마도 없을 것이라고 발표하면서 XHTML이 미래 환경을 위한 유일한 대안이라고 생각하게 되었다.”
“시간이 흐르면서 XHTML 사용의 문제점과 확장성의 한계가 밝혀졌지만 XHTML에 대한 장밋빛 환상만큼 널리 알려지지는 않았다. 이 사실을 알지 못하거나 개인적인 선호 때문에 많은 사람들은 여전히 HTML보다는 XHTML을 사용해야 한다고 주장하고 있다.”
여기서 말하는 XHTML은 XML의 기능이 사용되지 않아서 HTML로도 충분히 처리가 가능한 마크업을 말합니다. XML의 기능이 꼭 필요하다면 당연히 XHTML을 사용해야겠지요. 하지만 이 글을 읽으시는 분들 중에서 XML을 사용했기 때문에 인터넷 익스플로러로는 접근할 수 없는 그런 페이지를 단 한번이라도 보신 적이 있는지요?
† 인용한 문장에서는 HTML 4.01이 W3C의 마지막 HTML 표준이 될 것이라 생각하는데, 이것은 Tommy Olsson의 원문이 2006년 6월에 씌여졌기 때문입니다. 현재 W3C에서는 HTML 5와 XHTML 5를 위한 워킹 그룹이 새로운 표준의 밑그림을 그리고 있습니다. HTML 5는 애플, 모질라, 오페라 진영의 사람들이 모여서 설립한 WHATWG에서 자신들이 개발중인 규격을 W3C의 새로운 HTML 규격을 위한 초안으로 채택해줄 것을 제안했고, W3C가 이 제안을 받아들이면서 세상에 그 이름을 알리게 되었습니다(2007년 5월). 현재 이 워킹 그룹의 편집 책임자는 구글의 Ian Hickson과 애플의 David Hyatt입니다.
그럼에도 불구하고 XHTML을 사용하는 이유
Tommy Olsson은 XHTML이 HTML과 다를 바 없으므로 HTML을 사용하는 것이 더 나은 선택이라고 주장합니다. 하지만 역설적으로 그렇기 때문에 XHTML을 사용하는 것이 아닐까요? 다시 말해서 HTML 대신 XHTML을 사용해서 얻을 수 있는 이점은 없지만, 그렇다고 해서 특별히 단점이 있는 것도 아니니까요.
XHTML을 HTML처럼 사용하는 것이 잠재적인 문제점(potential pitfall)을 안고 있다고 하지만 그것은 어디까지나 브라우저 같은 사용자 에이전트(user agent)의 내부적인 처리 방식의 문제입니다. 결과적으로 XHTML은 HTML과의 호환성을 유지하고, XHTML 문법 규칙은 혼란을 일으키지 않을 만큼 충분히 명확하기 때문에 사용자에게는 아무런 문제가 되지 않습니다.
또한 XHTML을 사용하면 HTML보다 양식화된(well-formed) 문서를 작성할 수 있는데 이것은 브라우저가 아닌 사용자 입장에서 특히 유익합니다. 브라우저는 </p> 태그가 없어도 문단이 어디서 끝나는지 명확하게 알 수 있지만, 사용자는 그것을 알기가 어려우니까요.
물론 HTML을 사용해도 동일하게 양식화(well-formed)된 문서를 작성할 수 있습니다. </p> 태그는 생략할 수 있는 것이지 생략해야 하는 것이 아니기 때문입니다. 하지만 XHTML을 사용하면 마크업 검증기(validator)가 문서의 양식을 더 꼼꼼하게 확인합니다. 따라서 XHTML 마크업을 작성하고 검증해보는 것이 양식화된 마크업을 익히는데 유리합니다.
미래의 웹 환경이 어떻게 달라질지 예상하는 것은 어렵습니다. 하지만 단시일 내에 모든 브라우저들이 완벽하게 XML을 지원하리라고는 믿지 않습니다. 개인적으로는 XHTML 문서를 나타내는 .xhtml 확장자가 지금의 .html 확장자 만큼 익숙해져야 XHTML 문서가 그 힘을 발휘할 수 있다고 생각하는데 그 때를 대비해서 XHTML을 써야한다고 주장하는 것이 아닙니다. 앞서 말씀드렸듯이 지금 작성되는 대부분의 XHTML 문서에는 XML 만의 기능이 들어가 있지 않으니까요. XHTML의 하위 호환성을 고려했을 때 HTML 대신 사용해도 무방하다는 것이 제 의견의 요지입니다.
마치면서
XHTML과 HTML 규격의 차이점을 다루는 글을 쓰게 된 동기는 ‘웹 표준’과 XHTML 사용을 동일하게 받아들이는 일부의 시각 때문입니다. HTML 4.01 규격도 엄연히 W3C가 제정한 표준 권고안임에도 불구하고 XHTML과 CSS를 사용해야만 웹 표준을 지킬 수 있고, 그것이 무조건 더 좋은 방법이라고 생각하는 분들이 있는데 절대적으로 틀린 생각입니다.
웹 표준을 잘 지키고 그 장점을 누리기 위해서는 XHTML과 HTML의 차이가 아니라 Strict와 Transitional DTD의 차이를 아는 것이 훨씬 더 중요합니다. 이 주제에 관해서는 나중에 다루도록 하고, XHTML과 HTML 규격의 차이점에 관한 글은 이것으로 모두 마칩니다.
W3C가 2001년 5월에 발표한 최종XHTML 권고안이 XHTML 1.1 규격입니다. 하지만 XHTML을 소개하는 문서들의 대부분은 2000년 1월에 발표된 XHTML 1.0 규격에 관한 정보를 담고 있고, 현재 사용되는 XHTML 웹 문서들도 대부분 XHTML 1.0 규격을 따르고 있습니다.
† 2000년 1월에 발표된 XHTML 1.0 권고안이 2002년 8월에 개정(Second Edition)되었기 때문에 시기상으로 XHTML 1.0 권고안이 최신 규격입니다. XHTML 1.1도 개정판(Second Edition)을 준비하고 있지만 아직 정식 권고안으로 채택되지는 않았습니다(2008년 4월 23일 수정).
그렇다면 최신 규격이라고 말할 수 있는XHTML 1.1이 XHTML 1.0 규격에 비해 상대적으로 훨씬 덜 알려지고 덜 사용되는 이유는 무엇일까요? 해답을 찾기 위해서 먼저 두 규격의 차이점을 알아보겠습니다.
이 글은 앞서 작성한 글과는 달리 Tommy Olsson이 Site Point포럼에 올린 글의 일부만을 인용해서 설명하도록 하겠습니다. 원문에는 XHTML 1.1 규격에 관한 부분이 상당히 간략하게 설명되어 있거든요.
XHTML 1.1과 XHTML 1.0의 차이는 무엇인가?
크게 두 가지 차이점이 있습니다. 첫 번째는 기존의 XHTML 1.0 규격에 모듈화를 도입했다는 것이고, 두 번째는 루비 주석(Ruby annotation)을 지원하기 위한 태그가 있다는 것이지요.
사실 XHTML 1.1은 실질적으로 기존의 XHTML 1.0, 그중에서도 XHTML 1.0 Strict 규격과 큰 차이가 없습니다. 왜냐하면 이 규격을 기반으로 모듈화를 도입했기 때문이지요. 그래서 XHTML 1.0 Strict 규격에 맞게 작성된 페이지는 DOCTYPE만 1.1로 바꿔주면 거의 대부분 아무 문제없이 마크업 검증기(validator)를 통과합니다. 문법적으로 달라진 차이점은 정확하게 세 가지입니다.
모든 요소에 적용되던 lang 속성이 사라지고, 대신 xml:lang 속성이 도입되었다.
a와 map 요소에 적용되던 name 속성 대신 id 속성을 사용해야 한다.
루비(Ruby)를 지원하기 위한 요소가 추가되었다.
모듈화는 무엇을 의미하는가?
XHTML 1.1에 도입된 모듈화는 기존에 평등한 관계에 있던 태그 요소(element)들을 수행하는 기능에 따라 몇 개의 분류로 나눈 것입니다. 이렇게 나뉘어진 모듈들을 조합해서 XHTML 문서를 작성할 수 있고, 사용자에게 필요한 추가적인 모듈을 사용해서 문서의 기능을 확장할 수 있도록 한 것이지요.
W3C는 모듈화로 얻을 수 있는 이점을 다음과 같이 밝히고 있습니다.
“단순히 웹 문서에만 사용되던 HTML이 다양한 분야와 기기(모바일 기기, 디지탈 TV 등)에 점점 더 많이 적용되고 있는데 이들 각각은 서로 요구하는 조건이나 구현상의 한계가 다르므로 기존의 규격을 일괄적으로 적용시키기가 어렵다.”
“이런 문제를 해결하기 위해 도입된 모듈화를 통해서 서비스나 기기를 디자인할 때 표준에 맞게 만들어진 블록을 사용하고, 표준에 맞는 방법으로 어떤 블럭을 사용했는지 알려주는 방식으로 해당 기기가 어떤 모듈을 지원하는지 컨텐츠 커뮤니티(content community)에 명확하게 알려줄 수 있다. 그러면 컨텐츠 커뮤니티는 필요한 특정 모듈을 지원하는 이미 만들어진 기반(installed base)에만 신경을 써서 컨텐츠를 만들어낼 수 있다.”
“표준화된 방식을 사용함으로써 소프트웨어는 기기에 맞게 컨텐츠를 처리할 수 있고, 기기는 필요한 모듈을 처리하기 위한 소프트웨어를 자동으로 불러올(load) 수 있게 된다.”
“또한, 모듈화와 XML의 확장성을 이용해서 XHTML 표준을 어기지 않고도 XHTML 문서의 레이아웃과 디자인의 확장성을 높일 수 있다.”
† 원문을 의역하고 요약하는 과정에서 원래 의미를 잘못 전달할 수 있습니다. 언제나 오역을 염두에 두시고 봐주세요. ^^;
루비 주석(Ruby annotation)은 무엇인가?
루비는 특정한 텍스트와 관련 있는 다른 텍스트를 함께 표기하는 방법을 의미하며 중국어나 일본어 표기에 사용됩니다(프로그래밍 언어 ‘루비’와는 아무 관련 없음). XHTML 1.1 규격에는 루비 표기를 지원하는 모듈이 포함되어 있는데, W3C가 모듈화의 예를 들기 위해서 넣지 않았나 하는 생각이 드네요. 루비가 어떻게 사용되는지 알려드리기 위해서 W3C의 루비 주석 규격에서 가져온 이미지를 보여드리겠습니다.
설명하지 않아도 어떻게 사용되는지 아시겠지요? 다른 예를 이미지와 XHTML 1.1 코드로 알아보겠습니다.
일단 인터넷 익스플러러는 XHTML을 제대로 지원하지 않습니다. 앞선 글에서 Content-Type에 관해 설명했듯이 XHTML의 XML 기능을 사용하기 위한 필수 요구 조건인 application/xhtml+xmlMIME 타입을 인식하지 못하지요.
인터넷 익스플로러를 제외한 일부 브라우저, 예를 들어서 파이어폭스는 XHTML을 지원합니다. 하지만 그렇다고 해서 위에서 설명한 루비 주석을 작성하기 위한 마크업을 인식할 수 있을까요?
현재까지는 그렇지 않습니다. 파이어폭스에서 위에서 예로 들었던 루비 주석 마크업의 결과물을 보려면 플러그인을 따로 설치해야 합니다.
† 인터넷 익스플러로 5.0 이후의 브라우저는 제한적으로 루비 주석 표기를 지원합니다. 하지만 인터넷 익스플로러 5.0이 1999년에 발표되었다는 사실에서 짐작할 수 있듯이 W3C가 XHTML 1.1 규격에서 제안한 방식으로 구현된 것은 아닙니다. 비 표준적인 태그 지원이라는 얘기지요. 그러므로 XHTML이 아닌 HTML에서도 루비 주석을 표현할 수 있으며 XHTML의 MIME 타입과도 무관합니다.
XHTML 1.1은 XHTML 1.0과 마찬가지로 하위 호환성을 유지하는가?
이 중요한 문제의 답으로 Tommy Olsson의 글을 인용하겠습니다.
“XHTML 문서를 text/htmlMIME 타입으로 제공할 때에는 절대로 XHTML 1.1 규격을 사용하지 말아야 한다. 왜냐하면 XHTML 1.1에서 lang 속성이 금지(deprecate)되었기 때문에 HTML과의 하위 호환성을 유지할 수 없기 때문이다.”
XHTML 1.0에서는 HTML과의 호환성을 위해서 해당 문서가 어떤 언어로 작성되었는지 lang 속성과 xml:lang 속성 두 가지를 모두 지정할 것을 권장합니다. XHTML을 지원하는 브라우저는 xml:lang 속성을 이해할 수 있고, 그렇지 않은 브라우저는 lang 속성을 이해할 수 있으니까요.
하지만 XHTML 1.1을 text/htmlMIME 타입으로 제공하면 브라우저가 해당 문서를 HTML로 취급하게 됩니다. 당연히 xml:lang 속성을 해석할 수 없겠지요. 그 문서가 어떤 언어로 작성되었는지 알려줄 방법이 없다는 얘기입니다.
물론 사용한 언어를 지정하지 않아도 대부분의 브라우저는 지금 보시는 이 페이지 처럼 알아서 문서를 해석합니다. ^^; W3C의 XML 규격에는 이렇게 나와있네요.
“XML 문서를 처리할 때 문서가 어떤 언어로 작성되었는지 아는 것이 유용할 때가 많다(often useful). 어떤 언어로 작성되었는지 알려주기 위해서 xml:lang 속성을 사용할(may) 수 있다.”
하지만 DTD 선언을 한 상태에서 xml:lang 속성을 지정하지 않으면 XML 검증기(validator)가 마크업이 유효하지 않다고 불평한다고 하네요. 결국 선언해야 한다는 얘기지요.
또한, 당장 브라우저가 아무 문제없이 문서를 해석한다고 해도 다른 기기에서 문제를 일으킬 가능성이 있으므로 Tommy Olsson의 주장이 옳다고 생각합니다.
그러면 XHTML 1.1 규격을 사용하지 말라는 것인가?
역시 Tommy Olsson의 글을 인용하겠습니다.
“루비 주석을 표기할 필요가 있고, 그 문서를 이용하는 사용자가 루비 주석에 관한 마크업을 해석할 수 있는 플러그인을 설치했을 경우가 아니라면 XHTML 1.1을 사용해서 얻을 수 있는 것은 아무 것도 없다.”
한 마디로 불필요하다는 얘기지요. 사용자가 가장 많은 인터넷 익스플로러는 XHTML을 아예 지원하지 않고, 그나마 지원하는 브라우저에서도 XHTML 1.1의 새로운 기능인 루비 주석을 표현하려면 플러그인을 설치해야 합니다. 게다가 HTML과의 하위 호환성도 보장할 수 없으니 그렇게 주장하는 것이 당연하지 않을까요?
대부분의 XHTML 문서가 왜 최신 규격이 아닌 XHTML 1.0 규격을 따르는지 알아봤습니다. 원래는 이번 글을 끝으로 XHTML과 HTML의 차이에 관한 글을 마치려고 했는데 아직 설명해야 할 것들이 남아있네요. 다음 글에서는 여러가지 문제점에도 불구하고 많은 사람들이 XHTML에 관심을 갖고 사용하려는 이유에 대해서 알아보겠습니다.
일반적인 환경에서는 XHTML 규격에 맞게 적성된 모든 문서가 실질적으로 HTML과 동일하게 처리됩니다. 이번 글에서는 왜 그런 결과가 생기는지 그 이유를 알아보겠습니다.
이 글은 앞선 글과 마찬가지로 Tommy Olsson이 Site Point포럼에 쓴 글을 번역한 것으로 부분적으로 dagger 마크(†)로 시작하는 보충 설명을 넣었습니다. 따라서 이 글의 저작권은 원문의 저작자인 Tommy Olsson과 Site Point에 있으며, 블로그 전체에 적용되는 CCL보다 우선적으로 적용됩니다.
MIME 타입은 어떻게 적용되는가?
웹에 있는 문서나 자원(resource)을 HTTP 프로토콜을 통해서 요청하면 웹 서버는 요청에 맞는 결과(response)를 보내주게 된다. 요청에 대한 답변은 하나 이상의 헤더와 빈 행(CR+LR), 그리고 문서의 내용(body)으로 구성되는데, HTML이나 XHTML 문서에서는 우리가 작성한 마크업이 그 내용이 된다.
HTTP 헤더는 전송할 문서에 대한 메타 정보를 제공하게 되는데, 그 중에서 가장 중요한 헤더가 Content-Type 헤더이다. 이것은 브라우저와 같은 사용자 에이전트(user agent)에게 전송할 문서가 어떤 내용을 담고 있는 문서인지 알려주는 역할을 한다. 또한 이 헤더는 문서가 어떤 문자 인코딩을 사용하는지에 관한 정보도 포함할 수 있다. 일반적인 HTML 헤더는 아래와 같이 표현된다.
Content-Type: text/html; charset=iso-8859-1
여기에서 text/html 부분을 MIME 타입이라고 부르는데 이메일 전송에서 사용되던 문서의 내용을 정의하는 규격으로 HTTP 전송에도 동일하게 적용된다.
예로 든 MIME 타입은 미디어 타입 이름(text)과 서브타입 이름(html)으로 구성되며, 문자 인코딩 정보는 생략이 가능하다.
RFC 2854 규약에 따라서 이 MIME 타입은 문서의 내용이 HTML임을 나타낸다. 그러므로 브라우저는 해당하는 문서가 마이크로소프트의 워드 문서나 GIF 이미지, 또는 XHTML 문서라 해도 무조건 HTML로 인식하고 해석한다. 다시 말해서 MIME 타입이 text/html일 경우에 그 문서는 XHTML이 아닌 HTML 문서가 된다.
XHTML이 HTML로 해석된다는 것은 XML에서만 가능한 기능들을 전혀 사용할 수 없고, 반대로 HTML에서만 가능한 기능들은 사용할 수 있다는 의미이다. 하지만 그렇게 HTML의 기능을 사용하는 것은 XHTML로 마크업한 원래의 목적에 위배되는 일이 된다.
그러면 XHTML은 어떤 MIME 타입을 사용해야 하는가?
브라우저가 XHTML을 XML 문서로 인식하고 해석하려면 아래의 세 가지 MIME 타입 중의 하나를 사용해야 한다.
application/xhtml+xml (추천함)
application/xml
text/xml (추천하지 않음)
W3C가 추천하는 MIME 타입은 RFC 3236 규약에 정의된 application/xhtml+xml 타입이다. 하지만 인터넷 익스플로러는 2006년 6월 현재까지 이 MIME 타입을 지원하지 않는다.
text/xml 타입도 사용할 수 있지만 기본 문자 인코딩을 처리하는 방식의 문제 때문에 추천하지 않는다. 이 타입에서는 HTTP 헤더에 인코딩 정보가 반드시 포함시켜야 하는데, 이것은 XML 선언에서 변경할 수 없다. 게다가 이 타입의 기본 인코딩은 도움이 되지 않는 US-ASCII 방식이다.
브라우저는 XHTML을 제대로 지원하는가?
아니다. 오페라, 파이어폭스, 사파리 같은 일부 브라우저는 XHTML을 지원하지만, 가장 많은 사용자를 확보하고 있는 인터넷 익스플로러가 XHTML을 제대로 지원하지 않는다.
호환성을 위해서 W3C는 XHTML 1.0 규격에 포함시킨 HTML 호환성 가이드라인에서 text/htmlMIME 타입을 사용하는 방법을 제시하고 있다. 하지만 이 MIME 타입을 사용하면 모든 브라우저는 해당 문서를 HTML 문서로 인식하고 해석한다.
실질적으로 모든 브라우저가 self-closing 태그(예: <br />)의 슬래시 기호를 무시하는 해석상의 버그를 갖고 있으므로 XHTML은 HTML과 동일하게 해석된다.
† XML 문법에서는 self-closing 태그의 슬래시 기호 앞에 공백을 넣지 않아도 문법적으로 아무 문제가 없으며, <br /> 태그를 <br></br> 태그처럼 사용할 수도 있습니다. 하지만 XHTML에서는 호환성을 위해서 이런 문법을 허용하지 않습니다.
<meta/> 태그에 지정한 MIME 타입도 적용되는가?
그렇지 않다. 브라우저는 HTTP 요청에 대한 답변으로 전송받는 내용(body)을 해석하기 전에 그 문서가 어떤 문서인지를 알아야 한다. 브라우저가 아래와 같은 메타 태그를 발견했을 때에는 이미 늦은것이다.
MIME 타입은 반드시 HTTP 헤더로 보내야 한다. 문자 인코딩에 대한 정보는 메타 태그가 아닌 XML 선언에서 명시되어야 한다.
† Lachlan Hunt의 블로그에 실린 Content-Type에 관한 글을 참고해서 내용을 보충하자면 이렇습니다. 메타 태그의 Content-Type은 브라우저 같은 사용자 에이전트(user agent)를 위해 만들어진 것이 아니라 서버가 HTTP 헤더에 실어 보낼 Content-Type을 동적으로 변경하기 위한 목적으로 고안되었지만, 실제로는 그 역할을 못하고 있습니다. 이 메타 태그가 수행하는 유일한 역할은 W3C가 제안한 바와 같이 문서의 인코딩 정보를 알려주는 것입니다.
그러면 HTTP 헤더가 없는 로컬 문서는 브라우저가 어떻게 해석하는가?
오페라와 파이어폭스는 로컬 문서의 확장자를 보고 어떻게 해석해야 할지 판단한다. 예를 들어서 xhtml, .xht, .xml. 확장자를 인식할 수 있다. 인터넷 익스플로러는 XHTML을 전혀 지원하지 않으므로 이런 방법이 적용되지 않는다.
그러면 어떻게 해야 XHTML에 맞는 MIME 타입을 지정할 수 있는가?
서버 환경에 따라서 방법에 차이가 있지만, 아파치 서버의 경우 다음과 같은 AddType 지시문을 사용할 수 있다.
AddType application/xhtml+xml .xhtml .xht
이 지시문은 .xhtml과 .xht 확장자를 갖는 문서를 application/xhtml+xmlMIME 타입으로 전송하도록 서버에 지시한다. 이 명령은 아파치 서버의 전역 설정(/etc/httpd.conf)이나 웹 디렉토리의 .htaccess 파일에 적용된다.
이런 설정 파일에 접근할 수 없는 경우에는 서버-사이드 스크립트 언어를 사용해서 같은 결과를 얻을 수 있다. 예를 들어서 PHP 언어를 사용한 다음 코드를 이용할 수 있다.
XHTML을 application/xhtml+xml 타입으로 전송하면 어떤 장점이 있는가?
말 그대로 브라우저가 XHTML을 XHTML로 인식한다. XHTML을 사용할 경우에만 얻을 수 있는 장점 때문에 XHTML 문서를 작성했다면 그 장점을 그대로 누릴 수 있다.
Content Negotiation 방식을 사용하면 해결되지 않는가?
Content Negotiation은 하나의 HTTP 요청에 대해서 두 가지 이상의 자원(문서, 이미지 등)을 준비해서 사용자 에이전트(user agent)에 따라 선택적으로 제공하는 방법이다. 예를 들어서 application/xtml+xml을 지원하는 오페라, 파이어폭스, 사파리 브라우저는 XHTML 문서를 application/xtml+xml 형태로 제공하고 인터넷 익스플로러가 요청할 때에는 HTML 마크업으로 작성된 HTML 문서를 text/html 형태로 보낼 수 있다.
하지만 이런 방법으로 얻을 수 있는 이점은 다른 컴퓨터 광(geeks)들에게 자신의 능력을 보여주는 것 외에는 전혀 없다. HTML로 변환시킬 수 있는 문서라면 XML만이 지원하는 기능을 전혀 사용하지 않았을 것이기 때문이다. 그렇다면 이름만 다른 두 개의 문서(XHTML, HTML)를 준비하는 것보다 HTML 4.01 스팩을 따르거나 XHTML을 text/html로 제공하는 것이 훨씬 쉬운 방법이다.
Content Type Negotiation은 더 의미가 없다. 같은 문서를 브라우저에 따라 서로 다른 Content-Type으로 보내서 얻을 수 있는 이점은 전혀 없다.
† Content Negotiation을 쉽게 이해하려면 GIF 이미지와 PNG 이미지를 생각하면 됩니다. 동일한 두 가지 이미지를 준비해서 PNG를 제대로 지원하지 않는 인터넷 익스플로러 6.0에게만 GIF 이미지를 전송하는 방법이지요. 자세한 설명은 Content Negotiation에 관한 위키피디아 문서를 참고하세요.
Content Type Negotiation은 모든 요청에 대해 동일한 내용(content)을 전송하면서 HTTP 헤더 정보만 달리하는 것을 말합니다. 동일한 문서가 XHTML도 되고, HTML도 되는 방식입니다.
인터넷 익스플로러에서 XHTML을 사용할 수 있는가?
불가능하다. 익스플로러가 application/xhtml+xmlMIME 타입을 지원하지 않으므로 이런 헤더 정보를 받게 되면 해당 페이지를 다운로드하려고 한다. 레지스트리를 변경해서(hack) 이 MIME 타입을 인식하도록 할 수는 있지만 그렇다고 해도 해당 문서는 여전히 HTML로 취급된다.
XHTML의 XML 기능이 필요하다면 문서를 application/xml로 제공할 수 있다. 인터넷 익스플로러도 이 MIME 타입을 지원하지만 XHTML의 이름 영역(namespace)를 사용할 수 없으므로 해당 문서는 보통의 XML 문서로 인식된다. 따라서 스타일시트가 기본적으로 적용되지 않으므로, 모든 요소에 대한 스타일을 전부 지정해줘야 한다. 예를 들어서 모든 블록 레벨의 요소들에 display: block 속성을 지정해야 한다.
물론 XHTML을 text/html로 제공할 수 있다. 하지만 앞서 길게 설명했던 것처럼 브라우저는 그 XHTML 문서를 문법 오류가 있는 HTML 문서로 인식한다.
† 여기서 말하는 문법 오류는 닫는 태그 앞에 공백과 슬래시 기호가 있는 것을 의미합니다. 예를 들어서 <br /> 태그 같은 것이지요.
인터넷 익스플로러 7은 XHTML을 제대로 지원하는가?
그렇지 않다.
마지막 질문에 대한 짧은 답이 인상적입니다.
간단하게 요약하자면 브라우저가 XHTML을 제대로 지원하지 않고, XHTML과 HTML의 기능이 완벽하게 호환되지 않으므로 대부분의 XHTML 문서는 HTML과의 하위 호환성을 고려해서 작성된다는 얘기입니다. 그렇게 작성된 문서에 XML을 지원하는 브라우저에서만 해석 가능한 마크업이 들어갈 리 없으니 겉모습은 XHTML이라도 실제로는 HTML과 다를 바 없다는 것이 원문의 주장입니다.
다음 글에서는 그럼에도 불구하고 XHTML이 널리 사용되는 이유와 마지막으로 발표된 W3C의 XHTML 규격인 XHTML 1.1에 대해서 알아보도록 하겠습니다.
마지막으로 사용자가 자신의 웹 페이지를 요청했을 때 서버가 어떻게 답하는지 궁금한 분들은 W3C의 HTTP Head 서비스를 이용해 보시기 바랍니다. 제 블로그를 확인해 보니 아래 결과가 나오더군요.
200 OK
X-Powered-By: PHP/4.4.2AnNyung
Server: Apache -OOPS Development Organization-
Connection: close
Date: Thu, 24 May 2007 11:56:37 GMT
P3p: CP='CAO PSA CONi OTR OUR DEM ONL'
Content-Type: text/html; charset=utf-8
마지막 줄에 있는 Content-Type: text/html; charset=utf-8은 제가 이용하고 있는 비누넷 호스팅 서버의 기본 설정입니다. XHTML 문서의 메타 태그로는 바꿀 수 없다는 것에 주의하세요.
XHTML과 HTML은 현재 가장 널리 사용되는 웹 문서 규격입니다. 이름에서도 알 수 있듯이 XHTML은 기존에 사용되던 HTML 규격이 가진 문제점을 극복하고, 보다 다양한 분야에 응용될 수 있도록 해주는 여러가지 확장된 기능을 포함하고 있습니다.
HTML을 XML 바탕으로 새롭게 구성(reformulation)한 XHTML은 CSS와 함께 최근에 많은 관심을 받고 있는 ‘웹 표준’의 중요한 요소가 되었습니다. 하지만 XHTML이 XML을 기반으로 만들어졌고, 이 XML을 모든 브라우저가 지원하지 않는다는 현실적인 문제 때문에 XHTML과 HTML이 사실상 큰 차이 없이 사용된다고 주장하는 사람들도 많습니다.
이런 시각을 다루는 좋은 글이 있어서 번역해서 소개합니다. 내용이 많아서 세 번으로 나눠서 포스팅하려고 하는데 글의 전문성에 비해 제 이해가 많이 부족하고, 원문을 요약한 것이어서 그 내용을 완벽하게 전달하는데 한계가 있으니 감안해서 보시기 바랍니다.
첫 번째로 언급한 문법적인 차이를 다루는 문서는 많기 때문에 자세한 설명을 하지 않겠습니다.
XHTML을 사용하면 할 수 있으나, HTML로는 불가능한 일
CDATA 섹션(<![CDATA[ … ]]>) 사용.
이 섹션 안의 문자들은 태그로 처리되지 않기 때문에 따로 이스케이프(escape) 해 줄 필요가 없다.
processing-instruction 사용. 예를 들어 XML 문서에 스타일시트를 연결시킬 수 있다. <?xml-stylesheet type="text/css" href="style.css" media="screen"?>
다른 XML 이름 영역(namespace)에 있는 요소(element)들을 포함시킬 수 있다.
' 캐릭터 엔티티(character entity)를 사용할 수 있다.
HTML을 사용하면 할 수 있으나, XHTML로는 불가능한 일
기존 HTML에서 사용하던 <!-- … --> 코멘트로 스타일이나 스크립트의 일부를 주석 처리할 수 없다.
문서를 읽고 있는 도중에는 페이지의 일부를 동적으로 생성할 수 없다(예: document.write() 사용).
같은 named entity를 사용할 수 없다. 미리 정의된 <, >, &, "는 사용 가능.
자바 스크립트에서 .innerHTML 속성을 사용할 수 없다.
† 위 두 문단 중 첫 번째 문단은 XHTML로 할 수 있는 일을, 두 번째 문단은 XHTML로 불가능한 일을 열거하고 있습니다(2009.10.27).
CSS를 이해하는 방식의 차이
CSS의 Element type 선택자가 대문자와 소문자를 구별한다(case-sensitive).
HTML에서는 BODY 요소의 background-color, background-image, overflow 속성이 최상위 요소(HTML)에도 적용되지만 XHTML에서는 적용되지 않는다.
HTML의 일부 시작 태그는 명시적으로 지정하지 않아도 CSS가 적용된다. 예를 들어서 표(table) body 태그의 헤더 셀(header cell)에 스타일을 적용하려고 할 때 다음과 같이 CSS 규칙을 지정할 수 있다.
tbody th { text-align: left }
HTML 문서에서는 <tbody>와 </tbody> 태그를 마크업하지 않아도 이 CSS 스타일이 적용되지만 XHTML에서는 태그를 마크업하지 않으면 적용되지 않는다.
클라이언트 쪽의 스크립트(예: 자바 스크립트)를 다루는 방식의 차이
document.write() 메소드가 적용되지 않는다.
createElement() 같은 DOM 메소드는 반드시 이름 영역(namespace)에 대응되는 메소드로 바꿔줘야 한다(예: createElementNS() 사용).
표준이 아닌 .innerHTML 속성을 사용할 수 없다.
CSS에서와 마찬가지로 명시적이지 않은 요소(element)에 관한 문제가 자바 스크립트에도 적용된다.
XHTML이 HTML보다 더 엄격한가(strict)?
그렇지 않다. XHTML을 포함하는 XML의 문법 규칙이 HTML에 비해 더 단순하고, 일관적이지만 마크업이 유효(valid)하다면 XHTML과 HTML은 동일하게 해석(parsed)된다.
† 이 질문에서 말하는 엄격함은 문법 규칙만을 고려한 것으로 보입니다. 단순히 문법적인 면을 따져봤을 때에는 XHTML이 HTML보다 엄격한 것이 분명합니다. 하지만 원문에서 그렇지 않다고 말한 것은 브라우저가 XHTML을 HTML과 동일하게 해석하기 때문이라고 생각되네요.
그는 문단 태그(<p>)를 예로 들었는데 HTML에서는 문단을 </p> 태그로 닫지 않아도 어느 곳에서 그 태그가 닫혀야 하는지 명백하게 판단이 가능합니다. XHTML에서 </p> 태그를 생략하면 검증기(validator)는 에러를 찾아내지만 실제로 브라우저는 아무런 문제 없이 HTML과 동일한 결과를 출력하지요. 왜냐하면 거의 대부분의 XHTML 문서가 실제로는 HTML로 브라우저에게 인식되기 때문입니다. 이것은 브라우저의 XML 지원과 Content-Type에 관련된 문제인데 이 부분에 대해서는 추후에 다루겠습니다.
또한, ‘strict’라는 단어에는 ‘엄밀(정밀)하다’는 뜻도 있습니다. 이런 의미로 해석할 경우에는 HTML이 XHTML보다 정밀하다는 표현이 맞습니다. HTML을 해석하려면 생략된 태그를 판단하는 추가적인 로직이 필요하니까요. 원문에는 HTML의 문법 규칙이 XHTML보다 복잡(more complicated)하다고 표현하고 있습니다. 이 부분에 관한 자세한 내용은 원문에 달린 댓글을 참고하시기 바랍니다.
XHTML이 HTML보다 더 의미 있는 마크업인가(semantic)?
그렇지 않다. XHTML 1.0 규격은 HTML 4.01 규격을 새롭게 구성한 것이므로 두 규격은 똑같은 요소(element)와 속성(attribute)을 가지며 세 가지 문서 타입(DTD)도 동일하다. 의미론적으로는 두 규격에 아무 차이도 없다.
† 이 글을 쓰게 된 동기 중의 하나가 이 문제 때문입니다. 많은 사람들이 XHTML이 HTML보다 더 ‘의미 있는’ 규격이라고 생각하는데 실제로는 차이가 없습니다. 오히려 XHTML Transitional 규격과 HTML Strict 규격을 비교해보면 HTML Strict 규격이 ‘구조’와 ‘표현’을 훨씬 엄격하게 구분하므로 보다 의미 있는 규격입니다. 따라서 HTML Strict DTD로 작성된 문서가 XHTML Transitional 문서보다 ‘웹 표준’을 보다 잘 준수한다고 말할 수 있습니다.
CSS는 XHTML과 HTML에 모두 다 적용되는가?
그렇다. CSS를 XHTML에서만 사용할 수 있다고 생각하는 사람들이 있는데 이것은 분명히 잘못된 정보이다. 최초의 CSS 규격은 1996년에 만들어졌고, XHTML은 그 후 사 년 후에야 만들어졌다.
DOCTYPE 선언은 어떻게 사용되는가?
문서 맨 앞에 선언되는 DOCTYPE이 브라우저 같은 클라이언트 프로그램(user agent)에게 해당 문서가 XHTML이라는 것을 알려주는 역할을 한다고 생각하는 사람들이 있지만 이것 역시 사실이 아니다. DOCTYPE 선언이 만들어진 원래의 유일한 목적은 마크업을 검증하기 위한 것이며, 브라우저는 마크업을 검증할 필요가 없으므로 이 선언을 무시하고 마크업을 해석한 다음 화면에 출력했다.
하지만 매킨토시 버전의 인터넷 익스플로러 5.0(IE5/Mac)이 발표되면서 처음으로 DOCTYPE 선언을 브라우저가 이용하게 되었는데, IE5/Mac 브라우저는 구 버전이나 형제 격인 윈도우즈 버전의 브라우저보다 웹 표준을 지원하는 면에서 큰 향상을 가져왔다.
웹 표준을 보다 잘 지키면서 정확하지 않은 IE의 CSS 렌더링에 맞춰서 개발된 많은 웹 문서들에 대한 호환성을 유지하기 위해서 DOCTYPE이 사용되기 시작했다. 이 기능은 이후 인터넷 익스플로러 6.0 버전에 도입되었고, 최근에 사용되는 대부분의 브라우저에는 이 기능이 포함되어 있다.
현재 DOCTYPE 선언은 두 가지 기능을 한다. 첫 번째는 검증기(validator)가 어떤 기준으로 마크업의 유효성을 확인해야 하는지에 관한 정보를 제공하는 것이고, 두 번째는 브라우저에게 어떤 렌더링 모드를 사용할지 알려주는 기능이다. 이것은 XHTML과 HTML의 차이와는 근본적으로 아무 관련이 없다. 하지만 XHTML을 올바르게 지원하는 브라우저는 XHTML을 엄격한 표준(strict standard) 모드로 렌더링하는데 그러기 위해서는 XHTML을 올바르게 브라우저에게 인식시켜야 한다.
XHTML과 HTML의 차이에 관해서는 이것으로 마치겠습니다. 원문의 정보가 100% 옳다고 확신할 수는 없지만 100개 이상 달린 댓글을 보면 어느 정도 검증된 문서라고 판단할 수 있으리라 생각합니다.
다음 글에서는 브라우저가 왜 대부분의 XHTML 문서를 HTML과 동일하게 받아들이지는 알아보도록 하지요. 앞서 언급했던 브라우저의 XML 지원과 Content-Type에 관한 문제입니다.
올블로그에 포스팅된 SKT 모바일 웹과 웹표준이라는 글을 보고 호기심에 핸드폰을 열고 블로그에 접속해 봤습니다. 별 기대를 안했는데 의외로 제 핸드폰에 탑재된 KUN(KTF Unified Navigator) 브라우저가 블로그 글을 잘 보여주더군요. 물론 이미지가 제대로 표시되지 않는 문제가 있지만 글 검색도 가능하고 댓글도 달 수 있었습니다. 데이터 통신 요금이 생각보다 훨씬 비싸서 다양하게 시험해보진 않았지만 잠깐 동안의 사용으로도 웹 문서의 접근성이 왜 중요한지를 체험할 수 있었습니다.
제가 느꼈던 모바일 기기를 통한 웹 서핑의 가장 큰 불편함은 마우스를 사용할 수 없다는 점이었습니다. 원하는 링크로 이동하기 위해서는 중간에 있는 모든 링크를 순차적으로 거쳐가야 했으니까요. 이런 불편함을 느끼다가 텍스트패턴 기본 테마에 있는 네비게이션 메뉴가 왜 포함된 것인지 깨달았습니다. 먼저 어떤 메뉴인지 소개하는게 좋겠네요.
제 블로그에 맞게 약간 수정한 마크업인데 페이지의 중요한 부분으로 바로 접근할 수 있는 간단한 링크로 구성되어 있고, html 문서의 body 태그 바로 아래에 들어갑니다. 다시 말해서 문서의 맨 앞에 나오는 부분이지요. 택스트패턴 기본 테마에 있는 이 마크업을 봤을때 꼭 필요한 부분이 아니라고 생각해서 지금까지 적용하지 않았었습니다. 그럼 이 div 태그의 스타일이 어떻게 지정되었는지 볼까요?
#accessibility { display: none; }
† display 속성 대신 position: absolute; top: -10000px; 처럼 절대 위치를 사용할 수도 있습니다.
CSS 표준 규격에 따르면 display: none; 속성은 화면 뿐 아니라 스크린 리더에도 적용됩니다. 따라서 절대 위치(absolute positioning)을 이용하는 것이 옳은 방법입니다(2007년 8월 7일 추가).
이 메뉴는 CSS에 정의된 스타일에 의해서 일반적인 브라우저 환경에서는 보이지 않습니다. 하지만 문서에서 CSS가 제거되었을 경우에는 메뉴 리스트로서 화면에 보여지게 되지요. 예를 들기 위해서 오페라 브라우저의 ‘작은 화면 보기’ 메뉴로 이 페이지를 열었을 때 어떻게 보이는지를 스크린샷으로 첨부했습니다.
핸드폰에 탑재된 브라우저가 CSS를 적용하지 않고 문서를 보여주기 때문에 실제 핸드폰으로 보는 화면과 이 이미지가 거의 비슷합니다. 이렇게 문서 맨 앞에 네비게이션 메뉴가 있으면 사이드바나 댓글로 이동하는게 훨씬 쉬워지겠지요. 그런데… 테스트를 해보니 KTF의 모바일 브라우저가 문서 내에 포함된 책갈피(anchor)로의 바로가기를 지원하지 않더군요. 제대로 보이기는 하는데 링크를 눌러도 아무 반응이 없습니다^^;
그렇다고 해서 무의미한 마크업은 아닙니다. 스크린 리더를 이용할 경우에도 동일하게 적용될테니까요. 중간에 있는 여러 링크들을 거치지 않고 페이지의 다른 곳으로 바로 이동할 수 있는 수단을 제공하는 것은 접근성 향상에 큰 도움이 된다고 생각합니다. 게다가 간단하고 적용하기도 쉬운 방법이지요.
이런 방법 외에 html의 바로가기 키(accesskey) 속성을 사용해서 접근성을 향상시키는 방법도 있습니다. 하지만 모바일 기기에서는 알파벳 키를 적용하는데 어려움이 있고 브라우저가 자체적으로 지원하는 바로가기 키와 충돌할 가능성도 배제할 수 없습니다. 또한 인터넷 익스플로러와 파이어폭스, 오페라 브라우저에서 accesskey를 이용하는 방법이 제각각이라는 점도 이 속성을 사용하는데 방해물이 됩니다. 물론 접근성 향상을 위해서 만들어진 속성인 만큼 잘 적용하면 좋은 효과를 얻을 수 있다고 하네요. 이런 방법에 대해서는 이 페이지를 참고하시기 바랍니다.
마지막으로 주제와 직접적인 관련은 없지만 KTF 모바일 브라우저의 문제점을 하나 지적하고 마치겠습니다. 많이 사용되는 접근성을 높이기 위한 방법 중의 하나가 html label 태그를 사용하지 않는 텍스트 입력 폼에 alt 속성을 사용해서 대체 문자열을 지정하는 것입니다. 그런데 KTF 모바일 브라우저는 대체 문자열이 있으면 해당 요소 대신에 무조건 대체 문자열만을 보여주더군요. 그래서 왼쪽 상단의 검색 폼에 alt 속성을 지정할 경우에는 검색 기능을 아예 사용할 수 없었습니다. 그러니 혹시라도 핸드폰으로 접근한 자신의 블로그에서 어떤 폼을 사용할 수 없다면 alt 속성이 지정되었는지 확인해 보시기 바랍니다.
지난 글에서 <fieldset> 태그가 본래 의미와는 상관 없이 오용되고 있다고 지적하면서 정작 중요한 대체 방법에 대해서는 설명이 너무 부족했네요. 그래서 <fieldset> 태그를 사용하지 않고도 같은 시각 효과를 얻는 방법을 찾다가 The Scripts 사이트에서 해결 방법을 찾았습니다. 아래의 예는 이 사이트에 제시된 CSS 코드를 약간 수정해서 만든 그룹 박스랍니다.
그룹 박스1
그룹 박스를 만드는 기본 예제입니다.
인터넷 익스플로러 6.0 이상, 불여우 2.0, 오페라 9.2에서 테스트 해봤습니다.
어떤가요? 그럼 먼저 이 박스가 어떤 html 태그로 만들어졌는지 확인해 보겠습니다.
<div class="groupbox">
<h4><span>그룹 박스1</span></h4>
<p>그룹 박스를 만드는 기본 예제입니다.<br />
인터넷 익스플로러 6.0 이상, 불여우 2.0, 오페라 9.2에서 테스트 해봤습니다.</p>
</div>
소스는 간단히지요? 박스의 중요도에 따라서 적당한 헤드라인 태그(h1~h6)를 사용하면 됩니다. 이 태그에 대한 CSS는 다음과 같습니다.
div.groupbox {
width: 500px; /* 박스 너비, 지정하지 않으면 최대치 사용 */
height: auto;
margin: 2em 0 1em 0; /* 박스 주위 여백 */
border: 1px solid #999; /* 박스 테두리 색 */
padding: 0 8px; /* 박스 여백(padding) */
}
div.groupbox h4 {
line-height: 100%; /* 위쪽 테두리 선과 내용물 사이의 간격 */
padding-left: 8px; /* 왼쪽 테두리 선과 라벨 사이의 간격 */
font-size: 1em; /* h4 태그의 텍스트 크기 지정 */
font-weight: normal; /* h4 태그의 텍스트 두께 지정 */
}
div.groupbox h4 span {
background-color: #fff; /* 배경색과 동일해야 함 */
color: #333; /* 라벨 텍스트 색 */
padding: 0 4px; /* 라벨과 좌우 선 사이의 간격 */
position: relative;
top: -1.1em; /* 라벨의 상하 위치 조절 */
}
div.groupbox p {
margin-bottom: 1em;
line-height: 170%;
}
† 이 CSS 코드를 그대로 적용할 경우에는 일부 브라우저에서 문제가 생길 수 있으니 주석을 제거하고 사용하시기 바랍니다.
폰트 크기와 박스 여백을 em 단위로 설정한 이유는 인터넷 익스플로러 6.0 버전 사용자가 전체 글자 크기를 조절할 수 있도록 하기 위해서입니다. 폰트 크기를 상대 단위(em, %)가 아닌 절대 단위(px)로 설정하신 분들은 자신이 사용하는 단위에 맞는 수치로 바꿔주셔야 합니다.
또한 박스(groupbox div) 내부의 상하 여백(padding)이 0으로 지정되어 있는 점도 주의하세요. 박스 내부의 위쪽 여백은 h4 태그의 line-height 속성에 따라 결정되고 아래 여백은 박스 안에 들어가는 p 태그의 margin-bottom 속성을 이용하도록 했는데, 자신의 스타일에 맞게 수정하셔야 합니다.
이 박스를 표시하는데 가장 중요한 속성이 h4 span 태그에 적용되는 top 속성입니다. 위에서는 -1.1em을 사용했는데 사용자의 글꼴과 줄 간격 등에 따라서 달라질 수 있으니 자신에게 맞는 값을 찾아야 박스의 라벨이 올바르게 출력됩니다. 수치가 작아질수록(음수라는데 유의) 라벨 위치가 위로 올라갑니다.
사실 CSS의 어려운 점의 하나가 같은 코드라도 사용자에 따라서 다르게 적용될 수 있다는 점인데 그 이유는 CSS라는 이름 그대로 상위 레벨의 스타일이 단계적으로 하위 레벨까지 적용되기 때문입니다. 다시 말해서 CSS의 html이나 body에 적용한 스타일이 이런 박스에까지 영향을 미친다는 얘기지요. 예를 들어서 위 CSS 코드에 정의된 h4 태그의 글자 크기 1em은 제가 CSS body에 정의한 글자 크기에 따라 달라진답니다. 그러니 일부분의 CSS 코드를 문서에 적용할 때에는 충분히 테스트 해보고 수치를 조절하는 과정이 필요합니다.
‘웹 표준’을 다루는 글이 많아지면서 이에 대한 블로거들의 관심도 높아지고 있습니다. 그런데 대부분의 글들이 웹 표준을 지켜야 하는 이유와 그럼으로써 얻어지는 이점에만 초점을 맞추더군요.
사실 ‘접근성’이나 ‘크로스 브라우징’, ‘문서의 구조화’ 같은 표현은 대부분의 사용자들에게 쉽게 와 닿지 않을 겁니다. 그보다는 현실적인 예와 방법들을 제시하는게 웹 표준에 대한 이해를 이끌어내는데 도움이 되지 않을까 생각합니다. 어떻게 해야 웹 표준을 지키고 ‘의미 있는’ 마크업을 할 수 있는지에 관해 한글로 작성된 정보가 극히 적은 상황이니까요.
그래서 이번 글에서는 많은 html 문서에서 본래의 의미와는 상관없이 사용되는 태그 베스트 3를 뽑아볼까 합니다^^; 보다 나은 방법에 대한 얘기들도 다루고요.
<br /> 태그
대망의(?) 1위는 그 흔한 <br /> 태그입니다. 만들어진 용도는 문서에 빈 줄을 넣기 위해서이죠. 하지만 이 빈 줄은 문서의 한 단락 내에서 사용되어야 합니다. 다시 말하자면 문서의 흐름이나 내용의 전환 등을 구분하기 위해 사용되는 태그가 아니라는 얘기입니다.
우리가 흔히 보는 책들을 보면 한 페이지 내에서 단락 구분이 명확하게 나뉘어져 있습니다. 위에서 말한 내용의 전환 등을 표현하기 위해서이죠. 웹 문서도 마찬가지입니다. 단락을 구분하려면 <br /> 태그가 아니라 <p> 태그를 사용하는 것이 의미에 맞습니다.
그러면 <p> 태그로 단락을 구분하면 어떤 이점이 있을까요? 첫 번째는 문서의 흐름이 명확해진다는 것입니다. 물론 사용자의 눈에는 안보이지만 스크린 리더는 각 단락 사이를 끊어서 내용을 읽어줄 수 있을겁니다. 두 번째는 CSS를 이용해서 여러 가지 스타일을 줄 수 있다는 점입니다. 예를 들기 위해서 이후의 모든 단락을 들여쓰기 해보겠습니다. 간단히 아래와 같은 규칙을 지정해주면 되거든요.
p { text-indent: 0.6em; }
제 글은 모든 문단을 빈 줄로 구분하기 때문에 특별히 들여쓰기를 지정하지 않았지만 오프라인 인쇄물의 경우 대부분이 들여쓰기를 하고 있습니다. 눈에 잘 들어오고 정보 전달에도 유리하기 때문이지요.
사실 이 태그의 문제는 블로깅 툴의 지원과 밀접한 관계가 있습니다. 태터툴즈로 글을 작성하면 엔터 키를 사용할 때마다 <br /> 태그를 집어넣으니까요. 개인적으로는 태터툴즈의 이런 방식이 ‘의미 있는’ 마크업에 걸림돌이 된다고 생각합니다. 많이 사용되는 워드프레스나 (적게 사용되는^^;) 텍스트패턴 같은 블로깅 툴에서는 <br /> 태그 대신 <p> 태그를 넣어서 단락을 구분하는데, 그러면 CSS로 단락 사이의 간격을 조절할 수 있답니다. 이 글의 단락에 적용되는 CSS 규칙은 아래와 같습니다.
p { margin-bottom: 1em; }
<font> 태그
안타깝게도 많이 사용되는 태그입니다^^; 블로그를 돌아다니다 보면 다양한 글자색을 사용해서 내용이 눈에 확 들어오는 글들을 볼 수 있습니다. 보기에 좋아서 어떻게 작성했는지 소스를 봤더니 아래 예처럼 작성되었더군요.
<font color="#eee">연한 회색 텍스트</font>
소스를 보고 처음 들었던 생각은 이렇습니다.
“헉! 글이 수백 개 쌓이면 어떻게 스킨을 바꾸지? 배경색을 바꾸면 잘 안보이는 글자도 있을텐데…”
일단 말씀드릴 것은 <font> 태그가 HTML 4.01 권고안에서 금지된(deprecated) 태그란 사실입니다. 금지되었다는 표현을 다음과 같은 의미로 해석할 수 있습니다.
“호환성을 위해서 브라우저가 지원하지만 더 나은 방법이 있으므로 사용하지 않는 것이 좋다.”
사용을 금지시킨 근본적인 이유는 문서의 ‘구조’와 ‘표현’을 구분하기 위해서지만 현실적으로는 문서의 관리가 어려워지고 위에 언급한 것과 같은 문제가 생길 수 있기 때문이지요.
안타깝게도 이 태그의 오용 역시 태터툴즈가 안고 있는 문제인데 태터툴즈 기능 제안 포럼에 관련 글이 있으니 참고하시기 바랍니다. 다양한 해결 방법들이 제시되었는데 생각난 김에 저도 한 가지 아이디어를 제안하자면 이렇습니다.
“사용자가 몇 가지 색을 지정해서 사용하도록 하고 이 색에 대한 CSS 정보를 DB에 보관해서 페이지를 출력할 때마다 문서 head에 보관된 규칙을 불러오도록 한다.”
예를 들어서 두 가지의 색을 지정하도록 한다면 각각의 색을 사용할 때마다 아래와 같이 마크업을 작성하도록 하는 것입니다. DB에 usercolor1, usercolor2 class에 관한 CSS 규칙을 저장하면 언제든 전체 글에 적용된 글자 색을 바꿀 수 있으니까요.
본의 아니게 연이어 태터툴즈의 문제점을 지적했네요. 개인적으로 태터툴즈의 편리함이 설치형 블로그가 대중화되는데 큰 역할을 했고, 무엇보다 한글을 우선적으로 고려한 블로깅 툴이라는 점에서 높이 평가합니다. 편의성을 너무 추구한 나머지 문서의 효율적인 마크업에는 미흡한 점이 있지만 앞으로 계속 개선되리라 믿습니다.
<fieldset> 태그
위에서 다뤘던 두 태그만큼 많이 사용되지 않음에도 불구하고 당당히 3위를 차지한 것은^^; 제가 전혀 생각하지 못했던 용도로 사용되기 때문이랍니다. 어느 블로그에선가 글 내용과 관련 있는 다른 글들의 목록을 윈도우즈 프로그램에 사용되는 그룹 박스(정확한 명칭인지는 모르겠지만) 모양의 박스로 표현하는 것을 봤습니다. <div> 태그를 어떻게 사용했을까 하는 생각에 소스를 봤는데 전혀 예상하지 못했던 <fieldset> 태그가 있어서 깜짝 놀랐네요.
“이 태그는 여러 콘트롤(입력 폼 등)과 라벨을 한데 묶어주는 역할을 한다. 그럼으로써 사용자가 콘트롤들의 용도를 쉽게 인식하고, 브라우저나 스크린 리더 등의 프로그램으로 콘트롤 사이를 쉽게 이동할 수 있도록 해준다.”
간단히 말해서 <filedset> 태그는 문서에 들어가는 콘트롤을 위한 태그입니다. 그러면 이 태그를 폼(콘트롤)이 아닌 다른 용도로 사용하면 어떤 문제가 생길까요?
어떤 분들은 이 태그를 문서의 일부분을 강조하는데 사용합니다. 그런데 검색 엔진이 그 문서를 해석한다고 가정해 보면 어떨까요? 검색 엔진이 문서를 해석하는 구체적인 방법은 모르지만, 적어도 이 태그 안의 정보에는 크게 관심을 기울이지 않을 겁니다. 당연히 폼에 관한 정보라고 생각 할 테니까요. 원래 의도는 강조였고, 사용자의 눈에도 그렇게 보이지만 검색 엔진의 입장에서는 반대로 해석할 수도 있다는 얘기지요.
제가 제시하는 대안은 간단합니다. <div> 태그로 비슷한 시각 효과를 낼 수도 있겠지만 그보다는 디자인을 아주 조금만 양보해서 보다 ‘의미 있는’ 마크업을 작성하는 것이지요. 어떤 용도의 박스인지 표시해주는 텍스트가 꼭 테두리 선 위에 있어야 하는건 아니니까요.
마치는 말
<p> 태그 대신 <br /> 태그를 쓴다거나, <fieldset> 태그로 글을 강조하는 분들을 비난하는 글이 아님을 이해해 주시고 바랍니다. 또한 웹 표준이 더 많이 지켜지려면 그 방법을 먼저 익힌 분들이 보다 많은 정보를 오픈해야 한다고 생각합니다. 블로그에서 웹 표준에 관한 논쟁보다 어떻게 하면 웹 표준을 지킬 수 있는지 알려주는 글을 더 많이 볼 수 있기를 바라며 글 마칩니다.
<abbr> 태그와 <acronym> 태그는 W3C(월드와이드 웹 컨소시엄)가 1997년 제안한 HTML 4.0 권고안에 처음 수록된 태그들입니다.
이 두 태그는 영어와 같은 서양 언어에서 흔히 사용되는 축약어를 표현하기 위해 사용되는데 서로 다른 태그인 만큼 각각의 쓰임새가 다름에도 불구하고 브라우저의 지원 문제로 인해서 원래의 용도와는 다르게 사용되는 경우가 많습니다. 그래서 이 두 태그의 차이점과 ‘의미 있는’ 마크업을 위해 생각해봐야 할 점들을 정리해 봤습니다.
사전적 정의
두 태그는 각각 ‘abbreviation’, ‘acronym’ 단어에서 생겨났습니다. 그래서 먼저 위키피디아의 자료를 참고로 이 두 단어와 추가적으로 ‘initialism’의 의미를 정의해 보았습니다.
abbreviation (축약어)
라틴어의 ‘줄임(short)’에서 나온 말로 보통 단어나 구(단어의 집합)에서 하나 이상의 알파벳을 차용해서 만들어진다. 예를 들어 ‘abbreviation’이란 단어는 축약어를 사용해서 ‘abbr.’ 또는 ‘abbrev.’로 표기할 수 있다.
acronym (머리글자를 이용한 축약어)
축약어를 표현하는 방식의 하나로 각 단어에서 뽑은 머리글자를 알파벳 대문자로 표기하며, 각각의 머리글자는 이어서 발음한다. 대표적인 예로 NATO(북대서양 조약 기구)를 들 수 있다.
initialism (머리글자를 이용한 축약어)
머리글자를 이용하는 것은 ‘acronym’과 같지만 발음하는 방식에 차이가 있다. 각각의 머리글자를 개별적으로 발음한다. 예에는 HTML(하이퍼텍스트 마크업 언어), CSS(단계적인 스타일 시트) 등이 있다.
정리하자면 ‘acronym’과 ‘initialism’은 발음하는 방식만 다르며, 두 방식 모두 ‘abbreviation’에 속한다는 얘기지요.
W3C의 정의
그러면 W3C는 왜 <abbr> 태그와 <acronym> 태그를 따로 만들었을까요? 이유를 알아보기 전에 먼저 W3C가 이 두 태그를 어떻게 정의했는지 간단히 요약해 보겠습니다.
“‘abbreviation’과 ‘acronym’ 태그는 축약된 단어의 의미를 명확하게 표현하는데 사용한다. ‘acronym’의 예로는 ‘NATO’, ‘F.B.I.’ 등이 있고 ‘abbreviation’의 예는 ‘Inc’, ‘etc’ 등이 있으며, 이 태그들을 사용함으로써 웹 브라우저 같은 프로그램(user agent)이나 스크린 리더, 맞춤법 검사기, 검색 엔진에 유용한 정보를 제공할 수 있다.”
† ‘acronym’과 ‘abbreviation’ 단어가 뒤바뀐 오류를 수정했습니다. 성민장군님 고맙습니다. ^^
위에서 내렸던 정의와는 차이가 있지요? ‘initialism’을 ‘acronym’에 포함시키고 있는데 검색을 해보면 W3C의 용어 정의에 문제가 있다는 것을 확인할 수 있습니다.
오용되는 이유
많은 사용자들이 축약어를 표현할 때 용도와는 상관 없이 <abbr> 태그 대신 <acronym> 태그를 사용합니다. 그런 데에는 위에서 언급한 용어 정의 문제도 한몫 하지만 보다 큰 이유는 브라우저의 태그 지원 문제라고 주장하는 사람들이 많습니다. 즉, 점유율이 가장 높은 인터넷 익스플로러(6.0 이하 버전) 브라우저가 <abbr> 태그의 title 속성을 제대로 안보여주기 때문이라는 것이지요. 예를 들어보겠습니다.
마우스를 올려보세요.
IE 6.0 이하 버전을 사용하는 분들은 마우스를 올려도 아무 반응이 없을겁니다. 하지만 그 외의 브라우저들은 title 속성에 지정된 텍스트를 화면에 보여주지요. 그래서 이런 시각 효과를 제공하기 위해 <acronym> 태그가 용도 구분 없이 광범위하게 사용된 것이지요.
의미 있게 사용하면?
<abbr> 태그와 <acronym> 태그를 의미 있게 사용하면 스크린 리더나 검색 엔진에 유용한 정보를 제공할 수 있습니다. 예를 들어볼까요?
검색 엔진은 <abbr> 태그의 title 속성을 인식해서 검색 결과에 반영할 수 있습니다. ‘markup language’를 검색했는데 ‘html’ 관련 페이지가 검색되는 것처럼요.
또한 스크린 리더가 <abbr> 태그와 <acronym> 태그를 각각 다르게 발음하도록 할 수 있는데 비슷한 태그를 따로 구분해서 만든 것도 이런 이유 때문이 아닐까 생각합니다. 즉, ‘NATO’ 같은 ‘acronym’은 그대로 이어서 발음하고 ‘HTML’ 같은 ‘abbreviation’은 알파벳 단위로 발음하도록 지정해주는 것이지요. CSS에는 이런 기능을 다루는 속성이 따로 있습니다.
또한 머리글자를 이용하지 않는 info.(information), exam.(examination) 등의 축약어에 대해서는 어떤 태그 처리도 필요없다는 의견도 있고, class를 사용해서 구별하자는 의견도 있습니다.
요약하자면 전자의 경우는 머리글자를 이용하지 않는 대부분의 축약어가 하나의 의미로 사용되고 대부분의 사람들이 쉽게 이해할 수 있기 때문이라는 주장이고, 후자의 경우에는 머리글자를 사용하는 축약어와 그렇지 않은 축약어를 명확하게 구분해서 CSS를 이용해서 스크린 리더가 축약어를 읽는 방식을 지정해주자는 의견입니다. 아래 처럼 말이지요.
W3C의 모호한 태그 정의와 브라우저의 지원 문제로 <acronym> 태그가 오용되면서 이를 지적하는 사용자도 많아졌습니다. 이를 반영해서인지 현재 초안을 작성중인 XHTML 2.0 권고안에서는 <acronym> 태그를 삭제하고 <abbr> 태그로 이를 대체하도록 했습니다. 사실 비슷한 용도로 사용되는 두 태그가 있을 경우에 보다 상위 개념의 태그 하나로 통합시키고 각각을 담당하는 class 등을 부여하는 것이 이치에도 맞고 혼란도 줄일 수 있지요. W3C는 또한 웹 접근성 2.0 권고안을 통해서 <abbr> 태그의 사용 방법을 보다 명확하게 밝히고 있습니다.
“사전(dictionary)에 등재되지 않은 축약어를 처음 사용할 때에는 <abbr> 태그로 축약되지 않은 전체 텍스트를 명확하게 표현하라.”
스크린 리더에 대해서 잘은 모르지만 그렇게 간단한 프로그램은 아닐겁니다. 잘 알려진, 그리고 하나의 뜻을 가진 축약어는 자체적으로 충분히 해석할 수 있겠지요. Acrobot 사이트는 축약어 태그 작성을 도와주는 도구를 제공하는데 축약어의 머리글자만 입력하면 사전을 검색해서 자동으로 <abbr> 태그의 title 속성을 첨가해 준답니다. 스크린 리더도 이런 기능을 포함할 수 있겠지요.
실질적인 사용법
하지만 XHTML 2.0 표준이 지금 사용되는 XHTML 1.0을 완전히 대체하려면 최소한 수 년이 걸릴겁니다. 물론 그 안에 태그 정의가 바뀔 수도 있지요. 따라서 현실적으로는 <abbr> 태그와 <acronym> 태그를 보다 ‘의미 있게’ 사용하는 것이 중요합니다. 그러기 위해서는 구 버전의 익스플로러(6.0 이하)가 <abbr> 태그의 title 속성을 보여주지 않는다는 사실을 고려해야 합니다. 그러면 이 문제를 해결할 방법을 알아볼까요?
첫 번째 방법은 지극히 간단합니다. 신경쓰지 않는 것이지요^^; 이 태그들이 사용자가 아닌 프로그램(user agent)을 위한 것이므로 화면에 표시되지 않는 것이 오히려 낫다고 주장하는 사용자도 있습니다. 그에 따르면 사용자에게 축약어에 관한 자세한 정보를 제공하는 최고의 방법은 다음과 같이 일반적인 텍스트를 이용하는 것이 것이라고 하네요.
올바른 XHTML(Extensible HyperText Markup Language)을 사용합시다!
올바른 Extensible HyperText Markup Language(XHTML)을 사용합시다!
두 번째 방법은 <acronym> 태그와 class를 이용하는 것입니다. ‘의미 있는’ 마크업은 아니지만 class를 사용해서 스크린 리더에게 어떻게 발음해야 할 지 알려줄 수 있지요.
이외에도 각주를 사용하거나 해당 용어에 대한 설명이 있는 사이트를 직접 링크시키는 방법도 있습니다. 유명한 사이트인 A List Apart에 다양한 방법들이 소개되어 있으니 참고하시기 바랍니다.
Textile과 <abbr> 태그
Textile은 익스플로러 호환성을 고려해서 모든 축약어를 <acronym> 태그로 표현합니다. 따라서 <abbr> 태그를 사용하려면 직접 html을 사용해서 작성해줘야 합니다. 하지만 Textile 소스를 수정하면 몇 가지 변화를 줄 수 있지요. 물론 Textile이 업데이트 될 때마다 수정해줘야 하는 번거로움과 검증되지 않은 코드 수정으로 발생할 수 있는 호환성 문제는 사용자가 감수해야 합니다^^;
Textile 라이브러리인 ‘classTextile.php’ 파일은 거의 대부분이 정규 표현식으로 이루어져 있습니다. 그 중에서 <acronym> 변환을 담당하는 코드는 2258 버전 기준으로 1,008번째와 1,028번째 줄에 있습니다.
이 부분을 아래 코드를 참고해서 수정하면 기존의 <acronym> 태그 대신 <abbr> 태그와 <span> 태그를 사용하는 방식으로 바꿀 수 있습니다. 대문자와 소문자 구별 없이 두 글자 이상의 축약어에 적용되며, 축약어를 의미하는 마침표도 사용할 수 있습니다.
'/\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/', // 원본 소스
'<acronym title="$2">$1</acronym>',
'/\b([A-Za-z][A-Za-z0-9]{1,}\b[\.]?)(?:[(]([^)]*)[)])/', // 수정된 소스
'<span title="$2"><abbr title="$2">$1</abbr></span>',
어떻게 적용되는지 확인해볼까요? 위 박스는 Textile 입력을, 아래 박스는 브라우저 출력을 나타냅니다.
<abbr> 태그를 적용하기 위해 새로운 Textile 규칙도 만들 수도 있겠지만 Textile의 장점이 간단하고 쉬운 태그에 있는 만큼 기존의 태그를 최대한 이용하는 것이 옳다고 생각합니다. 물론 <abbr> 태그가 <acronym> 태그를 포함하는 개념이므로 의미 상으로도 큰 문제가 없지요.
† 정규 표현식을 잘 몰라서 그랬다고는 절대 얘기하지 않습니다^^;
결론
많이 사용되지도 않고, 우리말과 직접적으로 관계 없는 태그들을 이렇게 장황하게 설명하는 것은 단순히 흥미로왔기 때문입니다. W3C의 애매한 정의도 그렇고, 이와 관련해서 많은 사용자들이 다양한 의견과 해결 방법을 내놓은 점도 그렇습니다. 일례로 Tetile 포럼에서 가장 많은 댓글이 달린 글이 이 두 태그에 관한 글이더군요.
개인적으로 ‘의미 있는’ 마크업을 중요하게 생각하지만 특별히 영어 사용자를 위한 글이 아니라면 이 태그들을 너무 엄격하게 구분해서 사용할 필요는 없다고 생각합니다. 간단하게 <abbr> 태그만 사용해도 충분하지 않을까요? 때로는 어떤 축약어가 ‘acronym’과 ‘initialism’ 중에 어디에 속하는지 구분하기 힘든 경우도 있습니다. 두 방식을 섞어 쓰는 축약어도 있고요. 그런 경우에는 이렇게 하라는 지침을 어느 사이트에선가 봤습니다.
“잘 모르겠으면 <abbr> 태그를 사용하라!”
또한 단순히 어떤 생소한 용어를 설명하기 위해서라면 위에 언급했던 일반적인 텍스트를 이용하는 것이 최고의 방법입니다. 마우스를 사용하지 않아도 설명을 볼 수 있으니까요.
이 주제에 관한 의견이나 주장이 상당히 다양합니다. 이것 저것 요약해서 소개하려다 보니 잘못 인용하거나 해석한 부분도 많을 겁니다. 이 점 감안하시길 바라고 의문가는 점은 언제든지 댓글로 남겨주세요.
‘웹 표준을 지킨다는 것’의 의미와 그럼으로써 얻을 수 있는 이점에 관해 적어볼까 합니다.
웹 표준을 지키려면 먼저 그 의미를 알아야겠지요? 웹 표준에 관한 글을 읽다 보면 다음과 같은 생각을 하는 분들을 볼 수 있습니다.
“테이블 대신 div 태그와 CSS로 레이아웃을 만들고, XHTML 검증(Validation)을 통과하면 웹 표준을 지키는 것이다.”
틀린 얘기는 아닙니다. 하지만 웹 표준을 준수하려면 더 많은 것을 고려해야 합니다. 단순히 기술적인 면에 국한된 문제가 아니지요.
‘웹 표준’을 이해하기 위해서는 웹 표준을 제정하는 ‘월드 와이드 웹 컨소시엄(World Wide Web Consortium: 이하 W3C)’이 지향하는 바가 무엇인지를 알아야 합니다. W3C는 그들의 존재 이유를 다음과 같이 밝히고 있지요.
“웹(월드 와이드 웹)이 최대한의 능력을 발휘할 수 있도록 지침(Guideline)을 만을어서 웹의 장기적인 발전을 도모한다.”
즉, W3C의 목표는 웹의 지속적인 발전입니다. 그러기 위해서 아래와 같은 몇 가지 세부 목표를 세워서 추진하고 있지요.
모든 사람들을 위한 웹: 사람들이 생각과 정보를 나누고 경제 활동을 하는데 있어서 웹은 큰 비중을 갖습니다. 이런 이익을 하드웨어나 네트워크 인프라, 언어, 문화, 지역적인 차이, 육체적 또는 정신적 차이와 상관없이 모든 사람들이 누릴 수 있도록 하자는 것이지요.
모든 장치를 위한 웹: 컴퓨터나 핸드폰, 스마트폰 등의 어떤 장치로도 웹을 이용할 수 있도록 지원하고 있습니다.
정보의 기반: 웹의 힘은 단순히 나열된 정보에 기반하지 않습니다. 잘 구조화된 정보를 통해서 웹은 최대한의 힘을 발휘할 수 있지요. 이를 위해서 사람과 처리 장치 모두를 위한 정보를 담을 수 있는 표준을 만들고 있습니다.
믿을 수 있고 확실한 웹: 더 많은 사람들이 안전하게 참여할 수 있도록 신뢰성 향상을 위해 노력하고 있습니다.
이런 목표 달성을 돕기 위해서 XHTML, CSS, XML 등의 표준을 만들어내는 것이지요. 하지만 XHTML과 CSS 표준을 지켰다고 해서 위에 열거한 목표가 자동적으로 충족되는 것은 아닙니다.
많은 분들이 웹 표준을 지킴으로써 얻는 이점을 접근성 향상이라고 생각하시는데 물론 맞는 말씀입니다. 그 목적을 위해서 만들어진 표준이니까요. 하지만 XHTML과 CSS를 문법에 맞게 사용했다고 해서 접근성이 높고, 테이블을 썼다고 해서 접근성이 떨어지는 것은 아닙니다. 예를 들어볼까요?
지금 보시는 페이지는 엄격한(Strict) XHTML 1.0 규격을 준수합니다. 왼쪽 하단의 ‘valid XHTML’ 링크를 클릭하면 검증 결과를 보실 수 있지요. 하지만 이 페이지가 접근성이 높은 것은 아닙니다. W3C는 접근성에 관한 권고안도 제안했는데 사실상 접근성에 관한 표준이라 할 수 있습니다. 이 권고안이 제안하는 첫 번째 지침은 이렇습니다.
“눈으로 보거나 들을 수 있는 모든 정보의 대체 표현 수단을 제공하라!”
즉 보거나 들을 수 없는 사람들도 이용할 수 있도록 해야 한다는 것이지요. ‘스크린 리더’를 이용하면 되지 않느냐고 생각하실 분들도 계실겁니다. 물론 스크린 리더가 텍스트를 읽어줄 수 있습니다. 하지만 스크린 리더에게 충분한 정보를 제공하는건 아닙니다^^;
하나씩 생각해보지요. 먼저 이 블로그의 모든 링크에는 title 속성이 지정되지 않았습니다. 글에 삽입된 이미지에는 대체 문자열(alt 속성)을 입력하지 않았고, 키보드 접근키(Access Key)도 설정하지 않았습니다. 이밖에도 많은 요소들이 이 페이지의 접근성을 떨어뜨리고 있습니다.
반면에 테이블로 레이아웃을 작성했지만 위에 언급한 모든 요소들을 충실히 지켰다면 어떨까요?
‘테이블 레이아웃’이 무조건 복잡하고 중첩된 테이블 구조를 의미하지는 않습니다. 접근성을 최대한으로 고려한 테이블 레이아웃도 있으니까요. 이런 테크닉에 관심 있으신 분들은 Web Access Centre의 Layout tables 문서를 참고하시기 바랍니다.
사실 접근성에 대해서 자신있게 말하기는 어렵습니다. 그 문제에 대해서 직접 체험하지 못하기 때문이지요. 저만해도 이 글을 모든 분들이 ‘읽을’ 것이라고 생각하지 ‘들을’거라고 생각하지 않으니까요.
제가 생각하는 웹 표준 준수는 XHTML과 CSS 문법을 올바르게 사용하고, 더 나아가 열린 마음으로 접근성 향상을 위해 관심과 노력을 기울이는 것을 의미합니다. 그래야만 웹 표준을 지키는것이 접근성을 향상시킨다고 자신있게 말할 수 있으니까요.
웹 표준을 준수해서 누구나 평등하게 이용할 수 있을거라고 말하는 블로거들의 글 대부분은 접근성 향상을 위한 정보를 제대로 제공하지 않습니다.
어떤 분들은 XHTML과 CSS를 사용하면 ‘크로스 브라우징’을 제공할 수 있다고 말합니다. 하지만 사실은 그렇지 않지요. 테이블을 사용하는 레이아웃이 오랫동안 대세가 되었던 것은 대부분의 브라우저가 동일한 결과물을 보여주었기 때문입니다. 반면에 CSS로 인터넷 익스플로러와 파이어폭스에서 같은 화면을 보여주기 위해서 여러가지 핵(Hack)이 고안되었다는 것은 CSS 만으로는 크로스 브라우징에 한계가 있음을 잘 보여줍니다. 물론 MS 브라우저를 탓할 수 있지만 그렇다고 해서 표준 문법을 지켰으니 제대로 안보이는건 브라우저 책임이라고 말하기에는 무리가 있습니다.
그럼에도 불구하고 XHTML과 CSS를 올바르게 사용하는 ‘제한적인 웹 표준’을 지키는 것은 중요합니다. 많은 이점이 있기 때문이지요.
사실 “테이블 대신 div 레이아웃을 사용한다.”는 말에는 문서의 ‘구조’와 ‘표현’을 분리한다는 의미가 담겨 있습니다. 즉, 문서의 구조를 알려주는 div, p, blockquoe, h1 등의 태그로 내용을 체계화시키고, font, b, i 등의 표현을 담당하는 태그는 CSS로 대체한다는 뜻이지요. 이렇게 하면 위에서 언급한 W3C의 세 번째 세부 목표 달성에 큰 도움이 됩니다.
사람의 입장에서는 문서를 쉽게 작성하고 읽을 수 있게 됩니다. 레이아웃을 여러 개의 중첩된 테이블로 디자인 할 경우에는 어디에 어떤 정보가 있는지 찾기도 어렵지만 잘 구조화된 문서는 화면에 보이는 순서대로 표현되므로 관리가 쉽습니다. 전체적인 디자인을 수정하기 편해지고 표현을 담당하는 요소가 제거되니 입력해야 할 텍스트의 양도 많이 줄어들게 되고요.
또한 장치의 측면에서 잘 구조화된 문서는 브라우저가 더 빨리 페이지를 렌더링하게 해줍니다. 복잡한 중첩 테이블을 표현하려면 많은 연산이 필요하니까요. 또 전체적인 파일 크기가 작아져서 네트워크 트래픽을 아낄 수 있습니다. 게다가 검색 엔진이 문서의 내용을 쉽게 분석해서 보다 정확한 검색 결과를 제공할 수 있게 됩니다.
반면에 문서의 구조와 표현을 섞어놓음으로써 얻는 이점은 무엇이 있을까요? XHTML과 CSS 사용에 부정적인 생각을 갖고 계신 분들께 묻고 싶습니다.
단지 익숙하다는 점 하나가 아닐까요? CSS를 익히는 것은 html 이 처음 등장했을 때 table 태그 사용법을 익히는 것과 같다고 생각합니다. 생소하지만 계속 연습하다 보면 익숙해지지요.
html을 전혀 다루지 못하는 사용자들에게 XHTML과 CSS는 큰 의미가 없습니다. 그 분들을 위해서 글을 쓰는 것도 아니고요. 다만 직접 html 코드를 작성하는 분들이라면 기왕이면 여러모로 장점이 많은 방법을 사용하는게 좋지 않을까요?
깊이 생각해서 써야 할 주제인데 너무 두서없이 떠들었네요. 사실 ‘웹 표준’은 다양한 의미를 갖습니다. 표준 규격을 지키는 것에서부터 넓게는 표준 규격에 맞게 웹 사이트를 제작하자는 최근의 트랜드를 의미하기도 하지요. 그래서 누군가가 ‘웹 표준을 지키자’라고 주장하면 어떤 사람은 XHTML과 CSS를 사용하는 디자인을 떠올리고, 어떤 사람은 접근성 향상을 위한 보이스 리더를 생각할 것입니다. 불여우와 익스플로러의 렌더링 차이를 생각하는 분들도 있겠지요.
의미가 다양한 만큼 웹 표준에 관해서 어떤 생각이 절대적으로 옳다고는 누구도 말할 수 없을겁니다. 하지만 한 때의 유행으로 끝나지는 않을거라는데 많은 분들이 동의하시리라 생각합니다. 웹 표준이 무시할 수 없는 흐름이라면 다양한 생각들을 교환하면서 이해의 폭을 넓혀가는게 좋지 않을까 하는 마음으로 제 생각을 적어봤답니다.