[CSS3] 미디어 쿼리(Media Query)의 only 키워드

CSS3 미디어 쿼리 모듈은 웹의 미래에 있어서 굉장히 중요한 의미를 갖습니다. 미디어의 종류(type)별로만 스타일을 다르게 줄 수 있었던 이전과는 달리 미디어 각각의 특성(feature)에 맞춰서 스타일에 변화를 줄 수 있기 때문이지요.

그 배경에는 웹에 접근할 수 있는 장치의 다양성이 점점 커지는 현상과, 이렇게 다양한 장치에서의 뷰를 효과적으로 컨트롤하기 위한 W3C의 고심이 있습니다.

그리고 놀랍게도 W3C의 고심은 우리가 생각하는 것보다 훨씬 일찍 시작되었습니다. 우리에게 익숙한 오래된 표준, 즉 HTML 4.01에서 이미 이런 미래를 고려한 장치를 만들어 놓았기 때문입니다. HTML 4.01이 표준이 된 게 1999년이니 벌써 10년도 전이네요.

HTML 4.01 이전에도 관련된 내용이 있을지도 모르지만 확인은 안 해봤습니다.

이 글에서는 HTML 4.01이 미디어 쿼리를 위해 어떤 대비를 했는지, 그리고 그 결과 만들어진 미디어 쿼리의 only라는 키워드에 대한 얘기를 해볼까 합니다. 미디어 쿼리가 무엇이고, 또 어떻게 사용하는지에 관해서는 이미 웹에 많은 정보가 있으니 다루지 않습니다.

HTML 4.01에서 적용할 미디어를 결정하는 방식

HTML 4.01에서 link 요소를 사용해서 외부 CSS 파일을 불러올 때 대상(target) 미디어는 아래처럼 결정됩니다.

† 원문 링크: HTML 4.01 6.13 Media descriptors

미래의 HTML에서는 새로운 미디어 종류가 추가될 수 있고, 대상 미디어를 제한하는 기준이나 값(parameterized values)도 도입될 수 있다. 이런 확장에 대비해서 표준에 부합하는 사용자 에이전트(conforming user agent)는 media 속성을 반드시(MUST) 아래처럼 해석해야 한다.

  1. 결과 값은 미디어 종류를 쉼표(,)로 구분한 리스트이다. 예를 들어서,

    media="screen, 3d-glasses, print and resolution > 90dpi"

    이 속성 값은 아래처럼 변환된다.

    "screen"
    "3d-glasses"
    "print and resolution > 90dpi"
  2. 각각의 항목은 영문 대소문자, 0~9까지의 숫자, 하이픈이 아닌 첫 번째 문자 바로 앞에서 끊는다. 위 항목은 아래처럼 정리된다.

    "screen"
    "3d-glasses"
    "print"
  3. 각각의 항목은 대소문자를 구별해서 HTML 4.01에 정의된 미디어 종류인지 검사한다. 사용자 에이전트는 대소문자가 맞지 않는 항목을 무시할 수도 있다(MAY). 위 예에서는 screenprint가 최종적인 대상 미디어가 된다.

두 번째 단계가 쉽게 와 닿지 않을 수도 있습니다. 왜 띄어쓰기 앞에서 정리할까 의아하게 생각할 수도 있는데요. 그 이유는 상위 호환성(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을 보면서 새삼 그렇다는 것을 느끼게 되었네요.

댓글 7개가 달렸습니다. 태그: , , ,

CSS 이야기: position, float, display 속성간의 관계

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(기본 값)이어야 합니다. 만약 positionstatic이라면 해당 박스의 top, bottom, left, right 속성은 완전히 무시됩니다. relative가 지정된 박스도 일반적인 흐름에 따라 배치되지만, 배치된 위치를 기준으로 top 등의 속성에 따라 상대적으로 위치가 다시 조정됩니다(offset). 이렇게 박스에 offset이 발생하더라도 이어지는 박스는 offset이 없는 것처럼 배치되기 때문에 전체적인 흐름에는 영향을 주지 않습니다.

CSS 2.1에서는 position:relativetbody, thead, tfoot, tr, colgroup, col, td, th, caption 요소에 지정했을 때의 효과에 대해서는 정의하지 않습니다. 따라서 tdrelative를 지정하면 사용자 에이전트에 따라서 서로 다른 결과가 발생할 수 있습니다.

떠있는(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 속성이 absolutefixed가 아니고 float 속성이 none이 아니어야 합니다. absolutefixed 값은 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 속성 값이 absolutefixed여야 합니다.

† 위에 설명한 “절대 위치 방식”에서의 포함 블록 정의는 position 속성이 absolute일 때에만 적용됩니다. positionfixed일 때의 포함 블록은 “연속적인(continuous)” 미디어에서는 “뷰포트(viewport)”, 페이지로 구분되는(paged) 미디어에서는 “페이지 영역”을 기준으로 만들어집니다.

오류 지적해주신 정찬명님. 고맙습니다~ ^^

position, float, display 속성간의 관계

앞서 설명했던 내용을 정리해보겠습니다. 우선 요소의 배치 방식에 가장 큰 영향을 미치는 CSS 속성은 position입니다. display 속성은 요소가 어떻게 표현되는지를 결정하지만(심지어 보이거나 보이지 않게도 하지만) 근본적으로 배치 방식에는 영향을 주지 못합니다. positionabsolutefixed이면 절대 위치로 박스가 배치되고, static이나 relative이면 일반적인 배치나 떠있는 배치가 적용됩니다. 절대 위치로 배치되면 float 속성의 산출 값은 어떤 값을 지정하든 상관 없이 none으로 평가되고. display 속성은 아래 표에 따라 변환되어 적용됩니다.

지정한 값 산출 값
inline-table table
inline, run-in, table-row-group, table-column, table-column-group,
table-header-group, table-footer-group, table-row, table-cell, table-caption, inline-block
block
기타 지정한 값

† 문서의 시조(root) 요소에 지정된 display 값도 위 표에 따라 결정됩니다.

일반적인 배치와 떠있는 배치 중 어느 쪽이 적용되는지는 float 속성에 따라 결정됩니다. floatleftright이면 떠있는 배치 방식이 적용되고, 이 때 display 속성 값은 위 표에 따라 변환되어 적용됩니다.

display 속성 값은 요소의 표현 방식을 결정합니다. block 요소를 inline 요소처럼 표현할 수도 있고, 그 반대도 가능합니다. 하지만 앞서 알아본 것처럼 absolute 속성이나 float 속성 값에 따라서 지정한 값과는 다르게 적용될 수도 있다는 점에 주의해야 합니다.

positionfloat 속성이 display보다 우선하지만, 예외적으로 displaynone일 때에는 positionfloat이 적용되지 않습니다. 당연한 얘기지만 박스 자체가 만들어지지 않기 때문입니다.

마치며

간단하게 position, float, display 속성이 어떻게 관련되어 있는지 정리하려고 했는데 또 글이 길어졌네요. 한동안 글을 쓰지 않다가 갑자기 뭔가를 쓰려고 하니 어색하기도 하고, 무엇보다 이렇게 마음 내키는대로 주제를 정해서 글을 쓰는 것에 한계를 느낍니다. 이 글만 해도 CSS의 박스 모델과 포함 블록, 블록 서식과 인라인 서식 등을 먼저 설명해야 하는데 그런 체계 없이 쓰려다 보니 설명을 많이 생략하게 되거든요.

그래서 새해를 맞아서 처음부터 조금씩 정리해볼 생각입니다. CSS 2.1 소개Conformance, 속성 값 처리 방식등은 다루었으니, 박스 모델부터 시작해볼 생각입니다.

그리고 언제나 그렇듯이 글 내용에 오류가 있다면 꼭 알려주시기 바랍니다. 한동안 잠수 아닌 잠수 상태라서 댓글에 제대로 피드백을 못드렸는데 이제 수면 위로 올라왔습니다. ^^

댓글 12개가 달렸습니다. 태그: , , ,

CSS 이야기: overflow 속성의 float 해제 효과

예전에 float을 제거하는 방법이라는 글에서 overflow 속성을 이용하는 float 해제 방법을 다뤘습니다. 그 내용을 아래에 일부 인용하겠습니다.

“만약 width만 지정한 상태에서 overflow: hidden;을 적용하면 박스가 내용물의 크기만큼 아래로 늘어나니까요. 이 때 박스 안에 있는 float된 요소의 높이까지도 같이 계산됩니다. 결국 박스가 float된 요소를 포함할 만큼 커지기 때문에 float을 제거하는 효과가 나타나게 됩니다.”

글을 쓰던 당시에 overflowfloat된 요소를 포함하도록 박스 크기를 늘리는 명확한 이유는 몰랐습니다. CSS 2.1을 열심히 찾아봤는데 overflow 속성 설명에는 관련 내용이 전혀 없었거든요. 그래서 경험적인 추측일 뿐이었습니다.

그런데 어제 마진 병합에 관한 글을 쓰면서 그 원리가 CSS 2.1에 정확하게 명시되어 있다는 사실을 알게 되었습니다.

그 내용은 시각적인 서식 모델의 세부 사항(visual formatting model details)을 다루는 10장의 6.6, 6.7절입니다.

마진 병합을 다루면서 블록 레벨 요소의 height 결정 방식을 찾아봤는데 overflowvisible일 때에만 적용되는 내용이었습니다. 그래서 visible이 아닌 경우를 찾아봤는데 6.6절에 있더군요.

6.6절은 일반적이지 않은 상황에서의 height 결정 방식을 다룹니다. 핵심적인 내용은 아래와 같습니다.

“일반적인 문서 흐름(normal flow)에서 블록 레벨 요소의 overflow 값이 visible이 아니고 heightauto면 그 자손 요소에 따라서 6.7절에 명시된대로 높이가 결정된다.”

6.7절에서 실제 높이 결정 방식을 다루는데 float된 자식 요소과 관련된 부분은 다음과 같습니다.

“만약 요소가 float된 자손 요소를 갖고 이 자손 요소의 하단 마진 경계(bottom margin-edge)가 요소 박스 아래에 있으면 요소 박스의 높이는 자손 요소의 하단 마진 경계를 포함하도록 늘어난다.”

따라서 overflow를 이용한 float 해제는 CSS 2.1에 정의된 정확한 동작 방식입니다. 그동안 참 많이 궁금했었는데 결국은 궁금증이 풀렸네요. ^^

댓글 15개가 달렸습니다. 태그: , , ,

CSS 이야기: 마진 병합(collapsing margins)

CSS를 이용해서 블록 레벨 요소를 배치하다보면 간혹 수직 방향으로 마진이 적용되지 않을 때가 있습니다. 이런 현상은 대부분 CSS의 중요한 레이아웃 모델 중 하나인 마진 병합(collapsing margins) 때문에 발생하는데 브라우저에 따라서 다르게 나타나는 경우가 많기 때문에 크로스 브라우징에 어려움을 주기도 합니다.

사실 마진 병합은 블록 레벨 요소의 height 결정 방식이나 float, overflow같은 다른 여러 가지 내용과 연결되어 있습니다. 이 글에서는 마진 병합의 정의와 계산 방법, 그리고 일반적인 문서 흐름(normal-flow)에서의 세 가지 마진 병합 패턴에 대해서만 알아보고 나머지 내용은 다음 글에서 이어가도록 하겠습니다.

† 기본적으로 마진 병합은 hasLayout 모델을 쓰는 IE 7 이하 브라우저에서는 정확하게 표현되지 않을 가능성이 큽니다. 관련된 버그도 상당히 많고요. 그러니 직접 테스트를 해보실 분들은 반드시 IE 8이나 파이어폭스, 오페라, 사파리 등의 브라우저를 사용하시기 바랍니다. ^^;

그리고 언제나 그렇듯이 설명에 오류가 있을 수도 있습니다. 오류를 알려주시면 즉시 반영하도록 하겠습니다.

마진 병합의 정의

먼저 마진 병합이 정확하게 무엇을 뜻하는지 알아봐야겠지요. CSS 2.1 박스 모델의 마진 병합 설명에는 이렇게 정의되어 있습니다(세부적인 조건은 뒤에서 따로 설명합니다).

“마진 병합은 인접한 두 개 이상의 수직 방향 박스 마진이 하나의 마진으로 합쳐지는 것을 의미한다.”

무엇보다 마진 병합은 수직 방향의 마진, 다시 말해서 margin-topmargin-bottom에만 의미를 갖습니다. 따라서 margin-leftmargin-right는 전혀 그 고려 대상이 아닙니다.

또한, 두 개 이상의 마진이 인접했다는 것은 마진의 방향(top 또는 bottom)과 상관 없이 최소한 두 개의 마진이 서로 닿아있다는 의미입니다. 그렇다면 마진이 서로 닿으려면 어떻게 배치되어야 할까요? 크게 세 가지 경우가 있습니다.

  1. 두 요소가 형제(sibling) 관계일 때 위에 있는 요소의 margin-bottom과 아래 있는 요소의 margin-top이 서로 닿는 경우
  2. 두 요소가 부모, 자식 관계일 때 부모 요소의 margin-top과 자식 요소의 margin-top이 서로 닿는 경우(margin-bottom의 경우도 성립)
  3. 한 요소의 margin-topmargin-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)

세 가지 마진 병합 패턴

마진이 서로 닿게 되는 세 가지 경우를 앞서 살펴봤습니다. 마진 병합은 그 각각의 경우에 대응되는 형제 요소간의 병합, 부모와 자식 요소간의 병합, 자체 병합의 세 가지 패턴으로 구분할 수 있습니다. 복잡한 상황은 미뤄두고 일단 가장 간단한 사례를 생각해보겠습니다.

패턴 1. 형제 요소간의 병합

일반적인 문서 흐름에서 두 형제 요소가 인접하는 경우로 마크업 예는 아래와 같습니다.

<div style="margin-bottom: 10px; height: 30px; background-color: blue;"></div>
<div style="margin-top: 30px; height: 30px; background-color: orange;"></div>

마진 병합을 제대로 처리하는 브라우저에서는 아래 이미지처럼 랜더링됩니다.

형제 요소간의 마진 병합

블록 A의 margin-bottom과 블록 B의 margin-top이 하나로 합쳐져서 30px로 표현됩니다. 가장 흔히 발생하는 패턴으로 이해하기도 쉽습니다. 형제 요소(블록 B)가 clearance를 가질 때를 제외하면 언제나 성립하는데 이에 관해서는 나중에 설명하겠습니다.

패턴 2. 부모, 자식 요소간의 병합

일반적인 문서 흐름에서 부모, 자식 요소간의 마진 병합은 margin-topmargin-top이 인접하는 경우와 margin-bottommargin-bottom이 인접하는 두 가지 경우에 발생하며 각각의 성립 조건이 약간 다릅니다. 먼저 조금 더 간단한 margin-top의 경우를 살펴보지요.

<div style="margin-top: 10px; background-color: blue;">
	<div style="margin-top: 30px; height: 30px; background-color: orange;"></div>
</div>

직관적이지는 않지만 아래처럼 렌더링되는 것이 정상입니다.

부모, 자식 요소간의 마진 병합

언듯 생각하면 부모 요소와 자식 요소에 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이 합쳐지는 경우는 조건이 조금 더 복잡해지는데 우선 부모 요소의 heightauto여야 하며 min-height는 요소의 실제 높이보다 작고 max-height는 요소의 실제 높이보다 커야 합니다. 여기에서 min-heightmax-height 조건에 따라서 첫 번째 조건인 height 산출 값(computed value)이 달라질 수 있기 때문에(CSS 2.1 10.7 참고) 첫 번째 조건이 핵심이라고 할 수 있습니다.

이런 조건이 필요한 이유는 height가 지정되면 자식 요소와 상관 없이 높이가 결정되고, 마진 영역은 투명하기 때문에 overflowvisible인 상태에서는 가장 아래에 있는 자식 요소의 margin-bottom이 부모 요소의 렌더링에 영향을 미치지 않고, 만약 margin-bottom이 적용되면 부모 요소 다음에 배치되는 박스와의 관계에 혼란을 줄 수 있기 때문이 아닐까 생각합니다.

패턴 3. 요소의 자체 병합

마지막 세 번째 패턴입니다. 어떤 요소의 margin-topmargin-bottom이 합쳐지려면 까다로운 조건을 만족시켜야 하지만 실제로는 아주 쉽게 발생하기도 합니다. 자체 병합이 이루어지려면 min-height 속성 값이 0이고, top, bottom 보더와 패딩이 없고, height 속성 값이 0 또는 auto이고, 어떤 라인 박스도 포함하지 않고, 해당 요소의 흐름 안에 있는 자식 요소들의 마진이(있다면) 모두 인접해야 합니다.

이런 조건은 문서에 수직 방향 보더와 패딩이 없는 빈 블록 레벨 요소가 들어가면 간단히 만족됩니다. min-heightheight를 지정하는 경우가 별로 없으니까요. 간단한 마크업 예는 다음과 같습니다.

<div style="margin-top: 10px; background-color: blue;">
	<div style="margin: 30px 0 10px 0; background-color: orange;"></div>
	<div style="margin: 20px 0; background-color: orange;">블록 A</div>
	<div style="margin: 20px 0; background-color: orange;">블록 B</div>
</div>

랜더링 결과는 다음과 같습니다.

요소의 자체 병합

블록 A의 margin-top 20px과 빈 div 요소의 margin-bottom 10px, margin-top 30px, 부모 요소의 margin-top 10px이 하나로 합쳐져서 30px의 단일 마진으로 표현됩니다. 패턴 1, 2, 3가 함께 적용된 결과이지요.

† 처음에는 패턴 2, 3만 적용된다고 생각했는데 블록 A와 빈 요소가 형제 관계라서 패턴 1도 성립하네요. 관련해서 일부 내용을 업데이트했습니다.

이렇게 세 개 이상의 마진이 합쳐지고, 마진의 부호가 서로 다를 때에는 마진이 합쳐지는 순서가 중요합니다. 아래와 같은 상황을 생각해보지요.

<div style="margin-top: 50px; background-color: blue;">
	<div style="margin: 30px 0 -40px 0; background-color: orange;"></div>
	<div style="margin: 20px 0; background-color: orange;">블록 A</div>
	<div style="margin: 20px 0; background-color: orange;">블록 B</div>
</div>

만약에 빈 div의 마진이 먼저 합쳐지고, 이렇게 만들어진 단일 마진이 부모 요소와 블록 A의 마진과 합쳐진다면 최종 마진은 30 – 40 = -10(px), 50 – 10 = 40(px)이 됩니다. 하지만 네 마진이 한꺼번에 합쳐지면 앞서 설명한 계산 방법대로 50 – 40 = 10(px)이 됩니다.

파이어폭스 3, 사파리 3에서 테스트해보니 명세서대로 한꺼번에 합쳐져서 10px로 표현되었습니다. 오페라에서는 다른 결과가 나왔는데 버그일 가능성이 높다고 생각됩니다.

† 2010.06.22: 오페라 10에서 확인해보니 파이어폭스, 사파리와 동일하게 10px로 표현되네요. 이전에 테스트를 잘못했거나 아니면 버그가 수정되었나 봅니다. ^^;

요소의 마진이 자체적으로 병합될 때 마진이 topbottom 중 어느 방향으로 적용되는지에 관한 명확한 설명은 찾지 못했습니다. 그래서 나름대로 테스트를 해봤는데 방향 자체가 무의미하지 않을까 하는 생각이 듭니다. 최종 마진을 계산할 때 자체 병합되는 요소의 마진 값 두 개를 추가시키고, 그 결과 값을 문서 구조에 따라서 패턴 1, 2에 적용시키는 것이 아닐까 싶네요.

예를 들어서 바로 위 예제에서 최종 마진 값은 10px입니다. 이제 빈 요소를 무시하고 패턴 2에 따라서 부모 요소와 블록 A 사이에 10px의 마진이 있다고 가정하면 최종적으로 부모 요소에 10px의 margin-top이 적용됩니다.

물론 이것이 정확한 방식인지 확신할 수는 없습니다. 테스트를 더 하면서 추론과 위배되는 결과가 발생하거나 정확한 방식을 설명하는 자료를 찾으면 글을 업데이트하도록 하겠습니다.

마치며

다양한 조건에서 마진 병합이 발생하지만 일반적인 문서 흐름에서는 거의 대부분 위에 설명한 세 가지 패턴의 조합이라고 생각합니다. 하지만 float된 요소의 유무나 overflow, position 등의 속성 값에 따라서 마진 병합이 적용되지 않는 경우도 있는데 이런 상황에 대해서는 다음 글에서 알아보겠습니다.

댓글 5개가 달렸습니다. 태그: , , ,

CSS 이야기: CSS 2.1과 2의 관계

현재 공식적인 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 커뮤니티의 지속적인 피드백과 비판이 있었습니다. 그 예로 오페라 브라우저 개발에 참여하고 있는 Anne van Kesteren의 CSS 2.1 관련 글 일부를 인용하겠습니다.

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: markeraural 미디어 타입을 제대로 지원하는 사용자 에이전트는 극히 드뭅니다(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 속성 값
  • id 선택자의 다중 id 속성 처리
  • 자동 테이블 레이아웃 알고리즘
  • quotes 속성과 open-quote, close-quote, no-open-quote, no-close-quote 키워드 값
  • XHTML body 요소의 overflowbackground 처리 문제

† 관심을 기울여야 한다고 했는데 사실 실무적으로는 다섯 번째 항목을 제외하면 그리 중요하지 않다고 생각합니다.

다섯 번째 항목에서 XHTML과 HTML에서 body 요소의 overflowbackground 처리가 약간 다릅니다. overflow를 예로 들면 XHTML에서는 최상위 요소(html)에 지정된 overflow 속성 값을 뷰포트에 적용시켜야 하지만, HTML에서는 html 요소의 overflow 값이 visible일 경우에 한해서 body 요소의 속성 값을 뷰포트에 적용시키도록 규정되어 있는데 이런 예외 상황에 대한 처리가 XHTML에 그대로 이어졌다는 내용입니다.

마치며

참 긴 글이지만 결론은 한 줄로 요약할 수 있을만큼 간단합니다. ^^;

웹 제작자에게 중요한 규격은 CSS 2가 아닌 CSS 2.1이다.

나름대로 열심히 자료를 찾고, 해석해봤는데 과연 얼마나 정확한 내용을 담고 있을지 모르겠네요. 특히 CR에서 PR로, 다시 최종 권고안으로 진행되는 과정은 참고한 W3C의 프로세스 문서를 충분히 검토하지 않아서 오류가 있을 가능성이 다분합니다. 오류를 알려주시면 정오표에 수록한 다음 나중에 이 글의 리비전을 만들 때 반영하도록 하겠습니다. :)

댓글 5개가 달렸습니다. 태그: , , ,

플래시 대체 컨텐츠와 noscript 요소

adobe사의 플래시는 웹 페이지에 강력한 멀티미디어 효과를 불어넣을 수 있게 해주는 강력한 도구입니다. 하지만 기본적으로 “시각”적인 인지를 바탕으로 하기 때문에 비시각적인 환경에서는 접근성을 떨어뜨리는 원인이 되기도 합니다.

물론, 플래시 자체적으로 접근성 향상을 위한 대체 텍스트를 제공하기는 합니다. 하지만 Window-EyesJAWS 같은 일부 스크린 리더만이 이런 대체 텍스트를 읽을 수 있고, 플래시 플레이어 9가 지원하는 Microsoft Active Accessibility(MSAA) 기술은 윈도우즈 환경에 국한된 기술이기 때문에 윈도우즈 운영체제가 아닌 타 플랫폼에서는 제한적일 수 밖에 없다는 한계를 갖고 있습니다.

게다가 모든 사용자가 플래시 플러그인이 동작하는 환경에서 웹 페이지를 이용하지는 않습니다. 그렇기 때문에 페이지 네비게이션처럼 접근성이 중요한 컨텐츠에 대해서는 웹 페이지 제작자가 다양한 환경을 고려해서 최대한으로 대체 컨텐츠를 제공하는 것이 올바른 방법이라고 생각합니다. 그럼 어떤 방법이 있는지 알아볼까요?

예외적인 환경

대부분의 사용자는 일반적인 환경, 다시 말해서

  1. 브라우저가 자바스크립트를 지원하며,
  2. 브라우저가 지원하는 플래시 플러그인이 설치되어 있고,
  3. 브라우저가 CSS를 지원하는

환경에서 이 글을 보실 겁니다. 하지만 예외적인 환경에서 웹 서핑을 하는 분도 분명히 있겠지요. 각각의 환경에 따라서 대체 컨텐츠를 제공하는 방법이 달라집니다.

자바스크립트가 동작하지 않을 경우

자바스크립트와 플래시는 밀접한 관계를 갖고 있습니다. 특히 플래시에서 링크를 직접 처리하지 않고 자바스크립트 함수를 호출해서 페이지를 이동시키는 방법도 유지보수의 편의성 때문에 많이 사용되고 있는데 이런 경우에는 자바스크립트가 없으면 페이지 이동 자체가 불가능하게 됩니다.

또한, 마이크로소프트와 이올라스사와의 특허 분쟁 때문에(2007년 8월에 양사가 합의했지만) 외부 자바스크립트를 이용해서 플래시를 삽입하는 것이 일반화된 후로는 자바스크립트의 도움이 없으면 플래시 컨텐츠 자체를 볼 수 없는 경우도 많아졌습니다.

noscript 요소

이렇게 자바스크립트를 사용할 수 없는 환경을 고려해서 W3Cnoscript 요소를 HTML 권고안에 포함시켰습니다. HTML 4.01의 noscript관련 권고안 내용은 다음과 같습니다.

noscript 요소는 스크립트가 실행되지 않는 환경에서의 대체 컨텐츠를 제공한다.”

“스크립트를 이해하는 사용자 에이전트는 스크립트가 실행되지 않도록 설정되었거나 script 요소에 지정된 스크립트 언어를 지원하지 않을 경우에 noscript 요소 안의 컨텐츠를 렌더링하고, 사용자 측(client-side) 스크립트를 지원하지 않는 사용자 에이전트는 항상 noscript 요소를 렌더링해야 한다.”

따라서, 자바스크립트로 플래시를 삽입할 경우에 noscript 요소에 대체 컨텐츠를 넣으면 스크립트를 지원하지 않는 환경에서도 컨텐츠를 이용할 수 있습니다.

하지만 브라우저가 noscript 요소를 처리하는 방식에 대해서 세부적인 권고안이 없기 때문에 noscript 요소 안의 컨텐츠를 재활용할 때에는 문제가 발생하기도 합니다. 이 부분에 대해서는 잠시 후에 알아보겠습니다.

플래시 플러그인이 설치되어 있지 않은 경우

플래시 플러그인이 없으면 브라우저는 해당 컨텐츠를 인식하지 못합니다. 그래서 플래시를 삽입할 때 대체 컨텐츠를 제공해줘야 합니다. 다행히도 플래시 삽입에 사용되는 object 요소는 param 요소를 제외한 요소 내의 모든 컨텐츠를 자동으로 대체 컨텐츠로 인식합니다.

하지만 일반적으로 사용되는(adobe사가 기본적으로 제공하는) 플래시 삽입 스크립트는 objectembed 요소를 함께 이용하기 때문에 embed를 인식하는 넷스캐이프 계열 브라우저에서는 대체 컨텐츠를 인식하지 못합니다. 플래시 삽입 방법과 그에 따른 문제점들은 flash embed test suite 페이지를 참고하시기 바랍니다.

플래시 삽입 방법

대체 컨텐츠 제공을 위해서 플래시를 삽입하는 자바스크립트 함수를 약간 수정했습니다. 두 개의 object 요소를 인터넷 익스플로러만 인식하는 조건부 주석(conditional comment)과 함께 넣는 방법입니다.

function embedFlash(id, url, width, height, altText, flashVars, wmode) {
	if (!flashVars) flashVars = '';
	if (!wmode) wmode = 'window';
	if (!altText) altText = '';

	var str = '' +
	'<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0" width="' + width + '" height="' + height + '" id="' + id + '">' +
		'<param name="movie" value="' + url + '" />' +
		'<param name="wmode" value="' + wmode + '" />' +
		'<param name="FlashVars" value="' + flashVars + '" />' +
		'<!--[if !IE]>-->' +
		'<object type="application/x-shockwave-flash" data="' + url + '" width="' + width + '" height="' + height + '" name="' + id + '">' +
			'<param name="wmode" value="' + wmode + '" />' +
			'<param name="FlashVars" value="' + flashVars + '" />' +
		'<!--<![endif]-->' +
			'<div class="alt-content alt-' + id + '">' + altText + '</div>' +
		'<!--[if !IE]>-->' +
		'</object>' +
		'<!--<![endif]-->' +
	'</object>';
	document.write(str);
}

† 2008년 3월 28일 업데이트: IE가 인식하는 외부 object에는 id를 주고, 내부 object에는 name을 준 이유는 자바스크립트로 플래시 무비를 직접 제어할 때 두 개의 object에 동일한 id를 부여하면 문제를 일으킬 수도 있기 때문입니다. object에 각각 idname을 준 다음 먼저 document.getElementsByName DOM Level2 메소드로 내부 object를 찾고, object를 찾지 못했을 경우에는 다시 document.getElementById 메소드로 외부 object를 찾는 것이 안전한 방법이라고 하네요. Eionet의 Embedding Flash content에 자세한 설명과 자바스크립트 예제가 있으니 참고하시기 바랍니다.

이제 embedFlash 함수를 호출할 때 대체 컨텐츠를 문자열로 지정할 수 있습니다. 예를 한 번 들어보겠습니다.

embedFlash('navigation', 800, 80, '<a href="alt_content.html">대체 링크</a>');

그러면 object 요소 안에 다음과 같은 형식으로 대체 컨텐츠가 들어갑니다.

<div class="alt-content alt-navigation">
	<a href="alt_content.html">대체 링크</a>
</div>

두 개의 class가 지정된 div 요소를 앞서 설명한 noscript 요소 안에 넣으면 플래시 플러그인이 없거나 자바스크립트가 실행되지 않아도 동일한 대체 컨텐츠를 제공할 수 있고 CSS를 이용해서 스타일을 적용시킬 수도 있습니다.

효율적인 방법을 찾아서

자바스크립트로 플래시를 삽입할 때 대체 컨텐츠를 제공한다면 따로 문자열을 만들지 않고 이미 존재하는 noscript 요소 안의 컨텐츠를 이용할 수도 있지 않을까요? noscript 요소가 문서 구조 내에 있으면 innerHTML 같은 메소드를 이용해서 컨텐츠를 문자열로 가져올 수 있으니까요.

하지만, W3C의 권고안은 사용자 에이전트가 noscript 요소를 문서 구조 내에서 어떻게 이용하는지에 대해서는 다루지 않기 때문에 브라우저 제작사마다 처리 방식에 차이가 있습니다. 간단한 예를 들어볼까요?

<noscript id="alt-content-test">
	<p><a href="alt_content.html">대체 링크</a></p>
</noscript >

위와 같이 마크업하고 자바스크립트를 이용해서 alt-content-test 안의 컨텐츠를 가져와보겠습니다. 아래 소스를 이용해서요.

<input type="button" value="대체 컨텐츠 가져오기" onclick="alert(document.getElementById('alt-content-test').innerHTML); return false;" />

아래 버튼을 클릭하면 결과를 볼 수 있습니다.

인터넷 익스플로러 6에서는 noscript 요소 안에 있는 대체 컨텐츠를 올바른 HTML 컨텐츠로 인식하지만, 파이어폭스에서는 태그를 &lt;&gt;로 변환해서 일반 텍스트 형식으로 인식합니다. 자바스크립트 string 객체의 replace 메소드를 이용하면 일괄적으로 변환시킬 수 있지만 오페라에서는 더 큰 문제가 생깁니다. 자바스크립트가 활성화된 상태에서는 아예 noscript 요소를 인식하지 못한다는 점이지요. 다시 말해서 해당 요소가 없는 것과 마찬가지입니다.

noscript 요소 안에 div를 넣고 여기에 id를 주면 파이어폭스에서는 해당 div 요소를 인식하지 못합니다. 요소 노드가 아닌 텍스트 노드로 인식하니까요.

그래서 noscript 요소의 컨텐츠를 재사용하는 것에는 한계가 있습니다.

첫 번째 대안

noscript 요소를 이용하기 어렵다면 대신 div 요소를 만들고 여기에 대체 컨텐츠를 넣은 다음 이용하면 어떨까요? 그러기 위해서는 해당 div 요소를 자바스크립트가 실행되는 환경에서는 숨겨야 합니다. 가장 간단한 방법은 CSS의 display 속성을 이용하는 것입니다. 예를 들어서 다음과 같은 자바스크립트를 이용할 수 있습니다.

window.onload = function() {
	document.getElementById("alt-content-test").style.display = "none";
}

그러면 페이지가 로드되면서 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 ToolbarCSS 선택 메뉴를 이용하면 문제 없이 표현됩니다.

두 번째 대안

간단하고 쉬운 방법이 있는데 바로 swfobject 스크립트를 이용하는 것입니다.

swfobject는 div 같은 일반적인 요소에 대체 컨텐츠를 넣고, 페이지가 로드될 때 DOM 스크립트의 removeChild 메소드로 해당 요소를 문서 구조 내에서 제거합니다. 따라서 CSS가 지원되지 않는 상황에서도 문제 없이 동작합니다.

하지만, noscript를 쓰지 않는 이런 방식에서는 플래시 플러그인이 없는 상태에서 자동으로 플러그인을 설치해도 플래시 컨텐츠가 즉시 보여지지 않습니다. 페이지를 새로 읽기 전까지는요.

이런 문제와 1.5버전의 사소한 문제 때문에 그동안 사용하지 않았는데 글을 쓰면서 검색해보니 최근에 2.0 버전이 발표되었더군요. 프로젝트 페이지도 구글 코드로 옮겨졌습니다. 새 버전의 향상된 기능에 대해서는 swfobject 2.0 문서를 참고하시기 바랍니다.

또한, CSS의 display 속성 대신 removeChild 메소드를 이용하는 방법에 관해서는 오페라 개발자 포럼의 noscript 대체 방법에 예제와 설명이 있습니다.

세 번째 대안

여러 방법을 살펴보면서 그래도 noscript 요소를 이용하는 것이 낫다고 판단했습니다. 자바스크립트로 어떤 조작을 하지 않아도 되고, 기본적으로 브라우저가 지원하는 대체 컨텐츠 제공 방법이니까요. 물론 일부 구형 브라우저에서는 호환성 문제가 있다는 보고도 있지만요.

그래서 서버 사이드 스크립트 언어(PHP)로 대체 컨텐츠를 변수화한 다음 object 요소와 noscript 요소에 동일하게 넣는 방법을 사용했습니다. 문서의 파일 크기가 약간 늘어나긴 했지만 큰 영향을 줄 정도는 아니었습니다.

참고로 자바스크립트에서 문자열의 최대 길이는 명확하게 정의되어 있지 않습니다. 다만, 일반적으로 문제없이 사용할 만큼 충분히 길다고 하네요.

마치며

플래시를 삽입하는 방식은 다양합니다. embed를 쓸 수도 있고, 표준 방식인 object를 사용할 수도 있습니다. 방법이 많다는 것은 그만큼 문제점도 많다는 뜻으로 해석할 수 있을겁니다.

개인적으로 플래시를 자바스크립트 이용 없이 마크업으로 직접 넣는 것이 좋다고 생각하지만, 이올라스사와의 특허 문제로 아직까지는 실무에 적용하기가 어렵네요. swfobject 2.0 버전에서는 DOM 노드를 조작하는 기존 방식과 함께 “static” 퍼블리싱이라는 새로운 방식을 도입했는데 플래시는 표준 마크업으로 삽입하고, 자바스크립트로는 플래시 플러그인 버전 확인 같은 부가 기능만을 처리하는 방식입니다.

어떤 방식이든 대체 컨텐츠를 제공하는 것은 접근성 측면에서 무척 중요합니다. 예를 들어서 서두에서 예로 들었던 네비게이션을 플래시로 제공하는 사이트는 대체 컨텐츠가 없으면 플래시 플레이어를 지원하지 않는 아이팟 터치 같은 일부 사용자 에이전트에서는 정상적인 이용이 불가능합니다.

웹의 영역은 PC 모니터를 넘어서 다양한 플랫폼으로 확장되고 있습니다. 이런 다양한 환경에서 사용자가 불편없이 컨텐츠를 이용하기 위해서는 접근성에 대한 고려가 필수적이라 생각합니다. 저도 일정이 부족하고, 기획 단계에서 접근성에 대한 고려가 없다는 핑계로 이런 부분을 게을리 했는데 이제부터는 조금씩 바꿔가려고 합니다. 접근성에 관해서는 기술보다 정성이 더 중요하다는 생각이 드네요.

댓글 9개가 달렸습니다. 태그: , , , , , ,

인터넷 익스플로러 8의 레이아웃 모델

마이크로소프트(이하 MS)가 인터넷 익스플로러(이하 IE) 8 베타1을 공개했다는 소식을 듣고 간단한 테스트를 해봤습니다. 웹 페이지 제작자의 입장에서 이전 버전과의 가장 큰 차이점은 달라진 레이아웃 모델(정확히는 CSS의 “시각적인 서식 모델(Visual Formatting Model)”)이라고 생각하는데 이 부분에 관한 얘기를 다뤄볼까 합니다.

† 이하 글에서는 IE8 베타1을 IE8로 표현합니다. 현재 베타 버전이지만 아래 설명할 내용은 정식 버전에 그대로 적용될 것으로 생각하기 때문입니다.

IE7 이하 버전의 hasLayout 문제

먼저, 이전 버전의 IE에 적용됐던 방법을 알아봐야 하는데 이 부분에 관해서는 이전에 작성했던 hasLayout 속성과 홀리 핵이라는 글에서 다뤘기 때문에 간단히 정리하겠습니다.

hasLayout 개념이 중요하게 여겨진 까닭은 IE가 W3C의 권고안과는 전혀 다른 방식으로 레이아웃, 즉 요소 박스의 위치와 크기를 해석했기 때문입니다. 따라서 표준 방식으로 CSS를 작성해도 예상했던 것과 다르게 레이아웃이 표현되는 경우가 많았습니다. 간단한 예를 들어보지요.

<div id="wrap" style="width:300px; background-color: red;">
	<div style="width:100px; height: 50px; float:left; background-color: #666;"></div>
	<div style="width:100px; height: 50px; float:left; background-color: #ccc;"></div>
</div>

표준 레이아웃 모델에 따르면 float된 요소는 정상적인 문서의 흐름(normal flow)에서 벗어나 있기 때문에 idwrapdiv 요소는 높이가 계산되지 않습니다. 따라서 두 개의 회색 div만 표시되지요. 하지만, 독자적인 hasLayout 개념을 사용하는 IE에서는 width를 지정하는 것 만으로도 wrap 높이가 계산되기 때문에 빨간색 div까지 전부 세 개의 박스가 화면에 표현됩니다.

아래 결과를 IE7 이하 버전과 표준 레이아웃을 따르는 파이어폭스나 오페라 브라우저로 비교해보면 차이를 알 수 있습니다.


하지만, IE 8에서는 다른 주요 브라우저와 동일하게 표준 레이아웃 모델이 적용됩니다. 그러므로 두 개의 회색 박스만 표현되지요.

overflow 속성과 생성된 컨텐츠(generated content) 지원

IE 7은 이전 버전에서 Layout을 갖게 했던(hasLayout) widthheight 속성에 추가로 overflow 속성을 지원합니다. 즉, overflow 속성으로도 Layout을 갖게 만들 수 있습니다. 그런데 overflow 속성이 표준 레이아웃을 지원하는 브라우저에서 높이를 계산하도록 하는데(float 해제(clearing float)) 많이 사용되기 때문에 레이아웃 해석에 대한 실제 구현 방법은 다르지만 결과적으로는 같은 효과를 낼 수 있었지요. IE8에서의 overflow가 IE7 방식으로 해석되는지, 아니면 표준 방식을 사용하는지 확실하지는 않지만 적어도 제 생각으로는 기존 hasLayout 방식을 버리고 표준 방식을 받아들였을 것 같습니다.

또한, IE8은 생성된 컨텐츠를 만들 수 있는 가상 요소(Pseudo-element) 역시 지원합니다. 따라서 다음과 같은 class를 사용해서 float을 해제시킬 수도 있습니다.

.layoutFix:after{
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}

hasLayout과 마진 겹침(margin collapsing)

† hasLayout은 CSS의 마짐 겹침 방식에 다양한 영향을 끼칩니다. 이 부분을 설명하려고 간단한 예제를 넣었는데 소스와 설명에 오류가 있었네요. ^^; 자료를 찾아 보니 간단히 다룰 문제가 아니어서 추후에 따로 포스팅을 하려고 합니다. 일단 관련 예제와 설명이 있는 웹 페이지를 알려드릴게요.

Margin collapsing and hasLayout
hasLayout and margins of nested boxes

IE8을 고려한 조건 주석문(conditional comment)

새로 발표된 IE8로 위 예제를 확인해보면 파이어폭스나 오페라, 사파리 등과 동일한 결과를 보여줍니다. 즉, 표준 레이아웃 모델을 지원한다는 얘기지요. 따라서 Layout을 갖게 만들기 위해서 사용되던 홀리 핵(Holly hack) 등을 적용할 필요가 없어졌고, 전체 IE에 적용되는 조건 주석문이나 핵은 오히려 문제를 일으킬 수도 있기 때문에 이런 부분은 IE7 이하에만 적용되도록 해야 합니다. 예를 들어서

<!--[if IE]>
<link rel="stylesheet" type="text/css" href="/blog_ie.css" />
<![endif]-->

blog_ie.cssheight: 1%; 같은 규칙을 지정해서 Layout을 갖게 만들었다면 주석문의 조건을 IE7 이하로 한정하고 IE8에서는 앞서 설명한 overflowlayoutFix 같은 class를 사용해서 높이가 계산되도록 해야 합니다. 아래 조건 주석문은 IE 전용 CSS를 IE7 이하에만 적용시킵니다.

<!--[if lte IE 7]>
<link rel="stylesheet" type="text/css" href="/blog_ie.css" />
<![endif]-->

마치며

현재 IE8은 베타 버전인 만큼 많은 버그가 포함되어 있을 것입니다. 완성도 면에서 평가하기는 아직 이른 시점이지만 사용해보니 확실히 이전 버전보다 W3C의 권고안(표준) 지원 면에서 큰 향상을 확인할 수 있었습니다.

충분히 테스트해보지 않아서 확실히 말씀드릴 수는 없지만 다른 브라우저에서 잘 보이는 레이아웃이 IE8에서 어긋난다면 먼저 IE8에만 별도로 적용되는 핵이나 규칙을 사용하고 있는지를 의심해봐야 합니다. 그리고 나서 IE8의 버그 때문인지를 알아봐야 겠지요. 일반 사용자들이 IE8 테스트로 다음이나 네이버 등의 포탈 사이트를 확인하는데 이런 사이트는 아주 복잡하고 정교한 마크업과 CSS로 이루어져 있습니다. 그렇기 때문에 IE8의 표준 지원 여부를 렌더링되는 결과만으로 평가하는 것은 상당히 어렵다고 생각합니다. IE에만 적용되는 코드가 섞여 있을 수 있으니까요.

개인적으로는 IE8이 acid2 테스트를 통과했다는 사실 만으로도 이전 버전보다 훨씬 표준을 잘 따른다고 평가합니다. acid2 테스트가 간단해 보이지만 실제로는 다양한 positionCSS 선택자(selector), 기타 CSS 개념들을 사용하기 때문에 제대로 표현된다는 것은 그만큼 많은 부분에서 표준을 따른다는 얘기거든요.

IE8의 등장으로 이제 모든 주요 브라우저가 표준 CSS 렌더링 방식을 지원하게 되었습니다. 향후 출시될 정식 버전과 IE8 등장으로 달궈진 브라우저 제조사들의 표준 지원 경쟁이 기대되네요.

댓글 11개가 달렸습니다. 태그: , , ,

DOM 스크립트: 이미지, 텍스트 스크롤러

scrollObj는 자바스크립트의 문서 객체 모델(DOM)을 이용해서 이미지나 텍스트에 스크롤 효과를 주는 오브젝트(객체)입니다. 비슷한 효과를 내는 함수나 오브젝트들이 자바스크립트 상의 소스를 document.write 메소드로 화면상에 출력하는 것과 달리 HTML 소스를 그대로 이용하므로 자바스크립트를 사용할 수 없는 환경에서도 스크롤될 내용을 확인할 수 있고, 문서의 소스도 간단해지는 장점을 갖습니다.

그러면 scrollObj의 세부적인 사항에 대해서 하나씩 설명하도록 하겠습니다.

W3C웹 컨텐츠 접근성 지침(Web Content Accessibility Guidelines) 1.0 가이드라인 7은 화면 깜빡임을 유발하는 컨텐츠 스크롤을 사용하지 않도록 권고하고 있습니다. 가능하다면 기획이나 디자인 단계에서 아예 스크롤 효과를 배제시키는 것이 최선의 방법이라 생각합니다.

동작 원리

scrollObj는 이미지나 텍스트가 들어 있는 리스트(ul, ol)의 절대 위치(absolute position) 값을 바꾸는 것으로 스크롤 효과를 만듭니다. 즉, 리스트 요소 자체를 이동시키는 것이지요. 그러면서 리스트에 포함된 특정한 항목 요소(li)를 기준으로 하는 이동 거리를 계산합니다. 이 특정 요소의 너비(또는 높이)와 이동 거리가 같아질 때 리스트 항목의 순서를 바꾸어서 스크롤이 계속 이어지도록 하는 것이지요. 설명을 위해 간단한 예제를 만들어봤습니다.

  • 11111
  • 22222222222
  • 3333
  • 444444444444444

scrollObj 선언과 함게 먼저 리스트 요소의 순서가 바뀝니다. 예제에서 리스트의 마지막 요소였던 “444444444444444” 항목이 첫 번째 요소가 된 것처럼이요. 이 과정에서 앞으로 옮겨진 요소들의 너비(또는 높이)만큼 리스트의 절대 위치가 이동됩니다. 따라서 실제로는 리스트의 첫 번째 항목이 “11111” 요소인 것처럼 보이게 되지요.

“시작/정지” 버튼을 누르면 스크롤이 시작됩니다. “방향 전환” 버튼으로 스크롤 방향을 바꿀 수도 있고요. 리스트를 감싸는 divoverflow: hidden; 속성을 주지 않았기 때문에 실제 요소의 이동을 눈으로 확인할 수 있습니다.

앞서 리스트의 순서가 바뀌는 시점을 특정 요소의 크기만큼 위치가 이동했을 때라고 했는데, 스크롤 방향에 따라서 기준이 되는 요소가 다르다는 점에 주의해야 합니다. 위 예제에서 일반적인 좌측 이동일 경우에는 리스트의 두 번째 요소가 기준이고, 오른쪽으로 이동할 때에는 첫 번째 요소가 기준이 되거든요. 이렇게 기준 요소를 달리 정한 것은 리스트 순서가 바뀔 때 정지 효과를 넣기 위해서입니다.

scrollObj 사용법

scrollObj는 오브젝트만 선언하면 자동으로 스크롤이 시작됩니다. 추가적인 전역 변수 선언은 필요하지 않고요. 선언 시 지정할 수 있는 인수는 많지만 대부분 생략 가능합니다. 먼저 scrollObj가 어떻게 선언되어야 하는지 실제 자바스크립트 소스를 적어보겠습니다.

var scrollObj = function(targetEle, isVertical, sumMargin, movePx, startNum, interval, isInverse, stopDuration)

여덟 개의 인수들 중에서 필수적인 항목은 스크롤 효과를 적용할 리스트의 id 값을 의미하는 첫 번째 targetEle 뿐입니다.

so1 = new scrollObj("scrollTest");

위 예처럼 리스트 id만 넣어주면 기본 설정으로 스크롤이 시작되니까요. 그러면 생략 가능한 나머지 인수들의 역할과 기본값을 알아볼까요?

인수명 가능한 값 기본값 역할 변경 가능 여부
isVertical true 또는 false false 수직 스크롤 여부 선언 후 변경 불가
sumMargin 숫자값 0 리스트 항목의 마진값 선언 후 변경 불가
movePx 숫자값 1 스크롤 거리(px) 선언 후 변경 불가
startNum 숫자값 2 추후 설명 선언 후 변경 불가
interval 숫자값 25 스크롤 간격(ms) 선언 후 변경 가능
isInverse true 또는 false false 역방향 스크롤 여부 선언 후 변경 가능
stopDuration 숫자값 0 요소 변경시 멈출 시간(ms) 선언 후 변경 가능

오브젝트 선언 후에도 변경이 가능한 interval, isInverse, stopDuration 변수는 아래 예처럼 사용됩니다.

so1 = new scrollObj("scrollTest"); so1.isInterval = 50; so1.isInverse = true; so1.stopDuration = 1000;

하지만 이렇게 자유롭게 변경할 수 없는 인수들은 오브젝트 선언시 그 값을 정확히 지정해야 합니다. 예를 들어서 스크롤 거리를 2px로 지정하려면 다음과 같이 오브젝트가 선언되어야 합니다.

so1 = new scrollObj("scrollTest", false, 0, 2);

주의 사항

리스트 항목 요소들 사이에 마진(margin) 값이 존재할 경우에는 오브젝트 선언 시 이동 방향의 양쪽 마진을 합한 값을 sumMargin 인수에 넣어주여야 합니다. 만약 isVerticaltrue이고(수직 스크롤) margin이 있을 경우에는 마진이 합쳐지는 현상(collapsing-margins)도 고려해야 합니다. 예를 들어서 아래와 같은 스타일이 적용될 경우에 sumMargin 값은 20이 아니라 10이 되어야 합니다.

 #scrollTest li { margin: 10px 0; }

오브젝트 선언 시 사용되는 startNum 인수는 실제 보여질 화면 영역 왼쪽에 존재할 리스트 항목 요소의 수를 결정합니다. 예를 들어서 startNum이 기본값인 2라면 앞서 들었던 예처럼 리스트의 첫 번째 요소(“11111”)가 실제로는 두 번째 요소로 바뀐 상태에서 스크롤이 시작됩니다. 이 부분은 특히 역방향 스크롤에서 리스트 요소의 수가 적고 각각의 항목들 크기가 많이 차이날 때 중요한 역할을 합니다. 가급적이면 리스트 항목 요소들의 수를 충분히 확보한 상태에서 스크롤 효과를 주는 것이 좋습니다.

적용 예

scrollObj 데모 페이지에서 실제로 적용된 예를 보실 수 있습니다. 페이지 중앙에 있는 수평 텍스트 스크롤, 우측의 수직 텍스트 스크롤, 하단의 수평 이미지 스크롤이 모두 scrollObj로 구현되었습니다.

다운로드

아래 링크를 클릭하면 js 확장자를 가진 파일을 받으실 수 있습니다.

자바스크립트 스크롤러 다운로드 [4.66kB]

마치며

기존에 포스팅한 DOM 스크립트: 이미지 스크롤러를 다양한 용도로 사용할 수 있도록 수정하면서 내용이 많이 바뀌었습니다. 가장 큰 변화로는 기존 함수 기반의 소스를 오브젝트 기반으로 바꾼 것인데 그렇게 해서 전역 변수를 추가적으로 선언해야 하는 불편함을 없앴습니다. 범용성도 높이고요.

기존 소스에 비해서 오류 처리 부분이라든가 주석 처리가 많이 나아졌지만 충분한 테스트를 거치지 않았기 때문에 알 수 없는 문제가 있을 수도 있습니다. 혹시 이런 문제를 발견하시면 꼭 알려주세요.

댓글 1개가 달렸습니다. 태그: , , ,

float을 제거하는 방법(clearing float)

앞서 CSS로 이미지 정렬하기라는 글에서 CSSclear 속성으로 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 규격에 따라서 heightauto로 간주된다는 점도 중요합니다.

아래 예는 이미지가 포함된 단락(paragraph)에 overflow 속성을 적용하지 않은 경우입니다.

test imageLorem 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; 속성을 적용하면 아래처럼 그 차이를 확인할 수 있습니다.

test imageLorem 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에서는 overflowLayout을 갖게 만들어서 같은 효과를 냅니다. 하지만 IE6 이하 버전에서는 overflowLayout을 갖게 할 수 없기 때문에 Holly hack이 필요한 것이지요.

† IE7이 overflow 속성을 CSS 표준대로 적용시키는지는 잘 모르겠습니다. 하지만 아무래도 CSS 표준보다는 Layout을 갖게 만드는 역할만 하는 것이 아닐까 생각되네요.

:after CSS 가상 요소(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 속성을 사용하는 것과 같습니다. 단지 cleardivbr을 사용하지 않고 CSS가 자동으로 생성하는 컨텐츠를 사용하는 것만 다를 뿐이지요. 일반적으로 사용되는 CSS 규칙은 아래와 같습니다.

.layoutFix:after{
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}

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) 태그 사용에 대해 알아볼게요.

float 관련 글 안내

  1. CSS로 이미지 정렬하기
  2. hasLayout 속성과 홀리 핵(Holly hack)
  3. float을 제거하는 방법(clearing float)

댓글 8개가 달렸습니다. 태그: , , ,

UTF-8 인코딩에서의 BOM(Byte Order Mark) 문제

다양한 언어를 표현할 수 있도록 해주는 유니코드(Unicode) 인코딩에는 여러가지 방식이 있습니다. 최근 웹 환경에서 많이 쓰이는 UTF-8을 비롯해서 UTF-16, UTF-32 등이 이런 인코딩 방식을 나타내지요.

이렇게 비슷한 방식을 사용하는 문서는 Byte Order Mark(BOM)로 구별이 됩니다. 문서 맨 앞에 눈에 보이지 않는 특정 바이트(byte)를 넣은 다음 이것을 해석해서 정확히 어떤 인코딩 방식이 사용되었는지 알아내는 방법이지요.

그런데 UTF-8 인코딩 방식에서는 BOM이 문제를 일으킬 수 있습니다. BOM이 무엇이고 왜 문제를 일으키는지, 그리고 어떻게 해결해야 하는지 알아보겠습니다.

BOM의 용도와 종류

BOM은 인코딩된 문서 첫 머리에 사용되어 정확한 인코딩 방식을 알려주는 역할을 하는데 대표적인 인코딩 방식과 그에 따른 BOM 목록은 아래 표와 같습니다.

인코딩 방식 Byte Order Mark(BOM)
UTF-8 EF BB BF
UTF-16 Big Endian FE FF
UTF-16 Little Endian FF FE
UTF-32 Big Endian 00 00 FE FF
UTF-32 Little Endian FF FE 00 00

예를 들어서 문서 처음 2개의 바이트가 FE FF로 시작되면 그 문서는 UTF-16 Big Endian으로 해석되고, 반대로 FF FE로 시작되면 UTF-16 Little Endian으로 해석되는 것이지요.

그런데 UTF-8은 다른 인코딩 방식과는 다르게 BOM의 순서가 EF BB BF로 정해져 있습니다. 그래서 이 BOM은 바이트 순서와(Byte Order) 상관없기 때문에 UTF-8 Signature라고 불리지요. 즉, 해당 문서가 UTF-8로 인코딩되었다는 사실을 알리는 사인(signature)입니다.

UTF-8 BOM으로 생기는 문제

UTF-8은 인코딩 형식이 고정되어 있기 때문에 BOM이 없어도 인코딩 방식을 자동으로 알아낼 수 있습니다. 따라서 실제로는 BOM이 불필요하지요.

하지만 일부 윈도우즈 프로그램(메모장 같은)은 UTF-8 파일을 생성할 때 자동으로 BOM을 집어넣습니다. 윈도우즈 환경에서는 눈에 띄지 않는 경우가 많지만 리눅스(LINUX)나 유닉스(UNIX) 환경에서는 많은 문제를 일으키는 원인이 되지요.

대표적인 예로 PHP에서 include 구문을 사용할 때 생기는 여백(space)을 들 수 있습니다. 이것은 비단 BOM의 문제 뿐 아니라 웹 서버의 설정과도 관련이 있기 때문에 모든 경우에 생기는 문제는 아닙니다.

먼저 인터넷 익스플로러(이하 IE)에서 아래 두 링크를 열어보시기 바랍니다.

† 2010년 3월 20일: 아래 링크는 더 이상 유효하지 않습니다. ^^;

BOM이 있는 문서 인클루드, BOM이 없는 문서 인클루드

두 문서는 이미지를 인클루드하는 부분을 제외하면 같은 소스를 사용합니다. 인클루드되는 파일 역시 BOM 유무를 빼면 동일합니다.

따라서 브라우저에서 두 문서의 소스를 확인해 보면 전혀 차이가 없습니다. 하지만 IE에서 두 페이지는 다르게 보입니다.

† 파이어폭스는 문서 내에 BOM이 들어가도 제대로 처리합니다. 따라서 두 링크가 동일하게 보이지요. 또한 웹 서버 환경에 따라서도 문제 발생 여부가 달라집니다. 동일한 파일을 다른 서버에 올릴 경우에는 문제가 안생길 수도 있으니까요.

UTF-8 BOM 문제의 원인

이렇게 두 문서가 다르게 보이는 이유는 눈에 보이지 않는 BOM 때문입니다. 사실 두 문서는 완전히 동일하지 않거든요. 단지 이 차이가 일반적인 환경에서는 보이지 않을 뿐입니다. 하지만 인클루드 되는 파일을 헥사 에디터((hex editor)로 열어보면 아래 이미지처럼 차이가 드러납니다.

BOM이 있는 파일의 헥사 코드

test1.html에서 인클루드한 BOM이 있는 파일입니다.

BOM이 없는 파일의 헥사 코드

test2.html에서 인클루드한 BOM 없는 파일입니다.

† 급조해서 만들다 보니 img 태그에 alt 속성이 빠졌군요. 접근성 향상을 위해서 꼭 넣어주는 것이 좋습니다. ^^;

첫 번째 이미지 맨 앞에 보이는 세 개의 바이트, EF BB BFtest1.html에 들어가고, IE가 이 BOM을 제대로 해석하지 못하기 때문에 문제가 생기는 것이지요.

BOM 문제를 해결하는 방법

가장 좋은 방법은 BOM을 처음부터 넣지 않는 것입니다. 윈도우즈의 메모장 대신 BOM 설정이 가능한 전문적인 텍스트 에디터를 사용하는 것이 좋겠지요.

에디트플러스 BOM 설정

위 이미지는 텍스트 에디터로서 좋은 평가를 받고 있는 에디트플러스BOM 관련 옵션 설정 창입니다. UTF-8 Signature가 BOM을 가르키는데 선택 가능한 값과 그 의미는 아래와 같습니다.

  • Preserve existing signature: BOM이 있을 경우에만 그대로 유지합니다.
  • Always add signature: 항상 BOM을 넣습니다.
  • Always remove signature: BOM이 있으면 무조건 제거합니다.
  • Add signature if necessary: 필요할 경우에만 BOM을 넣습니다.

여기에서 ‘Always remove signature’로 지정하면 편집하는 모든 파일의 BOM이 제거됩니다. 다른 텍스트 에디터에도 비슷한 설정이 있는 경우가 많습니다. 예를 들어서 프리웨어 텍스트 에디터인 Notepad++는 옵션 설정 창의 ‘New Document’ 탭에서 인코딩 방식을 UTF-8 without BOM으로 설정하면 BOM이 없는 UTF-8 문서를 만들 수 있습니다.

마치며

지금껏 제 경험으로는 UTF-8 문서에서 BOM이 필요했던 경우는 없었습니다. 하지만 특정한 환경에서는 필요할 수도 있으니 상황에 따라 적절히 적용하는 것이 좋습니다.

여담이지만 처음 웹 표준을 접하고 홈페이지를 만들 때 웹 저작 툴인 마이크로 소프트익스프레션 웹 배타판을 사용했는데 CSS에서 * { margin: 0; padding: 0; }을 지정해도 여백이 생겨서 한참 헤맸었습니다. 알고보니 익스프레션 웹이 자동으로 넣은 BOM 때문이더군요.

댓글 19개가 달렸습니다. 태그: ,

hasLayout 속성과 홀리 핵(Holly hack)

CSS로 이미지 정렬하기에서 소개했던 CSSclear 속성을 이용하는 float 제거(clearing float)와 동일한 효과를 내는 방법은 몇 가지가 더 있습니다.

그 중 하나인 overflow 속성을 이용하는 방법을 설명하기 전에 인터넷 익스플로러(이하 IE)만의 독자적인 속성인 hasLayout에 대해서 먼저 알아보려고 하는데, 이 속성이 HTML 요소들의 레이아웃, 특히 float된 요소가 렌더링되는 방식에 크게 영향을 끼치기 때문입니다.

그러면 hasLayout 속성이란 무엇이고, 어떤 영향을 끼치는지, 그리고 어떤 방식으로 이 속성을 이용해야 하는지를 알아보도록 하겠습니다.

† 이 글은 hasLayout 속성에 관한 정보로 꾸준히 업데이트되고 있는 On having layout이라는 글을 바탕으로 작성했습니다. 따라서 이 글은 동일한 라이센스를 적용해야만 이용할 수 있도록 규정한 원문의 CCL을 따릅니다. 원문은 Holly Bergevin, Ingo Chao, Bruno Fassino, John Gallant, Georg Sørtun, Philippe Wittenbergh가 함께 작성했습니다.

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)이라고 정의하고 있습니다. 사용자가 직접 지정할 수 없고 내부적으로만 처리되기 때문입니다. 이 글에서는 LayouthasLayout 두 단어를 혼용해서 사용하는 경우가 있으니 이 점 감안하시길 바랍니다.

hasLayout 속성이 영향을 미치는 경우들

많은 개발자들이 hasLayout과 관련된 문제를 경험합니다. Layout이 특정한 요소와 그 하위 요소들의 렌더링 방식에 예측하기 어려운 영향을 끼치기 때문입니다.

이렇게 Layout 유무에 따라 발생할 수 있는 일반적인 문제점은 다음과 같습니다.

  • 흔히 발생하는 IE의 float 버그
  • 기본 속성(width, height 등)이 표준과 다르게 적용되는 박스
  • 요소와 컨테이너(container) 사이에 마진(margin)이 합쳐지는 현상
  • 리스트(ul, ol 등)를 만들 때 나타나는 다양한 현상들
  • 배경 이미지 위치를 다르게 해석하는 문제
  • 스크립트를 사용할 때 발생하는 브라우저 호환성 문제

† 원문에서는 이 목록을 간단하고(brief) 완성되지 않았다고(incomplete) 표현하고 있습니다. 다시 말해서, 다른 문제들과도 관련이 있다는 얘기입니다.

hasLayout 속성은 어떻게 지정하는가?

Layout 속성은 특이하게도 CSS를 이용해서 직접 지정할 수가 없습니다. 따라서 CSS에서는 Layout이라는 속성 자체가 사용되지 않습니다. 다만 일부 요소들은 기본적으로 Layout을 갖고(hasLayout = true), 특정한 CSS 규칙이 적용될 경우에도 Layout을 가질 수 있습니다.

기본적으로 Layout을 갖는다고 알려진 요소
  • <html>, <body>
  • <table>, <tr>, <th>, <td>
  • <img>
  • <hr>
  • <input>, <button>, <select>, <textarea>, <fieldset>, <legend>
  • <iframe>, <embed>, <object>, <applet>
  • <marquee>
Layout을 갖게 만드는 CSS 속성
  • position: absolute
  • float: left|right
  • display: inline-block
  • width: ‘auto’ 외의 모든 값
  • height: ‘auto’ 외의 모든 값
  • zoom: ‘normal’ 외의 모든 값 (IE 전용)
  • writing-mode: tb-rl (IE 전용)
  • overflow: hidden|scroll|auto (IE7만 적용됨)
  • overflow-x|-y: hidden|scroll|auto (IE7만 적용됨)

† 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을 대체하려면 다음과 같은 코드를 사용하면 됩니다.

<!--[if lt IE 7]>
<style>
.gainlayout { height: 0; }
</style>
<![endif]-->

<!--[if IE 7]>
<style>
.gainlayout { zoom: 1; }
</style>
<![endif]-->

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)에게는 height0으로 지정하고, height 속성이 문제를 일으킬 수 있는 IE7에는 zoom 속성을 적용시켜서 Layout을 갖게 만듭니다. 또한, 앞으로 발표될 IE 브라우저에서 Layout 속성을 어떻게 처리할 지 모르기 때문에 가급적이면 IE만의 방법인 conditional comment와 zoom 속성을 사용하는 것이 보다 나은 방법이라고 설명하고 있습니다.

마치며

원문은 이 글보다 훨씬 많은 내용을 담고 있습니다. 내용을 요약하는 과정에서 오역이 있을 수도 있다는 점 감안하시길 바래요. 또한, 원문에 링크된 다양한 글은 제목만 봐도 유용한 정보라는 것이 느껴질 정도입니다. IE에서 레이아웃 문제로 어려움을 겪는다면 관련 글들이 큰 도움이 되리라 생각합니다.

제 경험으로는 Layout과 관련된 대부분의 문제가 Holly hack만으로도 간단히 해결되더군요. 그래서 Holly hack에 관한 내용을 중점적으로 다루었습니다. 다음 글에서 Layout 속성과 overflow 속성을 이용해서 float 효과를 제거하는 방법(clearing float)에 대해서 알아보지요.

  1. CSS로 이미지 정렬하기
  2. hasLayout 속성과 홀리 핵(Holly hack)
  3. float을 제거하는 방법(clearing float)

댓글 5개가 달렸습니다. 태그: , , ,

CSS로 이미지 정렬하기

엄격한(Strict) 문서 규격 정의(DTD)에서는 이미지 정렬에 흔히 사용되던 align 속성을 허용하지 않습니다. 따라서 img 태그만으로는 이미지의 위치를 자유롭게 조절할 수 없고, 반드시 CSS를 함께 사용해야만 합니다.

단순히 하나의 이미지만 넣어야 할 경우에는 text-align이라는 CSS 속성으로 간단히 해결할 수 있지만 현실적으로는 이보다 훨씬 복잡한 경우가 많습니다. 특히 이미지와 텍스트를 함께 배치하려면 어쩔 수 없이 float 속성을 사용해야 하는데 이 속성에 대한 해석이 브라우저에 따라 차이가 있으므로 브라우저 호환성 면에서 생각보다 훨씬 많은 위험성을 갖고 있습니다. 이렇게 까다로운 이미지 태그를 잘 사용하기 위해 알아두어야 할 점과 float 속성으로 이미지를 정렬하는 방법에 대해서 정리해봤습니다.

† 앞으로 제시할 모든 예는 noimgstyle class가 적용된 div 안에 넣었고, 기본적으로 적용된 속성은 아래와 같습니다. 그 외의 모든 CSS 규칙은 인라인 스타일로 정의했으므로 소스를 확인하면 각 예에 적용된 속성을 확인할 수 있습니다.

.noimgstyle { border: 1px solid #699; padding: 1em 1em 0 1em; margin-bottom: 1em; line-height: normal; height: 1%; }
.noimgstyle img { border: none; margin: 0; padding: 0; display: inline; }
.noimgstyle p { text-align: justify; margin-bottom: 1em; }
.noimgstyle span { background-color:#666; color: #fff; }

인라인(inline) 레벨 요소인 img 태그

일반적으로 이미지는 직사각형의 영역을 갖고 있습니다. 따라서 div, p, blockquote 등의 태그처럼 블록(block) 레벨에 속한다고 착각하기 쉽지만 실제로는 일반 텍스트와 동일한 인라인 요소입니다. 따라서 특별한 처리 없이 사용될 경우 아래 예처럼 텍스트의 한 글자처럼 취급됩니다.

글자처럼 test image 취급되는 test image image

그런데 동일한 인라인 요소임에도 줄이 제대로 맞지 않는 것을 볼 수 있습니다. 이것은 알파벳의 g, p, y 등의 문자에서 베이스라인 아래로 내려오는 꼬리(descender)를 위한 영역 때문입니다. 즉, 이미지를 꼬리가 없는 i 문자처럼 취급한다는 얘기지요.

이 사이 간격을 없애는 방법은 많이 알려져 있습니다. 첫 번째는 이미지를 감싸는 상위 요소(div 등)의 높이를 이미지와 같도록 해주는 것이고, 두 번째는 CSS의 vertical-align: text-bottom 속성을 지정하는 것입니다. 이미지를 블록(block) 요소로 보이도록 하는 세 번째 방법은 나중에 알아보고 일단 vertical-align: text-bottom 속성을 적용한 이미지를 보겠습니다. CSS를 인라인 스타일(inline stye)로 지정했으므로 소스를 확인하면 바뀐 부분을 확인할 수 있습니다.

글자처럼 test image 취급되는 test image image

† 인라인 이미지와 텍스트의 배치를 결정해주는 vertical-align 속성에는 많은 브라우저 호환성 문제가 있습니다. 특히 line-height 속성과 결합되면 심각한 문제가 생길 수 있다고 하네요. 일반적으로 발생하는 문제가 아니기에 추가적으로 설명하지는 않겠습니다. 어떤 문제가 있는지 알아보려면 이미지 수직 정렬과 line-height와의 관계긴 이미지와 line-height와의 관계 페이지를 인터넷 익스플로러와 파이어폭스에서 비교해 보시기 바랍니다.

블록(block) 레벨 요소로 보이는 이미지

이미지를 인라인 요소가 아닌 블록 요소로 보여지도록 해야 할 경우가 있는데 이 때 사용되는 것이 CSS의 display 속성입니다. 먼저 알아두어야 할 것은 이 속성이 HTML 요소가 어떻게 보여질지만을 바꿀 수 있다는 점입니다. 다시 말해서 인라인 요소를 블록 요소로 바꾸어주는 것이 아니라는 것이지요. 간단한 예를 들자면 HTML 규격상 인라인 레벨 요소는 블록 레벨 요소를 포함할 수가 없습니다. 따라서 인라인 요소인 span 태그에 display: block; 속성을 지정한다고 해도 span 태그 안에 p 태그는 들어갈 수 없습니다.

하지만 인라인 요소를 블록 요소로 보이게(display) 하면 이미지 위, 아래에서 줄바꿈(line break)이 생깁니다. 아래 예는 이미지에 display: block; 속성이 적용되었을 때의 결과입니다.

블록으로 test image 취급되는 test image image

† 이미지와 텍스트에 적용되는 line-height 속성 때문에 서로 다른 요소가 일부 겹치는 경우가 있습니다. line-height 속성 값을 바꾸어도 문제가 해결되지 않는다면 Designer kukie 님의 오늘의 문제는 line-height라는 글을 참고하시기 바랍니다. 이 문제로 한참을 헤매다가 kukie님이 잘 정리해두신 덕에 해결했습니다. :-)

인라인 이미지 정렬

인라인 이미지는 텍스트와 동일하게 취급되므로 텍스트 정렬에 사용되는 CSS의 text-align 속성이 그대로 적용됩니다. 따라서 중앙 정렬시키려면 이미지를 감싸고 있는 p 태그에 text-align: center;를 지정하고, 오른쪽으로 보내려면 text-align: right;를 사용할 수 있습니다. 아래는 가운데 정렬의 예입니다.

글자처럼 test image 취급되는 test image image

text-align 속성은 블록 레벨 요소와 테이블 셀(table cell: th, td), 인라인 블록(inline-block)에 적용되고, 해당 요소가 아닌 하위 요소에 영향을 미칩니다(예: 텍스트).

그런데 이미지가 이런 방식으로 텍스트와 함께 사용되는 경우는 드뭅니다. 보통은 이미지 아래에 텍스트가 들어가거나 이미지 옆 공간에 글 단락이 들어가니까요. 텍스트가 아래 배치될 경우에는 p 태그에 이미지만 넣거나 이미지를 블록 레벨로 보이게 하면 되지만 후자의 경우에는 문제가 복잡해집니다. 그럼 왜 문제가 복잡한지 알아볼까요?

이미지에 float 적용하기

이미지 옆에 텍스트 단락을 넣기 위해서는 이미지에 CSS의 float 속성을 주어야만 합니다. 과도적인(Transitional) HTML 문서 규격에서는 이미지에 align 속성을 사용할 수 있지만 엄격한(Strict) 문서 규격에서는 허용되지 않은 속성이기 때문입니다.

먼저 이미지에 float: left; 속성만 적용시킨 예를 보겠습니다. 단락 구분이 잘 보이도록 p 태그에 테두리선을 넣었습니다.

test imageLorem 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 속성이 사용되어야 한다는 것입니다. 아래 예가 이 요건을 갖춘 경우입니다.

<p><img src="somepath" style="float:left" />some text<br style="clear:both" /></p>
<p>some text</p>

하지만 아래와 같이 마크업할 경우에는 브라우저에 따라서 다른 결과가 생깁니다. 이미지를 담고 있는 요소(containing block)은 첫 번째 p 단락인데 clear 속성은 p 단락 밖에서 적용되었으니까요.

<p><img src="somepath" style="float:left" />some text</p><br style="clear:both" />
<p>some text</p>

두 번째 요건은 인터넷 익스플로러에만 해당되는 것으로 float 요소가 포함된 블록(containing block)이 화면상에서 레이아웃을 갖는 요소(haslayout = true)로 인식되어야 합니다. float 문제는 주로 페이지의 레이아웃을 잡을 때 나타나는데 대부분의 경우 float을 포함하는 divwidthheight 속성을 지정하면서 자동으로 이런 요건을 갖춥니다. 하지만 아래 예처럼 이런 속성이 지정되지 않은 p 태그 안에서는 clear 속성이 인터넷 익스플로러에서만 다르게 적용됩니다. 즉, 인터넷 익스플로러에서는 파이어폭스에서와는 달리 p 태그 높이가 이미지 높이만큼 자동으로 늘어나지 않는 것을 볼 수 있지요.

test imageLorem 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를 적용시키면 문제가 해결됩니다. widthheight 중 어느 하나라도 정해지면 haslayout 속성이 적용되기 때문입니다.

p { height: 1%; }

float된 이미지의 옆 공간을 채우기 위해서 br 태그를 여러 개 이어서 사용하는 경우가 있는데 좋은 방법이 아닙니다. 그보다는 CSS에 clear를 담당하는 class를 지정해놓고 필요할 경우 적용시키는 것이 좋지요. 흔히 이용되는 코드는 다음과 같습니다.

.clearer { clear: both; }
<br class="clearer" />
<div class="clearer"></div>

한 가지 주의해야 할 점은 <div class="clearer"></div>가 만능은 아니라는 사실입니다. HTML의 컨텐츠 모델에 따라서 동일한 블록 레벨 요소라 해도 p 태그 안에는 div 태그가 들어갈 수 없으므로 상황에 따라서 적절한 태그를 골라서 적용시켜야 합니다.

간단한 방법이지만 float 제거만을 위한 마크업이 추가된다는 단점이 있습니다. 게다가 이미지 옆에 여러 개의 단락이 들어가야 할 경우에는 사용할 수가 없지요. 또한, 위 예처럼 두 개의 단락이 p 태그로 명확하게 구분되어 있을 경우에는 br 태그를 사용할 필요가 없으므로 ‘의미 있는’ 마크업도 아닙니다.

clear 속성이 적용되는 방식

W3Cclear 속성에 관한 CSS 규격에는 다음과 같이 정의되어 있습니다.

clear 속성은 적용된 요소의 어느쪽 박스 경계가 이전에 float된 박스와 인접하지 않을지를 결정한다. 이 속성은 float된 요소 자체에도 적용되나 이 경우 clear의 효과는 나타나지 않는다.”

clear 속성이 left로 지정되면 clear가 적용된 요소의 박스 상단 마진(margin-top)이 위에 있는 왼쪽으로 떠 있는(left-floating) 박스의 아래 경계에 닿을 수 있도록 늘어나게 된다.”

이런 상황을 잘 설명해주는 이미지를 float 속성에 관한 CSS 규격에서 가져왔습니다.

그림에서 볼 수 있듯이 두 번째 p 블록에 clear 속성이 적용되면 이미지 크기로 인해 생긴 공간만큼 p 블록의 위쪽 마진(margin-top)이 자동으로 늘어나게 되고, 그 결과 블록이 이미지 아래로 내려오게 됩니다. 그러면 실제 예를 볼까요?

<p><img src="somepath" style="float:left" />some text</p>
<p style="clear:both">some text</p>

결과는 아래와 같습니다.

test imageLorem 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 제거 방법과 그 외의 방법도 소개하겠습니다.

  1. CSS로 이미지 정렬하기
  2. hasLayout 속성과 홀리 핵(Holly hack)
  3. float을 제거하는 방법(clearing float)

댓글 11개가 달렸습니다. 태그: , ,

img 태그에 width와 height 속성이 필요한 이유

앞서 포스팅한 HTML Transitional과 Strict 규격 비교라는 글에서 엄격한 문서 타입(Strict DTD)에서는 ‘표현(presentation)’을 담당하던 속성들이 대부분 사라졌다고 알려드린 바 있습니다.

하지만 일부 태그에는 여전히 표현을 나타내는 속성이 남아있는데 그 중의 하나가 imgobject 태그에 사용되는 width, height 속성입니다. W3C가 이 속성들을 삭제하지 않은 이유를 이미지의 가로와 세로 크기를 지정하는 것이 페이지 로딩 속도 향상에 도움이 되기 때문이라고 설명하기도 합니다. 하지만 그런 효과는 부수적으로 얻어지는 것이고, 해당 속성이 필요한 근본적인 이유는 아니지요. 그럼 왜 img 태그에 widthheight 속성이 필요한지 알아볼까요?

브라우저가 HTML 문서를 해석하는 방식

브라우저가 HTML 문서를 어떻게 해석하는지에 대해서는 블로깅 툴간의 속도 차이라는 글에서 간단히 설명한 적이 있습니다. 중복을 피하기 위해서 일부를 인용하도록 하겠습니다.

“먼저 브라우저가 원하는 페이지를 전송해달라고 웹 서버에 요청하게 됩니다. 그러면 웹 서버가 이에 대한 응답으로 해당 페이지의 html 문서를 브라우저에게 전송합니다. 브라우저는 전송된 html 문서를 해석해서 페이지 출력(렌더링)에 필요한 CSS, 이미지, 스크립트 파일 등을 순차적으로 다시 웹 서버에 요청하고 그 결과를 받아옵니다. 그러면서 동시에 페이지를 그려나는데 이렇게 필요한 자원에 대한 요청과 전송, 렌더링이 동시에 이루어지기 때문에 이미지가 많이 포함된 페이지도 빠르게 화면에 표시됩니다.”

즉, HTML 문서를 해석하다가 img 태그를 발견하기 전까지는 이미지 파일이 브라우저에게 전송되지 않습니다. 하지만 이미 전송된(또는 전송중인) HTML 문서는 즉시 해석되고 화면에 출력되는데 이 과정에서 약간의 문제가 발생할 수 있지요.

페이지에서 이미지가 차지하는 영역

이미지가 많고 전송 회선이 느린 페이지를 열 경우에 이미지가 로딩되면서 페이지 길이가 계속 늘어나는 경우를 볼 수 있습니다. 스크롤바를 내려서 원하는 텍스트로 이동한 다음에도 계속 화면이 늘어나므로 불편함을 느낄 수도 있지요.

하지만, HTML 문서에 직접 이미지의 widthheight 속성을 지정했다면 얘기는 달라집니다. 브라우저가 HTML을 로딩하는 순간 이미 각각의 이미지가 차지하는 영역을 알고 있으니까요. 즉, 처음부터 문서의 길이를 모든 이미지를 수용할 수 있을 만큼 늘려서 렌더링한다는 얘기입니다.

또한, 브라우저가 이미지가 차지할 영역을 알고 있으면 문서 안에 책갈피(bookmark, anchor)를 넣을 경우 원하는 위치로 정확히 이동할 수 있습니다. 예를 들기 위해서 의미 없는 텍스트(dummy text) 사이에 이미지와 책갈피를 넣은 두 페이지를 준비했는데 실질적인 HTML 소스 상의 차이는 이미지의 widthheight 속성뿐입니다.

먼저 첫 번째 페이지에 포함된 이미지에는 widthheight 속성을 지정했습니다.

<img src="http://blog.wystan.net/images/42.png" width="180" height="120" />
<h4 id="withdimension">책갈피1: width, height 지정</h4>

속성을 지정하지 않은 두 번째 페이지 소스는 아래와 같습니다.

<img src="http://blog.wystan.net/images/43.png" />
<h4 id="withoutdimension">책갈피2: width, height 미지정</h4>

속성을 지정한 페이지지정하지 않은 페이지를 각각 클릭해보면 이동하는 위치에 차이가 있는 것을 알 수 있습니다. 일단 이미지가 로딩된 후에는 웹 서버에 있는 파일 대신 로컬 컴퓨터에 저장된 캐시(cache) 파일을 이용하므로 캐시를 비우지 않으면 처음과는 다른 결과나 나타납니다.

각각의 페이지 책갈피를 열였을 때 보여지는 브라우저 화면 맨 윗부분을 동일한 영역으로 캡처한 이미지는 아래와 같습니다.

img 태그에 width와 height를 적용한 경우 img 태그에 width와 height를 적용하지 않은 경우

왼쪽 이미지에서 볼 수 있듯이 가로와 세로 길이를 지정하면 책갈피로 이동하는 시점에서 이미지가 차지할 영역을 미리 계산하기 때문에 원했던 결과를 얻을 수 있습니다. idwithdimensionh4 태그로 정확하게 이동하지요.

오른쪽 이미지는 widthheight 속성을 지정하지 않았기 때문에 브라우저가 이미지의 크기를 알 수 없습니다. 이미지의 크기를 알 수 없어서 높이가 없다고 가정하고 페이지를 렌더링한 다음 실제로 이미지를 전송받고 화면에 표시하려다 보니 이미지 높이 만큼 아래로 밀려난 것이지요. 결과적으로 의도했던 withoutdimension 책갈피로 이동하지 못했습니다.

† 이 상태에서 페이지를 다시 읽으면(새로 고침) 이미지가 캐시 파일로 저장되었기 때문에 의도했던 곳으로 이동합니다. 또한, 이미지 상단의 테두리(border-top)가 표시되지 않는 것으로 봐서 이미지 크기가 지정되지 않으면 CSS의 border 속성이 적용되지 않는 것도 확인할 수 있습니다.

페이지 로딩 속도에 미치는 영향

이미지의 크기를 미리 알면 브라우저가 크기 정보를 파일에서 얻어 올 필요가 없어집니다. 하지만 이 과정에 소모되는 시간은 문서를 해석하고 렌더링하는데 걸리는 시간에 비교한다면 무시할 수 있을 정도라고 생각합니다. 실질적으로 로딩 속도 향상을 가져오는 것은 페이지에서 갱신되어야 하는 부분이 상대적으로 적기 때문이리라 판단됩니다.

페이지 렌더링은 먼저 컴퓨터의 메모리(RAM)에서 이루어집니다. 메모리에서 화면에 출력될 부분이 그려진 다음 이 부분이 그래픽 카드(VGA) 메모리에 복사되고 최종적으로 모니터 화면에 출력되는 것이지요. 이 과정에서 이미지 크기에 따라 화면이 계속 늘어나므로 갱신될 부분이 많아지고, 필연적으로 많은 연산이 필요하게 됩니다. 따라서 img 태그에 widthheight 속성을 지정하면 페이지 로딩 속도를 향상시킬 수 있는 것이지요.

† 이 부분은 정확한 정보가 아닌 추측입니다. 정확한 정보를 아시는 분들은 꼭 알려주세요.

마치며

W3C의 규격을 완벽하다고 할 수는 없지만 그렇다고 해서 아무렇게나 만들어진 것은 아닙니다. 나름대로 충분한 합리성을 갖고 있지요. img 태그에 widthheight 속성을 반드시 지정해야 하는 이유도 이런 합리성에 기초합니다. 비록 문서의 표현을 담당하는 속성이지만 현실적으로 꼭 필요하기 때문에 남겨둔 것이지요. 그러니 조금 불편하더라도 꼭 지정해 주는 것이 좋습니다.

또한, 현실적인 기능을 고려하지 않고 표현에 관한 속성이라는 이유만으로 ‘의미 있는’ 마크업에 반한다고 생각해서 사용하지 않는 것은 ‘웹 표준’의 진정한 의미를 잘못 해석하는 것이라 생각합니다. 각각의 태그와 속성이 갖고 있는 의미와 용도를 올바르게 이해하고 사용하는 것이 무엇보다 중요하니까요. 문서의 구조와 표현을 분리하려는 목적은 이 과정에서 자연스럽게 얻어지는 것이 아닐까요?

다음 글에서는 CSS를 사용해서 이미지를 정렬하는 방법에 대해서 다루겠습니다.

댓글 2개가 달렸습니다. 태그: , ,

HTML Transitional과 Strict 규격 비교

‘웹 표준’에 관한 흔한 오해 중의 하나는 HTML 대신에 XHTML을 사용하면 웹 표준을 더 잘 지킬 수 있다는 생각입니다. XHTML을 사용하면 문서의 ‘표현’‘구조’를 분리할 수 있고, 그래서 보다 ‘의미 있는’ 마크업이 가능하다는 주장도 있는데 이것 역시 사실이 아닙니다.

실제로 ‘의미 있는’ 마크업을 위해서는 XHTML과 HTML 중 어느 것을 사용했느냐가 아니라 어떤 문서 타입 정의(DTD)을 사용하느냐가 절대적으로 중요합니다. (X)HTML 문서는 크게 ‘Transitional(과도적인)’ 타입과 ‘Stict(엄격한)’ 타입으로 나눌 수 있는데 이 두 DTD가 어떻게 다른지 그 차이점을 간단히 알아보고, 웹 표준을 위해서 왜 엄격한 문서 타입이 권장되는지를 알아보도록 하겠습니다.

문서 타입 정의(DTD) 요약

HTML 4.01XHTML 1.0 규격은 각각 세 가지의 문서 타입 정의를 동일하게 갖고 있습니다.

DTD HTML 4.01 XHTML 1.0 비고
Strict HTML 4.01 Strict XHTML 1.0 Strict 엄격한 규격
Transitional HTML 4.01 Transitional XHTML 1.0 Transitional 과도적인 규격
Frameset HTML 4.01 Frameset XHTML 1.0 Frameset 프레임 사용 가능

XHTML 1.0은 HTML 4.01 규격을 XML에 맞춰 재해석한 규격이므로 약간의 문법 차이를 제외하면 사실상 차이가 없습니다. 따라서 앞으로는 XHTML과 HTML의 문서 타입 정의(DTD)를 따로 구분하지 않겠습니다. XHTML과 HTML의 차이점에 대해서는 앞서 포스팅한 XHTML과 HTML의 차이를 참고하시기 바랍니다.

Strict, Transitional DTD

W3C가 제안한 HTML 규격의 DTD 항목에는 다음과 같이 설명되어 있습니다.

“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 태그로 대체되었습니다.

사라진 속성(attribute)들
  • align : tabel 관련 태그에서만 허용됨(col, colgroup, tbody, td, tfoot, th, thead, tr).
  • language
  • background
  • bgcolor
  • border : table 태그에서만 허용됨.
  • height : img, object 태그에서만 허용됨.
  • hspace
  • name : HTML 4.01 Strict에서는 허용되지만, XHTML 1.0 Strict의 form, image 태그에는 허용되지 않음.
  • noshade
  • nowrap
  • target
  • text, link, vlink, alink
  • vspace
  • width : img, object, table, col, colgroup 태그에서만 허용됨.

보시는 바와 같이 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 태그의 사용법을 앞으로의 포스팅 주제로 삼을 생각입니다. 물론 자주 올리지는 않겠지만요. ^^;

댓글 4개가 달렸습니다. 태그: , , ,

태터툴즈로 웹 표준 지키기

‘웹 표준’에 관한 관심이 높아지면서 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님 블로그를 통해서 그 생각이 틀렸음을 알았답니다.

댓글 4개가 달렸습니다. 태그: , , ,

컨텐츠 관리 시스템(CMS) 소개

블로깅 툴을 얘기하다 보면 심심찮게 등장하는 CMS(Content Management Systme)란 용어는 무엇을 의미할까요?

일단 사전적인 의미로는 컨텐츠를 관리하는 시스템을 말합니다. 그런데 의미가 너무 포괄적이지요. 사실 CMS에 대한 정의는 명확하지가 않습니다. 특정한 규격이 정해져 있는 개념도 아니고요. 처음부터 CMS라는 정의하에 만들어진 것이 아니라 컨텐츠를 효율적으로 관리하기 위한 여러가지 방법들이 개발되면서 포괄적으로 CMS란 용어가 정립된 것이기 때문입니다.

그러므로 CMS의 의미를 알기 위해서는 컨텐츠란 무엇이고, 왜 컨텐츠를 관리할 필요가 생겨났는지, 그리고 어떤 방법들이 도입되었는지 알아야 합니다. CMS에 대한 설명을 담고 있는 위키피디아 문서CMS 솔루션 개발 업체인 콘텐츠와이즈에서 제공하는 PDF 문서를 참고로 해서 정리해봤습니다.

컨텐츠(Content)란?

‘컨텐츠’‘내용물’이라는 뜻으로 상당히 포괄적인 용어입니다. 하지만 일반적으로 컴퓨터나 인터넷 분야에서는 ‘컴퓨터 파일’, ‘이미지나 오디오 등의 멀티미디어 파일’, ‘전자 문서’, ‘웹 컨텐츠’ 등을 말합니다. 현재는 웹(World Wide Web)의 성장과 더불어서 ‘웹 컨텐츠’가 다양한 멀티미디어 파일과 전자 문서를 포괄하는 개념으로 확대되었지요. 넓은 의미의 ‘웹 컨텐츠”HTML를 이용하는 모든 문서와 서비스(블로그, 게시판, 검색 엔진 등), 그리고 그 안에 포함된 모든 파일과 데이타를 뜻합니다.

컨텐츠 관리의 시작

초기의 CMS는 기업에서 서로 다른 부서간에(inter-office) 네트웍(또는 웹)을 통해서 컨텐츠를 공동으로 이용할 목적으로 시작되었습니다. 많은 기업들이 공통 양식(non-proprietary form)으로 만들어진 문서들의 저장소(archival)로 CMS를 활용했는데 서버 기반의 소프트웨어로 운영되었기 때문에 이런 문서들을 쉽게 공유할 수 있기 때문이었지요.

웹의 중요성이 커지고 웹 컨텐츠나 웹 사이트 관리의 비중이 높아지면서 ‘웹 컨텐츠 관리 시스템(Web Content Management System)’이 도입되었는데 WCMS에는 웹 관련 작업의 효율성을 높여주는 다양한 기능들이 추가되었습니다. 엄밀하게 말해서 CMS는 WCMS를 포함하는 상위 개념이지만 최근에는 WCMS의 대체 용어로 많이 사용됩니다.

† 앞으로의 글은 WCMS에 초점을 맞추고 있습니다. 따라서 CMS란 용어는 WCMS를 의미합니다.

컨텐츠 관리가 필요한 이유

초기의 웹 문서와 웹 사이트는 HTML 마크업을 문서 편집기(text editor)로 입력해서 만들어졌습니다. 따라서 관련 기술에 대한 전문적인 지식 없이는 웹 컨텐츠를 만들기가 어려웠지요. 예를 들어서 기업에서 판매하는 제품의 사용자 매뉴얼을 웹에 게시하려면 먼저 실무자가 매뉴얼을 일반 문서 형식으로 만들고 상급자나 경영진의 승인을 받은 다음 웹 사이트를 관리하는 담당자에게 전달하면 웹 관리자는 이 문서를 HTML 형식으로 바꾸고 FTP 등을 이용해서 올리는(upload) 과정을 거쳐야만 했습니다.

전체적인 효율을 높이려면 누구나 쉽게 문서를 만들거나 수정하고 게시할 수 있어야 하는데 바로 이것이 CMS의 핵심 기능입니다. 많은 블로깅 툴이 CMS 툴(소프트웨어)로도 분류되는 것은 바로 이런 핵심 기능을 지원하기 때문인데 예를 들어서 태터툴즈워드프레스는 직접 HTML 마크업을 입력할 필요 없이 브라우저 내에서 이지윅(WYSIWYG (What You See Is What You Get)) 편집기로 쉽게 문서를 작성할 수 있도록 해줍니다. 완성된 문서는 버튼 하나만 클릭하면 FTP 프로그램 없이도 웹에 올릴 수 있지요.

CMS가 지원하는 기능

CMS는 일반적으로 새로운 소식을 알리는 글이나 관리자 매뉴얼, 기술 문서, 판매 지침, 상품 소개 페이지와 같은 컨텐츠의 보관과 버전 관리, 배포에 주로 사용되며, 효율성 향상을 위해 다음과 같은 기능들을 지원합니다.

  • 각종 문서와 멀티미디어 자료(이미지, 오디오 비디오 등)를 작성하거나 외부에서 불러올(import) 수 있음.
  • 컨텐츠 관리에 참여하는 사용자들의 역할(role)과 권한 차이를 인식할 수 있음.
  • 컨텐츠의 형태나 분류에 따라서 사용자들의 역할과 책임을 부여할 수 있음.
  • 컨텐츠에 대한 작업 흐름(workflow)을 설정하고 필요에 따라서 컨텐츠 내용 변경시 관리자에게 알려줄 수 있음.
  • 하나의 컨텐츠에 대한 다양한 버전의 관리와 추적(tracking) 가능.
  • 컨텐츠를 쉽게 수정, 관리할 수 있도록 검색 기능이 통합된 문서 저장소에 보관하도록 함.
  • 일부 CMS는 디자인적인 요소를 제외한 텍스트 컨텐츠만을 받아들인 다음 기본 글꼴이나 색상, 레이아웃 등을 통합적으로 설정할 수 있도록 해줌.

열거한 기능 중에서 중요한 기능에 대한 보충 설명을 해봤습니다.

컨텐츠 제작

HTML을 사용하지 않고도 컨텐츠를 만드는 것은 CMS의 기본 기능입니다. 따라서 대부분의 CMS 툴이 이지윅 에디터나 Textile이나 Markdown, BBCode 등의 가벼운 마크업 언어(lightweight markup language)를 이용한 문서 작성을 지원합니다.

역할 관리

역할(role) 관리는 CMS의 핵심 기능 중 하나입니다. 아래 설명할 작업 흐름 관리와 함께 사용되며 초안(draft) 작성 권한만을 갖는 실무자가 문서를 작성하면 발행 권한이 있는 상위 관리자가 문서에 대한 수정을 요청하거나 최종 배포를 결정하는 방식이지요. 간단한 역할 관리의 예는 이전에 포스팅한 Textpattern 사용자 타입이라는 글에서 볼 수 있습니다.

작업 흐름 관리

작업 흐름(workflow) 관리 역시 CMS의 핵심 기능으로 기업 내에서 이루어지는 오프라인 결제 시스템을 떠올리면 이해하기가 쉽습니다. 즉, 컨텐츠가 한 번의 작업으로 완성되고 게시되는 것이 아니라 여러 과정을 거치며 수정과 검토, 승인이 이루어진 다음 최종 완성본이 배포되는 것을 의미하지요. 많은 CMS 툴은 작업 흐름 관리를 위해 진행 과정을 이메일로 알려주거나, 다음 과정으로 자동 전달해주는 기능을 지원하고 있습니다.

CMS가 적용되는 곳

기본적으로 CMS는 개인 사용자를 위해 만들어지지 않았습니다. 처음부터 기업 환경의 효율성 재고를 위해 도입된 것이니까요. 또한 수시로 바뀌는 게시판 같은 커뮤니케이션 용로도로 적합하지 않습니다. CMS의 효능이 최대한 발휘되는 곳은 기업의 제품 소개나 안내 페이지 같은 정적인 정보성 페이지입니다.

CMS로서의 텍스트패턴

제가 사용중인 텍스트패턴은 공식적으로 CMS 툴임을 표방하고 있습니다. 비록 전문적인 CMS 툴로 보기에는 기능상의 한계가 있지만 기본적인 기능들은 갖추어져 있다고 생각합니다. 하나씩 열거해보지요.

  • 쉬운 문서 작성: 거의 모든 HTML 태그를 대체할 수 있는 Textile은 텍스트패턴의 큰 장점입니다. Textile에 관한 자세한 설명은 Textile 시작하기를 참고하세요.
  • 역할 관리: 앞서 설명한 기능입니다. 사용자들이 각각 권한이 다른 여섯 부류로 나누어지며 각각의 권한을 원하는대로 수정할 수도 있습니다.
  • 작업 흐름 관리: 문서를 ‘초안(draft)’, ‘숨김(hidden)’, ‘미결(pending)’, ‘발행(live)’, ‘고정(sticky)’ 상태로 저장할 수 있습니다. 또한 upm_pending_notify 플러그인을 이용하면 상태가 바뀔 때 자동으로 작성자나 승인자에게 이메일로 통보합니다.
  • 버전 관리: 자체적으로 지원하지 않지만 md_versions 플러그인을 사용하면 하나의 글을 여러 버전으로 관리할 수 있습니다.
  • 각종 파일 관리: 텍스트패턴은 글이나 댓글처럼 이미지와 파일, 링크 목록을 독립적으로 관리합니다. 관리자 페이지에서 각각의 목록을 볼 수 있으며 다양한 조건으로 검색할 수도 있습니다.

마치며

전문적인 CMS의 기능은 위에서 소개했던 것보다 훨씬 다양하고 강력하지만 이 글의 목적이 CMS를 소개하는데 있는 만큼 기본적인 기능만을 다루었습니다. CMS를 도입해서 얻을 수 있는 실질적인 이익이나 도입 전에 확인해야 할 사항은 앞서 소개한 ‘콘텐츠와이즈’ 사이트의 PDF 문서를 참고하시기 바랍니다.

댓글 1개가 달렸습니다. 태그: ,

현재 링크가 강조되는 네비게이션 메뉴

울티마 가이드 메뉴 구성

울티마 가이드 홈페이지의 네비게이션 메뉴는 왼쪽 이미지처럼 수평(horizontal) 주 메뉴와 수직(vertical) 보조 메뉴로 구성되어 있습니다. 그런데 주 메뉴의 ‘처음으로’ 항목은 오렌지색으로, 보조 메뉴의 ‘새 소식’은 밑줄로 강조된 것을 볼 수 있는데 이것은 페이지를 보는 사용자가 현재 위치를 쉽게 알 수 있도록 도와주는 역할을 하고 있습니다.

이런 기능은 강조할 현재 문서 링크에 CSS의 class 속성을 부여하는 것으로 간단히 구현할 수 있습니다. 하지만 각각의 페이지마다 링크 강조를 위한 마크업을 개별적으로 넣게 되면 전체적인 사이트 유지, 관리에 어려움이 생기게 됩니다.

일반적으로 다수의 페이지로 구성된 사이트의 경우 html 편집기(드림위버와 같은)가 지원하는 템플릿이나 PHP와 같은 스크립트 언어를 사용해서 페이지의 일부를 불러오는(include) 방식으로 관리를 하게 되는데 이런 방법으로는 메뉴에 개별적인 마크업을 넣기가 어렵습니다.

문제점을 해결하려면 강조를 담당하는 class가 자동으로 생성되도록 해야합니다. 방법은 여러 가지가 있는데 대표적인 것이 CSS 활용으로 유명한 A List Apart에 제시된 방법으로 PHP 언어로 각 페이지마다 변수를 만들고 이를 이용하는 것입니다. 하지만 이 방법 역시 개별적인 코드가 들어가는 단점이 있습니다.

다른 해결법으로는 모든 메뉴 링크에 id나 class를 미리 부여하는 방법이 있습니다. hicksdesign에서 제시한 방법으로 앞서 소개한 것과는 달리 개별적인 코드가 들어가지 않으므로 메뉴에 들어갈 항목 수가 적다면 이 방법이 가장 효율적일 수도 있습니다. 하지만 울티마 가이드의 일부 보조 메뉴처럼 스무 개 이상의 링크가 들어갈 경우에는 id나 class 부여하는 것도 상당히 번거롭더군요. ^^; 물론 이마저도 PHP 언어를 이용해서 자동으로 처리되도록 할 수 있습니다. 하지만 그보다 더 좋고 편한 방법이 있는데 지금부터 소개해보겠습니다.

요구 사항

일단 PHP 함수를 사용하기 때문에 당연히 PHP 언어가 지원되어야 합니다. 또한, 앞으로 들 예에서는 각각의 주 메뉴에 해당하는 디렉토리가 있고, 그 안에 보조 메뉴와 연결된 html 문서가 있다고 가정하겠습니다. 그런데 일반적으로 사이트의 인덱스 페이지는 웹 서버의 최상위 디렉토리(/)에 있으므로, 첫 번째 주 메뉴에 해당하는 문서들은 하위 디렉토리가 아닌 최상위 디렉토리에 있다고 생각해보지요.

예를 들어 위의 이미지에서 ‘처음으로’ 항목에 속하는 ‘새 소식(index.htm)’, ‘이용 안내(about.htm)’ 등의 문서는 최상위 디렉토리에 있고, ‘브리타니아 도서관’ 메뉴에 해당하는 모든 문서들은 하위 디렉토리인 /library에 있습니다.

PHP 코드

PHP에 익숙한 분들은 아래 코드만 봐도 어떻게 동작하는지 금방 아실겁니다. 일단 보도록 하지요.

<?php
define (INCPATH, '/path/to/include/dir');
function highlight_current($include_file, $target_str) {
	if ($target_str == 'index.htm') $target_str = './';
	$menu = file_get_contents($include_file);
	$menu = str_replace("\"" . $target_str . "\"", "\"" . $target_str . "\" class=\"current\"", $menu);
	echo $menu;
}
$target_file = basename($_SERVER['PHP_SELF']);
$target_dir = dirname($_SERVER['PHP_SELF']);
?>

처음 등장하는 define 문은 불러올(include) 메뉴 파일들이 있는 절대 경로를 선언합니다. 매번 경로 전체를 적어주기 보다 INCPATH 상수를 사용하기 위해서지요.

이어서 나오는 highlight_current 함수가 이 방법의 핵심입니다. 두 개의 인수를 필요한데 첫 번째 include_file은 불러올 메뉴 파일의 이름을, 두 번째 target_str은 현재 보고 있는 문서의 파일 이름이나 디렉토리 이름을 받습니다.

함수에 들어 있는 if 문은 현재 문서가 index.htm일 경우 이름을 ./로 바꿔주는데 각 디렉토리에 있는 인덱스 파일(index.htm)은 굳이 이름을 지정하지 않아도 다음과 같은 형식으로 링크를 만들 수 있기 때문입니다.

<a href="./">인덱스 페이지</a>

다음 등장하는 file_get_contents 함수를 사용하면 인수로 지정된 파일의 내용을 임의의 변수에 넣을 수 있습니다. 따라서 메뉴 링크만으로 구성된 html 파일의 내용을 임시로 보관할 수 있게 되지요.

그러면 str_replace 함수가 임시로 보관된 html 메뉴에서 target_str으로 지정된 문자열을 찾아서 current라는 class를 부여합니다. 예를 들어서 위의 링크가 다음과 같이 바뀌게 되지요.

<a href="./" class="current">인덱스 페이지</a>

마지막으로 class가 부여된 html 메뉴가 echo 명령으로 화면에 출력됩니다.

† 이 방법은 사실 제 독자적인 아이디어는 아닙니다. 예전에 어느 외국 포럼에서 봤는데 다시 찾으려니 안나오더군요. 참고했던 글에서는 정규 표현식(Regular Expression)을 사용했는데 단순한 문자열 치환을 사용하도록 수정했습니다. 그리고 위의 함수는 주 메뉴와 보조 메뉴에 동시에 적용시키려고 제가 만들었습니다.

이어서 두 개의 변수가 선언되는데 각각 현재 문서의 파일 이름과 속한 디렉토리 이름이 대입됩니다. 이 변수들을 상황에 따라서 highlight_current 함수의 두 번째 인수로 사용하게 되지요.

메뉴 불러오기

이제 실제 어떻게 사용되는지 알아보겠습니다. 먼저 울티마 가이드의 주 메뉴를 불러오는 예를 보여드리지요. 일단 주 메뉴는 menu-top.htm 파일에 아래 내용이 들어있습니다.

<div id="nav">
	<ul>
		<li><a href="/">처음으로</a></li>
		<li><a href="/library">브리타니아 도서관</a></li>
		<!-- 중간 생락 -->
	</ul>
</div>

이 메뉴를 다음 PHP 문으로 불러옵니다.

<?php highlight_current(INCPATH.'/menu-top.htm', $target_dir) ?>

현재 문서가 /library 디렉토리에 있다면 target_dir/library가 되므로 ‘브리타니아 도서관’ 메뉴에 자동적으로 current class가 부여됩니다.

그러면 이번에는 보조 메뉴를 불러와 볼까요? 불러올 보조 메뉴는 문서가 속한 디렉토리에 따라서 자동으로 정해집니다. 일단 코드를 보여드리지요.

<?php if ($target_dir == '/') $target_dir = '/root'; highlight_current(INCPATH.$target_dir.'-sm.htm', $target_file); ?>

이 코드에는 if 문이 들어가 있는데 웹 서버의 최상위 디렉토리(/)에 있는 문서일 경우 /root라는 디렉토리에 있다고 가정하게 됩니다. 위치한 디렉토리에 따라서 보조 메뉴를 불러오게 되는데 이 경우에는 root-sm.htm 파일이 그 대상이 됩니다. 하위 디렉토리에 있는 문서일 경우에는 디렉토리 이름 뒤에 -sm.htm이 붙은 파일을 불러오지요. 예를 들어서 /library 디렉토리에 있는 문서라면 library-sm.htm 파일에 메뉴가 들어있어야 합니다. 실제로 다음과 같은 메뉴가 들어 있습니다.

<div id="subnav">
	<h4>지식의 서</h4>
	<ul>
		<li><a href="./">머리말</a></li>
		<li><a href="folklore.htm">역사와 신화</a></li>
		<!-- 중간 생략 -->
	</ul>
</div>

그러면 highlight_current 함수가 현재 문서의 파일 이름을 바탕으로 현재 링크에 current class를 부여합니다.

CSS 작성

강조된 링크에 어떤 효과를 넣을지 지정하는 것은 간단한 CSS 규칙을 사용하면 됩니다. 예를 들어서 밑줄을 넣으려면 다음과 같이 작성하면 되겠지요.

a.current { text-decoration: underline; }

마치며

글이 무지 길어졌네요^^; 개인적으로 짧은 글을 선호하는데 쉽지가 않습니다. 이 방법을 잘 응용하면 블로그에도 적용할 수 있겠지만 메뉴나 최신 글 등에 속하지 않는 페이지에는 적용되지 않기 때문에 전체적인 메뉴의 일관성을 유지하기가 어려울 것 같아서 테스트만 해보고 실제로 적용하지는 않았습니다.

울티마 가이드는 앞서 소개했던 템플릿과 페이지 일부를 파일에서 불러오는(include) 방식을 함께 사용하는데 주 메뉴나 보조 메뉴는 파일 하나만 변경하면 모든 페이지에 적용되고, 레이아웃 역시 템플릿 파일 하나로 쉽게 관리됩니다.

그러나 결정적으로 내용을 업데이트 한한다는게 문제지요. ^^; 그래서 당분간 울티마 가이드를 우선적으로 업데이트 할 생각입니다. 결과는 알 수 없지만요~

댓글이 없습니다. 태그: , ,

XHTML을 사용하는 이유

XHTML이 어떤 마크업 언어이고, 어떤 한계를 가지고 있는지를 앞선 글에서 알아봤습니다. 그렇다면 HTML 대신 XHTML을 사용하는 것은 과연 옳은 선택일까요? 이 주제에 관해서 포스팅하게 된 동기가 되었던 Tommy Olsson의 글에서는 이 문제에 대해서 부정적인 입장을 취하고 있습니다. XHTML이 실제로는 HTML과 거의 동일하게 취급되므로 구태여 XHTML을 사용할 필요가 없다는 주장이지요.

하지만 XHTML을 이용한 홈페이지블로그를 만들고 운영하는 제 생각은 그와는 다릅니다. XHTMLHTML 대신 사용되는 것을 굳이 말릴 필요는 없다고 생각하거든요.

물론 이 문제에는 정답이 없습니다. 각자가 생각하고 판단해야 할 문제니까요. 그 판단을 돕기 위해서 각각의 주장에 대해서 자세히 설명하려는 것이 이 글의 목적입니다.

그리고 이 글은 XHTML 1.0과 HTML 4.01 규격을 비교하는데 중점을 두겠습니다. 하위 호환성을 보장할 수 없는 XHTML 1.1 규격을 특별한 목적 없이 사용해서 얻을 수 있는 것은 최신 규격을 지켰다는 심리적 만족 외에는 없다고 생각하므로 이 규격에 대해서는 언급하지 않겠습니다. 많은 사람들이 W3C의 권고안, 즉 표준을 완전무결한 기준으로 받아들이는데 그런 생각은 W3C의 권위가 불러오는 함정이 될 수 있습니다.

XHTML을 권장하지 않는 이유

먼저 Tommy Olsson의 글을 일부 인용하겠습니다.

XHTMLHTML 중에서 어느 것을 선택해야 하는지에 관한 절대적 기준은 없으며, 이 문제에 관한 여러가지 기술적인 문제들을 생각했을때 간단히 답할 수 있는 문제가 아니다. 하지만 현실적으로 가장 호환성이 높은 W3C의 마지막 표준은 HTML 4.01이라 말할 수 있다. 당신이 실제로 HTML로는 불가능한 XHTML의 기능을 사용해야 하는 경우를 제외하면 기술적인 면에서 XHTML을 사용해야 할 이유는 전혀 없다.”

XHTML을 사용해서 실익을 얻으려면 XHTMLHTML의 근본적인 차이점을 이해해야 한다. 하지만 XHTML을 제대로 사용하는 사이트를 이용할 수 있는 것은 전체 웹 사용자들의 일부일 뿐이다.”

“일부 웹 디자이너와 개발자들은 XHTML의 문법 규칙을 선호한다. 특정한 지침을 따른다면, XHTML의 기술적인 면을 전혀 사용하지 않고서도 XHTML의 문법을 사용할 수 있다. 이런 접근 방식에는 잠재적인 문제점이 있지만, <br> 태그 대신 반드시 <br /> 태그를 사용하기를 원한다면 그 방식을 따르면 된다.”

“당신의 문서가 미래의 환경에서도 유효하려면(future-proofing) XHTMLHTML에서 어느 것을 선택하느냐 보다 Transitional 대신 Strict DOCTYPE을 사용하는 것이 훨씬 중요하다.”

그의 주장의 바탕이 되는 이유는 앞선 글에서 설명했던 브라우저의 XHTML 호환성 문제 때문인데 이에 관한 설명은 브라우저가 XHTML을 해석하는 방식을 참고하시기 바랍니다.

마지막 문장에 대해서는 XHTMLHTML의 차이에서 이미 다루었지만, 중요한 의미가 있어서 다시 한번 짚고 넘어가겠습니다.

많은 사람들이 XHTML을 사용하면 문서의 ‘구조’‘표현’HTML보다 잘 분리해서 보다 ‘의미 있는’ 마크업을 할 수 있다고 생각하지만 이것은 사실이 아닙니다. 이런 면에서 두 규격은 서로 대등하니까요. 동일한 Strict DTD로 정의된 XHTML 1.0과 HTML 4.01 문서는 사용할 수 있는 요소(element)와 속성(attribute)에 차이가 거의 없습니다. 단지 <br> 태그 대신 <br /> 태그를 사용하는 것처럼 문법 규칙이 다를 뿐이지요.

CSS를 사용하는 것도 마찬가지입니다. XHTMLHTML 모두 동일하게 적용되지요. 그러므로 XHTML로 가능한 문서의 ‘구조’‘표현’의 분리는 HTML로도 똑같이 할 수 있습니다.

하지만 점점 더 많은 사람들이 HTML대신 XHTML을 사용해야 한다고 주장합니다. Tommy Olsson은 그 이유를 다음과 같이 밝히고 있지요.

“많은 웹 디자이너와 개발자들이 XHTML 1.0의 발표에 환호했다. XHTML은 당시에 크게 유행했던 XML이었고 HTML처럼 쉽게 사용할 수 있었으며 모든 브라우저에서 잘 동작했다. 사람들은 XHTML의 확장성에서 많은 가능성을 발견했고, W3C가 더 이상의 HTML 규격은 아마도 없을 것이라고 발표하면서 XHTML이 미래 환경을 위한 유일한 대안이라고 생각하게 되었다.”

“시간이 흐르면서 XHTML 사용의 문제점과 확장성의 한계가 밝혀졌지만 XHTML에 대한 장밋빛 환상만큼 널리 알려지지는 않았다. 이 사실을 알지 못하거나 개인적인 선호 때문에 많은 사람들은 여전히 HTML보다는 XHTML을 사용해야 한다고 주장하고 있다.”

여기서 말하는 XHTMLXML의 기능이 사용되지 않아서 HTML로도 충분히 처리가 가능한 마크업을 말합니다. XML의 기능이 꼭 필요하다면 당연히 XHTML을 사용해야겠지요. 하지만 이 글을 읽으시는 분들 중에서 XML을 사용했기 때문에 인터넷 익스플로러로는 접근할 수 없는 그런 페이지를 단 한번이라도 보신 적이 있는지요?

† 인용한 문장에서는 HTML 4.01이 W3C의 마지막 HTML 표준이 될 것이라 생각하는데, 이것은 Tommy Olsson의 원문이 2006년 6월에 씌여졌기 때문입니다. 현재 W3C에서는 HTML 5XHTML 5를 위한 워킹 그룹이 새로운 표준의 밑그림을 그리고 있습니다. HTML 5는 애플, 모질라, 오페라 진영의 사람들이 모여서 설립한 WHATWG에서 자신들이 개발중인 규격을 W3C의 새로운 HTML 규격을 위한 초안으로 채택해줄 것을 제안했고, W3C가 이 제안을 받아들이면서 세상에 그 이름을 알리게 되었습니다(2007년 5월). 현재 이 워킹 그룹의 편집 책임자는 구글의 Ian Hickson과 애플의 David Hyatt입니다.

그럼에도 불구하고 XHTML을 사용하는 이유

Tommy Olsson은 XHTMLHTML과 다를 바 없으므로 HTML을 사용하는 것이 더 나은 선택이라고 주장합니다. 하지만 역설적으로 그렇기 때문에 XHTML을 사용하는 것이 아닐까요? 다시 말해서 HTML 대신 XHTML을 사용해서 얻을 수 있는 이점은 없지만, 그렇다고 해서 특별히 단점이 있는 것도 아니니까요.

XHTMLHTML처럼 사용하는 것이 잠재적인 문제점(potential pitfall)을 안고 있다고 하지만 그것은 어디까지나 브라우저 같은 사용자 에이전트(user agent)의 내부적인 처리 방식의 문제입니다. 결과적으로 XHTMLHTML과의 호환성을 유지하고, XHTML 문법 규칙은 혼란을 일으키지 않을 만큼 충분히 명확하기 때문에 사용자에게는 아무런 문제가 되지 않습니다.

또한 XHTML을 사용하면 HTML보다 양식화된(well-formed) 문서를 작성할 수 있는데 이것은 브라우저가 아닌 사용자 입장에서 특히 유익합니다. 브라우저는 </p> 태그가 없어도 문단이 어디서 끝나는지 명확하게 알 수 있지만, 사용자는 그것을 알기가 어려우니까요.

물론 HTML을 사용해도 동일하게 양식화(well-formed)된 문서를 작성할 수 있습니다. </p> 태그는 생략할 수 있는 것이지 생략해야 하는 것이 아니기 때문입니다. 하지만 XHTML을 사용하면 마크업 검증기(validator)가 문서의 양식을 더 꼼꼼하게 확인합니다. 따라서 XHTML 마크업을 작성하고 검증해보는 것이 양식화된 마크업을 익히는데 유리합니다.

미래의 웹 환경이 어떻게 달라질지 예상하는 것은 어렵습니다. 하지만 단시일 내에 모든 브라우저들이 완벽하게 XML을 지원하리라고는 믿지 않습니다. 개인적으로는 XHTML 문서를 나타내는 .xhtml 확장자가 지금의 .html 확장자 만큼 익숙해져야 XHTML 문서가 그 힘을 발휘할 수 있다고 생각하는데 그 때를 대비해서 XHTML을 써야한다고 주장하는 것이 아닙니다. 앞서 말씀드렸듯이 지금 작성되는 대부분의 XHTML 문서에는 XML 만의 기능이 들어가 있지 않으니까요. XHTML의 하위 호환성을 고려했을 때 HTML 대신 사용해도 무방하다는 것이 제 의견의 요지입니다.

마치면서

XHTMLHTML 규격의 차이점을 다루는 글을 쓰게 된 동기는 ‘웹 표준’XHTML 사용을 동일하게 받아들이는 일부의 시각 때문입니다. HTML 4.01 규격도 엄연히 W3C가 제정한 표준 권고안임에도 불구하고 XHTMLCSS를 사용해야만 웹 표준을 지킬 수 있고, 그것이 무조건 더 좋은 방법이라고 생각하는 분들이 있는데 절대적으로 틀린 생각입니다.

웹 표준을 잘 지키고 그 장점을 누리기 위해서는 XHTMLHTML의 차이가 아니라 Strict와 Transitional DTD의 차이를 아는 것이 훨씬 더 중요합니다. 이 주제에 관해서는 나중에 다루도록 하고, XHTMLHTML 규격의 차이점에 관한 글은 이것으로 모두 마칩니다.

  1. XHTMLHTML의 차이
  2. 브라우저가 XHTML을 해석하는 방식
  3. XHTML 1.1 규격의 용도와 호환성
  4. XHTML을 사용하는 이유

댓글 7개가 달렸습니다. 태그: , ,

XHTML 1.1 규격의 용도와 호환성

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 속성이 도입되었다.
  • amap 요소에 적용되던 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 코드로 알아보겠습니다.

<ruby>
  <rb>WWW</rb>
  <rt>World Wide Web</rt>
</ruby>

루비 주석에 관한 자세한 설명은 생략하겠습니다. ^^

XHTML 1.1을 브라우저가 지원하는가?

일단 인터넷 익스플러러는 XHTML을 제대로 지원하지 않습니다. 앞선 글에서 Content-Type에 관해 설명했듯이 XHTML의 XML 기능을 사용하기 위한 필수 요구 조건인 application/xhtml+xml MIME 타입을 인식하지 못하지요.

인터넷 익스플로러를 제외한 일부 브라우저, 예를 들어서 파이어폭스는 XHTML을 지원합니다. 하지만 그렇다고 해서 위에서 설명한 루비 주석을 작성하기 위한 마크업을 인식할 수 있을까요?

현재까지는 그렇지 않습니다. 파이어폭스에서 위에서 예로 들었던 루비 주석 마크업의 결과물을 보려면 플러그인을 따로 설치해야 합니다.

† 인터넷 익스플러로 5.0 이후의 브라우저는 제한적으로 루비 주석 표기를 지원합니다. 하지만 인터넷 익스플로러 5.0이 1999년에 발표되었다는 사실에서 짐작할 수 있듯이 W3C가 XHTML 1.1 규격에서 제안한 방식으로 구현된 것은 아닙니다. 비 표준적인 태그 지원이라는 얘기지요. 그러므로 XHTML이 아닌 HTML에서도 루비 주석을 표현할 수 있으며 XHTML의 MIME 타입과도 무관합니다.

XHTML 1.1은 XHTML 1.0과 마찬가지로 하위 호환성을 유지하는가?

이 중요한 문제의 답으로 Tommy Olsson의 글을 인용하겠습니다.

XHTML 문서를 text/html MIME 타입으로 제공할 때에는 절대로 XHTML 1.1 규격을 사용하지 말아야 한다. 왜냐하면 XHTML 1.1에서 lang 속성이 금지(deprecate)되었기 때문에 HTML과의 하위 호환성을 유지할 수 없기 때문이다.”

XHTML 1.0에서는 HTML과의 호환성을 위해서 해당 문서가 어떤 언어로 작성되었는지 lang 속성과 xml:lang 속성 두 가지를 모두 지정할 것을 권장합니다. XHTML을 지원하는 브라우저는 xml:lang 속성을 이해할 수 있고, 그렇지 않은 브라우저는 lang 속성을 이해할 수 있으니까요.

하지만 XHTML 1.1을 text/html MIME 타입으로 제공하면 브라우저가 해당 문서를 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에 관심을 갖고 사용하려는 이유에 대해서 알아보겠습니다.

  1. XHTML과 HTML의 차이
  2. 브라우저가 XHTML을 해석하는 방식
  3. XHTML 1.1 규격의 용도와 호환성
  4. XHTML을 사용하는 이유

댓글이 없습니다. 태그: , ,

브라우저가 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 문서가 된다.

XHTMLHTML로 해석된다는 것은 XML에서만 가능한 기능들을 전혀 사용할 수 없고, 반대로 HTML에서만 가능한 기능들은 사용할 수 있다는 의미이다. 하지만 그렇게 HTML의 기능을 사용하는 것은 XHTML로 마크업한 원래의 목적에 위배되는 일이 된다.

그러면 XHTML은 어떤 MIME 타입을 사용해야 하는가?

브라우저가 XHTMLXML 문서로 인식하고 해석하려면 아래의 세 가지 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/html MIME 타입을 사용하는 방법을 제시하고 있다. 하지만 이 MIME 타입을 사용하면 모든 브라우저는 해당 문서를 HTML 문서로 인식하고 해석한다.

실질적으로 모든 브라우저가 self-closing 태그(예: <br />)의 슬래시 기호를 무시하는 해석상의 버그를 갖고 있으므로 XHTMLHTML과 동일하게 해석된다.

XML 문법에서는 self-closing 태그의 슬래시 기호 앞에 공백을 넣지 않아도 문법적으로 아무 문제가 없으며, <br /> 태그를 <br></br> 태그처럼 사용할 수도 있습니다. 하지만 XHTML에서는 호환성을 위해서 이런 문법을 허용하지 않습니다.

<meta/> 태그에 지정한 MIME 타입도 적용되는가?

그렇지 않다. 브라우저는 HTTP 요청에 대한 답변으로 전송받는 내용(body)을 해석하기 전에 그 문서가 어떤 문서인지를 알아야 한다. 브라우저가 아래와 같은 메타 태그를 발견했을 때에는 이미 늦은것이다.

<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8"/>

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+xml MIME 타입으로 전송하도록 서버에 지시한다. 이 명령은 아파치 서버의 전역 설정(/etc/httpd.conf)이나 웹 디렉토리의 .htaccess 파일에 적용된다.

이런 설정 파일에 접근할 수 없는 경우에는 서버-사이드 스크립트 언어를 사용해서 같은 결과를 얻을 수 있다. 예를 들어서 PHP 언어를 사용한 다음 코드를 이용할 수 있다.

header('Content-Type: application/xhtml+xml; charset=utf-8'); 

이 헤더가 문서의 내용이 전송되기 전에 브라우저에게 전해져야 한다는 것을 명심하라.

XHTMLapplication/xhtml+xml 타입으로 전송하면 어떤 장점이 있는가?

말 그대로 브라우저가 XHTMLXHTML로 인식한다. 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 스팩을 따르거나 XHTMLtext/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+xml MIME 타입을 지원하지 않으므로 이런 헤더 정보를 받게 되면 해당 페이지를 다운로드하려고 한다. 레지스트리를 변경해서(hack) 이 MIME 타입을 인식하도록 할 수는 있지만 그렇다고 해도 해당 문서는 여전히 HTML로 취급된다.

XHTMLXML 기능이 필요하다면 문서를 application/xml로 제공할 수 있다. 인터넷 익스플로러도 이 MIME 타입을 지원하지만 XHTML의 이름 영역(namespace)를 사용할 수 없으므로 해당 문서는 보통의 XML 문서로 인식된다. 따라서 스타일시트가 기본적으로 적용되지 않으므로, 모든 요소에 대한 스타일을 전부 지정해줘야 한다. 예를 들어서 모든 블록 레벨의 요소들에 display: block 속성을 지정해야 한다.

물론 XHTMLtext/html로 제공할 수 있다. 하지만 앞서 길게 설명했던 것처럼 브라우저는 그 XHTML 문서를 문법 오류가 있는 HTML 문서로 인식한다.

† 여기서 말하는 문법 오류는 닫는 태그 앞에 공백과 슬래시 기호가 있는 것을 의미합니다. 예를 들어서 <br /> 태그 같은 것이지요.

인터넷 익스플로러 7은 XHTML을 제대로 지원하는가?

그렇지 않다.


마지막 질문에 대한 짧은 답이 인상적입니다.

간단하게 요약하자면 브라우저가 XHTML을 제대로 지원하지 않고, XHTMLHTML의 기능이 완벽하게 호환되지 않으므로 대부분의 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 문서의 메타 태그로는 바꿀 수 없다는 것에 주의하세요.

관련 글 안내

  1. XHTMLHTML의 차이
  2. 브라우저가 XHTML을 해석하는 방식
  3. XHTML 1.1 규격의 용도와 호환성
  4. XHTML을 사용하는 이유

댓글 6개가 달렸습니다. 태그: , ,

XHTML과 HTML의 차이

XHTMLHTML은 현재 가장 널리 사용되는 웹 문서 규격입니다. 이름에서도 알 수 있듯이 XHTML은 기존에 사용되던 HTML 규격이 가진 문제점을 극복하고, 보다 다양한 분야에 응용될 수 있도록 해주는 여러가지 확장된 기능을 포함하고 있습니다.

HTML을 XML 바탕으로 새롭게 구성(reformulation)한 XHTML은 CSS와 함께 최근에 많은 관심을 받고 있는 ‘웹 표준’의 중요한 요소가 되었습니다. 하지만 XHTML이 XML을 기반으로 만들어졌고, 이 XML을 모든 브라우저가 지원하지 않는다는 현실적인 문제 때문에 XHTML과 HTML이 사실상 큰 차이 없이 사용된다고 주장하는 사람들도 많습니다.

이런 시각을 다루는 좋은 글이 있어서 번역해서 소개합니다. 내용이 많아서 세 번으로 나눠서 포스팅하려고 하는데 글의 전문성에 비해 제 이해가 많이 부족하고, 원문을 요약한 것이어서 그 내용을 완벽하게 전달하는데 한계가 있으니 감안해서 보시기 바랍니다.

Tommy Olsson이 쓴 원문은 Site Point 포럼에 올라온 FAQ About XHTML vs HTML이니 참고하시고, dagger 마크(†)로 시작하는 단락은 원문에는 없는 보충 설명입니다. 이 글의 저작권은 원문의 저작자인 Tommy Olsson과 Site Point에 있으며, 블로그 전체에 적용되는 CCL보다 우선적으로 적용됩니다.

XHTML과 HTML의 차이점

  • XHTML이 XML 문법을 따르므로 HTML과 문법 규칙이 약간 다르다.
  • XHTML을 사용하면 할 수 있으나, HTML로는 불가능한 일이 있다.
  • HTML을 사용하면 할 수 있으나, XHTML로는 불가능한 일이 있다.
  • CSS를 이해하는 방식에 차이가 있다.
  • 클라이언트 쪽의 스크립트(예: 자바 스크립트)를 다루는 방식에 차이가 있다.

첫 번째로 언급한 문법적인 차이를 다루는 문서는 많기 때문에 자세한 설명을 하지 않겠습니다.

XHTML을 사용하면 할 수 있으나, HTML로는 불가능한 일
  • CDATA 섹션(<![CDATA[ … ]]>) 사용.
    이 섹션 안의 문자들은 태그로 처리되지 않기 때문에 따로 이스케이프(escape) 해 줄 필요가 없다.
  • processing-instruction 사용. 예를 들어 XML 문서에 스타일시트를 연결시킬 수 있다.
    <?xml-stylesheet type="text/css" href="style.css" media="screen"?>
  • 다른 XML 이름 영역(namespace)에 있는 요소(element)들을 포함시킬 수 있다.
  • &apos; 캐릭터 엔티티(character entity)를 사용할 수 있다.
HTML을 사용하면 할 수 있으나, XHTML로는 불가능한 일
  • 기존 HTML에서 사용하던 <!-- … --> 코멘트로 스타일이나 스크립트의 일부를 주석 처리할 수 없다.
  • 문서를 읽고 있는 도중에는 페이지의 일부를 동적으로 생성할 수 없다(예: document.write() 사용).
  • &nbsp; 같은 named entity를 사용할 수 없다. 미리 정의된 &lt;, &gt;, &amp;, &quot;는 사용 가능.
  • 자바 스크립트에서 .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에 관한 문제입니다.

관련 글 안내

  1. XHTML과 HTML의 차이
  2. 브라우저가 XHTML을 해석하는 방식
  3. XHTML 1.1 규격의 용도와 호환성
  4. XHTML을 사용하는 이유

댓글 5개가 달렸습니다. 태그: , ,

접근성을 높여주는 네비게이션

올블로그에 포스팅된 SKT 모바일 웹과 웹표준이라는 글을 보고 호기심에 핸드폰을 열고 블로그에 접속해 봤습니다. 별 기대를 안했는데 의외로 제 핸드폰에 탑재된 KUN(KTF Unified Navigator) 브라우저가 블로그 글을 잘 보여주더군요. 물론 이미지가 제대로 표시되지 않는 문제가 있지만 글 검색도 가능하고 댓글도 달 수 있었습니다. 데이터 통신 요금이 생각보다 훨씬 비싸서 다양하게 시험해보진 않았지만 잠깐 동안의 사용으로도 웹 문서의 접근성이 왜 중요한지를 체험할 수 있었습니다.

제가 느꼈던 모바일 기기를 통한 웹 서핑의 가장 큰 불편함은 마우스를 사용할 수 없다는 점이었습니다. 원하는 링크로 이동하기 위해서는 중간에 있는 모든 링크를 순차적으로 거쳐가야 했으니까요. 이런 불편함을 느끼다가 텍스트패턴 기본 테마에 있는 네비게이션 메뉴가 왜 포함된 것인지 깨달았습니다. 먼저 어떤 메뉴인지 소개하는게 좋겠네요.

<div id="accessibility">
  <ul>
    <li><a href="#content">내용 바로가기</a></li>
    <li><a href="#sidebar">사이드바 바로가기</a></li>
    <li><a href="#search">검색 바로가기</a></li>
    <li><a href="#comment">댓글 바로가기</a></li>
  </ul>
</div>

제 블로그에 맞게 약간 수정한 마크업인데 페이지의 중요한 부분으로 바로 접근할 수 있는 간단한 링크로 구성되어 있고, 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 속성이 지정되었는지 확인해 보시기 바랍니다.

댓글 4개가 달렸습니다. 태그: , , , ,

CSS로 만든 그룹 박스

지난 글에서 <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 코드를 문서에 적용할 때에는 충분히 테스트 해보고 수치를 조절하는 과정이 필요합니다.

설명은 이만 마치고 몇 가지 예를 더 보여 드리겠습니다.

그룹 박스2

  1. div.groupbox { border: 1px solid #B4CEF5; }
  2. div.groupbox h4 span { color: #0066FF; }

그룹 박스3

  1. 너비 지정 안함 (최대 너비)
  2. div.groupbox h4 { line-height: 80%; padding-left: 18px; }
  3. div.groupbox h4 span { padding: 0 8px; top: -0.9em; }

h4 태그의 line-height 속성 값을 바꾸면 라벨의 상하 위치가 바뀌는데 이럴 경우에는 top 속성의 값으로 보정해주셔야 합니다.

조금 어렵더라도 의미에 맞는 태그를 사용하면 여러가지 이점을 얻을 수 있습니다. 박스 안의 내용이 중요하다면, 검색 엔진이 무시하지 않기를 바란다면 보다 ‘의미 있는’ 방법으로 바꿔보시길 바랍니다.

댓글 6개가 달렸습니다. 태그: , ,

실질적인 웹 표준

‘웹 표준’을 다루는 글이 많아지면서 이에 대한 블로거들의 관심도 높아지고 있습니다. 그런데 대부분의 글들이 웹 표준을 지켜야 하는 이유와 그럼으로써 얻어지는 이점에만 초점을 맞추더군요.

사실 ‘접근성’이나 ‘크로스 브라우징’, ‘문서의 구조화’ 같은 표현은 대부분의 사용자들에게 쉽게 와 닿지 않을 겁니다. 그보다는 현실적인 예와 방법들을 제시하는게 웹 표준에 대한 이해를 이끌어내는데 도움이 되지 않을까 생각합니다. 어떻게 해야 웹 표준을 지키고 ‘의미 있는’ 마크업을 할 수 있는지에 관해 한글로 작성된 정보가 극히 적은 상황이니까요.

그래서 이번 글에서는 많은 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 규칙을 저장하면 언제든 전체 글에 적용된 글자 색을 바꿀 수 있으니까요.

<span class="usercolor1">검정 텍스트</span>
<span class="usercolor2">빨강 텍스트</span>

본의 아니게 연이어 태터툴즈의 문제점을 지적했네요. 개인적으로 태터툴즈의 편리함이 설치형 블로그가 대중화되는데 큰 역할을 했고, 무엇보다 한글을 우선적으로 고려한 블로깅 툴이라는 점에서 높이 평가합니다. 편의성을 너무 추구한 나머지 문서의 효율적인 마크업에는 미흡한 점이 있지만 앞으로 계속 개선되리라 믿습니다.

<fieldset> 태그

위에서 다뤘던 두 태그만큼 많이 사용되지 않음에도 불구하고 당당히 3위를 차지한 것은^^; 제가 전혀 생각하지 못했던 용도로 사용되기 때문이랍니다. 어느 블로그에선가 글 내용과 관련 있는 다른 글들의 목록을 윈도우즈 프로그램에 사용되는 그룹 박스(정확한 명칭인지는 모르겠지만) 모양의 박스로 표현하는 것을 봤습니다. <div> 태그를 어떻게 사용했을까 하는 생각에 소스를 봤는데 전혀 예상하지 못했던 <fieldset> 태그가 있어서 깜짝 놀랐네요.

<fieldset> 태그는 W3C에 아래와 같이 정의되어 있습니다.

“이 태그는 여러 콘트롤(입력 폼 등)과 라벨을 한데 묶어주는 역할을 한다. 그럼으로써 사용자가 콘트롤들의 용도를 쉽게 인식하고, 브라우저나 스크린 리더 등의 프로그램으로 콘트롤 사이를 쉽게 이동할 수 있도록 해준다.”

간단히 말해서 <filedset> 태그는 문서에 들어가는 콘트롤을 위한 태그입니다. 그러면 이 태그를 폼(콘트롤)이 아닌 다른 용도로 사용하면 어떤 문제가 생길까요?

어떤 분들은 이 태그를 문서의 일부분을 강조하는데 사용합니다. 그런데 검색 엔진이 그 문서를 해석한다고 가정해 보면 어떨까요? 검색 엔진이 문서를 해석하는 구체적인 방법은 모르지만, 적어도 이 태그 안의 정보에는 크게 관심을 기울이지 않을 겁니다. 당연히 폼에 관한 정보라고 생각 할 테니까요. 원래 의도는 강조였고, 사용자의 눈에도 그렇게 보이지만 검색 엔진의 입장에서는 반대로 해석할 수도 있다는 얘기지요.

제가 제시하는 대안은 간단합니다. <div> 태그로 비슷한 시각 효과를 낼 수도 있겠지만 그보다는 디자인을 아주 조금만 양보해서 보다 ‘의미 있는’ 마크업을 작성하는 것이지요. 어떤 용도의 박스인지 표시해주는 텍스트가 꼭 테두리 선 위에 있어야 하는건 아니니까요.

마치는 말

<p> 태그 대신 <br /> 태그를 쓴다거나, <fieldset> 태그로 글을 강조하는 분들을 비난하는 글이 아님을 이해해 주시고 바랍니다. 또한 웹 표준이 더 많이 지켜지려면 그 방법을 먼저 익힌 분들이 보다 많은 정보를 오픈해야 한다고 생각합니다. 블로그에서 웹 표준에 관한 논쟁보다 어떻게 하면 웹 표준을 지킬 수 있는지 알려주는 글을 더 많이 볼 수 있기를 바라며 글 마칩니다.

댓글 6개가 달렸습니다. 태그: , , ,

abbr, acronym 태그 차이

<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에는 이런 기능을 다루는 속성이 따로 있습니다.

abbr { speak: spell-out; }
acronym { speak: normal; }

또한 머리글자를 이용하지 않는 info.(information), exam.(examination) 등의 축약어에 대해서는 어떤 태그 처리도 필요없다는 의견도 있고, class를 사용해서 구별하자는 의견도 있습니다.

요약하자면 전자의 경우는 머리글자를 이용하지 않는 대부분의 축약어가 하나의 의미로 사용되고 대부분의 사람들이 쉽게 이해할 수 있기 때문이라는 주장이고, 후자의 경우에는 머리글자를 사용하는 축약어와 그렇지 않은 축약어를 명확하게 구분해서 CSS를 이용해서 스크린 리더가 축약어를 읽는 방식을 지정해주자는 의견입니다. 아래 처럼 말이지요.

acronym { speak: normal; }
abbr.initialism { speak: spell-out; }
abbr.truncation { speak: normal; }

사라질 <acronym>

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를 사용해서 스크린 리더에게 어떻게 발음해야 할 지 알려줄 수 있지요.

<acronym class="abbr" title="HyperText Markup Language">HTML</acronym>

세 번째 방법은 <abbr> 태그와 <span> 태그를 함께 사용하는 방법입니다. 의미 없는 태그가 추가되지만 적어도 틀린 의미로 사용하는 것은 아니니까요.

<span title="HyperText Markup Languag">
<abbr title="HyperText Markup Languag">HTML</abbr></span>

익스플로러 6.0 이하 버전에서도 용어에 대한 설명을 볼 수 있습니다. 확인해 볼까요?

HTML

이외에도 각주를 사용하거나 해당 용어에 대한 설명이 있는 사이트를 직접 링크시키는 방법도 있습니다. 유명한 사이트인 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 입력을, 아래 박스는 브라우저 출력을 나타냅니다.

XHTML(Extensible HyperText Markup Language)
ex.(Example) etc.(et cetera)

XHTML
ex. etc.

<abbr> 태그를 적용하기 위해 새로운 Textile 규칙도 만들 수도 있겠지만 Textile의 장점이 간단하고 쉬운 태그에 있는 만큼 기존의 태그를 최대한 이용하는 것이 옳다고 생각합니다. 물론 <abbr> 태그가 <acronym> 태그를 포함하는 개념이므로 의미 상으로도 큰 문제가 없지요.

† 정규 표현식을 잘 몰라서 그랬다고는 절대 얘기하지 않습니다^^;

결론

많이 사용되지도 않고, 우리말과 직접적으로 관계 없는 태그들을 이렇게 장황하게 설명하는 것은 단순히 흥미로왔기 때문입니다. W3C의 애매한 정의도 그렇고, 이와 관련해서 많은 사용자들이 다양한 의견과 해결 방법을 내놓은 점도 그렇습니다. 일례로 Tetile 포럼에서 가장 많은 댓글이 달린 글이 이 두 태그에 관한 글이더군요.

개인적으로 ‘의미 있는’ 마크업을 중요하게 생각하지만 특별히 영어 사용자를 위한 글이 아니라면 이 태그들을 너무 엄격하게 구분해서 사용할 필요는 없다고 생각합니다. 간단하게 <abbr> 태그만 사용해도 충분하지 않을까요? 때로는 어떤 축약어가 ‘acronym’‘initialism’ 중에 어디에 속하는지 구분하기 힘든 경우도 있습니다. 두 방식을 섞어 쓰는 축약어도 있고요. 그런 경우에는 이렇게 하라는 지침을 어느 사이트에선가 봤습니다.

“잘 모르겠으면 <abbr> 태그를 사용하라!”

또한 단순히 어떤 생소한 용어를 설명하기 위해서라면 위에 언급했던 일반적인 텍스트를 이용하는 것이 최고의 방법입니다. 마우스를 사용하지 않아도 설명을 볼 수 있으니까요.

이 주제에 관한 의견이나 주장이 상당히 다양합니다. 이것 저것 요약해서 소개하려다 보니 잘못 인용하거나 해석한 부분도 많을 겁니다. 이 점 감안하시길 바라고 의문가는 점은 언제든지 댓글로 남겨주세요.

댓글 9개가 달렸습니다. 태그: , , ,

Textile 각주와 약어

자주 사용되거나 중요하다고 생각되는 Textile 태그들에 대해서는 거의 정리가 끝났네요^^ 그래서 자주 사용하지는 않지만 알아두면 편리한 몇 가지 기능들을 살펴보고 Textile 사용법을 마무리하려 합니다.

먼저 각주(footnote)를 글에 쉽게 넣을 수 있도록 해주는 태그를 알아보지요. 다른 태그들이 그렇듯이 문법은 간단합니다.

이 단어[1]에 대한 설명이 필요합니다.[2]
fn1. 단어의 의미
fn2. 상세한 설명
<p>이 단어<sup class="footnote"><a href="#fn30013461cba499ffc2">1</a></sup>
에 대한 설명이 필요합니다.
<sup class="footnote"><a href="#fn12594461cba49a0004">2</a></sup></p>
<p id="fn30013461cba499ffc2" class="footnote"><sup>1</sup> 단어의 의미</p>
<p id="fn12594461cba49a0004" class="footnote"><sup>2</sup> 상세한 설명</p>

소스가 복잡하네요^^; 우선 화면에 어떻게 표시되는지 볼까요? 시각 효과를 위해 적당히 CSS를 적용했습니다.

이 단어1에 대한 설명이 필요합니다.2


1 단어의 의미

2 상세한 설명

대괄호로 둘러싼 숫자에 링크를 걸고 설명이 있는 단락에 책갈피(anchor)를 만드는 방식으로, 각각의 책갈피에는 중복을 방지하기 위해 임의로 생성된 id가 부여됩니다.

그런데 설명이 있는 단락에는 용어 정의가 있는 곳으로 돌아가는 링크가 없답니다. Textile 포럼에 이에 대한 논의가 있는데 간단히 요약하면 용어 정의가 두 번 이상 반복해서 사용될 경우에 문제가 발생할 수 있기 때문에 기능을 제한했다는 얘기더군요. 물론 이렇게 사용되는 경우는 극히 드물겠지만요.

Textile의 각주 기능을 잘 사용하기 위해서는 몇 가지 주의할 점이 있는데 첫 번째가 fnn. 태그가 각각 하나의 단락(paragraph)으로 이루어진다는 사실입니다. Textile 사용법에 관한 첫 글에서 설명했듯이 각각의 단락을 구분짓는 것이 빈 줄이기 때문에 위의 예처럼 각각의 태그 사이에 빈 줄을 넣어주셔야 합니다.

두 번째는 대괄호 안에 띄어쓰기 없이 숫자를 넣으면 fnn. 태그가 없어도 무조건 각주로 인식한다는 점입니다. 이해를 돕기 위해 몇 가지 Textile 입력과 화면 출력의 예를 들어보겠습니다.

이[1] 단어[2]에 대한 [3]설명이 필요합니다.[4]
1 단어2에 대한 [3]설명이 필요합니다.4

즉, 대괄호와 숫자를 그냥 표시하려면 반드시 앞에 띄어쓰기가 있어야 된다는 얘기입니다. 하지만 ‘반드시’라는 조건이 자유로운 표현을 막아서는 안되겠지요. 그래서 대안이 있는데 바로 == 태그입니다. 사실 이 태그를 지금껏 소개하지 않았던 이유는 단 한 가지입니다. 제가 명확하게 이해를 못했기 때문이지요^^;

일단 이 태그는 기본적으로 notextile. 태그처럼 글의 특정 부분을 Textile이 해석하지 않도록 하기 위해 사용됩니다. 차이가 있다면 notextile. 태그처럼 블록을 만들지 않고 인라인 스타일처럼 적용된다는 것이지요. 일단 몇 가지 예를 들어보겠습니다.

*강조* ==*강조*== [*강조*] [==*강조*==]
==h1. Textile _적용_ 금지==
이[1] 단어에==[2]== 관한 설명이[==3==] 필요합니다.
이[1] 단어에 ==[2]== 관한 설명이[==3==] 필요합니다.
강조 *강조* 강조 [*강조*]
h1. Textile _적용_ 금지
이1 단어에==2== 관한 설명이[3] 필요합니다.
이1 단어에 [2] 관한 설명이[3] 필요합니다.

첫 번째 예는 == 태그의 적용 방식을 보여줍니다. * 태그나 _ 태그가 대괄호를 이용해서 태그의 시작과 끝을 표시할 수 있는데 반해 == 태그는 대괄호를 무시한다는 점에 주의해야 합니다. 앞선 글에서 설명했듯이 이 대괄호는 한글을 사용할 때 발생하는 문제점을 해결하는데 사용됩니다. 따라서 == 태그 앞에 띄어쓰기가 없을 경우에는 의도했던 것과는 다른 결과가 발생할 수 있습니다.

세 번째와 네 번째 예에서 이 차이를 분명히 확인할 수 있습니다. 또한 대괄호 안의 숫자에 == 태그를 적용해서 해당하는 부분을 각주로 인식하지 않게 할 수 있다는 사실도 알 수 있지요. 즉, 띄어쓰기 대신 대괄호로 태그의 시작을 표시할 수 있지만 * 태그와는 달리 대괄호도 그대로 화면에 출력해준다는 얘기입니다.

물론 Textile로 문서를 작성할 때 의도하지 않았던 태그가 적용되는 경우는 많지 않습니다. 제가 드는 예는 이런 문제점을 일부러 부각시킨 경우가 대부분이지요. 하지만 일단 문제가 생기고, 해결되지 않는다면 Textile을 계속 사용하기 힘들겁니다. 그래서 == 태그나 notextile. 태그를 적절히 사용하는 것이 중요하지요.

만약 이 두 태그 사용에 어려움을 느낀다면 간단히 다음과 같은 방법을 따르면 됩니다.

“의도하지 않은 태그가 적용될 경우에는 해당 부분을 notextile. 태그로 시작하고 내용은 직접 html 태그를 사용해서 입력한다.”

다시 말씀드리지만 이런 경우는 극히 드뭅니다. 그러니 이런 이유로 Textile의 편리함을 포기해서는 안되겠지요? ^^;

마지막으로 머리글자를 이용한 약어 표기법(acronym)을 알아보겠습니다. 무척 간단하니 예만 봐도 아실겁니다.

CSS(Cascading Style Sheet), XML(eXtensible Markup Language)
<acronym title="Cascading Style Sheet"><span class="caps">CSS</span></acronym>,
<acronym title="eXtensible Markup Language"><span class="caps">XML</span></acronym>

브라우저 화면에 어떻게 표시되는지 한 번 볼까요?

CSS, XML

열심히 입력한 약어에 대한 설명이 안보이네요. 하지만 마우스를 머리글자 위에 올리면 사라졌던 설명이 표시되는 것을 볼 수 있습니다. 바로 html의 <acronym> 태그가 적용되었기 때문이지요. 브라우저에 따라서 이 태그를 보여주는 방식이 다른데 위 예에서는 시각 효과를 위해 다음과 같은 CSS 스타일을 적용시켰습니다.

acronym { border-bottom: 1px dotted #699; cursor: help; }

또한 CSS와 XML이라는 텍스트에는 caps라는 class가 적용되는데, Textile에서는 석 자 이상의 알파벳 대문자가 이어질 경우에 자동으로 이 클래스가 적용됩니다. 글자 간격 같은 스타일을 적용하기 위해서라고 하는데 한글을 사용하는 입장에서는 가뿐히 무시하셔도 좋습니다^^

그러면 이번에는 어떻게 해야 <acronym> 태그가 자동으로 적용되는 것을 방지할 수 있는지 알아볼 차례겠지요? 앞서 설명한 == 태그를 사용하면 간단히 해결됩니다. 알파벳 약어는 앞에 띄어쓰기가 항상 있으니까 특별히 문제될 것도 없지요.

==CSS(Cascading Style Sheet), XML(eXtensible Markup Language)==
CSS(Cascading Style Sheet), XML(eXtensible Markup Language)

이 기능은 알파벳 약어를 사용할 경우에만 적용되지만 약어 설명에는 한글도 쓸 수 있습니다. 아래 약어 위에 마우스를 올리면 확인할 수 있습니다.

CSS, XML

이렇게 해서 Textile 사용법에 관한 글을 모두 마칩니다. 빠진 부분도 있고 대충 넘어간 부분도 있지만 그래도 Textile에 관심을 갖고 찾아오신 분들께 도움이 되었으면 하는 바램입니다.

혹시라도 궁금한 점 있으면 언제든지 댓글이나 메일 주세요~

Textile 관련 글 안내

  1. 시작하기
  2. 링크와 한글 입력
  3. 이미지 태그
  4. 리스트와 표
  5. 코드 출력과 인용문
  6. 각주와 약어

댓글 2개가 달렸습니다. 태그: , , ,

Textile 코드 출력과 인용문

Textile 사용법에 관한 첫 글에서 여러 가지 블록 설정 태그를 소개했던 적이 있습니다. 바로 아래 문장이지요.

Textile의 블록 설정 태그에는 이외에도 h2. ~ h6. , pre. , bc. , bq.. , fnn. 등이 있는데 이 태그들에 대해서는 나중에 따로 알아보겠습니다.

그래서 이 태그들을 하나씩 설명해볼까 합니다. 헤드라인을 설정할 때 사용하는 h1. ~ h6. 태그는 특별히 설명할 만한 내용이 없으니 그냥 넘어가고^^; 일반적인 텍스트가 아닌 html 코드를 직접 화면에 표시하는데 사용되는 태그들부터 알아보겠습니다.

당연한 얘기지만 html 문서는 html 태그로 이루어져 있습니다. 우리가 브라우저를 통해 보는 화면은 브라우저가 이 html 태그들을 해석한 결과물이지요. 그런데 이 html 태그를 브라우저가 해석하지 않고 보통의 텍스트처럼 화면에 보여줘야 할 경우도 있습니다. 예들 들어서 이런 경우지요.

<br> 태그와 <br /> 태그 중에서 어느 것이 맞나요?

간단하게 보이지만 사실 이 문장을 표시하려면 html 문서에 아래와 같이 입력해야 한답니다.

&#60;br&#62; 태그와 &#60;br /&#62; 태그 중에서 어느 것이 맞나요?

즉, html 태그를 나타내기 위해 사용하는 왼쪽(<)과 오른쪽 꺽쇠 기호(>)를 각각 &#60; , &#62;로 바꿔줘야 브라우저가 태그로 인식하지 않는다는 얘기지요. 어렵지는 않지만 이렇게 일일이 바꿔주려면 상당히 귀찮습니다.

&#60; , &#62; 대신 &lt; , &gt; 사용도 가능합니다. 각각 ‘less than’, ‘greater than’을 의미하지요.

그래서 Textile에서는 이런 변환을 쉽게 해주는 세 개의 태그를 고안했는데 각각 @ 태그, pre. , bc. 입니다. 하나씩 설명을 해보지요.

먼저 @ 기호로 어떤 텍스트를 감싸면 그 안에 있는 모든 꺽쇠 문자가 자동으로 변환되고, 텍스트에는 html의 <code> 태그가 적용됩니다. 예를 들어보지요.

@<br>@ 태그와 @<br />@ 태그 중에서 어느 것이 맞나요?
<code>&#60;br&#62;</code> 태그와 <code>&#60;br /&#62;</code> 태그 중에서 어느 것이 맞나요?

html의 <code> 태그는 컴퓨터와 관련된 모든 코드를 표시하기 위해 사용되는데 대부분의 브라우저는 이 태그 안의 문자와 기호를 고정폭 폰트로 출력해 줍니다. 물론 CSS를 이용하면 얼마든지 다른 스타일을 적용시킬 수 있지요.

그런데 <code> 태그 만으로는 여러 줄의 컴퓨터 코드(이하 소스 코드)를 보기 좋게 표현하는데 한계가 있습니다. 브라우저가 소스 코드의 줄바꿈과 띄어쓰기를 무시하기 때문이지요. 그래서 만들어진 html 태그가 <pre> 태그랍니다. 이 태그는 블록을 설정해서 그 안의 모든 내용을 사용자가 입력한 그대로 출력해줍니다. 그러면 <code> 태그와 <pre> 태그를 비교해 볼까요? 위 박스는 html 코드를, 아래 박스는 브라우저 출력을 나타냅니다.

<code>가나다
라마바    사아</code>
<pre>가나다
라마바    사아</pre>
가나다 라마바 사아
가나다
라마바    사아

차이를 아시겠지요? html의 <pre> 태그에 대응되는 Textile 태그가 pre. 태그입니다. pre. 태그는 html의 <pre> 태그처럼 소스 코드의 줄바꿈과 띄어쓰기를 그대로 표현해 주면서 앞서 설명한 @ 태그가 했던 꺽쇠 기호 변환까지 함께 해주므로 무척 편리하답니다. Textile로 입력한 텍스트가 어떻게 html 코드로 변환되는지 예를 들어보겠습니다.

pre. 
<div>
    <p>단락 1</p>
    <p>단락 2</p>
</div>
<pre>
&#60;div&#62;
    &#60;p&#62;단락 1&#60;/p&#62;
    &#60;p&#62;단락 2&#60;/p&#62;
&#60;/div&#62;
</pre>

html 문서에서 소스 코드를 표현할 때에는 보통 <code> 태그와 <pre> 태그를 함께 사용합니다. <pre> 태그가 안의 내용물을 입력한 그대로 출력해 주고, <code> 태그가 그 내용물이 소스 코드라는 것을 알려주는 식이지요. 그래서 이 둘을 결합한 Textile의 bc. 태그가 생겨났습니다. ‘Block Code’라는 말 그대로 소스 코드 블록을 설정하는 태그랍니다. 예를 들어보지요.

bc. <br> 태그와 <br /> 태그 중에서 어느 것이 맞나요?
<pre><code>&#60;br&#62; 태그와 &#60;br /&#62; 태그 중에서 어느 것이 맞나요?
</code></pre>

지금 보시는 이 박스 안의 결과들도 모두 bc. 태그로 작성한 것이랍니다. 그러면 이 태그에도 class와 id를 지정해 볼까요?

bc(someclass#someid). 소스 코드
<pre class="someclass" id="someid"><code class="someclass">소스 코드
</code></pre>

소스 코드를 감싸는 <pre> 태그에는 class와 id가 지정되고 <pre> 태그 안의 <code> 태그에는 class만 지정되는 것을 볼 수 있습니다. 내부의 <code> 태그에 따로 class를 지정할 수 없으므로 그냥 <pre> 태그의 class를 물려받는 방식입니다. id까지 물려받으면 한 문서에 동일한 id 값이 두 개 이상이어서 html 기본 문법에 어긋나니 당연히 안되겠지요.

이제 다른 태그로 넘어가볼까요? bq. 태그와 비슷한 bq.. 태그입니다. 이 태그는 앞서 간단히 소개했던 bq. 태그의 확장판이라고 생각하시면 됩니다. html의 <blockquote> 태그는 인용문을 표현하는데 사용되는데 이 인용문이 하나의 단락(paragraph)일 경우도 있지만 여러 단락으로 이루어진 경우도 많습니다. 그런데 bq. 태그를 사용하면 하나의 단락만 처리할 수 있지요. 예를 들어볼까요?

bq. 첫 번째 인용
두 번째 인용
세 번째 인용
<blockquote>
  <p>첫 번째 인용<br />
  두 번째 인용</p>
</blockquote>
<p>세 번째 인용</p>

물론 <br /> 태그를 사용해서 한 단락으로 처리할 수도 있겠지요. 하지만 ‘의미 있는’ 방법은 아닙니다. 이런 경우에 bq.. 태그가 필요하지요. 이 태그는 이후의 모든 단락을 <blackquote> 태그로 묶어준답니다. 그러면 어떻게 인용문의 끝을 알 수 있을까요? 이 예를 보면 아실겁니다. 아울러 class와 id도 함께 지정해보도록 하지요.

bq(someclass#someid).. 첫 번째 인용
두 번째 인용
세 번째 인용
p. 단락 시작
<blockquote class="someclass" id="someid">
  <p class="someclass">첫 번째 인용<br />
  두 번째 인용</p>
  <p class="someclass">세 번째 인용</p>
</blockquote>
<p>단락 시작</p>

즉, 새 단락이 시작된다는 것을 명시적으로 표현해주면 인용문을 끝내고 새 단락으로 인식하게 됩니다. 또한 bc. 태그와 마찬가지로 <p> 태그가 <blockquote> 태그의 class 지정을 물려받는 것도 확인할 수 있습니다.

간단한 내용을 너무 복잡하게 설명했네요. 이번 글로 Textile 사용법을 마치려고 했는데 다음으로 미뤄야겠습니다. 다음 글에서 각주(foot note) 사용법과 머리 글자를 이용하는 약어 표기법(acronym)을 알아보고 정말 마칠겁니다^^;

Textile 관련 글 안내

  1. 시작하기
  2. 링크와 한글 입력
  3. 이미지 태그
  4. 리스트와 표
  5. 코드 출력과 인용문
  6. 각주와 약어

댓글이 없습니다. 태그: , , ,

Textile 리스트와 표

리스트와 표 작성은 더 이상 짜증나는 작업이 아닙니다. Textile을 사용하면 간단하게 입력할 수 있거든요.

먼저 순서 없는 리스트(Unordered List)를 만들어 볼까요? 리스트의 각 항목을 * 기호로 시작하면 됩니다. 아래 예처럼요.

* 리스트 항목 1
* 리스트 항목 2
** 리스트 항목 2-1
* 리스트 항목 3
<ul>
  <li>리스트 항목 1</li>
  <li>리스트 항목 2
    <ul>
      <li>리스트 항목 2-1</li>
    </ul>
  </li>
  <li>리스트 항목 3</li>
</ul>

* 기호와 항목 사이가 띄어쓰기 되어있는 것만 주의하시면 됩니다. 중첩된 리스트의 경우는 * 기호를 두 개 써주시면 XHTML 문법에 맞는 html 코드를 만들어 준답니다.

순서가 있는 리스트(Ordered List)도 같은 방법으로 만들 수 있습니다. * 기호 대신 # 기호를 써줘야 한다는 것 빼고요.

그럼 이번에는 순서 있는 리스트에 class, id 속성을 지정해 볼까요? CSS로 리스트의 모양을 조절할 수 있도록 말입니다.

#(someclass#someid) 리스트 항목 1
# 리스트 항목 2
## 리스트 항목 2-1
## 리스트 항목 2-2
# 리스트 항목 3
<ol class="someclass" id="someid">
  <li>리스트 항목 1</li>
  <li>리스트 항목 2
    <ol>
      <li>리스트 항목 2-1</li>
      <li>리스트 항목 2-2</li>
    </ol>
  </li>
  <li>리스트 항목 3</li>
</ol>

리스트를 시작하는 #, * 기호에 class나 id를 괄호 안에 넣어서 붙여주면 된답니다. 중첩된 리스트(리스트 항목 2-1)에는 ##(someclass) 처럼 class나 id를 적용할 수 없지만 아무 문제 없이 CSS를 적용할 수 있습니다. 예를 들어 다음과 같이 CSS를 작성하면 상위 리스트와 중첩된 리스트에 서로 다른 스타일의 항목 번호를 표시할 수 있습니다.

ol.someclass { list-style-type: upper-roman; }
ol.someclass li ol { list-style-type: lower-roman; }

그럼 리스트가 아래와 같이 화면에 표시됩니다.

  1. 리스트 항목 1
  2. 리스트 항목 2
    1. 리스트 항목 2-1
    2. 리스트 항목 2-2
  3. 리스트 항목 3

리스트에 관해서는 더 설명드릴 내용이 없네요. 너무 간단하지요?

그러면 표 작성으로 넘어가볼까요? 일단 간단한 예로 시작하겠습니다.

|1행 1열|1행 2열|1행 3열|
|2행 1열|2행 2열|2행 3열|
<table>
  <tr><td>1행 1열</td><td>1행 2열</td><td>1행 3열</td></tr>
  <tr><td>2행 1열</td><td>2행 2열</td><td>2행 3열</td></tr>
</table>

리스트와 마찬가지로 너무 쉽습니다. | 기호로 각 항목을 묶어주면 표가 만들어지지요. 그런데 첫 번째 행은 나머지 행에 어떤 자료들이 들어가는지 알려주는 역할을 하는 경우가 많습니다. 그래서 그 행을 헤더로 만들어주면 CSS를 이용해서 표를 훨씬 보기 좋게 꾸밀 수 있지요.

|_. 1행 1열|_. 1행 2열|_. 1행 3열|
|2행 1열|2행 2열|2행 3열|
<table>
  <tr><th>1행 1열</th><th>1행 2열</th><th>1행 3열</th></tr>
  <tr><td>2행 1열</td><td>2행 2열</td><td>2행 3열</td></tr>
</table>

| 기호 다음에 _ 기호와 마침표를 이어서 쓰면 표의 헤더로 인식해서 자동으로 <td> 태그 대신 <th> 태그를 붙여줍니다.

이제 조금 복잡한 테이블을 만들어 보겠습니다. 두 개 이상의 셀을 가로나 세로 방향으로 병합한 테이블이지요.

|1행 1열|1행 2열|1행 3열|
|\2. 2행 1,2열|2행 3열|
<table>
  <tr><td>1행 1열</td><td>1행 2열</td><td>1행 3열</td></tr>
  <tr><td colspan="2">2행 1,2열</td><td>2행 3열</td></tr>
</table>
|1행 1열|/2. 1,2행 2열|1행 3열|
|2행 1열|2행 3열|
<table>
  <tr><td>1행 1열</td><td rowspan="2">1,2행 2열</td><td>1행 3열</td></tr>
  <tr><td>2행 1열</td><td>2행 3열</td></tr>
</table>

셀을 가로 방향(colspan 태그)으로 병합할 때에는 | 기호 다음에 백슬래시(\)와 병합할 셀의 개수를 이어서 써주면 됩니다. 세로 방향(rowspan)이라면 백슬래시를 그냥 슬래시(/) 기호로 바꿔주시기만 하면 됩니다. 마침표와 띄어쓰기 한 칸을 잊지마세요. 그래야 Textile이 그 셀을 특별한 처리가 필요한 셀이라고 인식한답니다.

표에 자료를 입력했으니 스타일을 입힐 수 있도록 class와 id를 지정해 봐야겠지요? 이렇게 하시면 됩니다.

table(someclass#someid).
|1행 1열|1행 2열|1행 3열|
|2행 1열|2행 2열|2행 3열|
<table class="someclass" id="someid">
  <tr><td>1행 1열</td><td>1행 2열</td><td>1행 3열</td></tr>
  <tr><td>2행 1열</td><td>2행 2열</td><td>2행 3열</td></tr>
</table>

table 태그에 class와 id를 지정했습니다. 이 table 태그는 p 태그처럼 꼭 필요한 경우가 아니면 생략할 수 있기 때문에 앞선 예에서는 볼 수 없었답니다. 그럼 table 태그는 class, id 지정 말고 또 어떤 경우에 사용할까요?

table{border:1px solid black}.
<table style="border:1px solid black;">

지난 글에서 다루었던 ‘인라인 스타일’을 적용시킬 때에도 사용할 수 있습니다. 물론 ‘의미있는 마크업’을 위해서는 class와 id를 사용하는 것이 좋겠지요. class와 id는 테이블 전체 뿐 아니라 특정한 행이나 셀에도 부여할 수 있습니다.

table(tableclass).
(rowclass). |1행 1열|1행 2열|1행 3열|
|(cellclass). 2행 1열|2행 2열|2행 3열|
<table class="tableclass">
  <tr class="rowclass"><td>1행 1열</td><td>1행 2열</td><td>1행 3열</td></tr>
  <tr><td class="cellclass">2행 1열</td><td>2행 2열</td><td>2행 3열</td></tr>
</table>

그럼 CSS를 이용해서 표를 자유롭게 꾸밀 수 있습니다. 예를 들어서 첫 번째 행의 배경색과 2행 1열의 글자 색을 바꿔보겠습니다.

table.tableclass tr.rowclass { background-color: #aaa; }
table.tableclass tr td.cellclass { color: red; }

아래 표에서 배경색과 글자색이 바뀌는 것을 확인할 수 있습니다. 물론 이 표의 실제 CSS는 조금 더 복잡하지만 배경색과 글자색은 위 CSS 규칙과 동일합니다.

1행 1열1행 2열1행 3열
2행 1열2행 2열2행 3열

이렇게 해서 Textile로 리스트와 표를 작성하는 법을 알아봤습니다. 개인적으로는 이 부분이 Textile의 편리함을 가장 잘 보여준다고 생각한답니다. 복잡한 표를 제외하고는 그냥 눈에 보이는대로 작성하면 되니까요.

이제 Textile에 관해서 대부분 설명했네요. 다음 글에서 html 코드를 그대로 출력하는 방법과 인용문을 표시하는 방법을 알아보고 몇 가지 기타 태그 사용법을 정리하는 것으로 Textile 사용법에 관한 글을 끝맺을까 합니다.

Textile 관련 글 안내

  1. 시작하기
  2. 링크와 한글 입력
  3. 이미지 태그
  4. 리스트와 표
  5. 코드 출력과 인용문
  6. 각주와 약어

댓글이 없습니다. 태그: , , ,

웹 표준에 관한 생각

‘웹 표준을 지킨다는 것’의 의미와 그럼으로써 얻을 수 있는 이점에 관해 적어볼까 합니다.

웹 표준을 지키려면 먼저 그 의미를 알아야겠지요? 웹 표준에 관한 글을 읽다 보면 다음과 같은 생각을 하는 분들을 볼 수 있습니다.

“테이블 대신 div 태그와 CSS로 레이아웃을 만들고, XHTML 검증(Validation)을 통과하면 웹 표준을 지키는 것이다.”

틀린 얘기는 아닙니다. 하지만 웹 표준을 준수하려면 더 많은 것을 고려해야 합니다. 단순히 기술적인 면에 국한된 문제가 아니지요.

‘웹 표준’을 이해하기 위해서는 웹 표준을 제정하는 ‘월드 와이드 웹 컨소시엄(World Wide Web Consortium: 이하 W3C)’이 지향하는 바가 무엇인지를 알아야 합니다. W3C는 그들의 존재 이유를 다음과 같이 밝히고 있지요.

“웹(월드 와이드 웹)이 최대한의 능력을 발휘할 수 있도록 지침(Guideline)을 만을어서 웹의 장기적인 발전을 도모한다.”

즉, W3C의 목표는 웹의 지속적인 발전입니다. 그러기 위해서 아래와 같은 몇 가지 세부 목표를 세워서 추진하고 있지요.

  1. 모든 사람들을 위한 웹: 사람들이 생각과 정보를 나누고 경제 활동을 하는데 있어서 웹은 큰 비중을 갖습니다. 이런 이익을 하드웨어나 네트워크 인프라, 언어, 문화, 지역적인 차이, 육체적 또는 정신적 차이와 상관없이 모든 사람들이 누릴 수 있도록 하자는 것이지요.
  2. 모든 장치를 위한 웹: 컴퓨터나 핸드폰, 스마트폰 등의 어떤 장치로도 웹을 이용할 수 있도록 지원하고 있습니다.
  3. 정보의 기반: 웹의 힘은 단순히 나열된 정보에 기반하지 않습니다. 잘 구조화된 정보를 통해서 웹은 최대한의 힘을 발휘할 수 있지요. 이를 위해서 사람과 처리 장치 모두를 위한 정보를 담을 수 있는 표준을 만들고 있습니다.
  4. 믿을 수 있고 확실한 웹: 더 많은 사람들이 안전하게 참여할 수 있도록 신뢰성 향상을 위해 노력하고 있습니다.

이런 목표 달성을 돕기 위해서 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를 사용하는 디자인을 떠올리고, 어떤 사람은 접근성 향상을 위한 보이스 리더를 생각할 것입니다. 불여우와 익스플로러의 렌더링 차이를 생각하는 분들도 있겠지요.

의미가 다양한 만큼 웹 표준에 관해서 어떤 생각이 절대적으로 옳다고는 누구도 말할 수 없을겁니다. 하지만 한 때의 유행으로 끝나지는 않을거라는데 많은 분들이 동의하시리라 생각합니다. 웹 표준이 무시할 수 없는 흐름이라면 다양한 생각들을 교환하면서 이해의 폭을 넓혀가는게 좋지 않을까 하는 마음으로 제 생각을 적어봤답니다.

댓글 3개가 달렸습니다. 태그: , , , ,

Textile 이미지 태그

Textpattern은 업로드된 이미지를 쉽게 불러올 수 있도록 해주는 자체적인 태그를 갖고 있습니다.

바로 <txp:article_image /><txp:image /> 태그지요. 하지만 외부 이미지를 불러올 때처럼 직접 img 태그를 써야 할 경우도 있는데 Textile을 사용하면 쉽고 편하게 태그를 입력할 수 있습니다.

계정 루트 디렉토리에 carver.gif 이미지가 있다고 가정하고 불러와 볼까요? 간단하게 불러올 파일의 절대경로를 느낌표로 묶어주면 됩니다.

!http://blog.wystan.net/carver.gif!
!/carver.gif!
<p><img src="http://blog.wystan.net/carver.gif" alt="" /><br />
<img src="/carver.gif" alt="" /></p

그럼 이번에는 img 태그의 title, alt 속성을 함께 넣어보겠습니다.

!/carver.gif(sometext)!
<p><img src="/carver.gif" title="sometext" alt="sometext" /></p>

위 예처럼 파일명 뒤에 텍스트를 괄호로 감싸서 넣어주면 두 가지 속성에 적용됩니다. 그러면 이 이미지에 링크를 넣어볼까요? 앞서 다루었던 Textile 링크 태그와 거의 같습니다. 따옴표가 느낌표로 바뀐 것 빼고는요.

!/carver.gif(sometext)!:http://.../
<p><a href="http://.../">
<img src="/carver.gif" title="sometext" alt="sometext" /></a></p>

이미지의 align 속성을 이용해서 왼쪽이나 오른쪽, 중앙 정렬을 시킬 수 있는데 각각 !< , !> , != 태그를 사용하면 됩니다.

!>/carver.gif!:http://.../
<p><a href="http://.../">
<img src="/carver.gif" align="right" /></a></p>

앞에서 소개하지 않았지만 Textile을 이용해서 태그에 직접 스타일을 지정할 수 있습니다. ‘인라인 스타일’이라고 하는데 간단한 예를 들어보지요.

!{border: 1px solid black;}/carver.gif!:http://.../
<p><a href="http://.../">
<img src="/carver.gif" style="border: 1px solid black;" /></a></p>

Textile의 인라인 스타일은 p, h1, table 등의 여러 태그에 적용됩니다. 하지만 지금껏 소개하지 않은 이유는 스타일을 적용시키는 더 좋은 방법이 있기 때문이랍니다. 바로 class와 id를 이용하는 것이지요. 이런 방법을 이용하면 보다 ‘의미있는(Semantic)’ html 문서를 만들 수 있습니다. 여기서 말하는 ‘의미있다’는 표현을 명확하게 정의하기는 어렵지만 제 생각은 이렇습니다.

“html 태그는 문서의 내용을 체계적으로 담는데 사용하고, 문서를 꾸미고 디자인하기 위해서는 CSS를 사용한다.”

간단히 요약하면 디자인을 위한 html 태그 사용을 최대한 줄이자는 것입니다. 위의 예를 다시 생각해볼까요? 이번에는 p 태그를 빼서 코드를 간단히 써보겠습니다.

!{border: 1px solid black;}/carver.gif!
!(someclass)/carver.gif!
<img src="/carver.gif" style="border: 1px solid black;" alt="" />
<img src="/carver.gif" class="someclass" alt="" />

인라인 스타일을 사용한 예는 이미지가 들어간다는 문서의 내용과 함께 그 이미지가 어떤 테두리를 가져야 하는지를 함께 알려주고 있습니다. 하지만 두 번째 예는 문서에 이미지가 들어가고, 그 이미지가 어떤 부류에 속하는가에 대한 정보만을 담고 있지요.

이미지가 어떤 특정한 ‘부류’에 속하기 때문에 CSS를 사용해서 이 부류에 적용될 스타일을 지정할 수 있습니다. 그러면 두 이미지가 브라우저에서 똑같이 보이게 됩니다.

img.someclass { border: 1px solid black; }

위에서 이미지를 정렬하기 위해서 align 속성을 이용했는데 이 속성도 문서의 내용과는 관련이 없고 다만 어떻게 보여지는가를 지정할 뿐입니다. 그래서 의미를 강조하는 엄격한 html 표준(XHTML 1.0 Strict)에서는 이 속성의 사용을 금지하고 있습니다. 이 속성 대신에 CSS를 사용하면 보다 의미있는 html 문서를 작성할 수 있는데 동일한 결과를 얻기 위해서는 다음과 같이 태그를 작성하면 됩니다.

p(pclass). !(imageclass)/carver.gif!
<p class="pclass"><img src="/carver.gif" class="imageclass" alt="" /></p>

CSS에서는 이미지에 직접 align 속성을 지정할 수 없지만 대신 이미지를 감싸는 p 태그에 오른쪽 정렬을 주거나 이미지 자체를 오른쪽으로 띄울 수 있습니다.

p.someclass { text-align: right; } or img.imageclass { float: right; }

이미지 태그에서 시작했는데 어느덧 주제에서 벗어난 글이 되었네요^^; ‘의미있는 마크업’의 장점에 대해서는 나중에 다시 다뤄볼 생각입니다. 원래 Textile을 이용한 리스트와 표 작성까지 정리하려고 했는데 다음 글로 미뤄야겠네요.

Textile 관련 글 안내

  1. 시작하기
  2. 링크와 한글 입력
  3. 이미지 태그
  4. 리스트와 표
  5. 코드 출력과 인용문
  6. 각주와 약어

댓글이 없습니다. 태그: , , ,

Textile 링크와 한글 입력

Textile을 사용하면 쉽고 편하게 html 태그를 입력할 수 있는데 그 이유중의 하나는 태그의 끝을 알리는 ‘닫는 태그’가 없기 때문입니다.

예를 들어 html과 Textile의 링크 태그를 비교해보겠습니다.

"링크":http://.../
<p><a href="http://.../">링크</a></p>

html은 태그의 끝을 </a>로 표시하지만 Textile은 이런 표시가 없습니다. 그럼 Textile은 어떻게 태그의 끝을 알 수 있을까요?

그건 Textile이 영어를 기반으로 만들어졌기 때문입니다. 영어에서는 강조나 링크 같은 어떤 표현의 기본 단위가 ‘단어’로 제한됩니다. 영어와 한글 링크의 예를 들어보겠습니다.

click here to go, 여기를 클릭하세요.

한글 링크에서는 체언과 조사가 띄어쓰기 없이 같이 쓰이기 때문에 단순히 앞 뒤의 띄어쓰기 만으로는 태그의 끝을 판별할 수 없습니다. 이 한글 링크를 Textile로 쓰면 아래와 같습니다.

"여기":http://.../를 클릭하세요.
<p><a href="http://.../�">여기</a>�� 클릭하세요.</p>

물론 이런 오류는 대부분 자동으로 수정됩니다. 지금까지 특별한 처리를 하지 않았음에도 링크 태그에 문제가 생긴적은 없었습니다. 하지만 명확하지 않은 문법은 언제든 문제를 일으키기 마련이지요. 초기 버전의 Textile은 이런 문제를 고려하지 않았지만 꾸준한 업데이트로 문제를 해결했습니다.

바로 대괄호[]를 사용하는 것이지요. 위의 예를 다시 쓰면 다음과 같습니다.

["여기":http://.../]를 클릭하세요.
<p><a href="http://.../">여기</a>를 클릭하세요.</p>

링크가 이상없이 연결되었으니 CSS 스타일링을 위해 class와 id를 지정해볼까요? 또한 링크의 title 속성도 함께 입력해보겠습니다.

["(someclass#someid)여기(sometitle)":http://.../]를 클릭하세요.
<p><a href="http://.../" class="someclass" id="someid" title="sometitle">여기</a>
를 클릭하세요.</p>

class 지정이 안되신다고요? 텍스트패턴 4.0.4 버전에 포함된 Textile 라이브러리를 최신 버전으로 업데이트하면 문제가 해결됩니다.

이 대괄호는 비단 링크 태그 뿐 아니라 비슷한 문제를 일으킬 수 있는 여러 인라인 태그에 동일하게 적용됩니다. 인라인 태그란 블록이 아닌 일부분의 텍스트에 강조나 링크 등의 의미를 부여할 때 사용되는데 그 예는 아래와 같습니다.

Textile 입력 html 변환 화면 출력
*강하게* <strong>강하게</strong> 강하게
**두껍게** <b>두껍게</b> 두껍게
_강조_ <em>강조</em> 강조
__이탤릭__ <i>이탤릭</i> 이탤릭
??사이트?? <cite>사이트</cite> 사이트
-지워짐- <del>강하게</del> 지워짐
+더해짐+ <ins>더해짐</ins> 더해짐
^윗 첨자^ <sup>윗 첨자</sup> 윗 첨자
~아랫 첨자~ <sub>아랫 첨자</sub> 아랫 첨자
@코드@ <code>코드</code> 코드
%span% <span>span</span> span

이런 태그들은 시작과 끝을 알리는 태그가 동일하고, 보통 글을 입력할 때 충분히 사용할 가능성이 있는 기호를 태그로 사용합니다. 그러면 글 중간에 단순히 기호로 사용하기 위해서 이 문자들을 입력하면 어떻게 될까요? 아래 예를 통해 확인하시기 바랍니다.

가나* 다라*마바 *사아*자차* 카타*
<p>가나* 다라*마바 <strong>사아*자차</strong> 카타*</p>

시작과 끝을 표시한다고 해서 문제가 다 해결되는 것은 아니라는 것을 알 수 있습니다. 여기서 앞서 얘기한 ‘단어’ 개념이 다시 등장하지요. 즉 시작되는 태그 앞과 닫는 태그 뒤에 공백이 있을 경우에만 태그가 적용되도록 한 것입니다. 당연히 링크 태그와 같은 문제가 생길 것이고, 마찬가지로 대괄호를 이용해서 문제없이 입력할 수 있습니다.

가나* 다라*마바 [*사아*]자차* 카타*
<p>가나* 다라*마바 <strong>사아</strong>자차* 카타*</p>

이번에는 Textile이 자동으로 바꿔주는 html 기호 문자(Symbolic Character Entities)에 대해 알아보지요. 이 기능을 통해서 일부 기호 문자를 쉽게 입력할 수 있습니다. 그럼 어떤 기호가 어떻게 바뀌는지 보실까요?

Textile 입력 html 변환 화면 출력
"큰 따옴표" &#8220;큰 따옴표&#8221; “큰 따옴표”
'작은 따옴표' &#8216;작은 따옴표&#8217; ‘작은 따옴표’
하이픈--둘 하이픈&#8212;둘 하이픈—둘
말줄임... 말줄임&#8230; 말줄임…
2x2 2&#215;2 2×2

편리한 기능이지만 역시 한글을 입력하면 문제가 생깁니다. 더군다나 현재까지는 대괄호를 사용해도 같은 결과가 발생합니다. 예를 들어볼까요? 앞으로는 아래 박스에 html 코드가 아닌 직접 화면에 출력되는 텍스트를 표시하겠습니다.

“큰 따옴표 쓰기”, “큰 따옴표“를 쓰기, ‘작은 따옴표 쓰기’, ‘작은 따옴표‘를 쓰기

"큰 따옴표"를 쓰기, ["큰 따옴표"]를 쓰기
“큰 따옴표“를 쓰기, [“큰 따옴표”]를 쓰기

대괄호가 아무 효과를 발휘하지 못하고 그냥 문자로 표시되는 것을 볼 수 있습니다. 그러면 어떻게 해야할까요?

제가 선택한 방법은 따옴표로 묶을 부분에 강조 태그를 넣는 겁니다. 따옴표를 인용문에 사용할 경우에는 대부분 따옴표로 행을 끝맺기 때문에 특별히 문제가 생기지 않습니다. 하지만 강조의 의미로 따옴표를 사용할 경우가 문제이지요.

"강조의 의미로 '따옴표'를 사용하기"
“강조의 의미로 ‘따옴표‘를 사용하기”

그렇기 때문에 강조 태그를 함께 써줘도 의미상 큰 차이가 없습니다. 강조를 표현하는 em 태그를 써볼까요?

"강조의 의미로 [_'따옴표'_]를 사용하기"
“강조의 의미로 ‘따옴표’를 사용하기”

작은 따옴표가 제대로 표시되는 것을 볼 수 있습니다. 다만 대부분의 브라우저에서 기본적으로 em 태그를 이탤릭체로 나타내므로 CSS에 다음과 같은 규칙을 추가시켜줘야 합니다.

em { font-style: normal; }

이런 방식으로 Textile에서의 한글 입력 문제를 해결할 수 있습니다. 다음 글에서는 Textile을 사용해서 이미지를 표시하고 리스트와 표를 작성하는 방법을 알아보겠습니다.

Textile 관련 글 안내

  1. 시작하기
  2. 링크와 한글 입력
  3. 이미지 태그
  4. 리스트와 표
  5. 코드 출력과 인용문
  6. 각주와 약어

댓글 2개가 달렸습니다. 태그: , , ,

Textile 시작하기

Textile은 ‘가벼운 마크업 언어’입니다. 여기서의 ‘가볍다’는 표현은 ‘간단한 문법’, ‘쉬운 태그 입력’, ‘사용자 친화적인 코드’ 등의 의미를 내포합니다. 즉 간단하고 쓰기 쉬운 마크업 언어라는 것이죠.

Textile은 Dean Allen에 의해 PHP로 개발되었으며, 펄, 파이썬, 루비, 자바 등으로 다양하게 컨버전되었습니다. Textile이 Textpattern에 포함된 것은 어찌보면 당연한 일입니다. 왜냐하면 Textpattern의 개발자가 앞서 말한 Dean Allen이기 때문이지요. 또한 워드프레스 사용자들도 Textile Wrapper 플러그인을 설치하면 Textile로 글을 쓸 수 있습니다.

Textile의 문법이 html보다 쉬운건 사실이지만 html 태그에 익숙한 분들이라도 어느 정도 연습을 해야만 쓸 수 있습니다. 새로운 문법을 배우는 것이니까요. 하지만 이지윅이 아닌 텍스트 입력 방식을 선호하는 분들께는 충분히 배울 만한 가치가 있답니다.

문법을 연습할 가장 좋은 장소는 Threshold State의 Textile 페이지입니다. 페이지 왼쪽의 도움말을 참고해서 글을 입력하면 변환된 html 코드와 그 출력 결과를 볼 수 있습니다.

문법에 관한 보다 자세한 설명은 Textile Reference 페이지를 참고하시면 됩니다.

그럼 Textile Reference의 글을 참고해서 몇 가지 실용적인 예를 들어보겠습니다. 각 예에서 위 박스는 입력한 텍스트를, 아래 박스는 변환된 html 코드를 나타냅니다.

가장 먼저 이해해야 할 것은 문단 태그인 p 태그입니다. Textile에서는 기본적으로 모든 입력이 p 태그 안에서 이루어집니다. 즉 태그 없이 입력한 텍스트에도 자동으로 p 태그가 붙게 되죠.

간단한 텍스트
<p>간단한 텍스트</p>

p 태그는 div, bq, ul, ol, h1, h2 등의 태그처럼 블록을 설정해서 그 안에 내용물을 표시해줍니다. 그럼 이 블록의 끝을 표시하려면 어떻게 해야할까요? Enter 키로 줄을 바꿔도 블록은 유지됩니다. 바뀐 줄 앞에 <br /> 태그가 삽입될 뿐이죠.

줄바꿈
테스트
<p>줄바꿈<br />
테스트</p>

하지만 Enter 키를 한 번 더 눌러서 중간에 빈 줄을 넣어주면 블록 태그가 닫히고 새 블록이 시작됩니다.

줄바꿈
테스트
<p>줄바꿈</p>
<p>테스트</p>

이렇게 자동으로 붙는 p 태그지만 때로는 직접 지정해줄 필요가 있습니다. 바로 CSS 스타일을 적용하기 위해서죠. Textile에서 태그에 id와 class를 지정하려면 괄호 안에 넣어주면 됩니다. 이제 p, h1, blockquote 태그에 id와 class를 지정해 볼까요?

p(#someid). id 지정

h1(someclass). class 지정

bq(someclass#someid). id, class 지정
<p id="someid">id 지정</p>
<h1 class="someclass">class 지정</h1>
<blockquote class="someclass" id="someid">
  <p class="someclass">id, class 지정</p>
</blockquote>

† blockquote 태그에 class를 지정할 경우 blockquote 태그 안의 p 태그에도 동일한 class가 적용됩니다. 오류 알려주신 연가시 님께 감사드립니다.

blockquote 태그 안의 텍스트에도 자동으로 p 태그가 붙는다는 것에 유의하세요. Textile의 블록 설정 태그에는 이외에도 h2. ~ h6. , pre. , bc. , bq.. , fnn. 등이 있는데 이 태그들에 대해서는 나중에 따로 알아보겠습니다. 다만 이 태그들이 식별자(p, h1, bq)와 마침표, 공백 하나로 시작된다는 것은 기억해두시길 바랍니다.

때로는 여러 블록을 div 태그로 감싸서 스타일을 적용해야 할 경우도 있습니다. Textile에서는 자체적으로 div 태그를 지원하지 않지만 모든 html 태그를 그대로 사용할 수 있으므로 아무 문제가 없습니다. 예를 보실까요?

<div class="someclass">
간단한 텍스트
</div>
<div class="someclass">
간단한 텍스트
</div>

하지만 div 태그 안에 빈 줄이 들어가게 되면 문제가 생깁니다. 빈 줄을 넣지 않으면 블록을 닫을 수 없기 때문에 div 태그 안에서는 Textile을 전혀 쓸 수 없게 됩니다.

<div class="someclass">
간단한 텍스트 </div>
<p><div class="someclass"></p>
<p>간단한 텍스트<br />
</div></p>

이런 문제를 해결하기 위해서는 특정한 행이나 블록에 Textile이 적용되지 않도록 해야하는데 두 가지 방법이 있습니다. 먼저 notextile. 태그를 사용해서 명시적으로 지정하는 방법입니다.

notextile. <div class="someclass">
notextile. 간단한 텍스트 </div>
<div class="someclass">
간단한 텍스트
</div>

위 예처럼 notextile. 로 시작되는 블록은 Textile이 적용되지 않습니다. 또 다른 방법은 무척 간단합니다. 태그 앞에 공백 하나를 넣는 것이지요. Textile은 항상 행의 첫 번째 문자부터 블록 레벨의 태그를 인식합니다. 즉, 행 중간에 h1. 같은 태그가 있으면 태그가 아닌 일반 택스트로 판단한다는 얘기지요. 예를 보시죠.

  <div class="someclass">
간단한 텍스트 </div>
  <div class="someclass">
   간단한 텍스트
  </div>

이런 방식으로 Textile 태그와 html 태그를 자유롭게 섞어서 사용하실 수 있습니다.

† Textile 사용법을 간단하게 정리하려고 글을 시작했는데 간단하게 정리가 안되네요^^; 그래서 부분적으로 나누어 쓰기로 했습니다. 다음 글에서는 자주 사용되는 링크와 강조 태그에 대해 알아보고 Textile로 한글을 입력할 경우 발생하는 문제와 해결책을 다루겠습니다.

Textile 관련 글 안내

  1. 시작하기
  2. 링크와 한글 입력
  3. 이미지 태그
  4. 리스트와 표
  5. 코드 출력과 인용문
  6. 각주와 약어

댓글 4개가 달렸습니다. 태그: , , ,

태그