반응형
CSS (Cascading Style Sheets) Level 1

CSS는 일찍이 HTML의 타락(문서의 구조가 아닌 표현과 관련된 태그로 오염되는)과 웹디자이너의 아픔과 고통을 덜고자 탄생했다.
CSS는 HTML을 보완하고, 사이트의 전체적인 스타일과 디자인을 통일성 있게 계획하고 제작할 수 있도록 도와주는 W3C의 표준입니다.
CSS 명세 … http://www.w3.org/Style/CSS/
CSS1 부라우저 호환성 표 … http://www.ddj.com/webreview/style/css1/charts/mastergrid.shtml
아래의 Form Value Example에서 "속성값1 | 속성값2" 로 적어준 것에서 | 는 or 의 의미로 사용하였다. 즉, 여러 속성값 중에 하나들 선택하여 적용할 수 있음을 뜻한다. || 는 속성값을 적용하는 또 다른 방법을 보여준다.


Cascading Style Sheet Level 1 (CSS1) Properties
Properties Set Property: Korean Name Form Value Example
Font
글꼴
font-family: 글꼴종류 font-family: family-name | generic-family || , ,"",
font-style: 글꼴체 font-style: normal | italic | oblique
font-variant: 글꼴변형 font-variant: normal | small-cap
font-weight: 글꼴굵기 font-weight: normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
font-size: 글꼴크기 font-size: xx-small | x-small | small | medium | large | x-large | xx- large || larger | smaller || length
font: 글꼴 font : font-style font-variant font-weight font-size line-height font-family
Color
and
Background
색상과 배경
color: 색상 color: #000000 | black
background-color: 배경색 background-color: #000000 | black
background-image: 배경그림 background-image: url(image.gif)
background-repeat: 배경그림 반복 background-repeat: repeat|repeat-x|repeat-y|no-repeat
background-attachment: 배경의 성격 background-attachment: scroll | fixed
background-position: 배경그림 위치 background-position: length || top left || top|center|bottom|left|center|right
background: 배경 background: background-color background-image background-repeat background-attachment background-position
Text
문장
word-spacing: 낱말간격 word-spacing: normal | length
letter-spacing: 문자간격 letter-spacing: normal | length
text-decoration: 장식 text-decoration: none | underline | overline | line-through | blink
vertical-align: 수직정렬 vertical-align: baseline | sub | super | top | text-top | middle | bottom | text-bottom | percentage
text-transform: 문자변환 text-transform: none | capitalize | uppercase | lowercase
text-align: 수평정렬 text-align: left | right | center | justify
text-indent: 들여쓰기 text-indent: length
line-height: 줄간격 line-height: normal | length
Box
바깥여백
margin-top:
margin-right:
margin-bottom:
margin-left:
margin: 바깥여백 DIV { margin: top right bottom left }
Box
안여백
padding-top:
padding-right:
padding-bottom:
padding-left:
padding: 안여백 DIV { margin: top right bottom left }
Box
테두리선
border-top-width:
border-right-width:
border-bottom-width:
border-left-width:
border-width: 선굵기 border-width: thin | medium | thick | length || top rigth bottom left
border-color: 선색상 border-color: color || top rigth bottom left
border-style: 선형태 border-style: none|dotted|dashed|solid|double|groove|ridge|inset|outset || top rigth bottom left
border-top:
border-right:
border-bottom:
border-left:
border: 테두리선 border: border-widht border-style color
Box
크기
width: 너비 width: length | percentage | auto
height: 높이 height: length | percentage | auto
Box
배치
float: 어울림 float: left | right | none
clear: 배척함 clear: none | left | right | both
Classification
Properties
문단형식
display: 표시 display: block | inline | list-item | none
white-space: 공백 white-space: normal | pre | nowrap
list-style-type: list-style-type: disc | circle | square | decimal | lower-roman | upper-roman | lower-alpha | upper-alpha | none
list-style-image: list-style-image: url(image.gif) | none
list-style-position: list-style-position: inside | outside
list-style: 목록 list-style: list-style-type list-style-position || url(image)




CSS Level 2
CSS2 Reference … http://www.w3schools.com/css/css_reference.asp

CSS2 Reference

속성 링크를 클릭하면 해당 속성의 유용한 정보를 볼 수 있습니다

Browser support :  NN: Netscape, IE: Internet Explorer, W3C: Web Standard

Background

On-line examples

Property Description Values NN IE W3C
background A shorthand property for setting all background properties in one declaration background-color
background-image
background-repeat background-attachment background-position
6.0 4.0 CSS1
background-attachment Sets whether a background image is fixed or scrolls with the rest of the page scroll
fixed
6.0 4.0 CSS1
background-color Sets the background color of an element color-rgb
color-hex
color-name
transparent
4.0 4.0 CSS1
background-image Sets an image as the background url
none
4.0 4.0 CSS1
background-position Sets the starting position of a background image top left
top center
top right
center left
center center
center right
bottom left
bottom center
bottom right
x-% y-%
x-pos y-pos
6.0 4.0 CSS1
background-repeat Sets if/how a background image will be repeated repeat
repeat-x
repeat-y
no-repeat
4.0 4.0 CSS1

Border

On-line examples

Property Description Values NN IE W3C
border A shorthand property for setting all of the properties for the four borders in one declaration border-width
border-style
border-color
4.0 4.0 CSS1
border-bottom A shorthand property for setting all of the properties for the bottom border in one declaration border-bottom-width
border-style
border-color
6.0 4.0 CSS1
border-bottom-color Sets the color of the bottom border border-color 6.0 4.0 CSS2
border-bottom-style Sets the style of the bottom border border-style 6.0 4.0 CSS2
border-bottom-width Sets the width of the bottom border thin
medium
thick
length
4.0 4.0 CSS1
border-color Sets the color of the four borders, can have from one to four colors color 6.0 4.0 CSS1
border-left A shorthand property for setting all of the properties for the left border in one declaration border-left-width
border-style
border-color
6.0 4.0 CSS1
border-left-color Sets the color of the left border border-color 6.0 4.0 CSS2
border-left-style Sets the style of the left border border-style 6.0 4.0 CSS2
border-left-width Sets the width of the left border thin
medium
thick
length
4.0 4.0 CSS1
border-right A shorthand property for setting all of the properties for the right border in one declaration border-right-width
border-style
border-color
6.0 4.0 CSS1
border-right-color Sets the color of the right border border-color 6.0 4.0 CSS2
border-right-style Sets the style of the right border border-style 6.0 4.0 CSS2
border-right-width Sets the width of the right border thin
medium
thick
length
4.0 4.0 CSS1
border-style Sets the style of the four borders, can have from one to four styles none
hidden
dotted
dashed
solid
double
groove
ridge
inset
outset
6.0 4.0 CSS1
border-top A shorthand property for setting all of the properties for the top border in one declaration border-top-width
border-style
border-color
6.0 4.0 CSS1
border-top-color Sets the color of the top border border-color 6.0 4.0 CSS2
border-top-style Sets the style of the top border border-style 6.0 4.0 CSS2
border-top-width Sets the width of the top border thin
medium
thick
length
4.0 4.0 CSS1
border-width A shorthand property for setting the width of the four borders in one declaration, can have from one to four values thin
medium
thick
length
4.0 4.0 CSS1

Classification

On-line examples

Property Description Values NN IE W3C
clear Sets the sides of an element where other floating elements are not allowed left
right
both
none
4.0 4.0 CSS1
cursor Specifies the type of cursor to be displayed url
auto
crosshair
default
pointer
move
e-resize
ne-resize
nw-resize
n-resize
se-resize
sw-resize
s-resize
w-resize
text
wait
help
6.0 4.0 CSS2
display Sets how/if an element is displayed none
inline
block
list-item
run-in
compact
marker
table
inline-table
table-row-group
table-header-group
table-footer-group
table-row
table-column-group
table-column
table-cell
table-caption
4.0 4.0 CSS1
float Sets where an image or a text will appear in another element left
right
none
4.0 4.0 CSS1
position Places an element in a static, relative, absolute or fixed position static
relative
absolute
fixed
4.0 4.0 CSS2
visibility Sets if an element should be visible or invisible visible
hidden
collapse
6.0 4.0 CSS2

Dimension

On-line examples

Property Description Values NN IE W3C
height Sets the height of an element auto
length
%
6.0 4.0 CSS1
line-height Sets the distance between lines normal
number
length
%
4.0 4.0 CSS1
max-height Sets the maximum height of an element none
length
%
    CSS2
max-width Sets the maximum width of an element none
length
%
    CSS2
min-height Sets the minimum height of an element length
%
    CSS2
min-width Sets the minimum width of an element length
%
    CSS2
width Sets the width of an element auto
%
length
 
4.0 4.0 CSS1

Font

On-line examples

Property Description Values NN IE W3C
font
A shorthand property for setting all of the properties for a font in one declaration font-style
font-variant
font-weight
font-size/line-height
font-family
caption
icon
menu
message-box
small-caption
status-bar
4.0 4.0 CSS1
font-family
A prioritized list of font family names and/or generic family names for an element family-name
generic-family
4.0 3.0 CSS1
font-size
Sets the size of a font xx-small
x-small
small
medium
large
x-large
xx-large
smaller
larger
length
%
4.0 3.0 CSS1
font-size-adjust Specifies an aspect value for an element that will preserve the x-height of the first-choice font none
number
    CSS2
font-stretch Condenses or expands the current font-family normal
wider
narrower
ultra-condensed
extra-condensed
condensed
semi-condensed
semi-expanded
expanded
extra-expanded
ultra-expanded
    CSS2
font-style
Sets the style of the font normal
italic
oblique
4.0 4.0 CSS1
font-variant
Displays text in a small-caps font or a normal font normal
small-caps
6.0 4.0 CSS1
font-weight
Sets the weight of a font normal
bold
bolder
lighter
100
200
300
400
500
600
700
800
900
4.0 4.0 CSS1

Generated Content

Property Description Values NN IE W3C
content Generates content in a document. Used with the :before and :after pseudo-elements string
url
counter(name)
counter(name, list-style-type)
counters(name, string)
counters(name, string, list-style-type)
attr(X)
open-quote
close-quote
no-open-quote
no-close-quote
    CSS2
counter-increment Sets how much the counter increments on each occurrence of a selector none
identifier number
    CSS2
counter-reset Sets the value the counter is set to on each occurrence of a selector none
identifier number
    CSS2
quotes Sets the type of quotation marks none
string string
    CSS2

List and Marker

On-line examples

Property Description Values NN IE W3C
list-style A shorthand property for setting all of the properties for a list in one declaration list-style-type
list-style-position
list-style-image
6.0 4.0 CSS1
list-style-image Sets an image as the list-item marker none
url
6.0 4.0 CSS1
list-style-position Sets where the list-item marker is placed in the list inside
outside
6.0 4.0 CSS1
list-style-type Sets the type of the list-item marker none
disc
circle
square
decimal
decimal-leading-zero
lower-roman
upper-roman
lower-alpha
upper-alpha
lower-greek
lower-latin
upper-latin
hebrew
armenian
georgian
cjk-ideographic
hiragana
katakana
hiragana-iroha
katakana-iroha
4.0 4.0 CSS1
marker-offset   auto
length
    CSS2

Margin

On-line examples

Property Description Values NN IE W3C
margin A shorthand property for setting the margin properties in one declaration margin-top
margin-right
margin-bottom
margin-left
4.0 4.0 CSS1

margin-bottom

Sets the bottom margin of an element auto
length
%
4.0 4.0 CSS1

margin-left

Sets the left margin of an element auto
length
%
4.0 3.0 CSS1

margin-right

Sets the right margin of an element auto
length
%
4.0 3.0 CSS1
margin-top Sets the top margin of an element auto
length
%
4.0 3.0 CSS1

Outlines

Property Description Values NN IE W3C
outline A shorthand property for setting all the outline properties in one declaration outline-color
outline-style
outline-width
    CSS2
outline-color Sets the color of the outline around an element color
invert
    CSS2
outline-style Sets the style of the outline around an element none
dotted
dashed
solid
double
groove
ridge
inset
outset
    CSS2
outline-width Sets the width of the outline around an element thin
medium
thick
length
    CSS2

Padding

On-line examples

Property Description Values NN IE W3C
padding A shorthand property for setting all of  the padding properties in one declaration padding-top
padding-right
padding-bottom
padding-left
4.0 4.0 CSS1

padding-bottom

Sets the bottom padding of an element length
%
4.0 4.0 CSS1

padding-left

Sets the left padding of an element length
%
4.0 4.0 CSS1

padding-right

Sets the right padding of an element length
%
4.0 4.0 CSS1
padding-top Sets the top padding of an element length
%
4.0 4.0 CSS1

Positioning

On-line examples

Property Description Values NN IE W3C
bottom Sets how far the bottom edge of an element is above/below the bottom edge of the parent element auto
%
length
6.0 5.0 CSS2
clip Sets the shape of an element. The element is clipped into this shape, and displayed shape
auto
6.0 4.0 CSS2
left Sets how far the left edge of an element is to the right/left of the left edge of the parent element auto
%
length
4.0 4.0 CSS2
overflow
Sets what happens if the content of an element overflow its area visible
hidden
scroll
auto
6.0 4.0 CSS2
right Sets how far the right edge of an element is to the left/right of the right edge of the parent element auto
%
length
  5.0 CSS2
top Sets how far the top edge of an element is above/below the top edge of the parent element auto
%
length
4.0 4.0 CSS2
vertical-align Sets the vertical alignment of an element baseline
sub
super
top
text-top
middle
bottom
text-bottom
length
%
4.0 4.0 CSS1
z-index Sets the stack order of an element auto
number
6.0 4.0 CSS2

Table

Property Description Values NN IE W3C
border-collapse Sets the border model of a table collapse
separate
  5.0 CSS2
border-spacing Sets the distance between the borders of adjacent cells (only for the "separated borders" model) length length     CSS2
caption-side Sets the position of the caption according to the table top
bottom
left
right
    CSS2
empty-cells Sets whether cells with no visible content should have borders or not (only for the "separated borders" model) show
hide
6.2   CSS2
table-layout Sets the algorithm used to lay out the table auto
fixed
  5.0 CSS2

Text

On-line examples

Property Description Possible Values NN IE W3C
color Sets the color of a text color 4.0 3.0 CSS1
direction Sets the text direction ltr
rtl
    CSS2
letter-spacing Increase or decrease the space between characters normal
length
6.0 4.0 CSS1
text-align Aligns the text in an element left
right
center
justify
4.0 4.0 CSS1
text-decoration Adds decoration to text none
underline
overline
line-through
blink
4.0 4.0 CSS1
text-indent Indents the first line of text in an element length
%
4.0 4.0 CSS1
text-shadow   none
color
length
     
text-transform Controls the letters in an element none
capitalize
uppercase
lowercase
4.0 4.0 CSS1
unicode-bidi   normal
embed
bidi-override
  5.0 CSS2
white-space Sets how white space inside an element is handled normal
pre
nowrap
4.0 5.5 CSS1
word-spacing Increase or decrease the space between words normal
length
6.0 6.0 CSS1

속성 120여개 (알파벳순)

azimuth:
background:
background-attachment:
background-color:
background-image:
background-position:
background-repeat:
border:
border-collapse:
border-color:
border-spacing:
border-style:
border-top:
border-right:
border-bottom:
border-left:
border-top-color:
border-right-color:
border-bottom-color:
border-left-color:
border-top-style:
border-right-style:
border-bottom-style:
border-left-style:
border-top-width:
border-right-width:
border-bottom-width:
border-left-width:
border-width:
bottom:
caption-side:
clear:
clip:
color:
content:
counter-increment:
counter-reset:
cue:
cue-after:
cue-before:
cursor:
direction:
display:
elevation:
empty-cells:
float:
font:
font-family:
font-size:
font-size-adjust:
font-stretch:
font-style:
font-variant:
font-weight:
height:
left:
letter-spacing:
line-height:
list-style:
list-style-image:
list-style-position:
list-style-type:
margin:
margin-top:
margin-right:
margin-bottom:
margin-left:
marker-offset:
marks:
max-height:
max-width:
min-height:
min-width:
orphans:
outline:
outline-color:
outline-style:
outline-width:
overflow:
padding:
padding-top:
padding-right:
padding-bottom:
padding-left:
page:
page-break-after:
page-break-before:
page-break-inside:
pause:
pause-after:
pause-before:
pitch:
pitch-range:
play-during:
position:
quotes:
richness:
right:
size:
speak:
speak-header:
speak-numeral:
speak-punctuation:
speech-rate:
stress:
table-layout:
text-align:
text-decoration:
text-indent:
text-shadow:
text-transform:
top:
unicode-bidi:
vertical-align:
visibility:
voice-family:
volume:
white-space:
widows:
width:
word-spacing:
z-index:

Posted by 1010
반응형
Cascading Style Sheets, level 1
CSS 2 규격 HTML 4 규격 XHTML 1.0 규격 XML 1.0 규격 HTML규격 스타일

번역자 주기: 변역자 주기는 이 색상으로 표시하였으며, 가급적 원본에 준하여 번역하였으나, 연결이 가능한 한글 문서에 연결하도록 하였다.
브라우저마다 다소의 표현이 다름을 명심하라.
스타일 표현에서 영문에만 적용되는 부분이 많으므로 예제에서는 영문을 그대로 표현한 것이 많이 있다.
또한 W3C에서 번역문에서 추가적인 기능을 부가하지 않도록 요청받아 설명에 추가하지 않고 가급적 원형 상태를 유지했다.


CSS1 카스케이딩 스타일쉬트 규격 번역문

W3C 추천안 1996년 12월 17일, 1999년 1월 11일 수정

이 버전은 REC-CSS1-19990111
  이 버전은: 영문 http://www.w3.org/TR/1999/REC-CSS1-19990111
최종 버전: 영문 http://www.w3.org/TR/REC-CSS1
이전 버전: 영문 http://www.w3.org/TR/REC-CSS1-961217
저자: 영문 Håkon Wium Lie (howcome@w3.org)
영문 Bert Bos (bert@w3.org)


이 규격의 상태

이 규격은 W3C의 추천안이다. 이는 영문 W3C (http://www.w3.org/) 멤버들에 의하여 점검 되었고, 이 규격이 사용하는데 적당하다는 일반적으로 공감대가 형성되었다. 이는 안정적 문서로서 조회하고 다른 문서에서 인용할 수 있다. W3C는 이 추천안 발전을 널리 보급하도록 장려한다.

현재 W3C의 추천안들의 목록과 다른 기술적 문서들을 영문 http://www.w3.org/TR/에서 볼 수 있다.

이 규격은 당초 1996년 12월 17일 제시된 것으로 부터 개정된 버전이다.
당초의 버전으로부터의 개정 내용은 목록 영문 부록 F에 있다.
이 규격의 알려진 오류는
영문 http://www.w3.org/Style/CSS/Errata/REC-CSS1-19990111-errata에 있다.


요약

이 규격(CSS1)은 Cascading Style Sheet 기능의 level 1을 정의한다. CSS1은 제작자들과 문서를 보는 리더들이 스타일(예를 들어 글꼴, 색상과 간격 주기)을 HTML 문서들에 추가할 수 있도록 하는 단순한 스타일쉬트 기능이다. CSS1 언어는 일반적인 컴퓨터(desktop)에서 문서 작성 용어로, 인간이 읽고, 쓰고, 표현할 수 있는 것이다.

CSS의 하나의 기초적인 능력은 style sheets cascade이다.; 제작자들은 선호하는 스타일쉬트를 첨부할 수 있으며, 리더는 장애자등을 위하여 그가 원하는 스타일쉬트로 조정할 수 있다. 이 규격에는 다른 스타일쉬트 간의 충돌을 해결하는 규칙이 정의되어 있다.

이 추천안 W3C의 영문 Style Sheets 분야 활동의 결과물이다. [1] 스타일쉬트에 대한 배경 정보를 참조하라.

목차

요약
용어

1         기본 개념
1.1         HTML 문서에 포함
1.2         구룹으로 묶기
1.3         전달(inherit)
1.4         선택자(selector)로서 클래스(class)
1.5         선택자(selector)로서 ID
1.6         복합 선택자(contextual selector)
1.7         코멘트(Comment)
2         가상 클래스(class)와 가상 엘레멘트
2.1         앤커(anchor) 가상 클래스(class)
2.2         인쇄(typographical) 가상 엘레멘트들
2.3         첫줄('first-line') 가상 엘레멘트
2.4         첫글자('first-letter') 가상 엘레멘트
2.5         선택자(selector) 안의 가상 엘레멘트
2.6         복수 가상 엘레멘트
3         카스케이드(cascade)
3.1         중요('important')
3.2         카스케이딩 순서
4         양식화(formatting) 모델
4.1         블럭레벨(block-level) 엘레멘트
4.1.1         수직 양식화
4.1.2         수평 양식화
4.1.3         목록(List-item) 엘레멘트들
4.1.4         유동(floating) 엘레멘트들
4.2         인라인(inline) 엘레멘트들
4.3         대체된(replaced) 엘레멘트들
4.4         줄의 높이
4.5         화면
4.6         'BR' 엘레멘트들
5         CSS1 속성들
5.1         속성값에 대한 주기
5.2         글자(font) 속성들
5.2.1         글자(font) 맞추기
5.2.2         글꼴들('font-family')
5.2.3         글꼴 스타일('font-style')
5.2.4         글꼴 변화('font-variant')
5.2.5         글꼴 굵기('font-weight')
5.2.6         글꼴 크기('font-size')
5.2.7         글꼴('font')
5.3         색상(color)과 배경(background) 속성
5.3.1         색상('color')
5.3.2         배경색('background-color')
5.3.3         배경 이미지('background-image')
5.3.4         배경 반복('background-repeat')
5.3.5         배경 첨부('background-attachment')
5.3.6         배경 위치('background-position')
5.3.7         배경('background')
5.4         텍스트(text) 속성들
5.4.1         단어 간격('word-spacing')
5.4.2         글자 간격('letter-spacing')
5.4.3         텍스트 장식('text-decoration')
5.4.4         수직 정렬('vertical-align')
5.4.5         텍스트 변환('text-transform')
5.4.6         텍스트 정렬('text-align')
5.4.7         텍스트 들여쓰기('text-indent')
5.4.8         줄높이('line-height')
5.5         박스(box) 속성들
5.5.1         위쪽 마진('margin-top')
5.5.2         오른쪽 마진('margin-right')
5.5.3         아래쪽 마진('margin-bottom')
5.5.4         왼쪽 마진('margin-left')
5.5.5         마진('margin')
5.5.6         위쪽 패딩('padding-top')
5.5.7         오른쪽 패딩('padding-right')
5.5.8         아래쪽 패딩('padding-bottom')
5.5.9         왼쪽 패딩('padding-left')
5.5.10         패딩('padding')
5.5.11         위쪽 테두리 두께('border-top-width')
5.5.12         오른쪽 테두리 두께('border-right-width')
5.5.13         아래쪽 테두리 두께('border-bottom-width')
5.5.14         왼쪽 테두리 두께('border-left-width')
5.5.15         테두리 두께('border-width')
5.5.16         테두리 색상('border-color')
5.5.17         테두리 스타일('border-style')
5.5.18         위쪽 테두리('border-top')
5.5.19         오른쪽 테두리('border-right')
5.5.20         아래쪽 테두리('border-bottom')
5.5.21         왼쪽 테두리('border-left')
5.5.22         테두리('border')
5.5.23         너비('width')
5.5.24         높이('height')
5.5.25         유동('float')
5.5.26         'clear'
5.6         속성들의 분류
5.6.1         'display'
5.6.2         공백('white-space')
5.6.3         목록 스타일 타입('list-style-type')
5.6.4         목록 스타일 이미지('list-style-image')
5.6.5         목록 스타일 위치('list-style-position')
5.6.6         목록 스타일('list-style')
6         단위(unit)들
6.1         길이 단위
6.2         백분율 단위(percentage unit)들
6.3         색상 단위(color unit)들
6.4         URL
7         CSS1에 부합
7.1         향 후 버전에 부합한 처리(parsing)
8         참고
9         문서를 구성한 인사들

부록 A: HTML 2.0을 위한 견본 스타일쉬트
부록 B: CSS1 문법
부록 C: 엔코딩(encoding)
부록 D: 감마(gamma) 수정
부록 E: CSS1의 적용성과 확장성
부록 F: 1996년 12월 17일 버전으로 부터의 변경들

용어

애트리뷰트
HTML 애트리뷰트
제작자
HTML 문서의 제작자
블럭레벨(block-level) 엘레멘트
이전과 이후에 줄바꿈이 일어난 부분의 한 엘레멘트(예를 들어 HTML의 'H1')
화면
문서들이 표현되는 사용도구의 부분
하위(child) 엘레멘트
SGML 용어[5]에서 하나의 하위 엘레멘트
복합 선택자(contextual selector)
해당하는 엘레멘트들 문서 구조에서의 위치에 기초한 선택자(selector). 하나의 복합 선택자(contextual selector)는 여러개의 단순한 선택자들(selectors)로 구성된다. 예를 들어, 'H1.initial B'의 복합 선택자(contextual selector)는 'H1.initial'과 'B' 두개의 단순한 선택자들(selectors)로 구성되어 있다.
CSS
캐스케이딩 스타일쉬트(Cascading Style Sheet)
CSS1
캐스케이딩 스타일쉬트(Cascading Style Sheet), level 1. 이 규격은 단순히 웹에서 스타일쉬트의 기능을 설명하는 CSS1을 정의한다.
CSS1 발전된 기능
이 규격에서 기술된 기능이지만, CSS1 핵심 기능으로 표시되지 않았다.
CSS1 핵심 기능
모든 CSS1 규격에 맞는 사용도구들에 필요한 CSS1 부분이다.
CSS1 처리자(parser)
CSS1 스타일쉬트를 읽는 사용도구
선언
속성(예를 들어 글꼴 크기('font-size'))과 이에 상응하는 값(예를 들어 '12pt')
설계자
스타일쉬트 설계자
문서
HTML 문서
엘레멘트
HTML 엘레멘트
엘레멘트 타입(type)
SGML 용어[5]에서 하나의 기본 인식자(generic identifier)
가상(fictional) 태그 순서
가상 클래스(class)와 가상 엘레멘트 행위를 기술하는 도구
글자 크기(font size)
글자의 크기를 지정한다. 전형적으로 그 글자 크기는 대략 아래로 튀어나온것(예:g)을 표함한 가장 낮은 글자의 바닥으로 부터 가장 키큰 글자의 위로 튀어나온 부분(예:h), 부호(예:Ü)를 포함한 맨위까지의 거리와 같다.
HTML
SGML의 하나인 Hypertext Markup Language: HTML 4 규격 번역문.
HTML 표현(extension)
사용도구에 의해 소개된 마크업(Markup)으로 대부분 보는 표현을 지원한다. "FONT", "CENTER"와 "BLINK" 엘레멘트과 "BGCOLOR" 애트리뷰트등은 HTML 표현의 예제들이다. CSS의 하나의 목표는 HTML 표현(extension)의 대용 기능을 주는 것이다.
인라인(inline) 엘레멘트
이전과 이후에 줄바꿈하지 않는 엘레멘트(예를 들어 HTML의 'STRONG')
원래의 규격(intrinsic dimension)
그 엘레멘트 자체에 의하여 지정된 너비(width)와 높이(height), 주위의 것을 포함하지 않는다. 이 규격에서 모든 대체된(replaced) 엘레멘트들 -- 그리고 대체된(replaced) 엘레멘트들 만 -- 원래의 규격(intrinsic dimension)들을 갖는 것으로 가정한다.
모체(parent) 엘레멘트
SGML 용어[5]에서 하나의 상위 엘레멘트
가상 엘레멘트
가상 엘레멘트는 가정적 항목을 지명하기 위하여 CSS 선택자(selector)에 사용된다.(예를 들어 구조적(structural) 엘레멘트 대신 엘레멘트의 첫번 줄)
가상 클래스(class)
가상 클래스는 HTML 자원의 외부 정보를 허용하기 위하여 CSS 선택자(selector)에 사용된다.(예를 들어 방문했던 앤커인가 방문하지 않았던 앤커인가의 엘레멘트 분류)
속성(property)
CSS를 통하여 영향을 주는 스타일 성질(parameter). 이 규격은 속성들의 목록과 그에 상응하는 값을 정의한 것이다.
리더(reader)
문서를 읽어 보는 사람
대체된(replaced) 엘레멘트
CSS 양식자(formatter)가 그 intrinsic dimensions을 알 때 하나의 엘레멘트. HTML의 'IMG', 'INPUT', 'TEXTAREA', 'SELECT', 'OBJECT' 엘레멘트들이 대체된(replaced) 엘레멘트의 예제가 될 수 있다. 예를 들어, 'IMG' 엘레멘트의 내용은 자주 그 SRC 애트리뷰트가 지시하는 이미지로 대체된다. CSS1은 어떻게 그 intrinsic dimensions을 찾는가를 정의하지 않는다.
명령(rule)
하나의 선언(예를 들어 'font-family: helvetica')와 그 선택자(selector)(예를 들어 'H1')
선택자(selector)
어떤 엘레멘트에 해당 명령(rule)이 적용되는가를 지정하는 하나의 문자열. 하나의 선택자(selector)는 단순한 선택자가 될 수 있고(예를 들어 'H1'), 또는 여러개의 단순 선택자로 구성된 복합 선택자(contextual selector:예를 들어 'H1 B')가 될 수 있다.
SGML
HTML도 이 적용의 하나인 Standard Generalized Markup Language[5]
단순 선택자(selector)
문서 구조 안에서 엘레멘트의 위치가 아닌, 엘레멘트 type과 애트리뷰트에 기초한 해당하는 엘레멘트의 하나의 선택자(selector), 예를 들어, 'H1.initial'는 하나의 단순 선택자(selector)이다.
스타일쉬트(style sheet)
여러 명령(rule)들의 집합체
사용도구
웹문서를 표현하는 도구로 웹브라우저를 포함하는 기타 메디아 브라우저
사용자
리어(reader)와 동의어
우선순위(weight)
명령(rule)의 우선순위

이 규격의 텍스트안에서, 단일 따옴표('...') 안의 내용은 HTML과 CSS 문장이다.

1    기본 개념

단일 스타일 쉬트를 설계하는 것은 간단하다. 누구나 을 간단히 알고 기본적인 편집을 알면된다. 예를 들어, 'H1' 엘레멘트의 색상을 청색으로 설정하려면, 쉽게 아래와 같이 표시하면 된다. <PRE>H1 { color: blue }</PRE>

위예제는 단일 CSS 명령(rule)이다. 명령(rule)은 두 부분으로 구성되는데: 선택자(selector) ('H1')와 선언('color: blue')이다. 선언은 두 부분으로 구성되는데: 속성 ('color')과 값('blue')이다. While the 위 예제에서는 HTML 문서를 표현하는데 한가지 속성 만 지정 했는데, 이로서 자신의 스타일쉬트가 되는 것이다. 다른 백여종의 기본 기능의 스타일쉬트들과 조합하여 최종적인 문서의 표현을 하게 되는 것이다.

선택자(selector)는 HTML 문서와 스타일쉬트를 연결시고, 모든 HTML 엘레멘트들이 선택자(selector)가 될 수 있다.
HTML 엘레멘트들은 HTML 규격을 참조하라.

색상('color') 속성은 약 50 속성들 중의 하나로 HTML 문서 표현을 결정한다. 속성들과 가능한 값들의 목록이 이 규격에 정의되어 있다.

HTML 제작자들은 그의 문서에서 특정 스타일을 제시하기를 원할 때 만 스타일쉬트를 사용할 필요가 있다. 각 사용도구는 문서의 합리적인 표현을 위한 디폴트 스타일쉬트를 가지고 있다. 그러나 제각기 다르다. 부록 A는 HTML 문서들을 표현하기 위해 제안된 [3] HTML 2.0 규격의 단순 스타일쉬트를 포함하고 있다.

공식적인 CSS1 언어의 문법은 부록 B에 정의되어 있다.

1.1    HTML 문서에 포함

스타일쉬트가 문서의 표현에 영향을 주기 위해서는, 사용도구는 그 존재를 알아야 한다. HTML 규격은 HTML를 어떻게 스타일쉬트와 연결시키는가를 정의하고 있다. 따라서 이 항목은 정보를 제공하는 것이며, 지명적인 것은 아니다. <PRE><HTML> <HEAD> <TITLE>title</TITLE> <LINK REL=STYLESHEET TYPE="text/css" HREF="http://style.com/cool" TITLE="Cool"> <STYLE TYPE="text/css"> @import url(http://style.com/basic); H1 { color: blue } </STYLE> </HEAD> <BODY> <H1>Headline is blue</H1> <P STYLE="color: green">While the paragraph is green. </BODY></HTML></PRE>

예제는 스타일과 HTML을 결합하는 네가지 방법을 보여준다.
1. 'LINK' 엘레멘트로 외부 스타일쉬트와 연결
2. 'HEAD' 엘레멘트 안에서 'STYLE' 엘레멘트 지정
3. CSS '@import'의 기술로 스타일 쉬트 도입(import)
4. 'BODY' 안에서 엘레멘트에 'STYLE' 애트리뷰트로
마지막 선택은 스타일과 내용을 섞어 사용하여 전통적인 스타일쉬트의 해당 잇점을 감소시킨다.

'LINK' 엘레멘트는 리더가 선택할 수 있는 대체 가능한 스타일쉬트를 조회하고, 도입(import)은 스타일쉬트를 자동적으로 불러 나머지 스타일쉬트와 통합한다.

전통적으로 사용도구는 조용히 알지 못하는 태그를 무시하여 왔다. 그 결과, 옛 사용도구들은 'STYLE' 엘레멘트를 무시한다. 그러나 그 내용들이 문서 본체(body)의 부분으로 처리되어 그렇게 표현된다. 이전 단계에서는, 'STYLE' 엘레멘트 내용은 SGML 코멘트(Comment)를 사용하여 감춰질 수 있다. <PRE><STYLE TYPE="text/css"><!-- H1 { color: green } --></STYLE></PRE>

'STYLE' 엘레멘트는 문서 타입 정의(DTD)에서 "CDATA"로 정의 되므로, 규격에 맞는 SGML 처리자(parser)는 위의 스타일쉬트를 스타일쉬트로 고려하지 않고 코멘트로 해석하여 표현하지 않을 것이다.

1.2    구룹으로 묶기

스타일쉬트의 크기를 줄이기 위하여 선택자을 컴마로 분리하여 구룹으로 묶어 목록을 만들 수 있다. <PRE>H1, H2, H3 { font-family: helvetica }</PRE>

같은 방법으로 선언도 구룹으로 묶을 수 있다. <PRE>H1 { font-weight: bold; font-size: 12pt; line-height: 14pt; font-family: helvetica; font-variant: normal; font-style: normal;}</PRE>

추가적으로 일부 속성들은 그들 자체로 구룹으로 묶기를 할 수 있는데 문법은 <PRE>H1 { font: bold 12pt/14pt helvetica }</PRE>

이는 위의 예제와 같다.

1.3    전달(inherit)

첫번째 예제에서, 'H1' 엘레멘트의 색상을 청색으로 지정하였다. 'H1' 엘레멘트에 강조된 엘레멘트가 있다고 가정하면 <PRE><H1>제목 중에 <EM>이 부분이</EM> 중요하다.</H1></PRE>

만일 'EM' 엘레멘트에 색상이 지정되지 않았으면, 강조된 "이 부분이"는 모체(parent) 엘레멘트 본래의 색상을 가질 것이다. 여기서 예를 들면 역시 청색으로 나타난다. 예를 들어 'font-family'글꼴 크기('font-size')등 다른 스타일 속성들은 같은 방식으로 전달된다.

한 문서의 디폴트("default") 스타일 속성을 설정하려면, 모든 보이는 엘레멘트들의 속성을 설정할 수 있다. HTML 문서들에서, 'BODY' 엘레멘트는 여러가지 이런 기능을 할 수 있다. <PRE>BODY { color: black; background: url(texture.gif) white; }</PRE>

제작자가 만일 'BODY' 태그를 생략하여도 HTML 표현기는 누락된 태그를 삽입하여 이것은 작용된다. 위 예제에서 텍스트의 색상을 검정으로하고 배경에 이미지를 넣었다. 이미지가 없으면 배경색은 백색으로 된다.(항목 5.3을 참조하라.)

일부 스타일 속성들은 모체(parent) 엘레멘트로 부터 하위(child) 엘레멘트로 전달되지 않는다. 대부분의 경우 그렇지 않은지는 쉽게 이해할 수 있다. 예를 들어, 배경('background') 속성은 전달되지 않으나, 모체(parent) 엘레멘트의 배경(background)은 디폴트로 전체적으로 적용된다.

자주 속성값이 백분율로 되는데, 이는 다른 속성(property)을 참조한다. <PRE>P { font-size: 10pt }P { line-height: 120% } /* 글꼴 크기('font-size')의 상대적인 값, 여기서는 12pt */</PRE>

백분율 값들을 허용하는 각 속성은, 그것이 어떤 속성을 참조하는지 정의한다. 'P'의 하위 엘레멘트들은 줄높이('line-height')의 전달된 값에서 백분율이 아니라 계산된 값이 된다(말하자면 12pt).

1.4    선택자(selector)로 클래스(class)

엘레멘트들에 대한 점진적인 제어를 향상시키기 위하여, 'CLASS'라는 새로운 애트리뷰트가 HTML에 글라스(class)로 추가 되었다. 'BODY' 엘레멘트 안의 모든 엘레멘트들은 클래스(class)화될 수 있고, 클래스(class)는 스타일쉬트에 지정될 수 있다. <PRE><HTML> <HEAD> <TITLE>Title</TITLE> <STYLE TYPE="text/css"> H1.pastoral { color: #00FF00 } </STYLE> </HEAD> <BODY> <H1 class=pastoral>녹색을 표현하는 방법</H1> </BODY></HTML></PRE>

일반적인 전달 명령(rule)들은 클래스(class)화된 엘레멘트들에 적용된다. 문서 구조안에서 모체로 부터 값이 전달된다.

모든 엘레멘트들에 같은 클래스(class)를 선택자(selector)를 생략하고 사용할 수 있다. <PRE>.pastoral { color: green } /* 모든 엘레멘트들을 CLASS pastoral로 */</PRE>

선택자(selector) 마다 하나의 클래스(class) 만을 지정할 수도 있다. 'P.pastoral.marine'는 CSS1에서 개별 선택자(selector)이다. 복합 선택자(contextual selector)들은 아래 설명하는데, 단일 선택자(selector)가 하나의 클래스(class)를 갖는다.

CSS는 CLASS 애트리뷰트에 큰 능력을 제공하지 않는다, 이것은 많은 경우 어떤 HTML 엘레멘트의 클래스(class)가 설정되었는가 문제가 되지 않고 어떤 엘레멘트에도 사용될 수 있기 때문이다. 이 기능에 의존하는 것은 추천되지 않는데, 이는 HTML 엘레멘트들의 공통적인 구조의 의미를 희석시키기 때문이다. CLASS에 기초한 구조는 클래스(class)의 의미가 상호 합의된 제한된 도메인에서 만 유용하다.

1.5    선택자(selector)로서 ID

HTML('id' 지정자)은 또한 전 문서를 통한 유일한 값을 보증하는 'ID' 애트리뷰트를 도입했다. 따라서 이는 스타일쉬트 선택자(selector)에서 특별히 중요한며, '#'로 시작하도록 지정한다. <PRE>#z98y { letter-spacing: 0.3em }H1#z98y { letter-spacing: 0.5em }<P ID=z98y>Wide text</P></PRE>

위 예제에서, 첫번째 선택자(selector)는 'P' 엘레멘트는 'ID' 애트리뷰트 값 때문에 맞는다. 두번째 선택자(selector)에서는 엘레멘트 type ('H1')와 ID 값 두가지를 다 지정 했으므로, 'P' 엘레멘트에 맞지 않는다.

ID 애트리뷰트를 선택자(selector)로 사용함에 있어서, 스타일 속성들을 엘레멘트 단위를 기준으로 설정할 수 있다. 스타일쉬트을은 문서 구조를 위하여 설계되었기 때문에, 이 기능은 제작자들이 HTML의 구조적 엘레멘트들의 잇점을 이용하지 않고 화면에 잘 표현되는 문서를 만들도록 한다. 스타일쉬트의 이와 같은 사용은 피하는 것이 좋다.

1.6    복합 선택자(contextual selector)

전달은 CSS 설계자들의 입력을 절약 해 준다. 모든 스타일 속성들을 지정하는 대신, 디폴트(default)를 만들고 제외되는 목록를 만들 수 있다. 'H1' 안의 'EM' 엘레멘트들을 다른 색상으로 지정하기 위하여 다음과 같이 할 수 있다. <PRE>H1 { color: blue }EM { color: red }</PRE>

이 스타일쉬트가 작용하면'H1'의 안에 있던 밖에 있던 모든 강조 부분이 붉은색이 된다. 'H1' 안에 있는 'EM' 엘레멘트들만 붉게 하려면 다음과 같이 하면 된다. <PRE>H1 EM { color: red }</PRE>

이 선택자(selector)는 이제 검색 형태를 가지고 열린 엘레멘트들을 검정한다. 이와 같은 선택자(selector)를 복합 선택자(contextual selector)라 한다. 복합 선택자들은 몇개의 단순 선택자들을 빈칸으로 구분하여 지정한 것이다(지금까지 설명한 것은 모두 단순 선택자들이었다). 마지막 단순 선택자에 맞는 엘레멘트들 만('EM' 엘레멘트) 그리고 이 검색 과정에 맞는 것 만이 표현된다. CSS1에서 복합 선택자(contextual selector)들은 원형적 관계를 검색한다. 그러나 다른 관계들(예를 들어 모체-하위)은 향 후 버전에 반영된다. 위의 예제에서, 검색 과정은 만일 'EM'이 'H1' 안에 있을 때 적용된다. <PRE>UL LI { font-size: small }UL UL LI { font-size: x-small }</PRE>

여기에서, 첫번째 선택자(selector)가 'LI' 엘레멘트들과 맞으면 최소의 하나의 'UL' 조상을 갖는다. 두번째 예제에서 선택자는 맞으면 첫째의 하위 'LI' 엘레멘트는 최소 두개의 'UL' 조상을 갖는다. 두번째 선택자의 보다 긴 검색 구조 때문에 구체적으로 되어 이 혼동은 해결된다. 항목 3.2 카스케이딩 순서를 참조하라.

복합 선택자(contextual selector)들은 엘레멘트 타입(type)들, CLASS 애트리뷰트들, ID 애트리뷰트들 또는 이들의 조합을 검정할 수 있다. <PRE>DIV P { font: small sans-serif }.reddish H1 { color: red }#x78y CODE { background: blue }DIV.sidenote H1 { font-size: large }</PRE>

첫번째 선택자(selector)는 'DIV' 조상들 중에서 모든 'P' 엘레멘트들이 맞는 것을, 두번째 선택자 클래스(class) 'reddish' 조상을 갖는 모든 'H1' 엘레멘트들이 맞는 것을, 세번째 선택자는 'ID=x78y'를 갖는 것들 중 모든 'CODE' 엘레멘트들을, 그리고 네번째 선택자는 'DIV' 조상에 클래스(class) 'sidenote'를 가진 모든 'H1' 엘레멘트들에 맞는 것이다.

여러 복합 선택자(contextual selector)들도 구룹지워 질 수 있다. <PRE>H1 B, H2 B, H1 EM, H2 EM { color: red }</PRE>

이는 아래와 같은 것이다. <PRE>H1 B { color: red }H2 B { color: red }H1 EM { color: red }H2 EM { color: red }</PRE>

1.7    코멘트(Comment)

CSS 스타일쉬트에서 코멘트(Comment) 텍스트는[7] 프로그램 언어 C에서와 비슷하다. <PRE>EM { color: red } /* red, 이는 적색이다 */</PRE>

코멘트(Comment)는 네스트될 수 없다. CSS1 표현기에서 코멘트(Comment)는 공간과 같다.

2    가상 클래스(class)와 가상 엘레멘트

CSS1에서, 스타일은 일반적으로 문서 구조의 해당 위치의 엘레멘트에 추가된다. 이 단순한 모델은 다양한 스타일들에 충분하나, 일부 보편적인 효과를 해결하지 못한다. 가상 클래스(class)와 가상 엘레멘트의 개념이 CSS1에서 양식화 과정에 외부 정보를 허용하도록 확장한다.

가상 클래스(class)들과 가상 엘레멘트들이 CSS 선택자(selector)로 사용될 수 있다. 그러나 이들은 HTML 자원에는 존재하지 않는다. 오히려 이들은 어떤 경우에 스타일쉬트로 사용될 수 있도록 사용도구에 의하여 삽입된다. 이들은 "글래스"와 "엘레멘트"로 불리우는데, 이는 그들의 행동을 기술하는데 편리하기 때문이다. 더 구체적으로, 이들의 행동은 가상 태그 기능으로 정의된다.

가상 엘레멘트들은 엘레멘트들의 하위 부분을 지명하는데 사용된다. 가상 클래스(class)들에서 스타일쉬트가 다른 엘레멘트 타입(type)들을 다르게 처리하기 때문이다.

2.1    앤커(anchor) 가상 클래스(class)

사용도구들은 일반적으로 새롭게 방문한 앤커를 과거에 방문한 것과 다르게 표현한다. CSS1에서 이것이 'A' 엘레멘트의 가상 클래스(class)를 통하여 처리된다. <PRE>A:link { color: red } /* 방문하지 않은 연결 */A:visited { color: blue } /* 방문했던(visited) 연결 */A:active { color: lime } /* 활성(active) 연결 */</PRE>

'HREF' 애트리뷰트를 갖는 모든 'A' 엘레멘트들은 하나의, 단지 하나의, 이들 구룹으로 된다(말하자면 목표(target) 앤커들은 영향을 받지 않는다). 사용도구들은 방문했던('visited')에서 일반 연결('link')로 일정한 시간 후에 변화시키는 것을 선택할 수 있다. 활성('active') 연결은 리더에 의하여 마우스 단추 느름 등으로 현재 선택한 연결을 말한다.

앤커(anchor) 가상 클래스(class)의 양식화는 클래스(class)가 수동적으로 삽입되는 것과 같이 이루어 진다. 사용도구는 현재 표현된 문서를 앤커(anchor) 가상 클래스(class) 활동 때문에 다시 양식화할 필요는 없다. 예를 들어, 스타일쉬트는 문법에 맞게 지정할 수 있다. 활성('active') 연결의 글꼴 크기('font-size')를 방문 했던('visited') 연결보다 크게 지정할 수 있다. 그러나 사용도구는 리더가 방문했던( 'visited') 연결을 선택했을 때 탄력성있게 그 문서를 재 양식화할 필요는 없다.

가상 클래스(class) 선택자들은 일반 클래스(class)들과 맞지 않으며 그 역도 마찬가지이다. 따라서 아래 예제의 스타일 명령(rule) 아무 영향이 없다. <PRE>A:link { color: red }<A class=link NAME=target5> ... </A></PRE>

CSS1에서 앤커(anchor) 가상 클래스(class)들은 'A' 엘레멘트 이외의 엘레멘트에는 영향이 없다. 따라서, 엘레멘트 type이 선택자에서 생략될 수 있다. <PRE>A:link { color: red }:link { color: red }</PRE>

CSS1에서 위의 두 선택자들은 같은 엘레멘트들을 선택한다.

가상 클래스(class)의 이름(name)들은 대소분자를 구별하지 않는다.

가상 클래스(class)들은 다른 복합 선택자(contextual selector)들 안에서 사용될 수 있다. <PRE>A:link IMG { border: solid blue }</PRE>

또한, 가상 클래스(class)들은 일반 클래스(class)들과 조합될 수 있다. <PRE>A.external:visited { color: blue }<A class=external HREF="http://out.side/">external link</A></PRE>

위의 예제에서 연결이 방문했던(visited) 것이면 청색으로 표현된다. 일반 클래스(class) 이름(name)들이 선택자의 가상 클래스(class)들보다 선행한다는 점에 주의하라.

2.2    인쇄(typographical) 가상 엘레멘트들

일부 보통 인쇄(typographical) 효과들은 구조적 엘레멘트들과 연관되지 않고, 화면에 양식화되는 인쇄(typographical) 항목들에 연관된다. CSS1에서, 두가지 이런 인쇄(typographical) 항목들을 가상 엘레멘트들을 통하여 지정할 수 있는데, 엘레멘트의 첫 줄과 첫 글자이다.

CSS1 핵심: 사용도구들은 모든 명령(rule)들에서 선택자의 첫 줄(':first-line') 혹은 첫 글자(':first-letter')을 무시할 수 있다. 또는 이들 가상 엘레멘트들 속성들의 하위 설정 만을 지원할 수 있다(항목 7 참조).

2.3    첫줄('first-line') 가상 엘레멘트

첫줄('first-line') 가상 엘레멘트는 화면에서 첫줄에 특수한 스타일을 적용하기 위하여 사용된다. <PRE><STYLE TYPE="text/css"> P:first-line { font-variant: small-caps }</STYLE> <P>The first line of an article in Newsweek.</PRE>

텍스트 기준 사용도구에서 이는 다음과 같이 양식화된다. <PRE>THE FIRST LINE OF AN article in Newsweek.</PRE>

위 예제의 가상 태그 기능은 <PRE><P><P:first-line>The first line of an </P:first-line>article in Newsweek. </P></PRE>

첫줄('first-line') 종료태그는 첫줄 끝에 삽입한다.

첫줄('first-line') 가상 엘레멘트는 블럭레벨(block-level) 엘레멘트에 만 사용될 수 있다.

첫줄('first-line') 가상 엘레멘트는 인라인(inline) 엘레멘트와 비슷하다. 그러나 제한들이 있다. 첫줄('first-line') 엘레멘트에는 다음 속성들 만이 적용된다.
(5.2 글자(font) 속성들), (5.3 색상과 배경 속성들), (5.4.1 단어 간격('word-spacing')), (5.4.2 글자 간격('letter-spacing')), (5.4.3 텍스트 장식('text-decoration')),(5.4.4 수직 정렬('vertical-align') ), (5.4.5 텍스트 변환('text-transform')), (5.4.8 줄높이('line-height')), (5.5.26 'clear').

2.4    첫글자('first-letter') 가상 엘레멘트

첫글자('first-letter') 가상 엘레멘트는 일반적인 인쇄(typographical) 효과를 갖는 "initial caps" 와 "drop caps"에 사용된다. 이는 유동('float') 속성이 'none'이면 인라인(inline) 엘레멘트와 유사하고, 아니면 유동(floating) 엘레멘트와 유사하다. 첫글자('first-letter') 가상 엘레멘트들에 적용되는 속성들은:
(5.2 글자(font) 속성들), (5.3 색상(color)과 배경(background) 속성), (5.4.3 텍스트 장식('text-decoration')), (유동('float')가 'none' 일 때 만, 5.4.4 수직 정렬('vertical-align')), (5.4.5 텍스트 변환('text-transform')), (5.4.8 줄높이('line-height')), (5.5.1 margin 속성들-5.5.5), (5.5.6 padding 속성들-5.5.10), (5.5.11 border 속성들-5.5.22), (5.5.25 유동('float')), (5.5.26 'clear').

이것은 드롭캡(dropcap) 최초 글자 스판(span) 두 줄을 만드는 것이다. <PRE><HTML> <HEAD> <TITLE>Title</TITLE> <STYLE TYPE="text/css"> P { font-size: 12pt; line-height: 12pt } P:first-letter { font-size: 200%; float: left } SPAN { text-transform: uppercase } </STYLE> </HEAD> <BODY> <P><SPAN>The first</SPAN> few words of an article in The Economist.</P> </BODY></HTML></PRE>

만일 택스트 기준 사용도구가 첫글자('first-letter') 가상 엘레멘트를 지원하면(아마 아닐 것이다), 이는 다음과 같이 양식화된다. <PRE>___ | HE FIRST few | words of an article in the Economist.</PRE>

가상 태그 기능으로 <PRE><P><SPAN><P:first-letter> T </P:first-letter>he first</SPAN>few words of an article in the Economist.</P></PRE>

첫글자('first-letter') 가상 엘레멘트 택그들은 내용(말하자면 첫 글자)에 인접하고, 첫글자('first-letter') 가상 엘레멘트 시작태그는 그것이 첨부된 엘레멘트 시작태그 바로 다음에 삽입된다는 점을 주시하라.

사용도구는 어떤 글자들이 첫글자('first-letter') 엘레멘트 안에 있는가를 판정한다. 일반적으로 첫글자 앞에 따옴으로 첫글자가 포함되어야 한다. <PRE>||/\ bird in/ \ the hand/----\ is worth/ \ two in the bush," says an old proverb.</PRE>

문단이 다른 구둣점으로 시작되거나(예를 들어 괄호와 구둣점들) 일반적으로 글자로 간주되지 않는 다른 글자들로 시작되면(예를 들어 숫자와 수학기호들), 첫글자('first-letter') 가상 엘레멘트들은 일반적으로 무시된다.

일부 언어들에서 어떤 문자 조합을 어떻게 처리할 것인지 특정 명령(rule)들을 지정할 수 있다. 예를 들어 홀랜드어에서, 단어의 시작에서 만일 글자 조합 "ij"가 나타나면, 이들은 두 글자 모두 첫글자('first-letter') 가상 엘레멘트로 고려되어야 한다.

첫글자('first-letter') 가상 엘레멘트는 블럭레벨(block-level) 엘레멘트에 만 사용할 수 있다.

2.5    선택자(selector)들 안에서 가상 엘레멘트

복합 선택자(contextual selector)에서, 가상 엘레멘트들은 그 선택자(selector) 맨 뒤에 만 허용된다. <PRE>BODY P:first-letter { color: purple }</PRE>

가상 엘레멘트들은 선택자(selector)들 안에서 클래스(class)들과 조합할 수 있다. <PRE>P.initial:first-letter { color: red }<P class=initial>First paragraph</A></PRE>

위 예제는 'CLASS=initial'을 갖는 모든 'P' 엘레멘트들의 첫글자를 붉은색으로 만들 것이다. 클래스(class)들 또는 가상 클래스(class)들이 조합되면, 가상 엘레멘트들은 선택자(selector) 맨 뒤에 지정되어야 한다. 선택자마다 하나의 가상 엘레멘트 만 지정할 수 있다.

2.6    복수 가상 엘레멘트

복수의 가상 엘레멘트들이 조합될 수 있다. <PRE>P { color: red; font-size: 12pt }P:first-letter { color: green; font-size: 200% }P:first-line { color: blue }<P>Some text that ends up on two lines</P></PRE>

이 예제에서, 각 'P' 엘레멘트의 첫글자는 녹색이며 글자 크기는 24pt이다. 나머지 첫줄은(화면에 양식화되는) 청색이고, 나머지 문단은 붉은색이 된다. 단어 "ends" 전에 줄바꿈이 발생되었다고 가정하면, 가상 택그 기능은 <PRE><P><P:first-line><P:first-letter> S </P:first-letter>ome text that </P:first-line>ends up on two lines</P></PRE>

첫글자('first-letter') 엘레멘트는 첫줄('first-line') 엘레멘트 안에 있다 점에 유의하라. 첫줄('first-line')에 설정된 속성들 첫글자('first-letter')로 부터 전달된다. 그러나 같은 첫글자('first-letter') 속성이 설정되면 덮어씌우기(override)가 된다.

만일 가상 엘레멘트가 본래 엘레멘트를 붕괴되면, 필요한 추가 태그들이 가상 태그 기능에서 다시 생성되어야 한다. 예를 들어, 만일 SPAN 엘레멘트가 </P:first-line> 태그 밖으로 확장되면, 종료태그와 시작태그가 다시 생성되어야 하며 가상 태그 기능은 다음과 같이 된다. <PRE><P><P:first-line><SPAN>This text is inside a long</SPAN></P:first-line><SPAN>span 엘레멘트</SPAN></PRE>

3    카스케이드(cascade)

CSS에서, 하나이상의 스타일쉬트가 표현에 동시에 영향을 줄 수 있다. 이는 두가지 주된 이유가 있는데 하나는 모듈화 속성이고 다른 하나는 제작자/리더 바란스이다.

모듈화 속성(modularity)
스타일쉬트는 복잡성을 피하기 위하여 여러개의 부분적인 스타일쉬트들을 조합하도록 설계되었다. <PRE>@import url(http://www.style.org/pastoral);@import url(http://www.style.org/marine);H1 { color: red } /* 도입된(imported) 스타일을 덮어씌움(override) */</PRE>
제작자/리더 바란스
리더와 제작자들이 스타일쉬트를 통하여 표현에 영향을 줄 수 있다. 이를 위해 그들은 같은 스타일쉬트 언어를 사용하여 웹의 기초 기능을 반영하여야 한다. 누구나 문서 발행자가 될 수 있다. 사숑도구는 개인적인 스타일쉬트 표현 기능의 선택이 자유이다.

때로는 스타일쉬트들이 표현에 영항하는데 모순이 일어난다. 모순의 해결은 각 스타일 명령(rule)에 기초하여 우선순위(weight)를 갖는다. 디폴트로 리더의 명령(rule)들 보다 제작자 문서의 명령(rule)들이 우선 적용된다. 말하자면, 만일 들어오는 문서와 리더의 개별 스타일쉬트 간의 마찰이 생기면, 제작자의 명령(rule)들이 사용된다. 리더나 제작자 명령(rule)들이 모두 사용도구의 디폴트 값을 덮어씌운다.

도입된(imported) 스타일쉬트 또한 서로 카스케이드(cascade)된다. 도입된 순서에 따라, 카스케이드(cascade) 명령(rule)은 아래 설명한다. 스타이쉬트에 지정된 어떤 명령(rule)들은 자체가 도입된(imported) 스타일쉬트의 명령(rule)들를 덮어씌운다. 이는 도입된 스타일쉬트가 지체 스타일쉬트에 있는 명령(rule)보다 낮은 카스케이딩 순서를 갖는다는 뜻이다. 도입된 스타일쉬트는 반복적으로 도입하고 다른 스타일쉬트를 덮어씌울 수 있다.

CSS1에서, 모든 '@import' 선언은 스타일쉬트 시작부분에 나와야 하며 선언 이전에 이루어 져야한다. 이는 보기 쉽게하며, 스타일쉬트 자체의 명령(rule)들이 도입된 스타일쉬트의 명령들을 덮어씌우게 한다.

3.1    중요('important')

스타일쉬트 설계자는 그들 선언의 중요도를 증가시킬 수 있다. <PRE>H1 { color: black ! important; background: white ! important }P { font-size: 12pt ! important; font-style: italic }</PRE>

위 예제에서, 첫 세가지 선언은 중요도를 증가시킨 선언들이고, 마지막 것은 보통의 중요도이다.

사용자의 중요 선언 명령(rule)은 제작자 보통 선언 명령(rule)을 덮어씌운다(override). 제작자 중요 선언 명령(rule)은 사용자의 중요 선언 명령(rule)을 덮어씌운다.

3.2    카스케이딩 순서

모순되는 명령(rule)들은 CSS 기능의 원칙에 따른다. 엘레멘트/속성 조합의 값을 찾기위하여 다음 순서의 기능을 따라야 한다.

  1. 문제의 모든 엘레멘트/속성에 적용되는 모든 선언들을 찾는다. 문제의 엘레멘트가 그 선택자(selector)와 맞으면 선언(declaration)들을 적용한다. 선언이 적용되지 않으면 전달된(inherited) 값이 사용된다. 전달된 값이 없으면('HTML' 엘레멘트와 속성들이 전달되지 않은 경우) 최초값이 적용된다.
  2. 표현 중요도에 따라 선언(declaration)들이 정렬된다. 중요한 표시('!important')가 된 것이 선언되지 않은 것 보다 우선한다.
  3. 원본의 순서에 따라 정렬된다. 제작자의 스타일쉬트가 리더 스타일쉬트를 덮어씌우고(override), 리더 스타일쉬트는 사용도구의 디폴트 값들을 덮어씌운다. 도입된(imported) 스타일쉬트는 그 스타일쉬트가 도입된 자원과 같은 원본이다.
  4. 지정된 선택자(selector)로 정렬된다. 보다 구체적인 선택자(selector)가 일반적인 선택자를 덮어씌운다. 보다 구체적으로 찾기 위해, ID 애트리뷰트들의 선택자(a) 갯수를 세고, CLASS 애트리뷰트들의 선택자(b) 갯수를 세고, 선택자 안의 태그 이름(c)의 갯수를 센다. 이 세 갯수들의 연쇄(큰 베이스의 수치 시스템 안에서)는 구체적으로 주어진다. 예제를 보면 <PRE>LI {...} /* a=0 b=0 c=1 -> 구체화수 = 1 */UL LI {...} /* a=0 b=0 c=2 -> 구체화수 = 2 */UL OL LI {...} /* a=0 b=0 c=3 -> 구체화수 = 3 */LI.red {...} /* a=0 b=1 c=1 -> 구체화수 = 11 */UL OL LI.red {...} /* a=0 b=1 c=3 -> 구체화수 = 13 */#x34y {...} /* a=1 b=0 c=0 -> 구체화수 = 100 */</PRE>

    가상 엘레멘트들과 가상 클래스(class)들은 각각 일반 엘레멘트들과 클래스(class)들로 합산된다.

  5. 지정된 우선순위로 정렬한다. 만일 두가지 명령(rule)이 같은 우선순위를 가지면, 나중에 지정된 것이 적용된다. 도입된(imported) 스타일쉬트의 명령(rule)들은 스타일쉬트 자체의 어떤 명령들 이전의 것으로 간주된다.

속성값의 검색은 한 명령(rule)이 같은 엘레멘트/속성 조합에 적용되는 다른 명령들보다 높은 우선순위를 갖는 것을 만나면 종료된다.

이 원칙은 제작자의 스타일쉬트가 리더의 스타일쉬트보다 상당히 높은 우선순위를 갖게한다. 따라서 리더는 어떤 스타일쉬트의 영향을 중지시킬 수 있게하는 것이 중요하다. 예를 들어 풀다운(pull-down) 메뉴를 통하여

어떤 엘레멘트의 'STYLE' 애트리뷰트에서 선언(예제는 항목 1.1 참조)은 스타일쉬트 맨 뒤에 지정한 ID 선택자(selector)와 같은 우선순위를 갖는다. <PRE><STYLE TYPE="text/css"> #x97z { color: blue }</STYLE><P ID=x97z STYLE="color: red"></PRE>

위 예제에서, 'P' 엘레멘트의 색상은 붉은색일 것이다. 두 선언에서 같은 구체화수를 갖지만, 'STYLE' 애트리뷰트의 선언이 'STYLE' 엘레멘트의 선언을 덮어씌울 것이다. 이는 위의 카스케이딩 원칙 5번을 따르기 때문이다.

사용도구는 다른 스타일적 HTML 애트리뷰트들 선택할 수 있다. 예를 들어 'ALIGN'. 그런 경우, 이들 애트리뷰트들은 해당 CSS 명령(rule)들로 해석하여, 구체화수는 1이 된다. 이 명령(rule)들은 제작자 스타일쉬트의 시작부분에 있는 것으로 간주된어 후속 스타일 명령들에 의하여 덮우씌우게 된다. 과도적 단계에서 이 정책은 스타일적 애트리뷰트들을 스타일쉬트와 동시에 사용하기 쉽게 한다.

4    양식화(formatting) 모델

CSS1은 단순 박스형(box-oriented) 양식 모델을 가정한다. 거기서 각 양식화된 엘레멘트가 하나이상의 사각형 박스들을 만드는 것이다. 'display' 값이 'none'인 엘레멘트들은 양식화되지 않고, 따라서 박스를 만들지 않을 것이다. 모든 박스(box)들은 중심 내용 지역(area)과 주위 패딩(padding), 테두리(border)와 마진(margin) 지역을 갖는다. <PRE>_______________________________________| || margin (마진: 투명) || _________________________________ || | | || | border (테두리) | || | ___________________________ | || | | | | || | | padding (패딩) | | || | | _____________________ | | || | | | | | | || | | | content (내용) | | | || | | |_____________________| | | || | |___________________________| | || |_________________________________| ||_______________________________________| | 엘레멘트 너비 || 박스(box) 너비 |</PRE>

마진(margin), 태두리(border) 그리고 패딩(padding)의 크기(size)는 각각 (5.5.1 margin-5.5.5), (5.5.6 padding-5.5.10) 와 (5.5.11 border-5.5.22) 속성들이 설명되어 있다. 패딩(padding) 지역은 엘레멘트 자체와 같은 배경을 사용한다. (5.3.2 background 속성들-5.3.7 참조). 테두리의 색상(color)과 스타일은 테두리(border) 속성들과 함께 설정한다. 마진은 항상 투명하여, 모체 엘레멘트가 잘 표현된다.

박스의 크기는 엘레멘트(말하자면 양식화된 택스트나 이미지) 너비와 패딩, 테두리, 마진 지역들의 합산이다.

양식화 견지에서 엘레멘트들의 두가지 주된 타입(type)들이 있는데, 블럭레벨(block-level)과 인라인(inline)이다.

4.1    블럭레벨(block-level) 엘레멘트

'display' 값이 블럭('block') 또는 목록('list-item') 인 엘레멘트들은 블럭레벨(block-level) 엘레멘트들이다. 또한, 유동('float') 값이 'none'이 아닌 다른 값을 가진 엘레멘트들인 유동(floating) 엘레멘트들도 블럭레벨(block-level) 엘레멘트들로 간주된다.

다음 예제는 2개의 하위 구조를 가진 'UL' 엘레멘트의 마진(margin)과 패딩(padding)이 어떻게 양식화되는지를 보여준다. 간단히 하기 위하여 도표는 테두리(border)들이 없다. 또한 이 예제에서 CSS1 분법에는 맞지 않으나, 스타일쉬트의 값들을 도표에 표시하도록 편이상 단일 글자 내용("constants")를 사용하였다. <PRE><STYLE TYPE="text/css">UL { background: red; margin: A B C D; padding: E F G H;}LI { color: white; background: blue; /* 청색바탕에 흰색 글씨 */ margin: a b c d; padding: e f g h;}</STYLE> ..<UL><LI>목록의 1번 엘레멘트<LI>목록의 2번 엘레멘트</UL></PRE><PRE> _______________________________________________________| || A UL 마진(margin: 투명) || _______________________________________________ || D | | B || | E UL 패딩(padding: 적색) | || | _______________________________________ | || | H | | F | || | | a LI 마진(margin: 투명, | | || | | 적색이 비침) | | || | | _______________________________ | | || | | d | | b | | || | | | e LI 패딩(padding: 청색) | | | || | | | | | | || | | | h 목록의 1번 엘레멘트 f | | | || | | | | | | || | | | g | | | || | | |_______________________________ | | | || | | | | || | | max(a, c) <- 최대 부분 | | || | | _______________________________ | | || | | | | | | || | | d | e LI 패딩(padding: 청색) | | | || | | | | | | || | | | h 목록의 2번 엘레멘트 f | | | || | | | | | | || | | | g | | | || | | |_______________________________ | | | || | | | | || | | c LI 마진(margin: 투명, | | || | | 적색이 비침) | | || | |_______________________________________ | | || | | || | G | || |_______________________________________________ | || || C ||_______________________________________________________ |</PRE>

전형적으로, 패딩(padding)과 마진(margin) 속성들은 전달(inherit)되지 않는다. 그러나, 예제에서 본바와 같이, 엘레멘트의 대체는 모체들과 형제들에 상대적으로 이루어 진다. 따라서 이들 엘레멘트들의 패딩(padding)과 마진(margin) 속성들이 그들의 하위 항목에서 영향을 받는다.

만일 위의 예제에 테두리(border)들이 있다면, 이 테두리들은 패딩과 마진들사이에 나타 날 것이다.

다음 도표는 유용한 용어들을 설명한다. <PRE> ----------------------- <-- 맨위(top) 위쪽 마진(top margin) ----------------------- 위쪽 테두리(top border) ----------------------- 위쪽 패딩(top padding) +-----------+ <-- 내부 맨위(inner top)| | | | | | | ||-왼쪽-|-왼쪽-|-왼쪽--|-- 내용 --|-오른쪽-|-오른쪽-|-오른쪽-|| 마진 |태두리| 패딩 | | 패딩 | 태두리 | 마진 ||-left-|-left-|-left--|- content -|-right--|-right--|-right--||margin|border|padding| |padding | border | margin || | | | | | | | +-----------+ <-- 내부 맨아래(inner bottom)^ ^ ^ ^왼쪽 왼쪽 오른쪽 오른쪽외부틀 내부틀 내부틀 외부틀left left right rightouter inner inner outeredge edge edge edge 아래쪽 패딩(bottom padding) ----------------------- 아래쪽 테두리(bottom border) ----------------------- 아래쪽 마진(bottom margin) ----------------------- <-- 맨아래(bottom)</PRE>

왼쪽 외부틀(left outer edge)은 그의 패딩(padding), 테두리(border)와 마진(margin)을 포함한 엘레멘트의 틀이다.
왼쪽 내부틀(left inner edge)는 어느 패딩(padding), 테두리(border)와 마진(margin) 안에 있는 내용(content) 만의 틀이다.
맨위(top)는 패딩(padding), 테두리(border)와 마진(margin)을 포함한 그 엘레멘트의 맨 위이다. 이는 인라인(inline)이며 유동(floating) 엘레멘트들에 만 지정되며, 유동하지 않는(non-floating) 블럭레벨(block-level) 엘레멘트들에는 지정되지 않는다.
내부 맨위(inner top)는 어느 패딩(padding), 테두리(border)와 마진(margin) 안에 있는 내용의 맨위이다.
맨아래(bottom)패딩(padding), 테두리(border)와 마진(margin)을 포함한 그 엘레멘트의 맨아래이다. 이는 인라인(inline)이며 유동(floating) 엘레멘트들에 만 지정되며, 유동하지 않는(non-floating) 블럭레벨(block-level) 엘레멘트들에는 지정되지 않는다.
내부 맨아래(inner bottom)는 어느 패딩(padding), 테두리(border)와 마진(margin) 안에 있는 내용의 맨아래이다.

엘레멘트의 너비(width)는 내용(content)의 너비이며, 말하자면, 왼쪽 내부틀(left inner edge)과 오른쪽 내부틀(right inner edge)과의 거리이고, 높이(height)는 내용(content)의 높이로 내부 맨위(inner top)와 내부 맨아래(inner bottom)와의 거리이다.

4.1.1    수직 양식화

유동 않는(non-floating) 블럭레벨(block-level) 엘레멘트들의 마진(margin) 너비는 주위 박스(box)의 틀(edge)들사이의 최소 거리이다. 두개 혹은 그이상의 인접한 수직 마진들은 패딩(padding), 테두리(border)가 없거나 그사이의 내용(content)이 없을 때 마진의 값을 최대로 사용하기 위하여 붕괴된다. 대부분의 경우에는, 수직 마진들이 붕괴된 후, 실제로 설계자가 기대하는 것에 가깝고 편하게 보이는 결과를 가져다 준다. 위의 예제에서, 1번 LI 엘레멘트의 아래쪽 마진('margin-bottom')과 2번 LI 엘레멘트의 위쪽 마진('margin-top')의 최대 사용으로, 두 'LI' 엘레멘트들은 붕괴된다. 같은 방식으로 만일 'UL' 과 1번 'LI' 엘레멘트(내용 "E")사이의 패딩이 0이 되면, UL 과 1번 LI 엘레멘트들의 마진들은 붕괴된다.

마진들이 음수인 경우, 음수 절대 최대 인접 마진들은 양수 절대 최대 인접 마진들로 부터 빼진다. 만일 양수 마진들이 없으면, 음수 절대 최대 인접 마진들은 0에서 빼진다.

4.1.2    수평 양식화

유동 않는(non-floating) 블럭레벨(block-level) 엘레멘트의 수평 위치와 크기(size)는 7가지 속성들에 의하여 결정된다.

  • 왼쪽 마진('margin-left')
  • 왼쪽 테두리('border-left')
  • 왼쪽 패딩('padding-left')
  • 너비('width')
  • 오른쪽 패딩('padding-right')
  • 오른쪽 테두리('border-right')
  • 오른쪽 마진('margin-right')
이들 7 가지의 합계는 항상 모체 엘레멘트의 너비('width')와 같다.

디폴트로, 어떤 엘레멘트의 너비('width')는 자동('auto')이다. 만일 그 엘레멘트가 대체된(replaced) 엘레멘트가 아니면, 이는 언급한 7 가지 속성들의 합산이 모체 너비과 같도록 너비('width')가 사용도구에 의해 계산된다는 의미한다. 만일 그 엘레멘트가 대체된(replaced) 엘레멘트이면, 너비 값 자동('auto')은 자동적으로 본래의(intrinsic) 그 엘레멘트의 너비로 대체된다.

7 가지 속성들 중 왼쪽 마진('margin-left'), 너비('width') 와 오른쪽 마진('margin-right') 3 가지는 자동('auto')으로 설정될 수 있다. 대체된(replaced) 엘레멘트들에서, 너비 값 'auto'는 본래의 너비로 대체되고 두가지 만 'auto' 값을 가질 수 있게 된다.

너비('width')가 음수가 아닌 경우, 엘레멘트에 따라 다르고 나아가 다른 속성들에 따라 다르지만 사용도구가 정의한 최소값이 된다. 만일 너비가 지명적으로 그렇게 지시하였거나, 자동('auto')을로 되었는데 그 명령(rule)이 너무 작게 요구하여, 그 한계 이하이면 그 대신 그 값은 최소값으로 대체된다.

만일 왼쪽 마진('margin-left'), 너비('width'), 오른쪽 마진('margin-right') 중 하나만 자동('auto')이면, 사용도구는 7 가지 합산이 모체의 너비와 같게 되도록 속성값을 지정한다.

만일, 아무 속성도 'auto'로 지정되지 않았으면, 오른쪽 마진('margin-right') 값이 'auto'가 설정된다.

만일 세개 중 한개이상이 'auto'이면, 그리고 그 중 하나가 너비('width')이면, 그러면 다른 것들은(왼쪽 마진('margin-left') 그리고/혹은 오른쪽 마진('margin-right')) 0으로 설정되고, 너비('width')는 7 가지 합산이 모체의 너비가 되도록 필요한 값을 갖게 된다.

아니면, 만일 왼쪽 마진('margin-left')와 오른쪽 마진('margin-right')가 'auto'이면, 같은 값들이 설정된다. 따라서 그의 모체 안에서 그 엘레멘트가 중앙에 위치하게 된다.

만일 'auto'가 7 가지 속성들 중 하나가 인라인(inline) 또는 유동(floating) 엘레멘트에 설정되면, 그것은 0으로 설정된 것으로 간주된다.

수직 마진(margin)들과는 달리, 수평 마진들은 붕괴되지 않는다.

4.1.3    목록(list-item) 엘레멘트들

'display' 속성의 목록('list-item') 값을 가진 엘레멘트들은 블럭레벨(block-level) 엘레멘트들로 양식화된다. 그러나 목록(list-item) 메이커(marker)가 먼저 나온다. 메이커(marker)의 타입(type)은 목록 스타일('list-style') 속성(property)에 의허여 결정된다. 메이커(marker)는 목록 스타일('list-style') 속성(property)값에 따라 위치한다. <PRE><STYLE TYPE="text/css">UL { list-style: outside }UL.compact { list-style: inside }</STYLE><UL><LI>1번 목록 1번 항목<LI>1번 목록 2번 항목</UL><UL class=COMPACT><LI>2번 목록 1번 항목<LI>2번 목록 2번 항목</UL></PRE>

위 예제는 다음과 같이 양식화된다. <PRE>* 1번 목록 1번 항목* 1번 목록 2번 항목 * 2번 목록 1번 항목 * 2번 목록 2번 항목</PRE>

오른쪽에서 왼쪽으로 쓰는 텍스트에서는, 그 메이커(marker)들은 박스의 오른쪽에 나온다.

HTML의 목록 설명을 참조하라

4.1.4    유동(floating) 엘레멘트

유동('float') 속성(property)을 사용하여, 한 엘레멘트는 엘레멘트들의 정상 유동(flow)인 외부(outside)로 선언될 수 있다. 그리고 그 것은 블럭레벨(block-level) 엘레멘트로 양식화된다. 예를 들어, 이미지(image)를 왼쪽('left')으로 유동('float') 속성을 지정하면, 그 이미지는 다른 블럭레벨(block-level) 엘레멘트의 마진(margin), 패딩(padding) 또는 테두리(border)에 도달할 때까지 왼쪽으로 이동한다. 일반적인 유동(flow)은 오른쪽에서 줄바꿈을 한다. 그 엘레멘트 지체의 margin, border 와 padding들은 그대로 표현될 것이고, 그 마진(margin)들은 인접 엘레멘트들의 마진들과 절대로 붕괴되지 않는다.

한 유동(floating) 엘레멘트는 다음의 내용에 따라 위치한다(section 4.1 블럭레벨 엘레멘트를 참조하라).

  1. 왼쪽 유동(left-floating) 엘레멘트의 왼쪽 외부틀(left outer edge)은 모체 엘레멘트의 왼쪽 내부틀(left inner edge) 왼쪽에 오지 않을 수 있다. 오른쪽 유동(right floating) 엘레멘트들도 마찬가지이다.
  2. 왼쪽 유동(left-floating) 엘레멘트의 왼쪽 외부틀(left outer edge)은 각 먼저(HTML 문서에서) 왼쪽 유동(left-floating) 엘레멘트의 오른쪽 외부틀(right outer edge) 보다 오른쪽에 있어야 한다. 또한 이전의 맨위(top)는 나중의 맨아래(bottom)보다 낮아야 한다. 오른쪽 유동(right floating) 엘레멘트들에서도 같은 원칙이 적용된다.
  3. 왼쪽 유동(left-floating) 엘레멘트의 오른쪽 외부틀(right outer edge)은 그 오른쪽에 있는 오른쪽 유동(right floating) 엘레멘트 왼쪽 외부틀(left outer edge)의 오른쪽이 아닐 수 있다. 오른쪽 유동(right floating) 엘레멘트들에서도 같은 원칙이 적용된다.
  4. 유동(floating) 엘레멘트의 맨위(top)는 그 모체의 내부 맨위(inner top)보다 높지 않을 수 있다.
  5. 유동(floating) 엘레멘트의 맨위(top)는 먼저의 유동 혹은 블럭레벨(block-level) 엘레멘트의 맨위(top)보다 높지 않을 수 있다.
  6. 유동(floating) 엘레멘트의 맨위(top)는 어떤 HTML에서 유동(floating) 엘레멘트보다 먼저의 내용 인라인 박스(line-box)(항목 4.4 참조)의 맨위보다 높지 않을 수 있다.
  7. 유동(floating) 엘레멘트는 가능한한 높게 위치하여야 한다.
  8. 왼쪽 유동(left-floating) 엘레멘트는 가급적 왼쪽에 멀리 위치하여야 하고, 오른쪽 유동(right floating) 엘레멘트는 가급적 오른쪽에 멀리 위치하여야 한다. 높은 위치가 왼쪽/오른쪽으로 멀리 나가는 것보다 선호된다.
<PRE><STYLE TYPE="text/css">IMG { float: left }BODY, P, IMG { margin: 2em }</STYLE><BODY><P><IMG SRC=img.gif> 간단한 설명 택스트 ...</BODY></PRE>

위의 예제는 다음과 같이 양식화된다. <PRE> ________________________________________|| 최대(BODY 마진(margin), P 마진)| ______________________________| | | 간단한 설명 택스트| B | P | IMG margins 유동(floating) 엘레멘트| O | | _____ 설명 목적 외에는| D | m | | | 다른 목적이 없다.| Y | a | | IMG | 유동 엘레멘트는 모체| | r | | | 엘레멘트 쪽으로| m | g | |_____| 마진(margin)들,| a | i | 테두리(border)들| r | n | 그리고 패딩(padding)을| g | | 유지하면서 이동하였다.| i | |인접 수직 마진들이 비유동(non-floating)| n | |블럭레벨(block-level) 엘레멘트들과의| | |사이에서 어떻게 붕괴되는가를 주시하라.</PRE>

'P' 엘레멘트의 마진이 유동(floating) 'IMG' 엘레멘트를 닫는다 점을 주시하라.

유동(floating) 엘레멘트들이 다른 엘레멘트들의 margin, border 그리고 padding 지역과 중복될 수 있는 2 가지 경우가 있다.

  • 유동(floating) 엘레멘트가 음수 마진을 가질 때: 유동(floating) 엘레멘트들의 음수 마진들은 다른 블럭레벨(block-level) 엘레멘트들에 표현된다.
  • 유동(floating) 엘레멘트가 안에 있는 엘레멘트보다 넓거나 높을 때

4.2    인라인(inline) 엘레멘트들

블럭레벨(block-level) 엘레멘트들로 양식화되지 않는 엘레멘트들은인라인(inline) 엘레멘트들이다. 인라인(inline) 엘레멘트는 라인 지역(space)을 다른 엘레멘트들과 공유할 수 있다. 다음 예제를 보라. <PRE><P>몇개의 <EM>강조된</EM> 단어들이<STRONG>나타난다</STRONG>.</P></PRE>

'P' 엘레멘트는 보통의 블럭레벨(block-level)이고, 'EM'과 'STRONG'는 인라인(inline) 엘레멘트들이다. 만일 'P' 엘레멘트가 모든 엘레멘트들을 한 줄에 양식화하기에 충분히 넓으면, 두개의 인라인(inline) 엘레멘트들이 한 줄에 오게 된다. <PRE>몇개의 강조된 단어들이 나타난다.</PRE>

만일 한 줄에 한 인라인(inline) 엘레멘트의 공간이 충분하지 않으면, 몇개의 박스(box)들로 나누게 된다. <PRE><P>몇개의 <EM>강조된 단어들이</EM> 여기에 나타난다.</P></PRE>

위 예제는 다음과 같이 양식화된다. <PRE>몇개의 강조된 단어들이 여기에 나타난다.</PRE>

만일 인라인(inline) 엘레멘트가 마진(margin)들, 테두리(border)들, 패딩(padding) 또는 첨부된 텍스트 장식들을 가지면, 이들은 엘레멘트가 깨져서(broken) 아무 효과도 없을 것이다. <PRE>---------- 몇개의|강조된 ---------- ----- 단어들이| 여기에 나타난다.-----</PRE>

위의 모양("figure")이 약간 찌그러 졌는데, 이는 ASCII 그래팩을 사용했기 때문이다. 항목 4.4 높이 계산 방식을 참조하라.

4.3    대체된(Replaced) 엘레멘트들

대체된(replaced) 엘레멘트는 하나의 그 엘레멘트가 지정하는 내용이 대체된(replaced) 엘레멘트이다. 예를 들어, HTML에서, 'IMG' 엘레멘트가 'SRC' 애트리뷰트가 지시하는 이미지로 대체된다(replaced). 대체된(replaced) 엘레멘트들은 그들 본연(intrinsic)의 규격(dimension)을 갖는다고 가정할 수 있다. 만일 너비('width') 속성값이 'auto'이면, 본연(intrinsic)의 너비를 그 엘레멘트의 너비로 사용한다. 만일 스타일쉬트에 지정한 그 값이 'auto'가 아니면, 이 값이 사용고, 그 대체된(replaced) 엘레멘트는 이에 따라 재싸이징(resize)된다. 재싸이징(resize) 방법은 메디아에 따라 다르다. 높이('height') 속성은 다음과 같은 방식으로 사용된다.

대체된(replaced) 엘레멘트들은 블럭레벨(block-level) 이나 인라인(inline)이 될 수 있다.

4.4    줄의 높이

모든 엘레멘트들은 줄높이('line-height') 속성은 갖느데, 이는 원칙적으로, 택스트의 총 높이를 준다. 공간이 택스트의 상부와 하부에 추가되어 줄높이를 현성한다. 예를 들어, 만일 텍스트가 12pt 높이이고 줄높이('line-height')가 '14pt'로 설정되면, 줄에 2pt의 공백이 상부에 1pt, 하부에 1pt가 추가된다. 빈 엘레멘트들은 내용을 가지고 있는 엘레멘트들과 꼭 같은 계산으로 영향을 준다.

글자크기(font size)와 줄높이('line-height')의 차이는 선행(leading)이라 불리운다. 선행(leading)의 반을 선행의 반(half-leading)이라 부른다. 양식화 이후에 각 줄은 사각형 줄박스(line-box)를 형성한다.

만일 택스트를 갖는 줄에 다른 줄높이('line-height') 값이있으면(줄에 다른 인라인(inline) 엘레멘트들이 있어서), 이들 각 부분들은 각각의 선행의 반(half-leading)을 아래, 위에 갖는다. 줄박스(line-box)의 높이는 가장 높은 부분의 맨위에서 가장 낮은 부분의 맨아래까지의 거리가 된다. 맨위와 맨아래는 반드시 가장 키가 큰 엘레멘트에 상응하는 것이 아님을 주시하라. 왜냐하면 엘레멘트들은 수직정렬('vertical-align') 속성(property)으로 수직적으로 배치되기 때문이다. 문단(paragraph)을 구성하기 위하여 각 줄박스(line-box)들은 전 줄의 바로 밑에 차곡 차곡 쌓여진다.

대체 안된(non-replaced) 인라인(inline) 엘레멘트들 위와 아래 어떤 패딩(padding), 테두리(border) 또는 마진(margin)은 줄높이에 영향을 주지 않는다 점에 주의하라. 다른 말로 줄높이('line-height')가 선택된 패딩이나 테두리를 위해 너무 작으면, 이 것들은 다른 줄들의 텍스트에 넘쳐 중복(overlap)된다.

줄에 있는 대체된(replaced) 엘레멘트들(예를 들어 이미지들)은 줄박스(line-box)를 크게 만들 수 있다. 만일 대체된(replaced) 엘레멘트의 맨위(top), 이를테면, 모든 그의 패딩(padding), 태두리(border), 마진(margin)을 포함하여, 가장 키가 큰 텍스트 맨위보다 높거나, 가장 낮은 맨아래 보다 낮을 수 있기 때문이다.

보통의 경우, 전 문단에 하나의 줄높이('line-height') 값 만 가지고 있는 경우, 그리고 키 큰 이미지들이 없는 경우, 위의 정의가 그대로 적용되어 후속 줄들의 기초라인(baseline)들이 정확히 줄높이('line-height') 만큼씩 떨어지는 것이 확실하다. 이는 예를 들어 표(table)에서 텍스트의 컬럼(column)들에서 다른 글자들 정렬(align)되는데 중요하다.

이는 두 인접 라인들에 있는 텍스트들이 서로 중복되는 것을 제외하지 않는다 점에 주의하라. 줄높이('line-height')는 텍스트 높이보다 작을 수 있는데, 이런 경우 선행(leading)은 음수가 된다. 이것이 텍스트가 모두 대문자이어 기준선 밑으로 튀어나오는 것이 없슴이 확실할 때 줄들이 서로 가깝게 나오게 할 때, 유용하다.

4.5    화면

화면은 표면에 문서들이 표현되는 사용도구의 한 부분이다. 화면에 해당하는 문서의 구조적 엘레멘트는 없다. 이는 문서의 양식화에 두가지 과제를 제공한다.

  • 어디서 부터 화면의 크기(dimension)를 산정할 것인가 ?
  • 문서가 전 화면을 커버(cover)하지 못 할 때, 어떻게 그 지역을 표현할 것인가 ?

첫번째 문제에 대한 합당한 대답은 최초의 화면의 너비는 윈도우 창 크기이다. 그러나 CSS1은 이 문제를 사용도구가 결정하도록 남겨두었다. 이 또한 사용도구가 창을 재싸이징(resize)할 때 화면의 너비를 변경하는 것을 기대하는 것이 합리적이다. 그러나 이 또한 CSS1 범위 밖이다.

HTML 표현(extension)들은 두번째 과제에 중점을 주었다. 'BODY' 엘레멘트에 설정하는 배경(background) 애트리뷰트들는 전체 화면에 배경을 깐다. 설계자의 기대를 지원하기 위하여, CSS1는 화면의 배경(background)을 찾기 위하여 특수 명령(rule)을 소개하였다.

만일 'HTML' 엘레멘트의 배경('background') 값이 투명('transparent')과 다르면 그것을 사용하고, 아니면 'BODY' 엘레멘트의 배경('background') 값을 사용한다. 만일 그 결과 값이 투명('transparent')이면, 표현은 정의되지 않은 것이다.

이 명령은 아래와 같은 사용을 허용한다. <PRE><HTML STYLE="background: url(http://style.com/marble.png)"><BODY STYLE="background: red"></PRE>

위의 예제에서, 화면은 대리석("marble") 이미지로 배경이 된다. 'BODY' 엘레멘트의 배경색은 전체 화면을 덮을 수도 있고 그렇지 않을 수도 있지만 붉은 색이다.

화면 지정에 대한 다른 방법이 유용하게 될 때까지는, 화면 속성들을 'BODY' 엘레멘트에 설정하는 것을 추천한다.

4.6    'BR' 엘레멘트들

현재의 CSS1 속성들과 그 값들은 'BR' 엘레멘트의 기능을 설명할 수 없다. HTML에서, 'BR' 엘레멘트는 단어사이에서 줄바꿈(line break)을 지정한다. 실제, 이 엘레멘트는 줄바꿈(line break)에 의해 대체된(replaced) 것이다. 향후 CSS 버전에서는 추가(added)와 대체된(replaced) 내용을 다루게 된다. 그러나 CSS1 기준 양식화에서는 'BR'를 특별히 취급하여야 한다.

5    CSS1 속성들

스타일쉬트(style sheet)들은 스타일(style) 속성들의 값을 설정하므로서 문서들의 표현에 영향을 준다. 이 장에서는 CSS1의 스타일(style) 속성들의 정의된 목록과 그에 해당하는 가능한 값의 목록을 다룬다.

5.1    속성값에 대한 주기

아래 텍스트는, 각 속성에 대한 허용된 값의 목록과 아래와 같이 문법을 기재하였다.

값: N | NW | NE
값: [ <길이> | thick | thin ]{1,4}
값: [<family-name>, ]* <family-name>
값: <url>? <color> [ / <color> ]?
값: <url> || <color>

  • "<"와 ">"사이의 단어들은 값의 타입(type)을 제공한다.
  • 가장 일반적인 타입들은 <길이>, <백분율>, <url>, <수치>와 <color>이며, 이들은 항목 6 단위에 기술 되었다.
  • 좀 더 전문화된 타입들(예를 들어 <font-family>와 <border-style>)은 해당 속성(property)에 지정하였다.
  • 다른 단어들은 키워드(keyword)들인데, 따옴표 없는 글자로 표시되었다.
  • 슬래쉬(/) 와 컴마(,) 또한 글자로 표시되었다.
  • 여러가지 나란히 된 수단은 그들 모든 것이 그 순서로 나와야 만 하는 것이다.
  • 그들 중 하나가 나타나야 하는 선택적 항목은 바(|)로 구분하였다.
  • 이중 바(A || B)는 A 또는 B 또는 둘 다, 명시된 순서로, 나타나야 하는 것을 의미한다.
  • 괄호들([])은 구룹으로 묶기한 것이다.
  • 나란히 나온 것은 이중 바들 보다 우선하고, 이중 바들은 다른 바보다 우선한다.
  • 따라서 "a b | c || d e"는 "[ a b ] | [ c || [ d e ]]"와 같다.

각 타입(type), 키워드(keyword), 또는 괄호 안의 구룹은 다음과 같은 것들 중 하나의 수정자(modifier)가 따라 나올 수 있다.

  • 별표 (*)는 앞의 타입(type), 단어(word) 또는 구룹이 0번 혹은 여러번 나올 수 있슴을 나타낸다.
  • 더하기표(+)는 앞의 타입(type), 단어(word) 또는 구룹이 한번이상 나옴을 나타낸다.
  • 물음표(?)는 앞의 타입(type), 단어(word) 또는 구룹이 선택적임을 나타낸다.
  • 괄호 안 수치들({A,B})의 짝은 앞의 타입(type), 단어(word) 또는 구룹이 최소 A번 최대 B번 반복 됨을 나타낸다.

5.2    글자(font) 속성들

글자(font) 속성들을 설정하는 것은 스타일쉬트 사용들 중 가장 보편적인 것이다. 불행햐게도, 잘 정의된 세계 공통적으로 수용되는 글꼴들의 분류가 없다는 것이다. 한가지 글꼴 가족(font family)에 적용되는 것이 다른것에서는 적용되지 않을 수 있다. 예를 들어 'italic'은 일반적인 기울어진 글자를 위하여 사용되나, 기울어진 글자들이 또한 Oblique, Slanted, Incline, Cursive 또는 Kursiv등으로 표시되기도 한다. 따라서 특정 글꼴(font) 선택 속성들로 특정 font를 지정하는 것이 간단치 않다.

CSS1는 그 속성들 글꼴들('font-family'), 글꼴 스타일('font-style'), 글꼴 변화('font-variant'), 글꼴 굵기('font-weight'), 글꼴 크기('font-size'), 'font'를 정의하고 있다.

5.2.1    글자(font) 맞추기

글자(font) 속성들의 세계 공통적으로 수용되는 글꼴들의 분류가 없기 때문에, 글꼴(font face)들에 속성들을 맞추는(matching) 것을 주의 깊게 하여야 한다. 그 속성들은 그 마춤 과정의 결과들이 가능한 한 여러 사용도구들(같은 글꼴이 같이 표현됨을 가정하면서) 간에 일정하게 할 수 있도록 잘 정의된 순서로 맞춰줘야 한다.

  1. 사용도구는 사용도구가 알고 있는 CSS1에 상응하는 모든 글자(font)들의 속성들의 데이터베이스를 만들고 접속한다. 사용도구는, 그 것이 지역적(locally)으로 설치(install)되었기 때문에, 혹은, 이전에 웹으로 부터 다운로드 받았가 때문에, 글자를 알고 있을 수 있다. 만일 두가지 글자가 꼭 같은 속성들을 가지면 하나는 무시한다.
  2. 주어진 엘레멘트에서 그리고 그 엘레멘트의 각 속성은, 사용도구는 그 엘레멘트에 적용할 수 있는 글자 속성들을 조합한다(assemble). 완전한 속성들의 세트(set)를 사용하여, 사용도구들은 그 글꼴들('font-family') 속성을 임시적인 글꼴(font family)로 선택하여 사용한다. 나머지 속성들은 각 속성(property)에 설정된 마춤(matching) 기준(criteria)에 따라 그 family에 대하여 검정한다. 만일 이 맞춤이 모든 나머지 속성들에 맞으면, 그것이 주어진 엘레멘트의 맞는 글꼴(font face)이 된다.
  3. 만일 글꼴들('font-family')들 중에 맞는 글꼴(font face)이 없으면, 두번째 단계로 진행한다. 만일 다음 가능한(alternative) 글꼴들('font-family')들 중에 맞는 글꼴이 있는가의 두번째 단계를 반복한다.
  4. 만일 맞는 글꼴이 있으나, 현재의 글자를 표현할 수 없고, 추가적인 가능한 글꼴이 있으면, 다음 글꼴로 두번째 단계를 반복한다. 부록 C 글꼴와 글자 엔코딩을 참조하라.
  5. 만일 두번째 단계에서 맞는 글꼴이 발견되지 않으면, 사용도구에 따른 디폴트 글꼴들('font-family')을 사용하여 두번째 단계를 반복하여 디폴트 글꼴 중에서 가장 잘 맞는 것을 찾기위하여 반복한다.

(위의 기능이 CSS1 속성들의 각 글자마다 재방문을 회피하기 위하여 적정화(optimized)될 수 있다.)

위 두번째 속성 맞춤(matching) 과정은 다음과 같다.

  1. 글꼴 스타일('font-style')이 제일 먼저 시도된다. 사용도구의 글꼴(font) 데이터베이스에서 CSS 키워드(keyword) 'italic' (선호 됨) 또는 'oblique'로 라벨된 글꼴이 있으면 'italic'이 만족스러워 진다. 아니면 그 값들 꼭 맞는 것이 찾아져야 하고 그렇지 않으면 font-style 실패가 된다.
  2. 다음 글꼴 변화('font-variant')가 시도된다. 'normal'을 'small-caps'로 라벨되지않는 글꼴과 맞춘다. 'small-caps'을 'small-caps'로 라벨된 글꼴과 맞춘다 matches(1). (2)는 small caps의 합성된(synthesized) 글꼴이다. 또는 (3)는 모든 소문자들이 대문자로 대체된(replaced) 글꼴이다. small-caps 글꼴은 정상 글꼴의 대문자들로 부터 전기적으로 비례적으로 합성(synthesized)할 수 있다.
  3. 다음은 글꼴 굵기('font-weight')를 점검한다. 이는 실패하지 않는다.(아래 글꼴 굵기('font-weight')를 참조하라)
  4. 글꼴 크기('font-size')는 사용도구에 따른 마진(margin)의 허용 범위(tolerance)에 맞춘다. (전형적으로, 크기(size)들을 비례적으로 변화시키는데(scale)는 가장 가까운 픽셀(pixel)로 반올림한다. 비트 단위로 구성된(bitmapped) 글꼴은 20%까지 크게 할 수 있다.) 다른 내용들, 예를 들어 'em'등 다른 속성들에서 값은 그 것이 사용하는 글꼴 크기('font-size') 값에 기초하고, 지정된 값으로 하지 않는다.

5.2.2    글꼴들('font-family')

값: [[<family-name> | <generic-family>],]* [<family-name> | <generic-family>]
최초값:사용도구에 따라 다름
적용: 모든 엘레멘트들
전달: 전달 됨
백분율 값들: 없슴

이 값은 글꼴 가족(font family name) 그리고/또는 일반 글꼴(generic family name)의 적용 우선순위를 열거한 목록이다. 다른 CSS1 속성들과는 달리, 그 값은 컴마로 분리하고, 이는 서로 대체(alternative)한다는 것을 나타낸다. <PRE>BODY {font-family: gill, helvetica, sans-serif}</PRE>

두가지의 타입(type)들의 목록 값들이 있다.

<family-name>
선택된 글꼴들의 이름이다. 마지막 예제에서, "gill"과 "helvetica"는 긁꼴들(font family)이다.
<generic-family>
위의 예제에서, 마지막 값은 일반 글꼴(generic family) name이다. 다음 일반 글꼴(generic family)들이 정의 되었다.
  • 'serif' (예를 들어 Times)
  • 'sans-serif' (예를 들어 Helvetica)
  • 'cursive' (예를 들어 Zapf-Chancery)
  • 'fantasy' (예를 들어 Western)
  • 'monospace' (예를 들어 Courier)

스타일쉬트는 설계자는 일반 글꼴(generic font family)을 마지막 대체(alternative) 글꼴로 제시하도록 추천한다.

글꼴 이름에 공백이 있으면 반드시 따옴표로 묶어야 한다. <PRE>BODY { font-family: "new century schoolbook", serif }<BODY STYLE="font-family: 'My own font', fantasy"></PRE>

만일 따옴표가 생략되면, 글꼴 이름의 앞과 뒤에나오는 공간을 무시고, 하나이상의 빈 공간은 하나의 빈 공간으로 간주된다.

font-family 표현 예제

5.2.3    글꼴 스타일('font-style')

값: normal | italic | oblique
최초값: normal
적용: 모든 엘레멘트들
전달: 전달 됨
백분율 값들: 없슴

글꼴 스타일('font-style') 속성은 글꼴(font family) 안에서 normal(때로는 "roman" 또는 "upright"로 불리운다), 'italic'과 'oblique' 중에서 선택한다.

값 'normal'은 사용도구의 글꼴 데이터베이스에서 'normal'로 분류된 글자를 선택한다. 'oblique'는 'oblique'로 라벨된 글꼴을, 'italic'은 'italic'으로 라벨된 글꼴을 찾으며 없으면 'oblique'로 라벨된 것을 찾는다.

사용도구의 글꼴 데이터베이스에서 'oblique'로 라벨된 글꼴은 실제적으로 정상 글자를 전자적으로 기우려서 생성할 수 있다.

Oblique, Slanted 또는 Incline으로 이름지워진 글꼴들는 사용도구의 글꼴 데이터베이스에서 전형적으로 'Ioblique'로 라벨된다. Italic, Cursive 또는 Kursiv로 이름 지워 진 글꼴들은 전형적으로 'italic'으로 라벨된다. <PRE>H1, H2, H3 { font-style: italic }H1 EM { font-style: normal }</PRE>

위의 예제에서, 'H1' 안의 강조된 텍스트는 보통 글꼴로 나타 날 것이다.

5.2.4    글꼴 변화('font-variant')

값: normal | small-caps
최초값: normal
적용: 모든 엘레멘트들
전달: 전달 됨
백분율 값들: 없슴

글꼴 안에서 다른 변형은 small-caps이다. small-caps 글꼴에서 소문자들은 대문자 비슷하게 나타난다. 그러나 작은 글꼴 크기에서는 약간 다른 비율들을 갖는다. 글꼴 변화('font-variant') 속성은 그 글꼴를 선택한다.

'normal' 값은 small-caps 글꼴을 선택하지 않고, 'small-caps'은 small-caps 글꼴을 선택한다. small-caps가 정상 글꼴로 부터 소문자를 대문자로 비율적(scale)으로 변환하여 만드는 것을 CSS1에서 수용(acceptable)한다. 그러나 필요한 것은 아니다. 마지막으로, 대문자들이 small-caps 글꼴을 위하여 사용될 수 있다.

다음 예제는 'H3' 엘레멘트 안에 small-caps로, 강조된 글자를 기울어진 oblique small-caps로 나타난다. <PRE>H3 { font-variant: small-caps }EM { font-style: oblique }</PRE>

글꼴 안에 old-style numerals, small-caps numerals, condensed 또는 expanded letters, 등 다른 종류의 변종(variant)들이 더 있을 수 있다. CSS1에는 이들을 선택하기 위한 속성들이 없다.

CSS1 핵심: 이 속성이 텍스트를 대문자로 변환을 설명한 바와 같이, 이와 같은 텍스트 변환('text-transform')의 적용이 고려된다.

5.2.5    글꼴 굵기('font-weight')

값: normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
최초값: normal
적용: 모든 엘레멘트들
전달: 전달 됨
백분율 값들: 없슴

글꼴 굵기('font-weight') 속성으 글꼴의 굵기를 선택한다. '100'에서 '900'의 그 값들은 순서대로 각 수치는 굵기를 지정하는데 뒤의 것이 앞의 것보다 더 어둡다. 키워드(keyword) 'normal'은 값 '400'에 해당하며, 'bold'는 값 '700'과 같다. 키워드(keyword) 'normal'과 'bold'는 글꼴 이름들과 수치 값과 자주 혼동되므로 위의 9 단계 값의 목록으로 하였다. <PRE>P { font-weight: normal } /* 400 */H1 { font-weight: 700 } /* bold */</PRE>

'bolder' 와 'lighter' 값은 글꼴 굵기(weight)를 모체로 부터 전달된(inherited) 값에 상대적으로 선택한다. <PRE>STRONG { font-weight: bolder }</PRE>

하위(child) 엘레멘트들은 결과 굵기(weight)를 전달한다. 그러나 키워드 값을 전달하는 것은 아니다.

글꼴 데이터들은 전형적으로 하나이상의 속성들을 갖는데, 글꼴의 두께("weight")를 설명하도록 주어진 이름들의 값을 갖는다. 이들 두께(weight) 이름들은 세계 공통적으로 수용되는 것은 없다. 그 일차적인 임무는한 글꼴 안에서 다른 검은 정도로 글꼴를 구별하는 것이다. 여러 글꼴들사이에서는 대단히 변이가 많다. 예를 들어 굵은(bold) 것으로 생각되는 글꼴이, 그 디자인 안에서 그 글꼴의 보통("normal")이 얼마나 검은가에 따라, Regular, Roman, Book, Medium, Semi-, DemiBold, Bold, 또는 Black로 지정된다. 이름들의 사용에 표준이 없으므로, 이 굵기(weight) 속성값들은 CSS1에서 수치 값으로 주어졌다. 여기서 값 '400' (='normal')이 그 글꼴의 보통("normal") 글꼴에 해당하는 것이다. 이 굵기(weight) 이름은 그 글꼴에서 전형적으로 Book, Regular, Roman, Normal 또는 때로는 Medium과 같이 주어진다.

그 글꼴에서 다른 굵기들과의 연관은 그 수치 굵기(weight)의 값들의 검은 정도의 순서를 유지하는 것 만을 목표로 하였다. 그러나 다음 체계는 전형적인 경우에 어떻게 지정하는가를 보여준다.

  • 만일 글꼴이 이미 9 단계(예를 들어 OpenType에서와 같이) 수치 값들을 사용하면, 그 글꼴의 두께(weight)는 직접 그에 의해 표현하여야 한다.
  • 만일 글꼴에 Medium으로 라벨된 것과 Book, Regular, Roman 또는 Normal로 라벨된 것이 있으면, 그 Medium은 일반적으로 값 '500'으로 할당한다.
  • 글꼴이 "Bold"로 라벨된 것은 자주 그 굵기(weight) 값 '700'에 상응한다.
  • 만일 글꼴 안에서 9 단계 보다 적은 단계로 되어있으면, 빈 것("holes")을 채우는 디폴트 기능은 다음에 따른다. 만일 '500'이 지정되지 않았으면, 이것은 같은 글꼴에서 '400'으로 설정한다. 만일 그 값들이 '600', '700', '800' 또는 '900' 중 어느 것도 지정되지 않았으면, 같은 글꼴에서 다음번 검은 키워드(keyword)를 지정한다. 그 중 어느 것이 지정되어 있지 않으면, 그 다음 엷은(lighter) 것이 된다. '300', '200' 또는 '100' 값이 지정되지 않았으면, 그 다음 엷은(lighter) 것의 키워드(keyword)를 지정한다. 지정되었으면 그 다음 검은 것이 지정된다.

다음 두가지 예제들은 이 과정을 설명한다. "예제1" 글꼴에서 4 가지 굵기 단계를 가정한다. 엷은 것에서 검은(어두운) 것으로의 순서는 Regular, Medium, Bold, Heavy이다. "예제2" 글꼴에서 6 가지 굵기 단계를 가정한다. 여기서는 Book, Medium, Bold, Heavy, Black, ExtraBlack 순서가 된다. 두번째 예제에서 "예제2 ExtraBlack"를 지정하지 않기로 결정하였음을 주시하라. <PRE>가능한 글꼴 |지정 | 기타------------------+-----+-------------------"예제1 Regular" | 400 | 100, 200, 300"예제1 Medium" | 500 |"예제1 Bold" | 700 | 600"예제1 Heavy" | 800 | 900가능한 글꼴 |지정 | 기타------------------+-----+-------------------"예제2 Book" | 400 | 100, 200, 300"예제2 Medium" | 500 |"예제2 Bold" | 700 | 600"예제2 Heavy" | 800 |"예제2 Black" | 900 |"예제2 ExtraBlack"|none |</PRE>

상대 키워드(keyword) 'bolder'와 'lighter'이 더 검은(darken, 어두운) 또는 더 엷은(lighten) 표면으로 그 글꼴 안에서 지정하는 것을 의도하였으므로, 또한 한 글꼴이 이 모든 굵기의 기호적 값들을 가지고 있지 않을 수 있기 때문에, 'bolder'에 마춤은 사용자에게 그 글꼴 안에서 가능한 그 다음 검은 표면을 사용하게 하였다. 그리고 'lighter'로 그 글꼴 안에서 그 다음 엷은 표면과 맞추게(matching) 하였다. 상대적(relative)인 키워드(keyword) 'bolder'와 'lighter'의 의미는 정확하게 다음과 같다.

  • 'bolder'는 전달된(inherited) 값보다 한 단계 더 검은 다음 번 두께(weight)를 선택한다. 만일 그런 두께(weight)가 없으면, 단순히 글꼴의 변동없이 다음 번 검은 수치 값을 지정한다. 전달된 값이 '900'인 경우에는 결과도 '900'이다.
  • 'lighter'도 이와 유사하다. 그러나 반대 방향으로 작용한다. 전달된(inherited) 값보다 한 단계 더 엷은 다음 번 두께(weight)를 선택한다. 만일 그런 두께(weight)가 없으면, 단순히 글꼴의 변동없이 다음 번 검은 수치 값을 지정한다.

각 글꼴 굵기('font-weight') 값이 더 검은 표면를 표현한다는 보장은 없다. 예를 들어, 일부 글꼴들은 정상(normal)과 굵은(bold) 표면 만을 갖는다. 다른 것들은 8 단계 다른 표면을 두께(weight)들은 갖는다. 사용도구가 글꼴 안에서 어떤 두께(weight) 값을 어떻게 글꼴 표면으로 표현할 것이라는 보증은 없다. 보증은 단지, 더 엷은 값들로 주어진 표면보다, 주어진 값의 표면이 덜 검지 않다는 것이다.

5.2.6    글꼴 크기('font-size')

값: <absolute-size> | <relative-size> | <길이> | <백분율>
최초값: medium
적용: 모든 엘레멘트들
전달: 전달 됨
백분율 값들: 모체 엘레멘트의 글꼴 크기(font size)에 대해

절대 크기(<absolute-size>)
키워드(keyword) <absolute-size>는 사용도구에 의하여 계산되고 유지되는 글꼴 크기 표(table)의 색인이다. 가능한 값은: [ xx-small | x-small | small | medium | large | x-large | xx-large ]이다. 컴퓨터 화면에서 인접 색인들 가운데 1.5 배율(scaling factor)이 암시된다. 만일 보통('medium') 크기가 10pt이면 'large' 글꼴는 15pt가 된다는 것이다. 다른 메디아(media)에서는 다른 배율(scaling factor)이 될 수 있다. 또한 사용도구는 그 표(table)를 계산하는데 가능한 글꼴들과 그들의 품질을 고려하여야 한다. 그 표는 글꼴에 따라 다를 수 있다.
상대 크기(<relative-size>)
키워드(keyword) <relative-size>는 모체 엘레멘트의 글꼴 크기와 글꼴 크기 표(table)의 상대적인 관계이다. 가능한 값은: [ larger | smaller ]이다. 예를 들어, 만일 모체 엘레멘트가 글꼴 크기 'medium'을 가지면, 'larger'는 현재 엘레멘트의 글꼴 크기를 'large'로 만들 것이다. 만일 모체 엘레멘트의 크기가 표(table)의 글자들의 크기와 비슷하지 않으면, 사용도구가 글자들 간의 비율 또는 가장 가까운 것을 택하는 것은 자유이다. 사용도구는 만일 수치 값이 키워드(keyword) 범위를 벋어나면, 추가적으로 표의 값을 계산해야 할 수 있다.

엘레멘트의 글꼴 크기를 계산하는데 길이와 백분율 값들은 글꼴 크기 표(table)에서 고려하지 않는다.

음수는 허용되지 않는다.

모든 다른 속성들에서, 'em' 과 'ex' 길이 값들은 현재 엘레멘트의 글꼴 크기를 참조한다. 그 글꼴 크기('font-size') 속성(property)에서, 이들 길이 단위들은 모체 엘레멘트의 글꼴 크기를 참조한다.

문장에 따라서 적용될 때 지정한 크기를 다시 해석할 수 있슴을 주지하라. 예를 들어, 비디오(VR)에서 글꼴는 틀어짐을 고려하여 다른 글꼴 크기를 가질 수 있다.

글꼴 크기의 예제 <PRE>P { font-size: 12pt; }BLOCKQUOTE { font-size: larger }EM { font-size: 150% }EM { font-size: 1.5em }</PRE>

만일 암시된 배율(scaling factor) 1.5를 사용한다면 뒤의 3 가지는 모두 같다.

5.2.7    글꼴('font')

값: [ <font-style> || <font-variant> || <font-weight> ]? <font-size> [ / <line-height> ]? <font-family>
최초값: 약식속성들에는 정의되지 않음
적용: 모든 엘레멘트들
전달: 전달 됨
백분율 값들: <font-size>와 <line-height>에 허용됨

글꼴('font') 속성은 같은 스타일쉬트에서 글꼴 스타일('font-style'), 글꼴 변화('font-variant'), 글꼴 굵기('font-weight'), 글꼴 크기('font-size'), 줄높이('line-height'), 글꼴들('font-family')를 설정하기 위한 약식속성이다. 이 속성의 문법은 관계된 글꼴들의 복수 속성들을 지정하는 전통적인 문구에 기초한다.

가능한 값과 최초값을 지정하기 위하여 이전에 정의된 속성들을 참조하라. 값이 주어지지 않는 속성들은 최초값으로 지정된다. <PRE>P { font: 12pt/14pt sans-serif }P { font: 80% sans-serif }P { font: x-large/110% "new century schoolbook", serif }P { font: bold italic large Palatino, serif }P { font: normal small-caps 120%/120% fantasy }</PRE>

두번째 명령(rule)에서, 글꼴 크기(font size) 백분율 값 ('80%')은 모체 엘레멘트의 글꼴 크기를 참조한다. 세번째 명령에서, 줄높이 백분율은 그 엘레멘트 자체의 글꼴 크기를 참조한다.

앞 3 개의 명령에서, 글꼴 스타일('font-style'), 글꼴 변화('font-variant')와 글꼴 굵기('font-weight')는 명시적으로 지정하지 않았다. 이는 모든 3 개의 예제에서 그들의 최초값 ('normal')이 설정되어 있다는 의미이다. 네번째 명령(rule)에서 글꼴 굵기('font-weight')가 'bold'로 설정되었는데, 그 글꼴 스타일('font-style')을 'italic'과 글꼴 변화('font-variant')를 'normal'로 명시적으로 설정하였다.

다섯번째 예제는 글꼴 변화('font-variant')를 ('small-caps')로 설정하였는데, 그 글꼴 크기('font-size')는 모체 글꼴의 120%, 줄높이('line-height')는 글꼴 크기의 120%, 그리고 글꼴들('font-family')는 'fantasy'이다. 키워드(keyword) 'normal'이 나머지 두가지 속성들, 글꼴 스타일('font-style')과 글꼴 굵기('font-weight')에 설정된다.

5.3    색상(color)과 엘레멘트의 배경(background) 속성

이들 속성들은 색상(자주 foreground color로 불리운다)과 배경(background:내용이 표현되는 표면)을 지정한다. 배경에 배경색 그리고/또는 배경 이미지를 설정할 수 있다. 또한 그 이미지의 위치, 반복, 고정되는지 굴리는지(scroll)를 그 화면에 상대적으로 설정할 수 있다.

색상('color') 속성은 일반적으로 전달(inherit)되며, 배경(background) 속성들은 전달되지 않는다. 그러나 그 모체 엘레멘트의 배경(background)은 배경색('background-color')에 최초값 투명('transparent')이 설정되어 있기 때문에 디폴트로 전체에 나타난다.

5.3.1    색상('color')

값: 색상(<color>)
최초값:사용도구에 따라 다름
적용: 모든 엘레멘트들
전달: 전달 됨
백분율 값들: 없슴

이 속성은 엘레멘트의 텍스트 색상(자주 foreground color 로 불리움)을 지정한다. 여러가지로 적색을 지정할 수 있다. <PRE>EM { color: red } /* 자연 언어 */EM { color: rgb(255,0,0) } /* RGB 범위 0-255 */</PRE>

항목 6.3 가능한 색상값들을 참조하라. HTML 색상표도 참조하라.

5.3.2    배경색('background-color')

값: <color> | transparent
최초값: transparent(투명)
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

이 속성은 엘레멘트의 배경색(background color)을 지정한다. <PRE>H1 { background-color: #F00 }</PRE>

5.3.3    배경 이미지('background-image')

값: <url> | none
최초값: none
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

이 속성은 엘레멘트의 배경 이미지(background image)를 설정한다. 배경 이미지가 설정되면, 그 이미지가 없을 때를 대비하여 표현될 배경색을 동시에 지정하여야 한다. 이미지가 유효하면 배경색 위에 표현된다. <PRE>BODY { background-image: url(marble.gif) }P { background-image: none }</PRE>

5.3.4    배경 반복('background-repeat')

값: repeat | repeat-x | repeat-y | no-repeat
최초값: repeat(반복)
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

만일 배경 이미지가 지정되면, 배경 반복('background-repeat')의 값은 어떻게 그 이미지를 반복할 것인가 혹은 반복하지 않을 것인가를 지정한다.

값 'repeat'는 이미지가 수평, 수직 양 방향으로 반복되는 것을 의미한다. 값 'repeat-x' ('repeat-y')는 이미지가 수평(수직) 방향으로 반복되는 것으로 이미지가 한 방향으로 띠를 형성한다. 값 'no-repeat'로는 반복 없이 한번 만 표현된다. <PRE>BODY { background: red url(pendant.gif); background-repeat: repeat-y;}</PRE>

위의 예제에서, 이미지는 수직적으로 반복된다.

5.3.5    배경 첨부('background-attachment')

값: scroll | fixed
최초값: scroll(굴림)
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

만일 배경 이미지가 지정되면, 배경 첨부('background-attachment') 값은 지정한다. 이미지를 화면에 고정시킬 것인가 내용에 따라 굴릴(scroll) 것인가를 지정한다. <PRE>BODY { background: red url(pendant.gif); background-repeat: repeat-y; background-attachment: fixed;}</PRE>

CSS1 핵심: 사용도구들은 'fixed'를 'scroll'로 처리할 수 있다. 그러나, 제작자가 'fixed' 만을 지원하는 브라우저들에게 이미지를 제공할 수 있는 방법이 없으므로, 최소한 HTML과 BODY 엘레멘트들에서 바르게 'fixed'로 처리할 것을 추천한다. (항목 7 참조.)

5.3.6    배경 위치('background-position')

값: [<백분율> | <길이>]{1,2} | [top | center | bottom] || [left | center | right]
최초값: 0% 0%
적용: 블럭레벨(block-level)과 대체된(replaced) 엘레멘트들
전달: 안됨
백분율 값들: 그 엘레멘트 자체의 크기를 참조하라

만일 배경 이미지가 지정되면, 배경 위치('background-position') 값은 최초 위치를 지정한다.

값이 '0% 0%'이면, 이미지의 위 왼쪽 모퉁이가 그 엘레멘트의 내용이 들어가는 박스(box)의 위 왼쪽 모퉁이에 위치 한다 (말하자면, 그 padding, border 또는 margin에 의하여 둘려 쌓인 박스가 아님). 값 '100% 100%'는 이미지의 아래 오른쪽 모퉁이가 그 엘레멘트의 아래 오른쪽 모퉁이에 위치 시킨다. 값 '14% 84%'는 이미지의 가로 14% 아래로 84% 지점에 그 엘레멘트의 가로 14% 아래로 84% 지점을 위치시킨다.

값 '2cm 2cm'는 이미지의 왼쪽 맨 위 지점을 그 엘레멘트의 왼쪽 끝에서 오른쪽으로 2cm, 맨 위에서 아래로 2cm 지점에 위치시킨다.

만일 백분율 또는 길이 값이 하나 만 지정되면, 수평 지점 만 설정되고 수직 위치는 50%로 설정된다. 두 값이 설정될 때 수평 위치가 먼저 나온다. 예를 들어 '50% 2cm'와 같이 길이와 백분율 값의 조합도 가능하다. 위치 값의 음수도 허용된다.

배경 이미지의 위치를 지정하기 위하여 키워드(keyword) 값들을 사용할 수도 있다. 키워드는 백분율 값이나 길이 값과 조합할 수 없다. 가능한 키워드들과 그 해석은 다음과 같다.

  • 'top left', 'left top' 모두 '0% 0%'와 같다.
  • 'top', 'top center', 'center top' 모두 '50% 0%'와 같다.
  • 'right top', 'top right' 모두 '100% 0%'와 같다.
  • 'left', 'left center', 'center left' 모두 '0% 50%'와 같다.
  • 'center', 'center center' 모두 '50% 50%'와 같다.
  • 'right', 'right center', 'center right' 모두 '100% 50%'와 같다.
  • 'bottom left', 'left bottom' 모두 '0% 100%'와 같다.
  • 'bottom', 'bottom center', 'center bottom' 모두 '50% 100%'와 같다.
  • 'bottom right', 'right bottom' 모두 '100% 100%'와 같다.

예제: <PRE>BODY { background: url(banner.jpeg) right top } /* 100% 0% */BODY { background: url(banner.jpeg) top center } /* 50% 0% */BODY { background: url(banner.jpeg) center } /* 50% 50% */BODY { background: url(banner.jpeg) bottom } /* 50% 100% */</PRE>

만일 배경 이미지가 그 화면에 대해 고정(fixed)되면(위 배경 첨부('background-attachment') 속성 참조), 그 이미지는 그 엘레멘트 대신 그 화면에 대해 위치한다. 예를 들어: <PRE>BODY { background-image: url(logo.png); background-attachment: fixed; background-position: 100% 100%;}</PRE>

위의 예제에서, 그 이미지는 그 화면의 오른쪽 맨 아래 위치한다.

5.3.7    배경('background')

값: <background-color> || <background-image> || <background-repeat> || <background-attachment> || <background-position>
최초값: 약식속성들에는 정의되지 않음
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: <background-position>에 허용됨

그 배경('background') 속성은 개별 배경 속성들, 말하자면, 배경색('background-color'), 배경 이미지('background-image'), 배경 반복('background-repeat'), 배경 첨부('background-attachment'), 배경 위치('background-position')을 한 곳에 지정하는 약식속성이다.

이 배경('background') 속성들의 가능한 값들은 개별 속성들의 모든 가능한 값들이다. <PRE>BODY { background: red }P { background: url(chess.png) gray 50% repeat fixed }</PRE>

이 배경('background') 속성은 항상 모든 개별 배경 속성들을 설정한다. 위 예제에서 첫번째 명령(rule)은 배경색('background-color') 값 만 갖고, 다른 개별 속성들은 그들의 최초값에 의하여 설정된다. 두번째 명령(rule)에는 모든 개별 속성들이 지정되었다.

5.4    텍스트(text) 속성들

5.4.1    단어 간격('word-spacing')

값: normal | <길이>
최초값: normal
적용: 모든 엘레멘트들
전달: 전달 됨
백분율 값들: 없슴

이 길이 단위는 단어 간격의 디폴트 공간에 추가하여 단어 간격의 공간을 지정한다. 값은 음수가 될 수 있으나, 적용에 따른 범위가 있을 수 있다. 사용도구는 정확한 간격 띄우기 기능을 선택하는데 방법은 자유이다. 단어 간격은 또한 정렬에 의하여 영향 받을 수 있다. 텍스트 정렬('text-align') 속성(property)값 참조. <PRE>H1 { word-spacing: 1em }</PRE>

여기서, 'H1' 엘레멘트들 안에서 단어 간격('word-spacing')은 '1em' 만큼 증가된다.

CSS1 핵심: 사용도구들은 단어 간격('word-spacing')의 어떤 값을 'normal'로 해석할 수 있다. (항목 7 참조.)

5.4.2    글자 간격('letter-spacing')

값: normal | <길이>
최초값: normal
적용: 모든 엘레멘트들
전달: 전달 됨
백분율 값들: 없슴

이 길이 단위는 글자 간격의 디폴트 공간에 추가하여 글자 간격의 공간을 지정한다. 값은 음수가 될 수 있으나, 적용에 따른 범위가 있을 수 있다. 사용도구는 정확한 간격 띄우기 기능을 선택하는데 방법은 자유이다. 글자 간격은 또한 정렬('align' 속성값)에 의하여 영향 받을 수 있다. <PRE>BLOCKQUOTE { letter-spacing: 0.1em }</PRE>

여기서 'BLOCKQUOTE' 엘레멘트들 안에서 각 글자의 글자 간격('letter-spacing')은 '0.1em' 만큼씩 증가된다.

값 'normal'로, 사용도구들은 글자들의 간격을 적당히 수정할 수 있다. 그러나 만일 글자 간격('letter-spacing')을 <길이> 값으로 명시하면 그렇지 않다. <PRE>BLOCKQUOTE { letter-spacing: 0 }BLOCKQUOTE { letter-spacing: 0cm }</PRE>

결과적인 글자 간격이 디폴트 간격과 같지 않으면 사용도구들은 그 것을 사용하지 말아야 한다.

CSS1 핵심: 사용도구들은 글자 간격('letter-spacing')의 어떤 값을 'normal'로 해석할 수 있다. (항목 7 참조.)

5.4.3    텍스트 장식('text-decoration')

값: none | [ underline || overline || line-through || blink ]
최초값: none
적용: 모든 엘레멘트들
전달: 안됨, 그러나 아래 설명을 보라
백분율 값들: 없슴

이 속성은 엘레멘트의 텍스트에 추가하는 장식(decoration)을 지정한다. 만일 이 엘레멘트가 텍스트를 가지고 있지 않으면(예를 들어 HTML에서 'IMG' 엘레멘트), 또는 이 것이 빈(empty) 엘레멘트(예를 들어 '<EM></EM>')이면, 이 속성은 아무 효과도 없다. 값 'blink'는 텍스트을 깜빡(blink)거리게 한다.

텍스트 장식을 위하여 색상이 필요하면, 'color' 속성값이 되어야 한다.

이 속성은 전달(inherit)되지 않는다. 그러나 엘레멘트들은 그 모체와 일치하여야 한다. 예를 들어, 만일 엘레멘트가 밑줄그어(underlined) 졌으면, 그 줄이 하위(child) 엘레멘트들로 확장되어야 한다. 밑줄의 색상은, 엘레멘트들이 다른 색상('color') 값을 가지고 있더라도 택스트 색상과 같다. <PRE>A:link, A:visited, A:active { text-decoration: underline }</PRE>

위 예제에서 'A' 엘레멘트들로서 'HREF' 애트리뷰트를 가진 모든 연결들 텍스트는 밑줄 쳐진다.

사용도구들은 키워드(keyword) 'blink'를 인식하여 하나, 깜빡이는 효과를 반드시 지원할 필요는 없다.

5.4.4   수직 정렬('vertical-align')

값: baseline | sub | super | top | text-top | middle | bottom | text-bottom | <백분율>
최초값: baseline
적용: 인라인(inline) 엘레멘트들
전달: 안됨
백분율 값들: 그 엘레멘트 자체의 줄높이('line-height') 참조

이 속성은 엘레멘트의 수직 위치에 영향을 준다. 키워드(keyword)가 설정되면 모체 엘레멘트에 상대적이다.

'baseline'
그 모체의 baseline으로 그 엘레멘트의 기초라인(baseline: 또는 그 엘레멘트가 baseline을 갖고 있지 않으면 맨아래( bottom) 정렬(align)한다.
'middle'
그 모체의 기초라인(baseline) 더하기 x-height의 반에 그 엘레멘트의 중심선을 수직으로 정렬한다(image에서 전형적).
'sub'
그 엘레멘트 아래첨자(subscript)
'super'
그 엘레멘트의 위첨자(superscript)
'text-top'
모체 엘레멘트의 글꼴 맨 위(top)에 그 엘레멘트의 맨 위에 정렬한다.
'text-bottom'
모체 엘레멘트의 글꼴 맨 아래(bottom)에 그 엘레멘트의 맨 위에 정렬한다.

다른 일단의 속성들은 그 엘레멘트의 일 부분인 양식화(formatted) 라인에 상대적이다.

'top'
그 줄에서 가장 키 큰(tallest) 엘레멘트를 그 엘레멘트의 맨 위(top)에 정렬한다.
'bottom'
그 줄에서 가장 낮은(lowest) 엘레멘트를 그 엘레멘트의 맨 아래(bottom)에 정렬한다.

'top'과 'bottom' 정렬은 사용하는데 있어서, 엘레멘트에 관련된 루프(loop) 형성하는데서, 해결하지 못하는 상황들이 발생할 수 있다.

백분율 값들은 그 엘레멘트 자체의 줄높이('line-height') 속성값을 참조한다. 이들은 엘레멘트의 기초라인(baseline)을, 그 모체의 기초라인에서부터, 지정한 양(amount) 만큼 끌어 올린다. 기초라인(baseline)이 없으면 바닥(bottom)라인에 적용한다. 음수값이 가능하다. 예를 들어, 값 '-100%'는 그 엘레멘트의 기초라인이 다음 줄의 텍스트가 와야하는 기초라인에서 끝나도록 그 엘레멘트를 낮춘다. 이것은 기초라인을 갖고 있지 않는 엘레멘트들(글자들 위치에서 사용되는 이미지들 등)의 수직 위치에 정밀한 제어를 허용한다.

향후 CSS 버전에서는 이 속성(property)값으로 <길이>가 허용될 것으로 기대된다.

5.4.5    텍스트 변환('text-transform')

값: capitalize | uppercase | lowercase | none
최초값: none
적용: 모든 엘레멘트들
전달: 전달 됨
백분율 값들: 없슴

'capitalize'
각 단어의 첫글자을 대문자(uppercase)로 바꿈
'uppercase'
엘레멘트의 모든 글자들을 대문자(uppercase)로 바꿈
'lowercase'
엘레멘트의 모든 글자들을 소문자(lowercase)로 바꿈
'none'
전달(inherit)된 값을 그 대로

실제적인 대소문자 변환은 인간언어에 따라 다르다. [4] 엘레멘트의 언어 찾기를 참조하라. HTML의 언어정보와 글자방향도 참조하라. <PRE>H1 { text-transform: uppercase }</PRE>

위의 예제에서 'H1' 엘레멘트들에서 텍스트을 대문자로 변환한다.

CSS1 핵심: 영어(Latin-1) 레파토리(repertoire)의 글자들이 아닌 경우와, 엘레멘트들이 언어들에서 그 변환이 Unicode [8]의 대소문자 변환 표(case-conversion table)에 의해 지정된 것과 다른 경우에, 사용도구들은 텍스트 변환('text-transform')을 처리하지 않고 무시할 수 있다.

5.4.6    텍스트 정렬('text-align')

값: left | right | center | justify
최초값:사용도구에 따라 다름
적용: 블럭레벨(block-level) 엘레멘트들
전달: 전달 됨
백분율 값들: 없슴

이 속성은 엘레멘트 안에서 텍스트가 어떻게 정렬(align)할 것인가를 지정한다. 실제적인 적용 기능은 사용도구와 인간언어에 따라 다르다.

예제: <PRE>DIV.center { text-align: center }</PRE>

텍스트 정렬('text-align')이 전달(inherit)되기 때문에, 'CLASS=center'를 갖고 있는 'DIV' 엘레멘트 안에 있는 모든 블럭레벨(block-level) 엘레멘트들 가운데(center) 위치한다. 정렬은 그 화면에 대한 것이 아니고, 그 엘레멘트의 너비(width)에 상대적인 것이다. 만일 'justify'가 지원되지 않으면, 사용도구는 대안을 제공할 것이다. 전형적으로 서구 언어에서 이것은 'left'가 된다.

CSS1 핵심: 그 엘레멘트의 디폴트 쓰는 방향이 왼쪽에서 오른쪽으로(left-to-right)인지 오른쪽에서 왼쪽으로(right-to-left)인지에 따라, 사용도구들은 'justify'를 'left' 또는 'right'로 취급할 수 있다.

5.4.7    텍스트 들여쓰기('text-indent')

값: <길이> | <백분율>
최초값: 0
적용: 블럭레벨(block-level) 엘레멘트들
전달: 전달 됨
백분율 값들: 모체 엘레멘트의 너비(width) 참조

이 속성은 양식화된 줄의 앞에 나타도록 들여쓰기(indent)를 지정한다. 텍스트 들여쓰기('text-indent')의 값은 음수가 될 수 있으나 적용에 따라 한계가 있을 수 있다. 들여쓰기는 HTML의 'BR'와 같은 줄바꿈과 같이 다른 것에 의하여 줄바꿈하는 엘레멘트의 중간에 삽입되는 것은 아니다.

예제: <PRE>P { text-indent: 3em }</PRE>

5.4.8    줄높이('line-height')

값: normal | <수치> | <길이> | <백분율>
최초값: normal
적용: 모든 엘레멘트들
전달: 전달 됨
백분율 값들: 그 엘레멘트 자체의 글꼴 크기(font size)에 상대적이다.

이 속성은 인접한 라인들의 기초라인(baseline)들 간의 거리를 지정한다.

수치 값이 지정되면, 그 줄높이는 현재 엘레멘트의 글꼴 트기(font size) 곱하기 수치 값이 된다. 이는 백분율 값과는 전달(inherit)에서 다르다. 수치 값이 지정되면, 하위(child) 엘레멘트들은, 해당 값이 전달되는 것이 아니고, 그 자체의 배율(factor)이 전달(inherit)된다. 백분율과 다른 단위들을 참조하라.

음수는 허용되지 않는다.

아래 예제에서 이 세가지는 같은 줄높이 결과를 준다. <PRE>DIV { line-height: 1.2; font-size: 10pt } /* 수치 */DIV { line-height: 1.2em; font-size: 10pt } /* 길이 */DIV { line-height: 120%; font-size: 10pt } /* 백분율 */</PRE>

값 'normal'은 줄높이('line-height')를 그 엘레멘트 글꼴의 합리적인 값을 설정한다. 사용도구들은 값 'normal'로 수치 범위 1.0과 1.2사이의 수치 설정을 암시한다.

어떻게 줄높이가 블럭레벨(block-level) 엘레멘트의 양식화에 영향하는가(항목 4.4)를 참조하라.

5.5    박스(box) 속성들

이 박스(box) 속성들은 엘레멘트들을 대표하는 박스들의 크기(size), circumference, 위치(position)를 지정한다. 양식화 모델(항목 4)에서 박스(box) 속성들의 사용 방법의 예를 참조하라.

margin 속성들은 엘레멘트의 마진을 설정한다. 다른 마진 속성들은 그 해당 면(side) 만을 설정하는데 반해, 이 'margin' 속성은 모든 4 면들을 위하여 마진(margin)들을 설정한다.

padding 속성들은 테두리(border)와 내용(content: 예를 들어, text 또는 image)사이에 얼마나 많은 공백을 삽입할 것인가를 지정한다. 다른 padding 속성들은 해당 면(side) 만을 설정하는데 반해, 패딩('padding') 속성은 모든 4 면의 padding들을 설정한다.

border 속성들은 엘레멘트의 테두리(border)들을 설저한다. 각 엘레멘트는 4개의 테두리들를 갖으며, 각 면(side)에 하나씩 갖고, 너비(width), 색상(color), 스타일(style)이 지정된다.

너비('width')와 높이('height') 속성들은 그 박스(box) 크기를 지정하며, 유동('float')과 'clear' 속성들이 엘레멘트들의 위치를 변경시킬 수 있다.

5.5.1    위쪽 마진('margin-top')

값: <길이> | <백분율> | auto
최초값: 0
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 가장 가까운 조상(ancestor) 블럭레벨(block-level)의 너비를 참조한다.

이 속성은 엘레멘트의 위쪽 마진(top margin)을 설정한다. <PRE>H1 { margin-top: 2em }</PRE>

음수가 허용되나 적용에 따라 한계가 있을 수 있다.

5.5.2    오른쪽 마진('margin-right')

값: <길이> | <백분율> | auto
최초값: 0
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 가장 가까운 조상(ancestor) 블럭레벨(block-level)의 너비를 참조한다.

이 속성은 엘레멘트의 오른쪽 마진을 설정한다. <PRE>H1 { margin-right: 12.3% }</PRE>

음수가 허용되나 적용에 따라 한계가 있을 수 있다.

5.5.3    아래쪽 마진('margin-bottom')

값: <길이> | <백분율> | auto
최초값: 0
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 가장 가까운 조상(ancestor) 블럭레벨(block-level)의 너비를 참조한다.

이 속성은 엘레멘트의 아래쪽 마진을 설정한다. <PRE>H1 { margin-bottom: 3px }</PRE>

음수가 허용되나 적용에 따라 한계가 있을 수 있다.

5.5.4    왼쪽 마진('margin-left')

값: <길이> | <백분율> | auto
최초값: 0
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 가장 가까운 조상(ancestor) 블럭레벨(block-level)의 너비를 참조한다.

이 속성은 엘레멘트의 왼쪽 마진을 설정한다. <PRE>H1 { margin-left: 2em }</PRE>

음수가 허용되나 적용에 따라 한계가 있을 수 있다.

5.5.5    마진('margin')

값: [ <길이> | <백분율> | auto ]{1,4}
최초값: 약식속성들에는 정의되지 않음
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 가장 가까운 조상(ancestor) 블럭레벨(block-level)의 너비를 참조한다.

'margin' 속성은 같은 스타일쉬트에서 위쪽 마진('margin-top'), 오른쪽 마진('margin-right'), 아래쪽 마진('margin-bottom'), 왼쪽 마진('margin-left')를 설정하는 약식속성이다.

만일 4 길이의 값들이 지정되면, 각 값은 top, right, bottom, left에 각각 적용된다. 하나의 값 만 지정되면 모든 면(side)들에 적용되고, 두 값이나 세 값들이 지정되면, 지정되지 않은 값은 반대편 면에서 택한다. <PRE>BODY { margin: 2em } /* 모든 마진(margin)들을 2em로 */BODY { margin: 1em 2em } /* top & bottom=1em, right & left = 2em */BODY { margin: 1em 2em 3em } /* top=1em, right=2em, bottom=3em, left=2em */</PRE>

위의 마지막 예제는 아래 예제와 같다. <PRE>BODY { margin-top: 1em; margin-right: 2em; margin-bottom: 3em; margin-left: 2em; /* 반대편(right) 면에서 복사 */}</PRE>

음수가 허용되나 적용에 따라 한계가 있을 수 있다.

5.5.6    위쪽 패딩('padding-top')

값: <길이> | <백분율>
최초값: 0
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 가장 가까운 조상(ancestor) 블럭레벨(block-level)의 너비를 참조한다.

이 속성은 엘레멘트의 위쪽 패딩을 설정한다. <PRE>BLOCKQUOTE { padding-top: 0.3em }</PRE>

Padding 값들은 음수가 될 수 없다.

5.5.7    오른쪽 패딩('padding-right')

값: <길이> | <백분율>
최초값: 0
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 가장 가까운 조상(ancestor) 블럭레벨(block-level)의 너비를 참조한다.

이 속성은 엘레멘트의 오른쪽 패딩을 설정한다. <PRE>BLOCKQUOTE { padding-right: 10px }</PRE>

Padding의 음수값은 허용되지 않는다.

5.5.8    아래쪽 패딩('padding-bottom')

값: <길이> | <백분율>
최초값: 0
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 가장 가까운 조상(ancestor) 블럭레벨(block-level)의 너비를 참조한다.

이 속성은 엘레멘트의 아래쪽 패딩을 설정한다. <PRE>BLOCKQUOTE { padding-bottom: 2em }</PRE>

Padding 음수값은 허용되지 않는다.

5.5.9    왼쪽 패딩('padding-left')

값: <길이> | <백분율>
최초값: 0
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 가장 가까운 조상(ancestor) 블럭레벨(block-level)의 너비를 참조한다.

이 속성은 엘레멘트의 왼쪽 패딩을 설정한다. <PRE>BLOCKQUOTE { padding-left: 20% }</PRE>

Padding은 음수값은 허용되지 않는다.

5.5.10    패딩('padding')

값: [ <길이> | <백분율> ]{1,4}
최초값: 약식속성들에서는 허용되지 않음
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 가장 가까운 조상(ancestor) 블럭레벨(block-level)의 너비를 참조한다.

패딩('padding') 속성은 한 스타일쉬트에서 위쪽 패딩('padding-top'), 오른쪽 패딩('padding-right'), 아래쪽 패딩('padding-bottom'), 왼쪽 패딩('padding-left')을 지정하는 약식속성이다.

만일 4 길이의 값들이 지정되면, 각 값은 top, right, bottom, left에 각각 적용된다. 하나의 값 만 지정되면 모든 면(side)들에 적용되고, 두 값이나 세 값들이 지정되면, 지정되지 않은 값은 반대편 면에서 택한다.

padding 지역의 표면은 배경('background') 속성(property)으로 지정한다. <PRE>H1 { background: white; padding: 1em 2em; }</PRE>

위 예제에서 '1em'이 수직 padding(위쪽 패딩('padding-top'), 아래쪽 패딩('padding-bottom'))에, '2em'이 수평(오른쪽 패딩('padding-right'), 왼쪽 패딩('padding-left'))에 설정된다. 'em' 단위는 엘레멘트의 글꼴 크기(font size)에 상대적이며 '1em'은 사용하고 있는 글꼴 크기와 같다.

Padding 음수값은 허용되지 않는다.

5.5.11    위쪽 테두리 두께('border-top-width')

값: thin | medium | thick | <길이>
최초값: 'medium'
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

이 속성은 엘레멘트 너비의 위쪽 테두리(border)를 설정한다. 너비의 키워드(keyword) 값들은 사용도구에 따라 다르나, 'thin' <= 'medium' <= 'thick' 공식이 성립된다.

이 키워드(keyword) 너비들는 한 문서 전체에 고정되어 적용된다. <PRE>H1 { border: solid thick red }P { border: solid thick blue }</PRE>

위의 예제에서, 'H1'과 'P' 엘레멘트들은 글꼴 크기에 관계없이 같은 테두리를 가질 것이다. 상대 너비들을 얻기 위해, 'em' 단위를 사용할 수 있다. <PRE>H1 { border: solid 0.5em }</PRE>

Border의 너비(width)들은 음수가 될 수 없다.

5.5.12    오른쪽 테두리 두께('border-right-width')

값: thin | medium | thick | <길이>
최초값: 'medium'
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

이 속성은 엘레멘트의 오른쪽 테두리의 두께를 지정한다. 지정하지 않으면 이는 위쪽 테두리 두께('border-top-width')와 같다.

5.5.13    아래쪽 테두리 두께('border-bottom-width')

값: thin | medium | thick | <길이>
최초값: 'medium'
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

이 속성은 엘레멘트의 아래쪽 테두리의 두께를 지정한다. 지정하지 않으면 이는 위쪽 테두리 두께('border-top-width')와 같다.

5.5.14    왼쪽 테두리 두께('border-left-width')

값: thin | medium | thick | <길이>
최초값: 'medium'
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

이 속성은 엘레멘트의 왼쪽 테두리의 두께를 지정한다. 지정하지 않으면 이는 위쪽 테두리 두께('border-top-width')와 같다.

5.5.15    테두리 두께('border-width')

값: [thin | medium | thick | <길이>]{1,4}
최초값: 약식속성들에는 정의되지 않음
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

이 속성은 한 스타일쉬트에서 'border-width-top', 'border-width-right', 'border-width-bottom', 'border-width-left'를 지정하는 약식속성이다.

값이 1 개 부터 4 개가 될 수 있으며 다음과 같이 적용된다.

  • 하나의 값: 모든 4 개의 테두리(border)의 너비들이 이 값이 된다.
  • 두개의 값: top, bottom 테두리(border)의 너비들이 첫번째 값이되고, right, left가 두번째 값이 된다.
  • 세개의 값: top은 첫번째 값이, right, left는 두번째 값이, bottom은 세번째 값이 된다.
  • 네개의 값: 각각 top, right, bottom, left를 지정한다.

아래 예제에서, 코멘트(Comment)는 결과적인 top, right, bottom, left 테두리들 각각의 두께를 나타낸다. <PRE>H1 { border-width: thin } /* thin thin thin thin */H1 { border-width: thin thick } /* thin thick thin thick */H1 { border-width: thin thick medium } /* thin thick medium thin */H1 { border-width: thin thick medium thin } /* thin thick medium thin */</PRE>

Border의 너비(width)들은 음수가 될 수 없다.

5.5.16    테두리 색상('border-color')

값: <color>{1,4}
최초값: 'color' 속성(property)값
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

테두리 색상('border-color') 속성은 4 개의 테두리(border) 색상을 설정한다. 테두리 색상('border-color')은 1 개 부터 4 개사이의 값들을 가질수 있고, 그 값들은 위의 테두리 두께('border-width')에서와 같이 다른 면(side)들의 값들을 설정한다.

색상이 지정되지 않으면, 그 엘레멘트 지체의 색상('color') 속성값이 적용된다. <PRE>P { color: black; background: white; border: solid;}</PRE>

위 예제에서, 테두리(border)는 굵은 검정 줄이 된다.

5.5.17    테두리 스타일('border-style')

값: none | dotted | dashed | solid | double | groove | ridge | inset | outset
최초값: none
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

테두리 스타일('border-style') 속성은 4 개의 테두리 스타일(border style)들를 설정한다. 값은 1 개 부터 4 개사이의 값들을 가질수 있고, 그 값들은 위의 테두리 두께('border-width')에서와 같이 다른 면(side)들의 값들을 설정한다. <PRE>#xy34 { border-style: solid dotted }</PRE>

위 예제에서, 수평 테두리들은 'solid', 수직 테두리들은 점선('dotted')이 된다.

테두리 스타일의 최초값이 'none'이므로, 테두리 스타일이 설정되지 않으면 테두리가 보이지 않을 것이다.

테두리 스타일들은 다음의 의미를 갖는다.

none
테두리 두께('border-width') 값에 관계 없이 테두리가 보이지 않는다.
dotted
테두리는 점선(dotted line)으로 그 엘레멘트의 배경 맨 위(top)에 그려진다.
dashed
테두리는 사선(dashed line)으로 그 엘레멘트의 배경 맨 위(top)에 그려진다.
solid
테두리는 연속(solid line)
double
테두리는 이중선(double line)으로 그 엘레멘트의 배경 맨 위(top)에 그려진다. 두개의 단일 선들의 합과 그사이의 공간은 <border-width>의 값과 같다.
groove
<color> 값에 기초한 색상으로 3D groove가 그려진다.
ridge
<color> 값에 기초한 색상으로 3D ridge가 그려진다.
inset
<color> 값에 기초한 색상으로 3D inset가 그려진다.
outset
<color> 값에 기초한 색상으로 3D outset가 그려진다.

CSS1 핵심: 사용도구들은 'dotted', 'dashed', 'double', 'groove', 'ridge', 'inset', 'outset' 모두를 'solid'로 해석할 수 있다.

5.5.18    위쪽 테두리('border-top')

값: <border-top-width> || <border-style> || <color>
최초값: 약식속성들에는 정의되지 않음
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

엘레멘트의 위쪽 테두리(top border)의 width, style, color을 설정하는 약식속성이다. <PRE>H1 { border-bottom: thick solid red }</PRE>

위의 예제는 H1 엘레멘트 아래 테두리의 width, style, color를 설정한다. 생략된 값들은 그들의 최초값들로 설정된다. <PRE>H1 { border-bottom: thick solid }</PRE>

위의 예제에서 색상 값이 생략되었으므로, 그 border color은 그 엘레멘트 자체의 색상('color') 값과 같다.

테두리 스타일('border-style') 속성은 4 개까지의 값들을 받을 수 있는데 반해, 이 속성은 하나의 값 만을 받을 수 있슴을 저시하라.

5.5.19    오른쪽 테두리('border-right')

값: <border-right-width> || <border-style> || <color>
최초값: 약식속성들에는 정의되지 않음
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

엘레멘트의 오른쪽 테두리(righ border)의 width, style, color을 설정하는 약식속성이다. 지정하지 않으면 위쪽 테두리('border-top')와 같다.

5.5.20    아래쪽 테두리('border-bottom')

값: <border-bottom-width> || <border-style> || <color>
최초값: 약식속성들에는 정의되지 않음
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

엘레멘트의 아래쪽 테두리(bottom border)의 width, style, color을 설정하는 약식속성이다. 지정하지 않으면 위쪽 테두리('border-top')와 같다.

5.5.21    왼쪽 테두리('border-left')

값: <border-left-width> || <border-style> || <color>
최초값: 약식속성들에는 정의되지 않음
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

엘레멘트의 왼쪽 테두리(left border)의 width, style, color을 설정하는 약식속성이다. 지정하지 않으면 위쪽 테두리('border-top')와 같다.

5.5.22    테두리('border')

값: <border-width> || <border-style> || <color>
최초값: 약식속성들에는 정의되지 않음
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

테두리('border') 속성은 엘레멘트 모든 4 개의 테두리의 같은 width, color, style를 설정하기 위한 단축 속성이다. 예를 들어, 첫번째 명령(rule)은 그 다음 4 개에서 각각 설정한 것과 같다. <PRE>P { border: solid red }P { border-top: solid red; border-right: solid red; border-bottom: solid red; border-left: solid red}</PRE>

마진('margin'), 패딩('padding') 약식속성들과는 달리, 테두리('border') 속성은 4 개의 테두리를 다른 값들로 설정할 수 없다. 이를 위해 하나이상의 다른 border 속성들을 사용하여야 한다.

이속성들이 기능적으로 일부 중복을 하므로 이들을 지정하는 순서가 중요하게 된다. 예제를 보면: <PRE>BLOCKQUOTE { border-color: red; border-left: double color: black;}</PRE>

위 예제에서, 왼쪽 테두리의 색상은 검정(black)이 될 것이고, 다른 테두리들은 적색(red)이 된다. 이는 왼쪽 테두리('border-left')에 width, style, color가 설정 되었기 때문이다. 왼쪽 테두리('border-left') 속성(property)에 색상이 설정되지 않았으므로, 이는 'color' 속성(property)에서 값을 받을 것이다. 실제로 'color' 속성이 나중에 설정 되었으므로, 왼쪽 테두리('border-left') 속성이 적용되지 않는다.

테두리 두께('border-width') 속성은 4 개 길이의 값들을 지정할 수 있지만, 이 속성은 하나 만 받을 수 있슴을 주시하라.

5.5.23    너비('width')

값: <길이> | <백분율> | auto
최초값: auto
적용: 블럭레벨(block-level)과 대체된(replaced) 엘레멘트들
전달: 안됨
백분율 값들: 모체 엘레멘트의 너비(width) 참조

이 속성은 text 엘레멘트들에 적용될 수 있으나, 이미지(image)들과 같은 대체된(replaced) 엘레멘트들에 가장 유용하게 사용된다. 너비(width)는 필요할 때, 배율(scale)을 조절하여 보완할 수 있다. 배율을 조절할 때, 이미지의 변경 비율(ratio)은 높이('height') 속성이 'auto'이면 그대로 유지된다.

예제: <PRE>IMG.icon { width: 100px }</PRE>

만일 대체된(replaced) 엘레멘트 너비('width')와 높이('height')가 둘 다 'auto'이면, 이들 속성들 그 엘레멘트의 규격을 그 대로 설정한다.

음수는 허용되지 않는다.

이 속성과 마진(margin), 패딩(padding)의 관계를 위하여 양식화 모델(항목 4)을 참조하라.

5.5.24    높이('height')

값: <길이> | auto
최초값: auto
적용: 블럭레벨(block-level)과 대체된(replaced) 엘레멘트들
전달: 안됨
백분율 값들: 없슴

이 속성은 text 엘레멘트들에 적용될 수 있으나, 이미지(image)들과 같은 대체된(replaced) 엘레멘트들에 가장 유용하게 사용된다. 높이(height)는 필요할 때, 배율(scale)을 조절하여 보완할 수 있다. 배율을 조절할 때, 이미지의 변경 비율(ratio)은 너비('width') 속성이 'auto'이면 그대로 유지된다.

예제: <PRE>IMG.icon { height: 100px }</PRE>

만일 대체된(replaced) 엘레멘트 너비('width')와 높이('height')가 둘 다 'auto'이면, 이들 속성들 그 엘레멘트의 규격을 그 대로 설정한다.

텍스트 엘레멘트에 적용되면, 높이(height)는 예를 들어 화면 굴리기(scrollbar)등으로 보완될 수 있다.

음수는 허용되지 않는다.

CSS1 핵심: 사용도구들은, 그 엘레멘트가 대체된(replaced) 엘레멘트가 아니면, 높이('height') 속성을 무시('auto' 처리)할 수도 있다.

5.5.25    유동('float')

값: left | right | none
최초값: none
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

값 'none'로, 그 엘레멘트는 그 텍스트(text) 안에서 나타 날 곳에 표현(display)된다. 값 'left' ('right')로 그 엘레멘트는 left (right)으로 이동하여, 그 텍스트(text)는 그 엘레멘트의 right (left) 면(side)에 줄바꿈(wrap)한다. 값 'left' 또는 'right'로, 그 엘레멘트는 블럭레벨(block-level)로 처리된다('display' 속성이 무시된다). 항목 4.1.4의 설명을 참조하라. <PRE>IMG.icon { float: left; margin-left: 0; }</PRE>

위 예제는 'CLASS=icon'를 갖는 모든 IMG 엘레멘트들은 그 모체 엘레멘트의 왼쪽(left )을 따라 위치시킨다.

이 속성은 인라인(inline) 이미지들에서 가장 자주 사용되나, 텍스트(text) 엘레멘트들에도 적용된다.

5.5.26    'clear'

값: none | left | right | both
최초값: none
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

이 속성은 엘레멘트를 유동(floating) 엘레멘트들의 옆면(side)들에 허용할 것인가를 지정한다. 더 구체적으로, 이 속성값은 유동(floating) 엘레멘트들이 허용되지 않는 면(side)들의 목록(list)이다. 'clear'가 'left'를 설정하면, 엘레멘트는 어떤 유동(floating) 엘레멘트 밑의 왼쪽으로 이동한다. 'clear'가 'none'으로 설정되면, 유동(floating) 엘레멘트들은 모든 면(side)들에 허용된다. 예제를 보면: <PRE>H1 { clear: left }</PRE>

5.6    속성들의 분류

이들 속성들은 엘레멘트들을 특정 보이는 파라메터(parameter)들를 설정하는 것에 추가하여 카테고리들(categories)로 분류한다.

이 목록 스타일(list-style) 속성들은 어떻게 목록 항목들(목록 항목('list-item')의 'display' 값을 갖는 엘레멘트들)을 기술하는가를 양식화한다. 이 목록 스타일(list-style) 속성들은 어떤 엘레멘트에도 설정될 수 있고, 이는 일반적으로 계통도(tree) 하부로 전달(inherit)된다. 그러나, 이들은 목록 항목('list-item')의 값이 'display' 일 때 만 엘레멘트들에 효과를 줄 것이다. HTML에서 이는 전형적으로 'LI' 엘레멘트의 경우이다.

5.6.1    'display'

값: block | inline | list-item | none
최초값: block
적용: 모든 엘레멘트들
전달: 안됨
백분율 값들: 없슴

이 속성은 엘레멘트가 화면에 표현(display)될 것인가, 그렇다면 어떻게 디스플레이될 것인가를 기술한다. 이는 인쇄에서나 컴퓨터 화면등이 될 수 있다.

엘레멘트가 'display' 값 'block'을 가지면 새로운 박스(box)를 연다. 그 박스는 CSS 양식화 모델에 따라 인접 박스들에 상대적으로 위치한다. 전형적으로, 'H1'와 'P'와 같은 엘레멘트들은 블럭('block') 타입니다. 값 목록 항목('list-item')은 목록(list-item) 메이커(marker)가 추가된다는 것 이외에는 블럭('block')과 유사하다. HTML에서, 'LI'는 전형적으로 이 값을 갖는다.

엘레멘트의 'display' 값 'inline'은 이전의 내용(content)이 있는 것과 같은 줄에 새로운 인라인(inline) 박스(box)를 생성한다. 이 박스(box)는 양식화(formatted)된 내용의 크기에 따라 크기(dimension)가 결정된다. 만일 내용이 텍스트이면, 이는 여러 줄들에 확장(span)할 수 있으며, 또한 그들은 각 줄에 하나의 박스가 있는 것이다. 마진(margin), 테두리(border), 패딩(padding) 속성들은 '인라인(inline)' 엘레멘트들에 적용되나, 줄바꿈들에서는 아무 효과도 없다.

값 'none'은 엘레멘트의 하위(child) 엘레멘트들과 주위 박스(box)을 포함하여 디스플레이를 중지시킨다. <PRE>P { display: block }EM { display: inline }LI { display: list-item }IMG { display:none }</PRE>

마지막 명령(rule)은 이미지들의 디스플레이를 중지시킨다.

'display'의 최초값은 'block'이지만, 사용도구는 모든 HTML 엘레멘트들을 위하여, HTML 규격에서 엘레멘트들의 표현을 위하여 제시된 바에 따라, 전형적인 디폴트 값들 가진다.

CSS1 핵심: 사용도구들은 'display'를 무시하고, 사용도구의 디폴트(default) 값들 만을 사용할 수 있다.(항목 7를 참조하라.)

5.6.2    공백('white-space')

값: normal | pre | nowrap
최초값: normal
적용: 블럭레벨(block-level) 엘레멘트들
전달: 전달 됨
백분율 값들: 없슴

이 속성은 엘레멘트 안에서 어떻게 공간(whitespace)을 처리할 것인가를 기술한다. 방법은 'normal' (공간이 붕괴 됨), 'pre' (HTML의 'PRE' 엘레멘트처럼 작용) 또는 'nowrap'(BR 엘레멘트들가 있을 때만 줄바꿈 함)이 있다. <PRE>PRE { white-space: pre }P { white-space: normal }</PRE>

공백('white-space')의 최초값이 'normal'이지만, 사용도구는 모든 HTML 엘레멘트들을 위하여, HTML 규격에서 엘레멘트들의 표현을 위하여 제시된 바에 따라, 전형적인 디폴트 값들을 갖는다.

CSS1 핵심: 사용도구들은 제작자와 리더의 스타일쉬트에서 공백('white-space') 속성 무시하고, 사용도구의 디폴트(default) 값들 만을 사용할 수 있다.(항목 7를 참조하라.)

5.6.3    목록 스타일 타입('list-style-type')

값: disc | circle | square | decimal | lower-roman | upper-roman | lower-alpha | upper-alpha | none
최초값: disc
적용: 목록('list-item') 값 'display'를 갖는 엘레멘트들
전달: 전달 됨
백분율 값들: 없슴

이 속성은 목록(list-item) 메이커(marker)의 모양을 결정하는데, 목록 스타일 이미지('list-style-image')가 'none'이거나, URL에 의하여 지정되는 이미지가 표현될 수 없를 때 사용된다. <PRE>OL { list-style-type: decimal } /* 1 2 3 4 5 ... */OL { list-style-type: lower-alpha } /* a b c d e ... */OL { list-style-type: lower-roman } /* i ii iii iv v ... */</PRE>

5.6.4    목록 스타일 이미지('list-style-image')

값: <url> | none
최초값: none
적용: 목록('list-item') 값 'display'를 갖는 엘레멘트들
전달: 전달 됨
백분율 값들: 없슴

이 속성은 목록(list-item) 메이커(marker)에 사용될 이미지를 설정한다. 이미지가 유효하면 이 이미지는 목록 스타일 타입('list-style-type') 메이커(marker)가 설정한 것을 대체한다. <PRE>UL { list-style-image: url(http://png.com/ellipse.png) }</PRE>

5.6.5    목록 스타일 위치('list-style-position')

값: inside | outside
최초값: outside
적용: 목록('list-item') 값 'display'를 갖는 엘레멘트들
전달: 전달 됨
백분율 값들: 없슴

목록 스타일 위치('list-style-position') 값은 목록(list-item) 메이커(marker)가 내용에 대하여 어떻게 그려 지는가를 결정한다. 양식화(formatting) 예제는 목록 엘레멘트(항목 4.1.3)를 참조하라.

5.6.6    목록 스타일('list-style')

값: [disc | circle | square | decimal | lower-roman | upper-roman | lower-alpha | upper-alpha | none] || [inside | outside] || [<url> | none]
최초값: 약식속성들에는 정의되지 않음
적용: 목록('list-item') 값 'display'를 갖는 엘레멘트들
전달: 전달 됨
백분율 값들: 없슴

목록 스타일('list-style') 속성은 목록 스타일 타입('list-style-type'), 목록 스타일 이미지('list-style-image'), 목록 스타일 위치('list-style-position') 세가지 속성을 한 스타일쉬트에서 지정하는약식속성이다. <PRE>UL { list-style: upper-roman inside }UL UL { list-style: circle outside }LI.square { list-style: square }</PRE>

'LI' 엘레멘트들에 직접 목록 스타일('list-style')를 설정하는 것은 기대하지 않은 결과를 초래할 수 있다. 예제를 보라: <PRE><STYLE TYPE="text/css"> OL.alpha LI { list-style: lower-alpha } UL LI { list-style: disc }</STYLE><BODY> <OL class=alpha> <LI>수준 1 <UL> <LI>수준 2 </UL> </OL></BODY></PRE>

위의 예제에서 스타일쉬트 안의 첫번째 명령(rule)이 높은 우선순위(카스케이딩 순서에 정의된 것과 같이)를 갖기 때문에, 이는 모든 'LI' 엘레멘트들의 두번째 명령(rule)을 덮어씌울(override) 것이며, 'lower-alpha' 목록 스타일 만이 사용될 것니다. 따라서 목록 스타일('list-style')는 목록 타입(list type) 엘레멘트들에 만 지정할 것을 추천한다. <PRE>OL.alpha { list-style: lower-alpha }UL { list-style: disc }</PRE>

위 예제에서, 목록 스타일('list-style') 값들은 'OL' 과 'UL' 엘레멘트들로 부터 'LI' 엘레멘트들로 전달된다.

URL 값은 다른 어떤 값의 조합될 수 있다. <PRE>UL { list-style: url(http://png.com/ellipse.png) disc }</PRE>

위의 예제에서, 이미지가 우효하지 않으면 'disc'가 사용된다.

6    단위들(Units)

6.1    길이 단위

길이 값의 양식은 선택적 부호('+' 또는 '-', 디폴트는 '+')와 그 뒤 바로 따라오는 수치(소수점이 있거나 없거나) 그리고 그 바로 뒤에 두 글자로 간단히 된 단위 인식자(identifier)로 된다. 수치 0 뒤의 단위 지정자는 선택적이다.

일부 속성들은 음수의 길이 단위들을 허용하나, 이는 양식화 모델을 복잡하게 하고 적용에 따라 한계가 있을 수 있다. 만일 음수 길이 값이 지원되지 않으면, 지원되는 값 중에서 가장 가까운 값으로 대체된다.

길이의 단위들에는 상대적(relative)인 것과 절대적(absolute)인 것 두가지가 있다. 상대적인 단위들은 다른 길이 속성(property)에 상대적으로 나타낸다. 상대적인 단위들을 사용하는 스타일쉬트들은 한 메디아에서 다른 메디아로(예를 들어 컴퓨터 화면에서 레이저 프린터로) 스테일(scale)하는 것이 보다 용이하다. 아래 설명하는 백분율 단위(percentage unit)들과 키워드(keyword) 값(예를 들어 'x-large')들은 이와 비슷한 잇점들이 있다.

아래와 같은 상대(relative) 단위들이 지원된다. <PRE>H1 { margin: 0.5em } /* em, 엘레멘트의 글꼴(font) 높이 */H1 { margin: 1ex } /* x-height, 글자 'x'의 높이 */P { font-size: 12px } /* pixels, 화면에 상대적으로 */</PRE>

상대적인 단위 'em'과 'ex'는 그 엘레멘트 자체의 글꼴 크기(font size)에 상대적이다. CSS1에서 한가지 예외는 글꼴 크기('font-size') 속성인데, 여기서는 'em'과 'ex' 값은 모체 엘레멘트의 글꼴 크기(font size)를 참조한다.

예제의 마지막 줄에서 사용된 픽셀(pixel) 단위는, 그 화면의 해상도(resolution), 말하자면 대부분의 경우 컴퓨터 디스플레이에 상대적이다. 만일 출력 장티의 픽셀(pixel) 밀도(density)가 일반적인 컴퓨터 디스플레이에서와 다르면, 사용도구는 픽셀(pixel) 값들을 재 스케일(rescale)하여야 한다. 암시된 참조 픽셀(pixel)은 픽셀 밀도 90dpi(dots per inch) 장치에서 리더가 한 팔 거리에서 한개의 픽셀의 볼 수 있는 시각의 각도이다. 일반적인 한 팔 거리는 28인치이고 보는 각도는 약 0.0227도이다.

하위(Child) 엘레멘트들에는 상대값이 아닌 계산된 값이 전달(inherit)된다. <PRE>BODY { font-size: 12pt; text-indent: 3em; /* 말하자면 36pt */ }H1 { font-size: 15pt }</PRE>

위의 예제에서, 'H1' 엘레멘트들의 텍스트 들여쓰기('text-indent') 값은 45pt가 아니라 36pt이다.

절대(Absolute) 길이 단위들은 출력 장치의 물리적 속성들이 알려졌을 때에 만 유용하다. 이들 절대(absolute) 단위들은 아래와 같이 지원된다. <PRE>H1 { margin: 0.5in } /* 인치(inche), 1in = 2.54cm */H2 { line-height: 3cm } /* cm, centimeter */H3 { word-spacing: 4mm } /* mm, millimeters */H4 { font-size: 12pt } /* 포인트(point), 1pt = 1/72 in */H4 { font-size: 1pc } /* 피카(pica), 1pc = 12pt */</PRE>

특정 길이가 지원되지 않으면, 사용도구들은 대략적으로 시도하여야 한다. 모든 CSS1 속성들에서, 추가적인 계산과 전달은 이 대략적인 값을 기준으로 하여야 한다.

6.2    백분율 단위(percentage unit)들

백분율 값의 양식은 선택적 기호('+' 또는 '-', 디폴트는 '+')와 그 뒤에 바로 따라오는 수치(소수점 있거나 없거나) 그리고 바로 뒤에 '%'로 된다.

백분율 값들은 항상, 예를 들어 길이 단위등, 다른 값에 대해 상대적이다. 백분율 단위(percentage unit)들이 허용되는 각 속성은 그 백분율 값이 무엇을 참조하는가가 정의되어 있다. 그 엘레멘트 자체의 글꼴 크기(font size)를 참조하는 경우가 가장 많다. <PRE>P { line-height: 120% } /* 엘레멘트의 글꼴 크기('font-size')의 120% */</PRE>

모든 전달(inherit)된 CSS1 속성들이 백분율 값을 가지면, 하위(Child) 엘레멘트들에는 그 백분율 값이 아닌 계산된 값이 전달(inherit)된다.

6.3    색상 단위(color unit)들

색상(color)은 키워드(keyword) 또는 수치적 RGB 규격이다.

암시된 색상 이름들의 키워드(keyword) 목록은 aqua, black, blue, fuchsia, gray, green, lime, maroon, navy, olive, purple, red, silver, teal, white, yellow등이다. 이들 16 색상(color)들은 윈도우즈(Windows) VGA palette로부터 온 것이고, 그 들 RGB 값들은 이 규격에 정의되어 있지 않다. <PRE>BODY {color: black; background: white }H1 { color: maroon }H2 { color: olive }</PRE>

RGB 색상 모델은 수치 색상 규격으로 사용된다. 아래 예제에서 모두 같은 색상을 나타낸다. <PRE>EM { color: #f00 } /* #rgb */EM { color: #ff0000 } /* #rrggbb */EM { color: rgb(255,0,0) } /* 정수 범위: 0 - 255 */EM { color: rgb(100%, 0%, 0%) } /* 유동(float) 범위: 0.0% - 100.0% */</PRE>

RGB 값의 양식은 '#'로 시작하는 16 진수(hexadecimal) 표현이다. '#' 다음에 바로 3 자 혹은 6 자 16진수 글자(0,1,2,3...,a,b,c,d,e,f)들이 나온다. 3 자 RGB 표현(#rgb)은 각 글자를 복사하여(0을 더하는 것이 아니고) 6 자 (#rrggbb) 양식을 만든다. 예를 들어, #fb0는 #ffbb00로 된다. 이 것으로 흰색(#ffffff)을 약식(#fff)으로, 색상 깊이 등 부속 변화를 생략하고, 확실히 표현할 수 있다.

RGB 값은 기능적 표현 양식으로 기술할 수 있는데, 'rgb(' 다음에 컴마(,)로 분리한 세가지 색상 값을 목록화 하고 ')'로 닫는다. 여기서 세가지 색상의 각 색상 값은 정수 0-255 범위의 수치, 또는 0.0%에서 100.0%까지 범위의 세개의 백분율 값들이 된다. 수치 앞과 뒤에 공백(whitespace)이 허용된다.

수치 범위 밖의 수치 값들은 잘려진다. 아래 예제에서 세가지는 모두 같다. <PRE>EM { color: rgb(255,0,0) } /* 정수 범위: 0 - 255 */EM { color: rgb(300,0,0) } /* 255로 잘림 */EM { color: rgb(110%, 0%, 0%) } /* 100%로 잘림 */</PRE>

RGB 색상(color)들은 [9] sRGB color space에 정의되어 있다. 사용도구들은 색상들을 표현하는 주파수(fidelity)가 서로 다를 수 있으나, sRGB 사용은 모호하지 않고, 어떤 색상이 되어야 한다는 것이 확실히 양적으로 국제적인 규격들[10]에 정의되어 있다.

사용도구들은 색상들을 디스플레이 하는데 색상 보정(gamma-correction) 수행을 위한 그들의 노력을 생략할 수 있다. sRGB는 지정된 보이는 상황에서 디스플레이 감마(gamma)를 2.2로 정의하고 있다. 사용도구들은 CSS에서 주어진 색상들을 출력 장치의 자연("natural") 디스플레이 감마(gamma)와 조합하여, 실효 디스플레이 감마(gamma)가 2.2가 되도록 보정(부록 D)한다. CSS에서 정의한 색상들 에서 만 영향을 받는다는 점을 주시하라. 예를 들어 이미지들은 그들 자신의 색상 정보를 표현할 것으로 기대된다.

6.4    URL

URL(Uniform Resource Locator:공통 자원 지정자)는 기능적 표현으로 지정한다. <PRE>BODY { background: url(http://www.bg.com/pinkish.gif) }</PRE>

URL 값은 'url('로 시작하고 바로 뒤에 선택적 공백, 그 다음 선택적 단일 따옴(') 또는 이중 따옴("), 그 다음에 ([11] URL 자체에서 정의된 것과 같이)가 나온다. 그리고 다시 선택적 단일 따옴(') 또는 이중 따옴("), 그 다음 선택적 공백, 그리고 ')'로 닫는다. 따옴표는 URL 자체의 부분은 아니며 반드시 짝을 맞춰야 한다.

URL 안의 괄호, 컴마, 공백, 단일 따옴('), 이중 따옴(")들은 역슬래쉬(\)를 사용하여 '\(', '\)', '\,' 등으로 에스케이프(escape)되어야 한다.

부분적 URL들은, 그 문서에 상대적이 아니라, 스타일쉬트 자원(source)에 상대적으로 해석된다. <PRE>BODY { background: url(yellow) }</PRE>HTML의 URI 설명을 참조하라.

7    CSS1에 부합

문서들을 표현하는 CSS1를 사용하는 사용도구는 다음 경우 CSS1 규격에 부합한다.

  • 이 규격에 따라 모든 참조 스타일쉬트를 가져오도록 시도하고 해석(parse)하도록 시도한다.
  • 카스케이딩 순서에 따라 선언들을 정렬(sort)한다.
  • 표현 도구의 능력 범위 안에서 CSS1 기능을 적용한다.(아래 설명 참고)

CSS1 스타일쉬트 출력 사용도구가 CSS1 규격에 부합하려면

  • 유효한 CSS1 스타일쉬트 출력

문서들을 디스플레이 하는데 CSS1를 사용하는, 그리고, CSS1 스타일쉬트를 출력(output)하는, 두가지 부합 필요 조건을 충족시키는 사용도구는 CSS1 규격에 부합하는 것이다.

사용도구는 CSS1의 모든 기능들을 적용해야 하는 것은 아니다. 핵심 기능들을 적용하면 CSS1에 부합하는 것이 될 수 있다. 제외된 부분이라는 명시된 것을 제외하고, 핵심(core) 기능(functionality)이 CSS1 규격의 전체를 구성한다. 이 규격에서는 "CSS1 핵심:"이라고 표시하고, 그 뒤에 어떤 기능이 핵심 기능 밖에 있는가의 설명이 따른다. 핵심 기능 밖의 것들을 CSS1 발전된 기능이라 한다.

이 항목에서는 단지 CSS1 부합성을 정의한다. 향 후 CSS 수준에서 부합하기 위하여 사용도구는 다른 기능들의 수행이 필요하게 된다.

메디아의 표현에서 제한적인 예제들은, 제한된 자원들(fonts, color)과 제한된 해상도(resolution), 따라서 테두리(margin)들이 정확하지 않은 것 등이다. 이런 경우 사용도구는 스타일쉬트 값들의 대략을 사용하여야 한다. 또한, 다른 사용자 인터페이스(interface) 기준에서 그 들 자신의 제한을 가질 수 있는데 예를 들어 비디오(VR) 브라우저에서 사용자와의 "거리"에 따라 스케일을 다시(rescale)할 수 있다.

사용도구들은 리더(for reader)에게 표현의 추가적인 선택을 제공할 수 있다. 예를 들어, 사용도구가 리더에게 시각 장애자 선택 또는 깜빡거림(blink) 중지 선택을 줄 수 있다.

CSS1은 양식화의 모든 견지들을 정의하지 않는다는 점을 주시하라. 예를 들어, 사용도구는 글자 간격(letter-spacing)이 기능 방법(algorithm) 선택은 자유이다.

이 규격은 사용도구에, 요구하지 않으나, 추천하는 것들이 있다.

  • 리더(reader)에게 개인적인 스타일쉬트를 지정할 수 있게 허용
  • 개별 스타일쉬트를 켜고, 끌 수 있게 허용

위의 부합성 설명은. 사용자에게 표현(user interface)되는 것이 아니고. 그 기능적 면 만을 설명한 것이다.

7.1    향 후 버전에 부합한 처리(parsing)

이 규격은 CSS 수준(level) 1을 정의한다. 추가적인 기능들를 갖는 CSS의 높은 수준이 기대되며 이는 향후 정의될 것이다. 사용도구들이 단순히 CSS1를 지원하지 않고, 향 후 더 높은 수준의 스타일쉬트를 읽을 수 있도록 지원을 확실히 하기 위하여, 이 항목은 사용도구가 CSS1에서 유효하지 않은 구조를 만나면, 어떻게 하여야 하는가를 정의한다.

  • 모르는 속성의 선언은 무시한다. 예를 들어, 스타일쉬트가 <PRE>H1 { color: red; rotation: 70deg }</PRE>

    사용도구는 이를 아래와 같은 스타일쉬트로 처리한다. <PRE>H1 { color: red; }</PRE>

  • 유효하지 않은 값들, 또는 유효하지 않은 부분을 갖는 값들은 그 선언이 없는 것으로 처리한다. <PRE>IMG { float: left } /* CSS1 */IMG { float: left top } /* "top"은 유동('float')의 값이 아님 */IMG { background: "red" } /* CSS1의 키워드(keyword)에는 따옴표가 없슴 */IMG { border-width: 3 } /* 단위는 길이의 값으로 지정하여야 함 */</PRE>

    위 예제에서, CSS1 처리자(parser)는 첫 명령(rule) 만 인정하고 나머지는 무시 하여 다음과 같아 질 것이다. <PRE>IMG { float: left }IMG { }IMG { }IMG { }</PRE>

    향 후 CSS 규격에 부합하는 사용도구는 하나이상의 다른 규칙도 받아 드릴 수 있어야 한다.

  • 개별 무효(invalid) at-keyword는, 그 이후에 따라나오는 것을 쎄미콜론(;), 또는 ({...}) 짝 중에서 먼저 나오는 것까지 포함하여 모두 무시된다. 예를 들어, 다음을 보면: <PRE>@three-dee { @background-lighting { azimuth: 30deg; elevation: 190deg; } H1 { color: red }}H1 {color: blue}</PRE>

    CSS1에서 '@three-dee'는 무효 코드이다. 따라서 모든 at-rule( 세번째 '}'를 포함하여 그 것까지) 무시된다. CSS1 사용도구는 건너 띄워, 스타일쉬트를 효과적으로 아래와 같이 줄인다. <PRE>H1 {color: blue}</PRE>

더 자세히 설명하면:

CSS 각 버전의 CSS 스타일쉬트는 statements의 목록으로 구성되어 있다. 두종류의 statements가 있는데, at-rulesrulesets이다. statements의 앞과 뒤에 공백(space, tab, newline)이 있어도 된다.

CSS 스타일쉬트는 자주 HTML 문서들에 깔리며(embed), 옛날(older) 사용도구들에서는 스타일쉬트를 감출 수 있는데, 이는 스타일쉬트를 HTML 코멘트(Comment) 안에 넣는데 편리하다. HTML 코멘트(Comment)의 "<!--"와 "-->"가 statements의 앞, 뒤, 그리고 그 안에 나올 수 있고, 그 주위에 공백이 올 수 있다.

At-rules은 at-keyword로 시작되며, 그 인식자(identifier)의 시작을 알리는 '@'을 사용한다(예: '@import', '@page'). 인식자(identifier)는 글자, 수치, 대쉬(-)와 에스케입된(escaped) 글자들로 구성된다(아래 정의).

at-rule은 다음에 나오는 쎄미콜론(;) 또는 블럭(block: 곧 설명 함) 중 먼저 나오는 것까지, 그리고 그것을 포함하여, 모든 것으로 구성된다. CSS1 사용도구는, '@import' 이외의 다른 at-keyword로 시작되는 at-rule을 만나면, at-rule과 그 다음의 계속적인 처리(parsing)을 전부 무시한다. 만일 이것이 스타일쉬트의 맨 위에 나오지 않으면, 말하자면 어떤 명령(rule) 다음에 나온다면 그것이 유효하지 않더라도, '@import'로 시작되는 at-rule도 무시한다. 여기 예제가 있다.

CSS1 처리자(parser)가 아래 스타일쉬트를 만났다면: <PRE>@import "subs.css";H1 { color: blue }@import "list.css";</PRE>

두번째 '@import'는 CSS1에서 유효하지 않다. CSS1 처리자(parser)는 전체 at-rule을 무시하고, 효과적으로 아래와 같이 간단히 한다. <PRE>@import "subs.css";H1 {color: blue}</PRE>

블럭(block)은 '{'로시작되고 '}'로 끝난다. 그 사이에, 항상 짝이 맞아야 하고 네스트(nest)될 수 있는 괄호들'(), [], {}'들은 제외하고, 글자들이 나올 수 있다. 단일 따옴표(')와 이중 따옴표(") 도 짝을 맞추어 나오고, 그 사이의 글자들은 문자열(string)로 처리(parse)된다. 부록 B 문자열 정의 토큰(token)을 참조하라. 여기 블럭(block)의 예제가 있다. 따옴표 속의 오른쪽 '}'는 블럭(block) 시작 '{'와 짝이 맞지 않고, 두번째 단일 따옴표는 에스케입(escape)된 글자이며, 따라서 열린 따옴표와 짝이 맞지 않음을 주시하라. <PRE>{ causta: "}" + ({7} * '\'') }</PRE>

ruleset는 selector-string와 그 뒤에 declaration-block으로 구성된다. selector-string는 처음 '{'까지, 그 '{'를 포함하지 않는, 모든 것으로 구성된다. selector-string으로 시작하는 ruleset는 무효 CSS1는 건너 뛴다.

CSS1 처리자(parser)가 다음 예제의 스타일쉬트를 만났다면 <PRE>H1 { color: blue }P[align], UL { color: red; font-size: large }P EM { font-weight: bold }</PRE>

두번째 줄은 CSS1에서 무효인 selector-string를 만났다. CSS1 사용도구는 이 ruleset를 건너 뛰어, 다음과 같이 된다. <PRE>H1 { color: blue }P EM { font-weight: bold }</PRE>

선언블럭(declaration-block)은 '{'로 시작하고 짝 맞는 '}'로 끝난다. 그 사이에 하나도 없거나 여러개의 선언(declaration)들이 쎄미콜론(;)으로 분리되어 위치한다.

선언(declaration)은 속성(property), 콜론(:) 그리고 값(value)으로 구성된다. 그 앞, 뒤에 공간(whitespace)이 들어 갈 수 있다. 속성은 앞에서 정의한 바와 같은 인식자(identifier)이다. 값에는 어떤 글자도 올 수 있는데 괄호들'(), [], {}'과 단일 따옴표(')와 이중 따옴표(") 도 짝을 맞추어 사용하여야 한다. 괄호들'(), [], {}'은 네스트(nest)될 수 있다. 따옴표 속의 글자들은 문자열(string)로 처리(parse)된다

현재의 속성들에 새로운 속성들과 값들을 향 후 추가할 수 있게하기 위하여, 사용도구는 유효하지 않은 속성 이름이나 유효하지 않은 값을 갖는 선언을 건너 뛰어야 한다. 각 CSS1 속성은 그것이 수용(accept)하는 값들에 문법적, 의미적 제한이 있다.

CSS1 처리자(parser)가 다음 예제의 스타일쉬트를 만났다면 <PRE>H1 { color: red; font-style: 12pt }P { color: blue; font-vendor: any; font-variant: small-caps }EM EM { font-style: normal }</PRE>

첫번째 줄의 두번째 선언에서 '12pt'는 무효 값이다. 두번째 줄의 두번째 선언에서 'font-vendor'는 정의되지 않은 속성이다. CSS1 처리자(parser) 이 선언들을 건너 띄고, 다음과 같이 줄일 것이다. <PRE>H1 { color: red; }P { color: blue; font-variant: small-caps }EM EM { font-style: normal }</PRE>

코멘트(Comment: 항목 1.7 참조)는, 공백으로 고려되는, 공백이 있는 곳에는 어디나 나올 수 있다. CSS1는 값의 안에서 추가적으로 공백이 나올 수 있는 곳을 정의하였다. 그 곳에서 코멘트(Comment)도 허용된다.

다음 규칙이 항상 적용된다.

  • 모든 CSS 스타일쉬트는, CSS의 통제(control)를 받지 않는 부분을 제외하고는, 대소분자를 구분(case-insensitive)한다. CSS1에서 글꼴(font family) 이름과 URL은 대소분자를 구분(case-insensitive)할 수 있다. 또한 HTML [2] 제어 아래 있는 CLASS와 ID 애트리뷰트들은 대소분자를 구분(case-insensitive)한다.
  • CSS1에서, 선택자(selector: 엘레멘트의 name, class, ID)들은 글자 A-Z, 0-9, Unicode 글자 161-255, '+', '-' 만을 가질 수 있다. '-'나 수자로 시작될 수 없다. 에스케입(escape) 글자와 Unicode 글자의 수치 코드(다음 참조)를 가질 수 있다.
  • \(backslash) 다음의 16 진수(01..9abcdef)는 Unicode 글자의 번호이다.
  • 16 진수 이외의 어느 글자는, \(backslash)를 그 글자 앞에 넣어, 그 특수 의미를 제거하여, 에스케입(escape)될 수 있다. 예를 들어 (\")는 한 이중 따옴표 한 글자의 배열변수(string)이다.
  • 위 두가지는 백슬래쉬 에스케입(backslash-escape)을 정의하였다. 백슬래쉬 에스케입은, 문자열(string) 속의 것을 제외하고는, 항상 인식자(identifier)의 한 부분으로 고려된다. 말하자면, "{"는 구둣점인데, "\7B"는 구둣점이 아니고, "2"는 허용되지 않으나, "\32"는 글라스(class) 이름 시작에 허용된다.

주기: HTML의 CLASS 애트리뷰트는 클래스(class) 이름에 위 선택자(selector)로 허용된 글자 이외의 다른 글자들을 허용한다. CSS1에서, 이들 글자들은 에스케입(escape)되거나 또는 Unicode 번호로 써야 한다.
"B&W?"는 "B\&W\?" 또는 "B\26W\3F"로 쓸 수 있고,
그리스어(Greek: "kouros"): "κουρος"는 "\3BA\3BF\3C5\3C1\3BF\3C2"로 써야한다.
항 후 CSS 버전에서는 더 많은 글자를 직접 입력할 수 있을 것으로 기대된다.

부록 B CSS1 문법을 참조하라.

8    참고

[1] 영문 W3C 스타일쉬트 자원 페이지 (http://www.w3.org/Style)

[2] HTML 4 규격 번역문,
영문 HTML 4.0 규격 "http://www.w3.org/TR/REC-html40/",
D. Raggett, A. Le Hors, I. Jacobs, December 1997.

[3] T Berners-Lee, D Connolly: "Hypertext MarkupLanguage - HTML 2.0",
영문 RFC1866,
MIT/W3C, November 1995.
영문 규격 웹양식 "http://www.w3.org/MarkUp/html-spec/html-spec_toc.html"

[4] F Yergeau, G Nicol, G Adams, M Dürst:
영문 Hypertext Markup Language의 국제화 "ftp://ds.internic.net/rfc/rfc2070.txt"

[5] 영문 ISO 8879:1986
정보 처리 - 텍스트와 오피스 시스템 -
Standard Generalized Markup Language (SGML)
HTML의 SGML 설명을 참조하라.

[6] 영문 ISO/IEC 10179:1996
정보 기술 -- 프로그램 언어 --
Document Style Semantics and Specification Language (DSSSL).

[7] 영문 ISO/IEC 9899:1990
프로그램 언어 -- C.

[8] 유니코드 컨소시움(The Unicode Consortium),
Unicode 표준 -- 세계 글자 엔코딩 -- Version 1.0,
Addison-Wesley, Volume 1, 1991, Volume 2, 1992.

[9] 영문 인터넷을 위한 표준 디폴트 색상, version 1.10,
M. Stokes, M. Anderson, S. Chandrasekar, and R. Motta, 5 November 1996.

[10] CIE Publication 15.2-1986, 영문 Colorimetry, 제 2 판,
ISBN 3-900-734-00-3
"http://www.hike.te.chiba-u.ac.jp/ikeda/CIE/publ/abst/15-2-86.html"

[11] T Berners-Lee, L Masinter, M McCahill: "Uniform Resource Locators (URL)",
영문 RFC1738,
CERN, Xerox Corporation, University of Minnesota, December 1994

[12] 영문 PNG (Portable Network Graphics) 규격, Version 1.0
"http://www.w3.org/TR/REC-png-multi.html"

[13] Charles A. Poynton: 영문 Macintosh Platform에서 감마(gamma) 수정
"ftp://ftp.inforamp.net/pub/users/poynton/doc/Mac/Mac_gamma.pdf"

[14] 국제 색상 컨소시움(International Color Consortium):
영문 ICC Profile Format Specification, version 3.2, 1995
"ftp://sgigate.sgi.com/pub/icc/ICC32.pdf"

[15] S C Johnson: "YACC - Yet another compiler compiler",
Technical Report, Murray Hill, 1975

[16] "Flex: The Lexical Scanner Generator", Version 2.3.7, ISBN 1882114213

9    문서를 구성한 인사들

짧은 HTML의 역사 동안, 여러번의 영문 스타일쉬트 제안들이 있었는데, 이 제안은 그 것들에 기인하였다. 특히 Robert Raisch, Joe English와 Pei Wei의 제안들에서 영향을 많이 받았다.

CSS1 발전에 여러 사람들이 공헌하였다. 우리는 특히 다음 사람들에게 감사드린다. Terry Allen, Murray Altheim, Glenn Adams, Walter Bender, Tim Berners-Lee, Yves Bertot, Scott Bigham, Steve Byrne, Robert Cailliau, James Clark, Daniel Connolly, Donna Converse, Adam Costello, Todd Fahrner, Todd Freter, Roy Fielding, Neil Galarneau, Wayne Gramlich, Phill Hallam-Baker, Philipp Hoschka, Kevin Hughes, Scott Isaacs, Tony Jebson, William Johnston, Gilles Kahn, Philippe Kaplan, Phil Karlton, Evan Kirshenbaum, Yves Lafon, Murray Maloney, Lou Montulli, Colas Nahaboo, Henrik Frystyk Nielsen, David Perrell, William Perry, Scott Preece, Paul Prescod, Liam Quin, Vincent Quint, Jenny Raggett, Thomas Reardon, Cécile Roisin, Michael Seaton, David Seibert, David Siegel, David Singer, Benjamin Sittler, Jon Smirl, Charles Peyton Taylor, Irène Vatton, Daniel Veillard, Mandira Virmani, Greg Watkins, Mike Wexler, Lydja Williams, Brian Wilson, Chris Wilson, Lauren Wood and Stephen Zilles.

이 작업과 HTML3을 작업한 Dave Raggett, 특히 색상과 글꼴 분야에서 계속적인 공헌한 Chris Lilley, 그리고 이 구성과 창의적인 숙련을 제공한 Steven Pemberton, 이 세 분의 공헌을 특별히 명시한다.

부록 A: HTML 2.0을 위한 견본 스타일쉬트

(이 부록은 지명적이 아니고 정보를 제공하기 위한 것이다.)

다음 스타일쉬트는 작성 [3] HTML 2.0 규격으로 암시되는 표현을 하기 위해 제공 되었다. 일부 스타일들, 예를 들어, 색상들은 완전성을 위하여 추가되었다. 아래의 제시된 스타일쉬트와 유사한 것이 사용도구의 디폴트로 사용되기를 제안한다. <PRE>BODY { margin: 1em; font-family: serif; line-height: 1.1; background: white; color: black;}H1, H2, H3, H4, H5, H6, P, UL, OL, DIR, MENU, DIV,DT, DD, ADDRESS, BLOCKQUOTE, PRE, BR, HR, FORM, DL { display: block }B, STRONG, I, EM, CITE, VAR, TT, CODE, KBD, SAMP, IMG, SPAN { display: inline }LI { display: list-item }H1, H2, H3, H4 { margin-top: 1em; margin-bottom: 1em }H5, H6 { margin-top: 1em }H1 { text-align: center }H1, H2, H4, H6 { font-weight: bold }H3, H5 { font-style: italic }H1 { font-size: xx-large }H2 { font-size: x-large }H3 { font-size: large }B, STRONG { font-weight: bolder } /* 그 모체에 상대적 */I, CITE, EM, VAR, ADDRESS, BLOCKQUOTE { font-style: italic }PRE, TT, CODE, KBD, SAMP { font-family: monospace }PRE { white-space: pre }ADDRESS { margin-left: 3em }BLOCKQUOTE { margin-left: 3em; margin-right: 3em }UL, DIR { list-style: disc }OL { list-style: decimal }MENU { margin: 0 } /* 치밀한 양식 */LI { margin-left: 3em }DT { margin-bottom: 0 }DD { margin-top: 0; margin-left: 3em }HR { border-top: solid } /* 'border-bottom'도 사용될 수 있다 */A:link { color: blue } /* 방문하지 않은 연결 */A:visited { color: red } /* 방문 했던 연결(visited link) */A:active { color: lime } /* 활성 연결(active link) *//* 앤커 이미지 엘레멘트 주위의 테두리 설정은 복합(contextual) 선택자(selector)가 필요하다 */A:link IMG { border: 2px solid blue }A:visited IMG { border: 2px solid red }A:active IMG { border: 2px solid lime }</PRE>

부록 B: CSS1 문법

(이 부록은 지명적이다)

(CSS의 어떤 버전의) 최소의 CSS 문법은 지원할 필요가 있는 모든 적용들이 항목 7에 정의되어 있다. 아래의 문법은 훨신 짧게 기술되어 있는데 이는 CSS1의 문법(syntax)을 정의한다.

그러나 어떤 의미에서는 여전히 CSS1의 superset이다. 이 문법에는 표현되지 않은 추가적인 의미적인 제한들이 있다. 부합하는 사용도구는 또한 향 후 버전 부합성(항목 7.1) 처리(parsing), 그 속성과 값 표현(항목 5) 그리고 단위 표현(항목 6)를 준수하여야 한다. 또한 HTML도 제한이 있는데, 예를 들면, CLASS 애트리뷰트의 가능한 값들 등이다.

아래 문법은 LL(1)이다. 그러나 대부분의 사용도구들은 직접 사용하지 않아야 한다. 왜냐하면 이는 그 처리(parsing) 자체를 표현한 것이 아니고, CSS1의 문법 만을 다룬 것이기 때문이다. 이 양식은 인간이 읽기 좋게 최적화하였으며, [15] yacc 이외의 약식 표기도 사용하였다. <PRE>* : 0 또는 그 이상+ : 1 또는 그 이상? : 0 또는 1| : 대체 가능한(alternative) 항목의 분리[] : 구룹지우기(grouping)</PRE>

결과물은 다음과 같다. <PRE>stylesheet : [CDO|CDC]* [ import [CDO|CDC]* ]* [ ruleset [CDO|CDC]* ]* ;import : IMPORT_SYM [STRING|URL] ';' /* 예: @import url(fun.css); */ ;unary_operator : '-' | '+' ;operator : '/' | ',' | /* empty */ ;property : IDENT ;ruleset : selector [ ',' selector ]* '{' declaration [ ';' declaration ]* '}' ;selector : simple_selector+ [ pseudo_element | solitary_pseudo_element ]? | solitary_pseudo_element ; /* "id"는 엘레멘트 타입에 왼쪽에 P#p007와 같이 추가되는 ID이다. ** "solitary_id" 는 #p007 처럼 그렇게 추가되지 않은 ID이다. ** 글라스(class)들과 가상 글라스(pseudo-class)에서 동시에. */simple_selector : element_name id? class? pseudo_class? /* 예: H1.subject */ | solitary_id class? pseudo_class? /* 예: #xyz33 */ | solitary_class pseudo_class? /* 예: .author */ | solitary_pseudo_class /* 예: :link */ ;element_name : IDENT ;pseudo_class /* A:link에서 처럼 */ : LINK_PSCLASS_AFTER_IDENT | VISITED_PSCLASS_AFTER_IDENT | ACTIVE_PSCLASS_AFTER_IDENT ;solitary_pseudo_class /* :link에서 처럼 */ : LINK_PSCLASS | VISITED_PSCLASS | ACTIVE_PSCLASS ;class /* P.note에서 처럼 */ : CLASS_AFTER_IDENT ;solitary_class /* .note에서 처럼 */ : CLASS ;pseudo_element /* P:first-line에서 처럼 */ : FIRST_LETTER_AFTER_IDENT | FIRST_LINE_AFTER_IDENT ;solitary_pseudo_element /* :first-line에서 처럼 */ : FIRST_LETTER | FIRST_LINE ; /* id와 solitary_id에서 "#" 다음 부분은 ** 유효한 HTML ID 값 이어야 한다는 제한이 있다. ** 예: "#x77"는 OK, 그러나 "#77"는 무효. */id : HASH_AFTER_IDENT ;solitary_id : HASH ;declaration : property ':' expr prio? | /* empty */ /* 문법 오류를 방지하기 위하여 */ ;prio : IMPORTANT_SYM /* 중요(!important) */ ;expr : term [ operator term ]* ;term : unary_operator? [ NUMBER | STRING | PERCENTAGE | LENGTH | EMS | EXS | IDENT | hexcolor | URL | RGB ] ; /* 색상에서 "#" 다음에 16 진수(0-9a-fA-F)가 ** 3 개 또는 6 개가 나와야 한다는 제한이 있다. ** 예: "#000"는 OK, 그러나 "#abcd"는 무효. */hexcolor : HASH | HASH_AFTER_IDENT ;</PRE>

다음은 [16] flex로 기술한 토큰화하는 것(tokenizer)이다. flex의 8-bit 적용을 가정함을 주시하라. 토큰화하는 것(tokenizer)은 대소문자를 구분한다(case-insensitive). (flex command line option -i). <PRE>unicode \\[0-9a-f]{1,4}latin1 [¡-ÿ]escape {unicode}|\\[ -~¡-ÿ]stringchar {escape}|{latin1}|[ !#$%&(-~]nmstrt [a-z]|{latin1}|{escape}nmchar [-a-z0-9]|{latin1}|{escape}ident {nmstrt}{nmchar}*name {nmchar}+d [0-9]notnm [^-a-z0-9\\]|{latin1}w [ \t\n]*num {d}+|{d}*\.{d}+string \"({stringchar}|\')*\"|\'({stringchar}|\")*\'%x COMMENT%s AFTER_IDENT%%"/*" {BEGIN(COMMENT);}<COMMENT>"*/" {BEGIN(0);}<COMMENT>\n {/* ignore */}<COMMENT>. {/* ignore */}@import {BEGIN(0); return IMPORT_SYM;}"!"{w}important {BEGIN(0); return IMPORTANT_SYM;}{ident} {BEGIN(AFTER_IDENT); return IDENT;}{string} {BEGIN(0); return STRING;}{num} {BEGIN(0); return NUMBER;}{num}"%" {BEGIN(0); return PERCENTAGE;}{num}pt/{notnm} {BEGIN(0); return LENGTH;}{num}mm/{notnm} {BEGIN(0); return LENGTH;}{num}cm/{notnm} {BEGIN(0); return LENGTH;}{num}pc/{notnm} {BEGIN(0); return LENGTH;}{num}in/{notnm} {BEGIN(0); return LENGTH;}{num}px/{notnm} {BEGIN(0); return LENGTH;}{num}em/{notnm} {BEGIN(0); return EMS;}{num}ex/{notnm} {BEGIN(0); return EXS;}<AFTER_IDENT>":"link {return LINK_PSCLASS_AFTER_IDENT;}<AFTER_IDENT>":"visited {return VISITED_PSCLASS_AFTER_IDENT;}<AFTER_IDENT>":"active {return ACTIVE_PSCLASS_AFTER_IDENT;}<AFTER_IDENT>":"first-line {return FIRST_LINE_AFTER_IDENT;}<AFTER_IDENT>":"first-letter {return FIRST_LETTER_AFTER_IDENT;}<AFTER_IDENT>"#"{name} {return HASH_AFTER_IDENT;}<AFTER_IDENT>"."{name} {return CLASS_AFTER_IDENT;}":"link {BEGIN(AFTER_IDENT); return LINK_PSCLASS;}":"visited {BEGIN(AFTER_IDENT); return VISITED_PSCLASS;}":"active {BEGIN(AFTER_IDENT); return ACTIVE_PSCLASS;}":"first-line {BEGIN(AFTER_IDENT); return FIRST_LINE;}":"first-letter {BEGIN(AFTER_IDENT); return FIRST_LETTER;}"#"{name} {BEGIN(AFTER_IDENT); return HASH;}"."{name} {BEGIN(AFTER_IDENT); return CLASS;}url\({w}{string}{w}\)|url\({w}([^ \n\'\")]|\\\ |\\\'|\\\"|\\\))+{w}\) {BEGIN(0); return URL;}rgb\({w}{num}%?{w}\,{w}{num}%?{w}\,{w}{num}%?{w}\) {BEGIN(0); return RGB;}[-/+{};,#:] {BEGIN(0); return *yytext;}[ \t]+ {BEGIN(0); /* 공간 무시 */}\n {BEGIN(0); /* 공간 무시 */}\<\!\-\- {BEGIN(0); return CDO;}\-\-\> {BEGIN(0); return CDC;}. {fprintf(stderr, "%d: Illegal character (%d)\n", lineno, *yytext);}</PRE>

부록 C: 엔코딩(encoding)

(이 부록은 지명적이 아니고 정보를 제공하기 위한 것이다.)

HTML 문서들은 대략 30,000개의 유니코드(Unicode)에서 정의한 다른 글자들을 가질 수 있다. 많은 문서들은 몇 백가지 글자로서 충분하다. 많은 글꼴들 또한 몇 백가지의 도형(glyph)들 만을 가지고 있다. 이 부록은, 항목 5.2 글꼴의 속성들과 조합하여, 문서의 글자들과 글꼴의 도형(glyph)들이 어떻게 서로 맞는가를 설명한다.

글자 엔코딩(encoding)

HTML 문서의 내용(content)은 글자(character)들과 마크업(markup)들의 연속이다. 쓰여진 것이 송신되면, 이는, 여러가지 가능한 방법 중 한가지 엔코딩(encoding)을 사용하여, 바이트(byte)들의 연속으로 바뀌어(encode) 진다. HTML 문서는 글자들은 찾기 위 해 엔코딩되어야 한다. 예를 들어, 서부 유럽에서, 관습적으로 a-with-grave-accent (à)를 위하여, 244 바이트(bite)를 사용하였다. 그러나 히브리어(Hebrew)에서는, 224을 Aleph를 위하여 사용하는 것이 더 보편적이다. 일본어에서는 한 바이트(byte)의 의미가 그 뒤의 바이트들에 의하여 달라진다. 일부 엔코딩(encoding)에서는 한 글자가 두개(혹은 그 이상)의 바이트들로 엔코딩된다.

사용도구는 http header에 있는 글자세트("charset")를 점검하여 어떻게 엔코딩할 것인가를 안다. 전형적인 엔코딩(encoding: 글자세트의 값)들은 영어에서 아스키("ASCII"), 서유럽에서 "ISO-8859-1", 히브리어에서 "ISO-8859-8", 일본어에서 "Shift-JIS", 한글에서 "EUC-KR"이다.

[2] HTML 2.0[4] HTML 4에서, 일반적으로 유니코드(Unicode)에 의하여 정의되어 있는 30,000여 다른 글자들을 허용한다. 그렇게 많은 글자들을 사용하는 문서들은 많지 않을 것이다. 그리고 올바른 엔코딩(encoding)의 선택은 일반적으로 그 문서가 한 글자마다 한 바이트(byte) 만 필요하게 해 줄 것이다. 엔코딩 밖에 있는 때때로 사용하는 글자들도 글자 참조 수치를 입력하여 사용할 수 있다. '&#928;'는 어느 엔코딩를 사용하던 관계없이 항상 그리스어 Pi의 대문자(Π)를 의미한다. 사용도구들은, 단지 몇가지 엔코딩(encoding)들 만을 채택한다 하더라도, 어떤 유니코드(Unicode) 글자도 처리할 수 있어야 한다는 점을 주시하라.

HTML의 엔코딩 설명을 참조하라.

글꼴(font) 엔코딩(encoding)

글꼴(font)는 글자(character)들을 포함하지 않고 글자들의 도형(glyph)이라 불리우는 그림(picture)들을 갖는다. 이 도형(glyph)들은 아우트라인(outline) 비트맵(bitmap)에서 글자의 독특한 표현을 한다. 명시적(explicit)으로 혹은 암시적(implicit)으로, 각 글꼴는 그에 연관된 글꼴 엔코딩 표(font encoding table)를 갖는데, 이는 각 도형(glyph)이 어떤 글자을 표현하는가를 말해 준다. 타입(Type) 1 글꼴(font)는, 표에서 엔코딩 벡터(encoding vector)로 참조된다.

실제로, 많은 글꼴들은 한 글자를 위하여 여러가지 도형(glyph)들을 같는다. 어느 도형(glyph)이 사용되는가는 언어의 명령(rule)들이나 도형 설계자를 참조하는데 따라 채택된다.

예를 들어 아랍어(Arabic)에서, 모든 글자들은 네가지 다른 모양(shape)들을 갖는데, 그 글자가 단어의 앞에 오는가, 가운데 오는가, 끝에오는가 혹은 독립적으로 사용되는가에 따라 다르다. 이는 모든 경우에 같이 적용되고, 따라서 HTML 문서에서 한 가지의 글자인 것이다. 그러나 인쇄되면 매 번 다르게 보인다.

그래픽 디자이너들이 여러 대체 모양들 중에서 골라 사용할 수 있는 글꼴들도 남겨 놓았다. 불행하게도 CSS1은 아직 이들 대체 모양을 선택하는 수단을 제공하지 못하고 있다. 현재로서는 선택된 그런 글꼴는 항상 디폴트 모양(shape)으로 된다.

글꼴쎄트(font set)

단일 글꼴로 문서나 단일 엘레멘트의 모든 글자들을 표현하기에 불 충분한 경우의 문제를 다루기 위하여, CSS1는 글꼴쎄트(font set)들의 사용을 허용한다.

CSS1에서 글꼴쎄트(font set)는 글꼴들의 목록이다. 모두 같은 스타일(style)과 크기를 갖고있으며, 어떤 글자가 도형(glyph)을 갖고 있는가를 점검하는 일련의 순서이다. 한 엘레멘트가 영어 텍스트를 가지고 수학기호(mathematical symbol)들과 섞여 있을 때, 하나는 글자와 수자, 다른 하나는 수학기호를 갖는, 두가지 글꼴의 글꼴쎄트가 필요할 수 있다. 글꼴쎄트를 선택하는 기능(mechanism)에 대한 설명은 항목 5.2 글꼴 속성을 참조하라.

아래 글꼴쎄트 예제는 문장에 영어(Latin) 글자들, 일본어 글자들과 수학기호들이 들어가는 것이 예상되는 경우에 적당하다. <PRE>BODY { font-family: Baskerville, Mincho, Symbol, serif }</PRE>

Baskerville 글꼴(Latin 글자만 있슴)에 있으면 그 글꼴에서 채택하고, 일본어는 Mincho 글꼴에서, 그리고 수학기호는 Symbol 글꼴에서 올 것이다. 다른 글자들은 (희망적으로) 일반 글꼴(generic font family)인 'serif' 글꼴에서 올 것이다. 'serif' 글꼴는 하나이상의 다른 글꼴들이 없을 때도 사용될 수 있다.

부록 D: 감마(gamma) 수정

(이 부록은 지명적이 아니고 정보를 제공하기 위한 것이다.)

감마(gamma)에 대하여 잘 모르면 [12] PNG 규격영문 감마 안내서(Gamma Tutorial)를 참조하라.

사용도구들이 CRT(화면)에 디스플레이는, 계산하는데 있어, 이상적인 CRT를 가정하고 떨림(dithering)에 의하여 발생되는 gamma의 효과를 무시할 수 있다. 이는 현재의 프래트폼(platform)들에서 필요한 처리를 최소화 함을 의미한다.

MS-Windows를 사용하는 PC
없슴
X11을 사용하는 Unix
없슴
QuickDraw를 사용하는 Mac
감마(gamma) 1.39 적용 [13] (ColorSync-savvy 적용들은 올바른 색상 보정을 위하여 단순히 sRGB ICC profile [14]을 ColorSync에 전달한다.)
X를 사용하는 SGI
감마(gamma) 값을 /etc/config/system.glGammaVal로 부터 적용
(디폴트 값은 1.70; Irix 6.2 이상에서 운영되는 적용들은 단순히 sRGB ICC profile을 색상 관리 시스템에 전달한다)
NeXT using NeXTStep
감마(gamma) 2.22 적용

감마를 적용한다("applying gamma")는 것은 운영체계(OS)에서 처리되기 전에 각 R, G, B 삼색이 R'=Rgamma, G'=Ggamma, B'=Bgamma로 환산되어야 한다는 의미이다.

이는 브라우저마다 아래와 같이 한번에 256-엘레멘트 조견표(table)를 만들므로서 신속히 이루어 질 수 있다. <PRE>for i := 0 to 255 do raw := i / 255; corr := pow (raw, gamma); table[i] := trunc (0.5 + corr * 255.0)end</PRE>

그러면 이것은 색상 애트리뷰트마다나 픽셀(pixel)마다의 어떤 고급 계산의 필요를 피할 수 있다.

부록 E: CSS1의 적용성과 확장성

(이 부록은 지명적이 아니고 정보를 제공하기 위한 것이다.)

CSS1에 대하여 작업하는 목표는 HTML 문서들을 위하여 간단한 스타일쉬트 기능을 만들기 위한 것이다. 현재의 규격은 스타일쉬트을 웹에 사용 타당성을 제시하는 간단성과 풍부한 보이는 제어를 위하여 제작자들로부터의 압력에 의한 것의 사이에서 균형을 갖춘 상태이다. CSS1는 다음 사항들을 제공한다.

  • 보이(visual)는 마크업(markup) 대체: HTML 표현(extension)들, 예를 들어 "CENTER", "FONT", "SPACER" 등은 CSS1 스타일쉬트로 쉽게 대체된다.
  • 더 멋있는 마크업(markup): 인기있는 작은 대분자(small-caps) 스타일을 얻기 위해 "FONT" 엘레멘트들을 사용하는 대신에 스타일쉬트에서 하나의 선언(declaration)으로 충분하다. 마크업(markup)과 비교하면: <PRE><H1>H<FONT SIZE=-1>EADLINE</FONT></H1></PRE>

    스타일쉬트로는: <PRE>H1 { font-style: small-caps }<H1>Headline</H1></PRE>

  • 여러가지 통합 레벨들: CSS1 스타일 명령(rule)들은 외부 스타일쉬트로 부터 가져 올 수 있고, 'STYLE' 엘레멘트에 포함시킬 수 있고, 또는 'STYLE' 애트리뷰트 안에 넣을 수 있다. 나중의 선택은 HTML 표현(extension)들로 부터의 변환을 용이하게 한다.
  • 새로운 효과들: 일부 새로운 보이는 효과들이 사용자의 흥미를 위하여 추가되었다. 인쇄술을 위한 가상 엘레멘트들과 배경(background) 속성의 추가적 값들은 여기에 해당된다.
  • 배수에 의한 조정 가능(scalability): CSS1는 단순한 텍스트 터미날들에서부터 고 해상도 색상 워크스테이션(workstation)들까지 두루 유용하다. 제작자들은 한 스타일쉬트을 써서 합리적으로 의도하는 스타일이 가능한 가장 좋은 방식으로 나타 날 것이라는 것을 확실히 할 수 있다.

CSS1는 아래 사항들을 제공하지 않는다.

  • 픽셀(pixel) 단위 제어: CSS1 값들의 제어 수준보다는 단순성에 중점을 두어, 이미지 배경과 스타일화된 HTML의 조합이 강력 함에도 불구하고, 픽셀(pixel) 수준의 제어는 불가능하다.
  • 제작자 제어: 제작자는, 암시는 할 수 있을 뿐, 어떤 스타일의 사용을 보완할 수 없다.
  • 배치(layout) 언어: CSS1는, 텍스트의 흐름(text-flow), 프레임의 겹침(overlapping) 등, 복수 컬럼들을 제공하지 않는다.
  • 처리(parse) 계통(tree)에서 풍부한 쿼리(query) 언어: 다른 스타일쉬트들(예를 들어 [6] DSSSL)은 완전한 쿼리(query) 언어를 제공하는데 반 해, CSS1는 처리(parse) 계통(tree)에서 조상(ancestor) 엘레멘트들을 찾는 기능 만을 제공할 수 있다.

CSS에서 다음 여러 방향으로 확장될 것으로 기대한다.

  • 종이(paper): HTML 문서들의 개선된 인쇄 지원
  • 보이지 않는(non-visua) 메디아 지원: 속성들 목록에 추가하는 작업이 진행되고 있으며, 해당 값들은 음성 장치나 점자 출력을 지원한다.
  • 색상명(color name)들: 현재의 목록의 확장
  • 글꼴(font)들: 현재의 CSS1 글자(font) 속성들을 보완하기 위하여 보다 정확한 글꼴 규격 체계가 기대 됨.
  • 값들과 속성들: 관련 업체(vendor)들에 의한 값들과 속성들의 CSS1 쎄트에 확장들이 제안될 것으로 기대한다. 이 방향으로의 확장은 규격의 자질구레한 부분이나, 서로 다른 사용도구들 사이에서 공동적 사용(interoperability)을 다룬다.
  • 배치(layout) 언어: 전통적인 편집기등에서 두 차원 배치(two-dimensional layout)를 지원
  • 다른 문서타입정의(DTD)들: CSS1은 예를 들어 'CLASS'와 'ID' 애트리뷰트들의 특수 상태(status) 등 HTML에 맞는(HTML-specific) 부분들을 갖는다. 그러나 쉽게 다른 문서타입정의(DTD)들의 적용에 확장되어야 할 것이다.

CSS는 다음 사항을 취급하지 않을 것이다.

  • 프로그램 언어

부록 F: 1996년 12월 17일 버전으로 부터의 변경들

(이 부록은 지명적이 아니고 정보를 제공하기 위한 것이다.)

이 규격은 1996년 11월 17일 최초 발표된 것으로부터 개정된 CSS1 추천안으로, 아래 목록은 모든 변경들을 설명한다. 스타일쉬트 오류("errata")를 선택 함으로서 해당 변경들이 부각된다.

Komachi Yushi, Steve Byrne, Liam Quinn, Kazuteru Okahashi, Susan Lesch, Tantek Çelik에게 이 개정을 준비하는데 도움을 준 것에 대해 감사한다.

철자와 인쇄 상의 오류들, 일반 오류들, 구조와 구성 조정

오류들은 과거의 오류에서 부터 수정된 내용을 기술할 것으로, 번역문에서는 특별한 의미가 없고, 이미 수정되었기 때문에 번역을 생략하였다.
필요하면 원문을 참고하라.
Posted by 1010
반응형
 
prototype.js를 위한 개발자 노트

1.5.0버전을 다룸

Sergio Pereira에 의해 작성됨
이동국에 의해 번역됨
최근 업데이트: 2007년 3월 4일

목차

Prototype은 무엇인가.?

prototype.jsSam Stephenson에 의해 작성된 자바스크립트 라이브러리이다. 이 놀랍도록 멋진 생각과 표준에 의해 잘 작성된 코드의 일부는 웹2.0의 특성을 나타내는 풍부하고 상호작용하는 웹페이지와 많은 연관을 가진다.

만약 당신이 최근 이 라이브러리를 사용하기 시작했다면, 당신은 아마도 이 문서가 가장 좋은 지시사항중에 하나는 아니라는것을 알아차렸을것이다. 나 이전에 다른 많은 개발자들처럼, 나는 소스코드와 이것을 사용한 경험에서 prototype.js에 대한 지식을 가지게 되었다. 나는 모든 이가 배우고 공유하는 동안 좀더 많은 정보를 얻게 되는게 가장 좋은 것이라고 생각한다.

나는 objects, classes, functions, 그리고 이 라이브러리에 의해 제공되는 확장을 위한 비공식적인 참조문서 또한 제공한다.

당신이 예제와 참조문서를 읽었을때, Ruby프로그래밍 언어에 친숙한 개발자는 Ruby의 내장 클래스와 이 라이브러리에 의해 구현된 많은 확장 사이의 의도적인 유사성을 알아차리게 될것이다.

toc

관련글

고급 자바스크립트 가이드

toc

유틸리티 함수들

라이브러리는 미리 정의된 많은 수의 객체와 유틸리티 함수를 가진다. 이 알기쉬운 함수들의 목적은 반복적인 타이핑과 어구를 많이 줄이는데 있다.

toc

$() 함수 사용하기

$()함수는 가장 많이 사용되는 DOM의 document.getElementById()함수에 대한 편리한 단축키이다. DOM함수처럼, 이것은 인자로 던져진 id를 가진 요소를 하나 반환한다.

DOM함수와는 달리 이 함수는 더 많은 작업을 수행한다. 반환된 element객체는 몇가지 추가적인 작업을 하게 될것이다. element를 숨기거나 보여주고 크기를 알아내며 element에 대해 스크롤을 하는 것과 같은 추가적인 많은 작업을 간단하게 만든다. Element 객체를 위한 참조문서에서 반환된 element객체에 추가된 메소드 목록을 얻을수 있다.

<html>
<head>
<title> Test Page </title>
<script src="prototype.js"></script>

<script>
	function test(){
		var d = $('myDiv');
		alert(d.innerHTML);
		d.hide();
		d.show();
		d.addClassName('active');
	}
</script>
</head>

<body>
	<div id="myDiv">
		<p>This is a paragraph</p>
	</div>
	<div id="myOtherDiv">
		<p>This is another paragraph</p>
	</div>

	<input type="button" value="Test $()" onclick="test();"/><br/> 

</body>
</html>

이 함수의 좋은 점은 이것은 인자형태를 가질수 있는 다른 함수를 생성할때 매우 유용하도록 만들어주는 id문자열이나 요소객체 자체를 던질수 있다는 것이다.

toc

$$() 함수 사용하기

$$() 함수는 내용물에서 CSS를 일관되게 분리할때 많이 도와줄것이다. 하나 이상의 CSS필터링 표현식을 파싱한다면, CSS 룰을 정의하기 위해 사용되는 것과 유사하고 이러한 필터에 일치하는 요소를 반환한다.

이 함수는 터무니 없을 정도로 사용하기가 쉽다. 체크해보라.

<script>
function test$$(){
	/*
	  in case CSS is not your forte, the expression below says
	  'find all the INPUT elements that are inside 
	  elements with class=field that are inside a DIV
	  with id equal to loginForm.'
	*/
	var f = $$('div#loginForm .field input');
	var s = '';
	for(var i=0; i<f.length; i++){
		s += f[i].value + '/';
	}
	alert(s); // shows: "joedoe1/secret/"
	
	//now passing more than one expression
	f = $$('div#loginForm .field input', 'div#loginForm .fieldName');
	s = '';
	for(var i=0; i<f.length; i++){
		s += ( f[i].value ? f[i].value : f[i].innerHTML ) + '/';
	}
	alert(s); //shows: "joedoe1/secret/User name:/Password:/"
}


</script>

<div id='loginForm'>
	<div class='field'>
		<span class='fieldName'>User name:</span>
		<input type='text' id='txtName' value='joedoe1'/>
	</div>
	<div class='field'>
		<span class='fieldName'>Password:</span>
		<input type='password' id='txtPass' value='secret' />
	</div>
	<input type='submit' value='login' />
</div> 
<input type=button value='test $$()' onclick='test$$();' />
			

성능에 대한 빠른 노트. prototype.js에서 $$() 함수의 현재 구현체는 특별히 효과적으로 여겨지지 않는다. 이 함수를 자주 사용하여 복잡한 HTML문서를 처리하고자 계힉중이라면, 가능한 $$()함수 자체를 대체하는 다른 구현체를 고려하고자 할것이다.

toc

$F() 함수 사용하기

$F() 함수는 다른 단축키이다. 이것은 텍스트 박스나 드랍다운 리스트와 같은 어떤 필드의 입력 컨트롤의 값을 반환한다. 이 함수는 요소 id나 요소객체 자체를 인자로 가질수 있다.

<script>
	function test3()
	{
		alert(  $F('userName')  );
	}
</script>

<input type="text" id="userName" value="Joe Doe"><br/> 
<input type="button" value="Test3" onclick="test3();"><br/> 
			

toc

$A() 함수 사용하기

$A() 함수는 이것을 받아들이는 하나의 인자를 Array객체로 변환한다.

Array 클래스를 위한 확장과 조합된 이 함수는 열거가능한 리스트를 Array 객체로 변환하거나 복사하는 것을 더욱 쉽게 만든다. 예를 들면, 작성한 함수는 인자의 수를 유연하게 받아들인다. 여기서 추천되는 사용법은 DOM NodeLists를 좀더 효과적으로 처리할수 있도록 일반적인 배열로 변환하기 위해 사용하는 것이다. 아래의 예제를 보라.

<script>

	function showOptions(){
		var someNodeList = $('lstEmployees').getElementsByTagName('option');
		var nodes = $A(someNodeList);

		nodes.each(function(node){
				alert(node.nodeName + ': ' + node.innerHTML);
			});
	}
</script>

<select id="lstEmployees" size="10" >
	<option value="5">Buchanan, Steven</option>
	<option value="8">Callahan, Laura</option>
	<option value="1">Davolio, Nancy</option>
</select>

<input type="button" value="Show the options" onclick="showOptions();" > 
			

toc

$H() 함수 사용하기

$H() 함수는 객체를 결합된 배열을 열거하는 Hash객체로 변환한다.

<script>
	function testHash()
	{
		//let's create the object
		var a = {
			first: 10,
			second: 20,
			third: 30
			};

		//now transform it into a hash
		var h = $H(a);
		alert(h.toQueryString()); //displays: first=10&second=20&third=30
	}

</script>
			

toc

$R() 함수 사용하기

$R() 함수는 new ObjectRange(lowerBound, upperBound, excludeBounds)를 작성하기 위한 짧은 형태이다.

이 클래스의 완전한 설명을 보기 위해 ObjectRange 클래스 문서를 보라. each 메소드를 통해 반복(iterators)의 사용법을 보여주는 간단한 예제를 보자. 더 많은 메소드는 Enumerable 클래스 문서에서 볼수 있을것이다.

<script>
	function demoDollar_R(){
		var range = $R(10, 20, false);
		range.each(function(value, index){
			alert(value);
		});
	}

</script>

<input type="button" value="Sample Count" onclick="demoDollar_R();" /> 
			

toc

Try.these() 함수 사용하기

Try.these() 함수는 인자처럼 많은 수의 함수를 가지고 그것들을 순서대로 차례차례 호출하도록 해준다. 이것은 함수중에 하나씩 수행하고 성공적인 함수호출의 결과를 반환할때까지 순차적으로 수행된다.

아래의 예제에서 xmlNode.text 함수는 몇몇 브라우저에서 작동하고 xmlNode.textContent는 다른 브라우저에서 작동한다. Try.these()함수를 사용하면 당신은 작동하는 것 중 하나를 반환할수 있다.

<script>
function getXmlNodeValue(xmlNode){
	return Try.these(
		function() {return xmlNode.text;},
		function() {return xmlNode.textContent;}
		);
}
</script>
			

toc

String을 향상시키기

String은 강력한 객체이다. Prototype.js는 그 강력함을 가지고 있으며 다른 방법으로 그 강력함을 향상시킨다.

문자열 대체

문자열 대체를 사용할때 자바스크립트는 이미 String.Replace와 같은 메소드를 제공하고 있다. 정규표현식으로 작동하지만 prototype.js에서 소개한 대체 함수만큼 유연하지는 않다.

새로운 String.gsub 메소드를 사용해보라. 이 메소드를 사용하면 고정 문자열이나 정규 표현식 패턴을 찾고 변경할수 있을 뿐 아니라 교체를 넘어서는 더 많은 제어를 하게 된다. 예를 들어 찾은 요소를 변형하고자 하는 방법을 메소드에 지시하도록 문자열 템플릿을 사용할수 있다.

아래의 예제는 't'를 포함하는 단어를 찾고 그 위치에 'tizzle' 로 변경하는 것이다. 이 예제의 경우 명확하게 설명되지는 않는다. 우리가 선택한 정규 표현식인 괄호안의 \w+은 그룹 선언을 가져온다. 대체 템플릿 문자열로 #{1}를 사용하여 이 그룹에 의해 해당되는 값을 가져올수 있다.

예제에서 우리는 't'앞의 문자들을 가져와서 'tizzle'를 뒤에 붙인다. 정규 표현식으로 더 많은 찾을 수 있다면, #{2}, #{3} 등등을 사용하여 값을 가져올것이다.

<script>
function talkLikeYouKnowSomething(){
	var s = 'prototype string extensions can help you';
	var snoopdogfy = /\b(\w+)t\w+\b/;
	var snooptalk = s.gsub(snoopdogfy, '#{1}tizzle' );
	alert(snooptalk); // shows: "prototizzle stizzle extizzle can help you"				
}
</script>
			

여기서 멈추지 말자. 우리가 만든 대체기능은 패턴에 일치하면 대체하는데 제한되기 때문에 그다지 강력하다고 보기 힘들다. 그렇다면 원하는 대체 값을 만들기 위해 사용자 정의 로직에 일치하는 작업을 할수 있을까.? gsub에 두번째 인자로 함수를 넘길수 있다면 그렇게 할수 있을것이다. 여기서 인자로 넘기는 함수는 일치하는 텍스트를 가진 배열(인덱스값이 0)을 받고 어떤 그룹값(인덱스값이 1에서 N)을 가져올것이다.

<script>
function scamCustomers(){
	var prices = 'book1 $12.5, magazine $5.50, pencil $1.20';
	var priceFinder = /\$([0-9\.]+)/;
	var r = prices.gsub(priceFinder, jackUp);
	alert(r);//shows: "book1 $13.75, magazine $6.05, pencil $1.32"
}
	
function jackUp(matches){
	//increases the prices by 10%
	var price = parseFloat(matches[1]);
   	return '$' + Math.round(110 * price)/100;
}
</script>
			

문자열 템플릿

애플리케이션에 자바스크립트 코드의 양이 증가하는 만큼, increasingly you'll find yourself with collections of objects of the same type and that you need to list or present in a formatted way.

애플리케이션에서 객체 리스트를 통해 루프를 처리하고 객체 프라퍼티와 몇가지 고정된 형태의 요소에 기초하여 문자열을 만드는 코드를 찾는것이 드물게 발생하지는 않는다. Prototype.js는 이러한 타입의 시나리오를 다루는데 도움을 주는 Template class를 가진다.

아래의 예제는 다중 HTML라인에서 장바구니에 있는 항목 리스트를 형상화하는 방법을 보여준다.

<script>
function printCart(){
	//creating a sample cart
	var cart = new Object();
	cart.items = [ ];
	//putting some sample items in the cart
	cart.items.push({product: 'Book 123', price: 24.50, quantity: 1});
	cart.items.push({product: 'Set of Pens', price: 5.44, quantity: 3});
	cart.items.push({product: 'Gift Card', price: 10.00, quantity: 4});
	
	//here we create our template for formatting each item
	var itemFormat = new Template(
			'You are ordering #{quantity} units ' + 
			'of #{product} at $#{price} each'
			);
	var formatted = '';
	
	for(var i=0; i<cart.items.length; i++){
		var cartItem = cart.items[i];
		formatted += itemFormat.evaluate(cartItem) + '<br/>\n';
	}
	
	alert(formatted);
	/* SHOWS:
	You are ordering 1 units of Book 123 at $24.5 each<br/>
	You are ordering 3 units of Set of Pens at $5.44 each<br/>
	You are ordering 4 units of Gift Card at $10 each<br/>
	*/
}
</script>
			

새로운 메소드 목록에 대한 좀더 완전한 정보를 보기 위해서는 문자열 확장 참조를 보라.

toc

Ajax 객체

위에서 언급된 유틸리티 함수들은 좋다. 하지만 다시 보자. 그것들은 대부분 고급(advanced) 형태는 아니다. 당신은 스스로 이것들을 만들수 있고 당신 자신만의 스크립트에 유사한 함수를 이미 가지고 있을수도 있다. 하지만 이러한 함수들은 단지 일부분에 해당되는 팁일뿐이다.

나는 prototype.js에 대한 당신의 관심이 대부분의 AJAX기능을 다룰수 있다는 것이라고 확신한다. 그래서 당신이 AJAX로직을 수행할 필요가 있을때 좀더 쉽게 사용하도록 도와주는 라이브러리를 사용하는 방법을 살펴보자.

AJAX객체는 AJAX함수를 작성할 때 포함되는 트릭성격의 코드를 포장하고 단순화하기 위한 라이브러리에 의해 생성된 미리-정의된 객체이다. 이 객체는 캡슐화된 AJAX로직을 제공하는 많은 수의 클래스를 포함한다. 그 클래스중에 몇개를 살펴보자.

toc

Ajax.Request 클래스 사용하기

만약 당신이 어떠한 헬퍼(helper) 라이브러리도 사용하지 않는다면, 당신은 XMLHttpRequest객체를 생성하기 위한 많은 코드를 작성할 것이고 단계를 비동기적으로 수행할것이다. 그리고나서 응답을 뽑아내고 이것을 처리한다. 그리고나서는 한가지 이상의 브라우저를 지원하지 않는다면 스스로 행운이라고 생각할 것이다.

AJAX기능을 지원하기 위해, 라이브러리는 Ajax.Request클래스를 정의한다.

당신이 다음처럼 XML응답을 반환하는 http://yourserver/app/get_sales?empID=1234&year=1998 url을 통해 서버와 통신할수 있는 애플리케이션을 가지고 있다고 해보자.

<?xml version="1.0" encoding="utf-8" ?> 
<ajax-response>
	<response type="object" id="productDetails">
		<monthly-sales>
			<employee-sales>
				<employee-id>1234</employee-id> 
				<year-month>1998-01</year-month> 
				<sales>$8,115.36</sales> 
			</employee-sales>
			<employee-sales>
				<employee-id>1234</employee-id> 
				<year-month>1998-02</year-month> 
				<sales>$11,147.51</sales> 
			</employee-sales>
		</monthly-sales>
	</response>
</ajax-response>			
			

XML을 가져오기 위해 서버와 통신하는 것은 Ajax.Request객체를 사용하면 매우 간단하다. 아래의 샘플은 이것을 수행하는 방법을 보여준다.

<script>
	function searchSales()
	{
		var empID = $F('lstEmployees');
		var y = $F('lstYears');
		var url = 'http://yourserver/app/get_sales';
		var pars = 'empID=' + empID + '&year=' + y;
		
		var myAjax = new Ajax.Request(
			url, 
			{
				method: 'get', 
				parameters: pars, 
				onComplete: showResponse
			});
		
	}

	function showResponse(originalRequest)
	{
		//put returned XML in the textarea
		$('result').value = originalRequest.responseText;
	}
</script>

<select id="lstEmployees" size="10" onchange="searchSales()">
	<option value="5">Buchanan, Steven</option>
	<option value="8">Callahan, Laura</option>
	<option value="1">Davolio, Nancy</option>
</select>
<select id="lstYears" size="3" onchange="searchSales()">
	<option selected="selected" value="1996">1996</option>
	<option value="1997">1997</option>
	<option value="1998">1998</option>
</select>
<br/><textarea id="result" cols=60 rows=10 ></textarea>
			

Ajax.Request객체 생성자의 두번째 파라미터를 알아보겠는가.? {method: 'get', parameters: pars, onComplete: showResponse} 파라미터는 문자적 표기법으로 익명 객체를 나타낸다. 이것이 의미하는 것은 'get' 문자열을 포함하는 명명된 메소드(method)의 프라퍼티, HTTP요청 문자열을 포함하는 명명된 파라미터(parameter)라는 프라퍼티, 그리고 함수 showResponse를 포함하는 onComplete 프라퍼티/메소드를 가지는 객체를 전달한다는 것이다.

당신이 AJAX를 비동기적으로(asynchronous) 서버에 호출할지를 결정하고 truefalse값으로 셋팅할수 있는 asynchronous(디폴트 값은 true이다.)와 같은 이 객체내 정의하고 활성화시킬수 있는 다른 프라퍼티가 몇개 있다.

이 파라미터는 AJAX호출을 위한 옵션을 정의한다. 샘플에서, 우리는 HTTP GET명령을 통해 첫번째 인자에서 url을 호출한다. 변수 pars내 포함된 조회문자열(querystring)을 전달하고 Ajax.Request객체는 응답을 받아들이는 작업을 마칠때 showResponse함수를 호출할 것이다.

당신이 아는것처럼, XMLHttpRequest는 HTTP호출을 하는 동안 진행과정을 보고한다. 이 진행과정은 4가지의 단계(Loading, Loaded, Interactive, 또는 Complete)를 알릴수 있다. 당신은 이러한 단계중에서 Ajax.Request객체 호출을 사용자정의 함수로 만들수 있다. Complete는 가장 공통적인 단계이다. 함수를 객체에게 알리기 위해, 우리 예제의 onComplete처럼 요청옵션내 onXXXXX로 명명된 프라퍼티/메소드를 간단히 제공하라. 당신이 전달하는 이 함수는 XMLHttpRequest객체 자체가 될 하나의 인자를 가진 객체에 의해 호출될것이다. 당신은 반환 데이터를 얻기 위해 이 객체를 사용할수 있고 아마도 호출의 HTTP결과 코드를 포함할 상태(status) 프라퍼티를 체크할것이다. 몇가지 스크립트나 JSON형태의 데이터를 반환하고자 한다면 X-JSON 헤더가 유용하다.

두개의 다른 흥미로운 옵션은 결과를 처리하기 위해 사용될수 있다. 우리는 AJAX호출이 에러없이 수행될때 호출될 함수처럼 onSuccess옵션을 명시할수 있다. onFailure옵션은 서버에러가 발생할때 호출될 함수가 될수 있다. onXXXXX의 선택적인 함수처럼, 이 두가지는 AJAX호출을 옮기고 X-JSON헤더를 체크하는 XMLHttpRequest를 전달하도록 호출될 것이다.

우리의 샘플은 흥미로운 방법으로 XML응답을 처리하지는 않았다. 우리는 textarea내 XML을 집어넣었다. 응답의 전형적인 사용법은 XML내부에서 바라는 정보를 찾고자 할것이고 몇몇 페이지 요소나 페이지내 HTML을 만드는 몇가지의 XSLT변형을 업데이트할것이다.

1.4.0 버전에서, 이벤트 콜랙 핸들링의 새로운 형태가 소개되었다. 만약 당신이 AJAX호출이 발생하는데도 불구하고 특정 이벤트를 위해 수행되어야 하는 코드를 가지고 있다면, 당신은 새로운 Ajax.Responders 객체를 사용할수 있다.

당신이 AJAX호출이 진행중이라는 시각적 표시를 보여주길 원한다고 해보자. 당신은 두개의 전역 이벤트 핸들러를 사용할수 있다. 하나는 첫번째 호출이 시작되었을때 아이콘을 보여주는것이고 다른 하나는 적어도 하나가 끝났을때 아이콘을 숨기는 것이다. 아래의 예제를 보자.

<script>
	var myGlobalHandlers = {
		onCreate: function(){
			Element.show('systemWorking');
		},

		onComplete: function() {
			if(Ajax.activeRequestCount == 0){
				Element.hide('systemWorking');
			}
		}
	};

	Ajax.Responders.register(myGlobalHandlers);
</script>

<div id='systemWorking'><img src='spinner.gif'>Loading...</div>
	

좀더 완전한 설명을 보기 위해서, Ajax.Request 참조options 참조를 보라..

toc

Ajax.Updater 클래스 사용하기

만약 당신이 HTML로 이미 포맷팅된 정보를 반환할수 있는 서버 종료점(endpoint)을 가진다면, 라이브러리는 당신이 Ajax.Updater클래스를 사용하는것을 좀더 쉽게 만들어준다. 이것으로 당신은 어느 요소가 AJAX호출로부터 반환된 HTML을 채우는지 알리게 된다. 예제는 내가 글로 표현하는 것보다 당신을 좀더 쉽게 이해하도록 도와줄것이다.

<script>
	function getHTML()
	{
		var url = 'http://yourserver/app/getSomeHTML';
		var pars = 'someParameter=ABC';
		
		var myAjax = new Ajax.Updater(
			'placeholder', 
			url, 
			{
				method: 'get', 
				parameters: pars
			});
		
	}
</script>

<input type="button" value="GetHtml" onclick="getHTML()"/>
<div id="placeholder"></div>
			

당신이 보는것처럼, 코드는 onComplete함수와 생성자에 전달된 요소 id를 제외하고 이전예제에 비해서 매우 간단하다. 클라이언트에서 서버 에러들을 다루는 것이 어떻게 가능한지 보기 위해 코드를 조금 변경해 보자.

우리는 호출을 위해 더 많은 옵션을 추가하고 에러 상황을 뽑아내기 위해 함수를 명시한다. 이것은 onFailure옵션을 사용하여 수행한다. 우리는 성공적인 작동의 경우에만 활성화될 묶음자(placeholder)를 명시할것이다. 이것을 달성하기 위해, 우리는 간단한 요소 id에서 두개의 프라퍼티(success-모든것이 정상적일때 사용되는, failure-어떤것이 실패일때 사용되는)를 가지는 객체로 첫번째 파라미터를 변경할 것이다. 우리는 예제에서 failure 프라퍼티를 사용하지 않을것이고, onFailure옵션에서 reportError함수를 사용할것이다.

<script>
	function getHTML()
	{
		var url = 'http://yourserver/app/getSomeHTML';
		var pars = 'someParameter=ABC';
		
		var myAjax = new Ajax.Updater(
					{success: 'placeholder'}, 
					url, 
					{
						method: 'get', 
						parameters: pars, 
						onFailure: reportError
					});
		
	}

	function reportError(request)
	{
		alert('Sorry. There was an error.');
	}
</script>

<input type="button" value="GetHtml" onclick="getHTML()"/>
<div id="placeholder"></div>

			

만약 당신의 서버 로직이 HTML마크업 대신에 자바스크립트 코드를 반환한다면, Ajax.Updater객체는 자바스크립트 코드가 될수 있다. 자바스크립트로 응답을 처리하기 위한 객체를 얻기 위해, 당신은 객체 생성자의 마지막 인자로 프라퍼티들의 목록에 evalScripts: true;를 간단히 추가한다. 하지만 여기엔 문제가 있다. 이러한 스크립트 블럭은 페이지의 스크립트에 추가되지 않을것이다. 옵션이름인 evalScripts이 제시하는것처럼, 스크립트는 평가될것이다. 차이점이 무엇일까.? 요청된 URL이 반환하는 것이 무엇인지 추측해보자.

<script language="javascript" type="text/javascript">
	function sayHi(){
		alert('Hi');
	}
</script>

<input type="button" value="Click Me" onclick="sayHi()"/>
			

이 경우 당신이 이전에 이것을 시도했다면 이것이 작동하지 않는것을 알고 있을것이다. 이유는 스크립트 블럭은 평가될것이고 평가된 스크립트는 sayHi 라는 이름의 함수를 생성하지 않을것이다. 이것은 아무것도 하지 않을것이다. 이 함수를 생성하기 위해, 우리는 함수를 생성하기 위해 변경할 필요가 있다. 아래를 보라.

<script language="javascript" type="text/javascript">
	sayHi = function(){
		alert('Hi');
	};
</script>

<input type="button" value="Click Me" onclick="sayHi()"/>
			

이전 예제에서, 우리는 변수를 선언하기 위해 var 키워드를 사용하지 않았다. 그렇게 하는 것은 스크립트 블럭에 지역화될 함수 객체를 생성할것이다. var 키워드 없이 함수 객체는 window범위에서 작동한다.

좀더 상세한 complete설명을 위해서는, Ajax.Updater 참조문서options 참조문서를 보라.

toc

What are all those "?" and squares?

So you went and wrote some quick test scripts to update your pages using the Ajax.Updater object and it all worked fine. Life was good until you ran your scripts against real data. All of a sudden the updated text was displayed with question marks or unprintable character symbols where the non-English characters should be.

Your first suspect is prototype.js, Of course, it seemed too easy to be true. But don't blame the library just yet. Ask yourself how much you really understand character encoding, code pages, and how the browser deals with it. If you have a positive answer then I bet you are on your way to fix the problem. If you are among the other 80% (another useless, imprecise author's estimate) of web developers that take character encoding for granted, keep reading.

I won't pretend to be an authority on the topic, much less give you a complete explanation of how this is best handled. Instead you go straight to the solution that I use and provide hints on how this could be fixed in your own scenario.

Simply put, the solution revolves around the following statement: Serve what the browser is expecting you to serve. If we are going to update the page with text that contains Unicode/UTF-8 characters then we better make the browser aware of that.

Let's start with the simple case when you are just updating the page with text from a static HTML file that resides on your server. When you created that file, depending on which text editor you employed, it is very possible that the file was saved in ANSI (or better said, non-Unicode) format. This is the default for many text editors, especially source code editors, because the file size will be smaller and it's rather unusual to edit source code with Unicode characters in it.

Suppose you have the following file named static-content.html on your server. You saved this file saved in ANSI format.

<div>
	Hi there, José. Yo no hablo español.
</div>

Your main page updates itself using something like the snippet below.

<script>
	function updateWithFile(){
		var url = 'static-content.html';
		var pars = '';
		var myAjax = new Ajax.Updater(
				'placeholder', url, 
				{method: 'get', parameters: pars});
	}
</script>
<div id="placeholder">(this will be replaced)</div>
<input id="btn" value="Test With Static File" 
                 onclick="updateWithFile()" type="button"/>

When you click the button the static file is retrieved but the non-English characters are replaced by question marks or some other symbol. The displayed text will look similar to "Hi there, Jos?. Yo no hablo espa?ol." or "Hi there, Jos?Yo no hablo espa?", depending on your browser.

In this case, the solution is straightforward, simply save the static file in an appropriate format. Let's save it in UTF-8 and run the script again (any decent text editor will have an option in the Save As dialog.) You should now see the correct text (if not, your browser may have cached the old version, try using a different file name.)

If the HTML that you are serving is not static, if it is being dynamically generated by some application framework (like ASP.NET, PHP, or even Perl,) make sure the code that generates this HTML is producing the text in the appropriate encoding and code page, and include in the HTTP response headers one header that informs this. Each platform has a different way to achieve this, but they are very similar.

For example, in ASP.NET you can set this globally in your web.config file and the default configuration is good enough to avoid this problem in the first place. You should already have the following section in your web.config.

<globalization requestEncoding="utf-8" responseEncoding="utf-8" />

고전적인 ASP 3.0에서 다음의 코드를 사용하여 이 문제를 해결할수 있다.

Response.CodePage = 65001
Response.CharSet = "utf-8" 

PHP에서 응답 헤더를 추가하기 위한 문법은 다음과 같을것이다.

<?php header('Content-Type: text/html; charset=utf-8'); ?>

어떤 경우에는, 당신이 생각하는 목표가 응답 메시지에 다음 HTTP 헤더를 보내는 것이다.

Content-Type: text/html; charset=utf-8 

위 예제에서는 UTF-8을 사용했지만 다른 셋팅이 필요하다면 쉽게 바꿀수 있다.

열거(Enumerating)...

우리는 루프(loop)에 친숙하다. 당신이 알다시피, 배열 자체를 생성하고 같은 종류의 요소로 채운다. 루프 제어구조(이를 테면, foreach, while, repeat 등등)을 생성하고 숫자로 된 인덱스를 통해 순차적으로 각각의 요소에 접근하고 그 요소로 작업을 수행한다.

당신이 이것에 대해 생각할때, 언제나 당신은 코드에 배열을 가지고 루프내 배열을 사용할것이라는것을 의미한다. 이러한 반복을 다루기 위해 좀더 많은 기능을 가진 배열 객체가 있다면 좋지 않겠는가.? 그렇다. 많은 프로그래밍 언어는 배열이나 유사한 구조(collection과 list와 같은)에서 이러한 기능을 제공한다.

prototype.js는 우리에게 반복가능한 데이터를 다룰때 사용하도록 구현된 Enumerable 객체를 제공한다. prototype.js 라이브러리는 더 나아가 Enumerable의 모든 메소드로 Array 클래스를 확장한다

toc

루프, 루비-스타일

표준 자바스크립트에서, 당신이 배열의 요소를 순차적으로 표시하길 원한다면, 당신은 다음처럼 작성할수 있다.

<script>
	function showList(){
		var simpsons = ['Homer', 'Marge', 'Lisa', 'Bart', 'Maggie'];
		for(i=0;i<simpsons.length;i++){
			alert(simpsons[i]);
		}
	}

</script>

<input type="button" value="Show List" onclick="showList();" /> 
			

prototype.js를 사용하면, 다음과 같이 다시 작성할수 있다.


	function showList(){
		var simpsons = ['Homer', 'Marge', 'Lisa', 'Bart', 'Maggie'];
		simpsons.each( function(familyMember){
			alert(familyMember);
		});
	}
			

당신은 특이한 문법으로 별로 좋지않다고 생각할지도 모른다. 위 예제에서, 엉망으로 만드는 것은 아무것도 없다. After all, there's not much to be changed in such a drop-dead-simple example. But keep reading, nonetheless.

each 메소드에 대한 인자처럼 전달되는 이 함수는 보았는가.? iterator 함수처럼 이것을 참조해보자.

toc

스테로이드(steroids)에서 당신의 배열

위에서 언급된것처럼, 이것은 같은 프라퍼티와 메소드를 가지는 배열내 모든 요소를 위해 공통이다. 우리의 새로운 배열을 가지고 iterator함수의 장점을 가질수 있는 방법을 보자.

문법에 따르는 요소를 찾아라.

<script>
	function findEmployeeById(emp_id){
		var listBox = $('lstEmployees')
		var options = listBox.getElementsByTagName('option');
		options = $A(options);
		var opt = options.find( function(employee){
			return (employee.value == emp_id);
		});
		alert(opt.innerHTML); //displays the employee name
	}
</script>

<select id="lstEmployees" size="10" >
	<option value="5">Buchanan, Steven</option>
	<option value="8">Callahan, Laura</option>
	<option value="1">Davolio, Nancy</option>
</select>

<input type="button" value="Find Laura" onclick="findEmployeeById(8);" /> 
			

배열에서 항목을 걸러내는 방법을 보자. 그리고나서 각각의 요소로부터 맴버를 가져온다.

<script>
	function showLocalLinks(paragraph){
		paragraph = $(paragraph);
		var links = $A(paragraph.getElementsByTagName('a'));
		//find links that do not start with 'http'
		var localLinks = links.findAll( function(link){
			//we'll just assume for now that external links
			// do not have a '#' in their url
			return link.href.indexOf('#') >= 0;
		});
		//now the link texts
		var texts = localLinks.pluck('innerHTML');
		//get them in a single string
		var result = texts.inspect();
		alert(result);
	}

</script>
<p id="someText">
	This <a href="http://othersite.com/page.html">text</a> has 
	a <a href="#localAnchor">lot</a> of 
	<a href="#otherAnchor">links</a>. Some are 
	<a href="http://wherever.com/page.html">external</a>
	and some are <a href="#someAnchor">local</a>
</p>
<input type="button" value="Find Local Links" onclick="showLocalLinks('someText')"/>
			

이것은 이 문법에 완전히 빠지도록 하기 위한 몇가지 예제를 가진다. 사용가능한 모든 함수를 위해 Enumerable and Array 참조문서를 보라.

toc

내가 강력하게 추천하는 책들.

다음의 책들은 AJAX애플리케이션을 만들기 위해 요구되는 새로운 스킬을 배우는데 많은 도움을 주었고 이미 알고 있던 스킬을 좀더 탄탄하게 만들어주었다. 나는 좋은 책이 충분히 금적적인 가치를 하고 오랜시간동안 가치를 이어간다고 생각한다.

toc

prototype.js 참조

JavaScript 클래스에 대한 확장

prototype.js라이브러리에 기능을 추가하기 위한 방법중 하나는 현재 존재하는 JavaScript클래스를 확장하는 것이다.

toc

Object 클래스를 위한 확장

메소드 종류 인자 상세설명
extend(destination, source) static destination: 객체, source: 객체 source에서 destination으로 모든 프라퍼티와 메소드를 복사하여 상속을 구현하기 위한 방법을 제공
inspect(targetObj) static targetObj: 객체 targetObj의 사람이 읽을수 있는 문자열 표현으로 반환. 주어진 객체가 inspect 인스턴스 메소드를 정의하지 않는다면, toString 의 값을 반환
keys(targetObj) static targetObj: 객체 모든 프라퍼티의 이름과 주어진 객체의 메소드를 가진 Array를 반환
values(targetObj) static targetObj: 객체 모든 프라퍼티의 값과 주어진 객체의 메소드를 가진 Array를 반환
clone(targetObj) static targetObj: 객체 targetObj의 얕은(shallow) 복사물을 반환

toc

Number 클래스를 위한 확장

메소드 종류 인자 상세설명
toColorPart() instance (none) 숫자의 16진법 표현을 반환. 색상의 RGB컴포넌트를 HTML표현으로 변환할때 유용
succ() instance (none) 다음 숫자를 반환. 이 함수는 반복을 포함하는 시나리오에서 사용된다.
times(iterator) instance iterator: Function(value, index)를 충족하는 함수 객체 인자 valueindex를 반복적으로 전달하는 iterator 함수를 호출하는 것은 iteration과 현재 index내 현재 값을 각각 포함한다.

다음의 예제는 0에서 9까지의 메시지 박스를 표시할것이다.

<script>
	function demoTimes(){
		var n = 10;
		n.times(function(index){
			alert(index);
		});
		/***************************
		 * you could have also used: 
		 *           (10).times( .... ); 
		 ***************************/
	}

</script>

<input type="button" value="Test Number.times()" onclick="demoTimes()"/>
			

toc

Function 클래스를 위한 확장

메소드 종류 인자 상세설명
bind(object [, arg1 [, arg2 [...]]]) instance object: 메소드를 소유하는 객체 함수(=메소드) 소유자 객체로 미리 묶는 함수의 인스턴스를 반환. 반환된 함수는 원래의 것과 같은 인자를 가질것이다.
bindAsEventListener(object [, arg1 [, arg2 [...]]]) instance object: 메소드를 소유하는 객체 유하는 객체 함수(=메소드) 소유자 객체로 미리 묶는 함수의 인스턴스를 반환. 반환된 함수는 이것의 인자로 현재 이벤트 객체를 가질것이다.

실제로 이 확장 중 하나를 보자.

<input type="checkbox" id="myChk" value="1"/> Test?
<script>
	//declaring the class
	var CheckboxWatcher = Class.create();

	//defining the rest of the class implementation
	CheckboxWatcher.prototype = {

	   initialize: function(chkBox, message) {
			this.chkBox = $(chkBox);
			this.message = message;
			//assigning our method to the event
			
			this.chkBox.onclick = 
			   this.showMessage.bindAsEventListener(this, ' from checkbox');
			
	   },

	   showMessage: function(evt, extraInfo) {
		  alert(this.message + ' (' + evt.type + ')' + extraInfo);
	   }
	};


	var watcher = new CheckboxWatcher('myChk', 'Changed');
</script>

			

toc

String 클래스를 위한 확장

메소드 종류 인자 상세설명
camelize() instance (none) -(하이픈)으로 분리된 문자열을 camelCaseString으로 변환하기. 이 함수는 예를 들면, 프라퍼티 스타일을 다루는 코드를 작성할때 유용하다.
capitalize() instance (none) 첫번째 글자를 대문자로 변환
dasherize() instance (none) '_' 기호를 '-' 기호로 대체
escapeHTML() instance (none) HTML마크업 문자들이 escaped된 문자열 반환
evalScripts() instance (none) 문자열내에서 발견되는 각각의 <script />블럭을 평가하기
extractScripts() instance (none) 문자열내에서 발견되는 모든 <script />블럭을 포함하는 Array객체 반환
gsub(pattern, replacement) instance pattern: 검색하는 문자열이나 정규 표현식 replacement: 간단한 문자열, 템플릿 문자열 또는 대체물을 만들기 위한 Function(strings[]) 현재 문자열에서 패턴 문자열을 찾은 결과의 문자열을 반환하고 대체 문자열이나 패턴에 일치하는 문자열을 가진 배열을 전달하는 대체함수를 호출한 결과로 대체한다. 대체물이 문자열일때, #{n}과 같은 특별한 템플릿 형태의 토큰을 포함할수 있다. 여기서 n이라는 값은 정규표현식 그룹의 인덱스이다. #{0}는 완전히 일치하면 대체될것이고 #{1}는 첫번째 그룹, #{2}는 두번째이다.
parseQuery() instance (none) toQueryParams()와 같음.
scan(pattern, replacement) instance pattern: 검색하는 문자열이나 정규 표현식. replacement: 반복을 통해 일치하는지 보는 Function(strings[]) 반복을 통해 문자열이 일치하는 패턴을 찾기 위한 방법을 제공한다. pattern인자는 문자열이나 RegExp가 될수 있지만 RegExp는 좀더 유용하다. 유사하게도 replacement인자는 문자열이나 함수가 될수 있지만 유용한것을 만들수 있도록 함수에 전달하는것이 좋다.
strip() instance (none) 문자열의 앞뒤로 공백 없는 문자열을 반환
stripScripts() instance (none) 삭제된 <script /> 블럭을 가진 문자열을 반환
stripTags() instance (none) HTML이나 XML태그가 삭제된 문자열을 반환
sub(pattern, replacement [, count]) instance pattern: 검색하는 문자열이나 정규 표현식. replacement: 문자열 또는 대체물을 만드는 Function(strings[]) count: 숫자나 대체물 - 디폴트는 1 gsub와 매우 유사하지만 count파라미터로 지정되는 대체물의 수에 제한이 있다
toArray() instance (none) 문자열을 이것의 문자들의 Array로 쪼개기
toQueryParams() instance (none) 쿼리문자열(querystring)을 파라미터 이름에 의해 인덱스화되는 결합된 Array로 쪼개기
truncate(length [, truncation]) instance length: 결과 문자열의 최대 길이 truncation: 결과 문자열의 마지막 글자를 대체하기 위해 사용되는 문자열 - 디폴트는 '...' 최대 길이의 문자열을 만들기 위해 사용. 문자열이 최대 길이를 유지하기 위해 짤릴필요가 있을 경우, truncation인자의 텍스트는 마지막의 몇개의 글자를 대체하기 위해 사용된다. (이를테면.: var s='123456790'; alert(s.truncate(5)); //displays '12...' )
underscore() instance (none) CamelizedStringValue를 uderscore_formatted_string로 변환. (이를테면.: var s='Namespace::MyClass123'; alert(s.underscore()); //displays 'namespace/my_class123' ). 이 함수는 루비 온 레일즈 기능에서 직접 대상이 될것처럼 보인다.
unescapeHTML() instance (none) escapeHTML()의 반대

toc

Array 클래스를 위한 확장

시작하기 위해, ArrayEnumerable를 확장한다. 그래서 Enumerable객체내에 정의되는 모든 편리한 메소드는 사용가능하다. 이것외에도, 아래의 메소드들이 구현되었다.

메소드 종류 인자 상세설명
clear() instance (none) 배열을 비우고 자체를 반환한다.
compact() instance (none) null 이거나 undefined인 요소를 제외하고 배열을 반환한다. 이 메소드는 배열자체를 변경하지 않는다.
first() instance (none) 배열의 첫번째 요소를 반환한다.
flatten() instance (none) 기복이 없고, 1차원의 배열을 반환한다. 이 함수는 배열이고 반환된 배열내 요소를 포함하는 배열의 각 요소를 찾음으로써 수행된다.
indexOf(value) instance value: what you are looking for. 배열에서 찾아진다면 주어진 value의 0부터 시작하는 인덱스의 위치를 반환. value이 없다면 -1을 반환
inspect() instance (none) 요소를 가진 배열의 잘 포맷팅된 문자열 표시를 반환하기 위해 변경
last() instance (none) 배열의 마지막 요소를 반환한다.
reverse([applyToSelf]) instance applyToSelf: 배열 자체가 반전되는지 표시 역순서로 배열을 반환. 인자가 주어지지 않거나 인자가 true라면, 배열자체는 반전될것이다. 그렇지 않으면 변경되지 않고 남는다.
shift() instance (none) 첫번째 요소를 반환하고 배열로부터 이것을 제거한다. 배열의 길이는 1 감소한다.
without(value1 [, value2 [, .. valueN]]) instance value1 ... valueN: 배열내 존재한다면 제외될 값 인자의 리스트에 포함된 요소를 제외한 배열을 반환. 이 메소드는 배열 자체를 변경하지는 않는다.

이 메소드들을 사용하는 것을 보자.

<script>
var A = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
alert(A.inspect()); // "['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']"
var B = A.without('e','f');
alert(B.inspect()); // "['a', 'b', 'c', 'd', 'g', 'h']"
alert(A.inspect()); // did not change A: "['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']"
A.push(null);
A.push('x');
A.push(null);
A.push('y');
alert(A.inspect()); // "['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', null, 'x', null, 'y']"
A = A.compact();
alert(A.inspect()); // "['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'x', 'y']"
var e = A.shift();
alert(e); // "a" 
alert(A.inspect()); // "['b', 'c', 'd', 'e', 'f', 'g', 'h', 'x', 'y']"
alert(A.indexOf('c')); // 1
alert(A.first()); // 'b'
alert(A.last()); // 'y'
A.clear();
alert(A.inspect()); // "[]"
A = ['a', 'b', 'c'];
B = A.reverse(false);
alert(B.inspect()); // "['c', 'b', 'a']"
alert(A.inspect()); // A left untouched: "['a', 'b', 'c']"
A.reverse(true);
alert(A.inspect()); // "['c', 'b', 'a']"	
A = ['a', 'b',  ['c1','c2','c3'] , 'd',  ['e1','e2']  ];
B = A.flatten();
alert(B.inspect()); // "['a','b','c1','c2','c3','d','e1','e2']"		
alert(A.inspect()); // unchanged: "['a','b',['c1','c2','c3'],'d',['e1','e2']]"		
</script>
			

toc

document DOM 객체를 위한 확장

메소드 종류 인자 상세설명
getElementsByClassName(className [, parentElement]) instance className: 요소와 연관된 CSS 클래스 이름, parentElement: 객체 또는 가져올 요소를 포함하는 요소의 객체나 id 주어진 CSS 클래스명과 연관된 모든 요소를 반환. parentElement id가 주어졌다면, 전체 문서가 검색될것이다.

toc

Event 객체를 위한 확장

프라퍼티 타입 상세설명
KEY_BACKSPACE Number 8: 되돌리기(<-) 키를 위한 상수 코드.
KEY_TAB Number 9: 탭키를 위한 상수코드
KEY_RETURN Number 13: 리턴키를 위한 상수코드
KEY_ESC Number 27: Esc키를 위한 상수코드
KEY_LEFT Number 37: 왼쪽 화살표 키를 위한 상수코드
KEY_UP Number 38: 위쪽 화살표 키를 위한 상수코드
KEY_RIGHT Number 39: 오른쪽 화살표 키를 위한 상수코드
KEY_DOWN Number 40: 아래쪽 화살표 키를 위한 상수코드
KEY_DELETE Number 46: Delete키를 위한 상수코드
observers: Array 캐시된 관찰자(observers)의 목록. 상세한 객체의 내부구현의 일부
메소드 종류 인자 상세설명
element(event) static event: Event객체 이벤트를 일으키는 요소를 반환
isLeftClick(event) static event: Event객체 마우스 왼쪽 버튼을 클릭시 true값 반환
pointerX(event) static event: Event객체 페이지에서 마우스 포인터의 x측 좌표값 반환
pointerY(event) static event: Event객체 페이지에서 마우스 포인터의 y측 좌표값 반환
stop(event) static event: Event객체 이벤트의 디폴트 행위를 취소하고 위임을 연기하기 위해 이 함수를 사용
findElement(event, tagName) static event: Event객체, tagName: 원하는 태그명 DOM트리 위쪽으로 가로지른다. 주어진 태그명을 가진 첫번째 요소를 검색한다. 이벤트를 발생시키는 요소로부터 시작한다.
observe(element, name, observer, useCapture) static element: 객체 또는 아이디, name: 이벤트 명 (like 'click', 'load', etc), observer: 이벤트를 다루는 함수, useCapture: true라면, capture내 이벤트를 다루고 false라면 bubbling 내 이벤트를 다룬다. 이벤트를 위한 이벤트 핸들러 함수를 추가
stopObserving(element, name, observer, useCapture) static element: 객체 또는 아이디, name: 이벤트 명 (like 'click'), observer: 이벤트를 다루는 함수, useCapture: true이면, capture내 이벤트를 다루고 false이면 bubbling 내 이벤트를 다룬다. 이벤트로부터 이벤트 핸들러를 제거
_observeAndCache(element, name, observer, useCapture) static   private메소드, 이것에 대해 걱정하지말라
unloadCache() static (none) private메소드, 이것에 대해 걱정하지말라. 메모리로부터 캐시된 모든 관찰자(observer)를 지운다.

window객체의 이벤트를 로그하기 위한 이벤트 핸들러를 추가하는 객체를 사용하는 방법을 보자.

<script>
	Event.observe(window, 'load', page_loaded, false);

	function page_loaded(evt) {
	  Event.observe('parent_node', 'click', item_clicked, false);
	}
	
	function item_clicked(evt){
		var child = Event.element(evt);
		alert('The child node with id=' + child.id + ' was clicked');
		Event.stop(evt); //avoid another call related to 'parent_node' itself
	}
</script>	
...
<div id="parent_node">
	<div id="child1">First</div>
	<div id="child2">Second</div>
	<div id="child3">Third</div>
</div>		
			

toc

prototype.js에 새롭게 정의된 객체와 클래스

라이브러리가 당신을 돕는 다른 방법은 객체지향 디자인과 공통적인 기능을 위한 지원 모두를 구현하는 많은 객체를 제공하는 것이다.

toc

PeriodicalExecuter 객체

이 객체는 주어진 함수를 주어진 시간간격으로 반복적으로 호출하기 위한 로직을 제공한다.

메소드 종류 인자 상세설명
[ctor](callback, interval) constructor callback: 오직 인자로 PeriodcalExecuter 객체 자체가 전달될 함수, interval: 초단위 시간간격 함수를 반복적으로 호출할 이 객체의 하나의 인스턴스를 생성
registerCallback() instance (none) 타이머를 다시 셋팅한다.
stop() instance (none) 타이머를 취소하고 콜백 실행을 하지 않도록 한다.
onTimerEvent() instance (none) 타이머가 호출하는 메소드. 순차적으로 객체 자체를 전달하는 콜백 메소드를 호출할것이다.
프라퍼티 타입 상세설명
callback Function(objExecuter) 호출되기 위한 함수. objExecuter: PeriodcalExecuter가 호출을 만든다.
timer Timer 콜백 메소드를 반복적으로 호출하기 위해 타이머 객체를 다룬다.
frequency Number 이것은 수초내 간격으로 실질적으로 작용
currentlyExecuting Boolean 만약 함수 호출이 진행중이라면 표시

toc

Prototype 객체

Prototype 객체는 사용되는 라이브러리의 버전을 명시하는 것보다 중요한 역활을 가지지 않는다.

프라퍼티 타입 상세설명
Version String 라이브러리의 버전
emptyFunction Function() 비어있는(empty) 함수 객체
K Function(obj) 주어진 파라미터를 되돌리는 함수 객체
ScriptFragment String 스크립트를 확인하는 정규식 표현

toc

Enumerable 객체

Enumerable 객체는 list형태의 구조내에서 항목을 반복하기 위한 좀더 멋진 코드를 작성하는 것을 허용한다.

많은 객체들은 유용한 인터페이스에 영향을 끼치기 위해 Enumerable 을 확장한다.

프라퍼티 타입 상세설명
each(iterator) instance iterator: Function(value, index)를 충족하는 함수 객체 주어진 iterator함수를 호출하는 것은 첫번째 인자내 목록으로 각각의 요소와 두번째 인자내 요소의 인덱스 전달한다
all([iterator]) instance iterator: Function(value, index)를 충족하는 함수 객체(선택사항) 이 함수는 주어진 함수를 사용하여 값들의 전체 집합을 테스트하기 위한 방법이다. iterator 함수가 어떤 요소를 위해 falsenull을 반환한다면, all은 false를 반환할것이다. 그렇지 않다면 true를 반환할것이다. iterator가 주어지지 않는다면, 요소 자체가 falsenull이 아닌지 테스트할것이다. 당신은 "모든 요소가 false가 아닌지 체크한다"와 같이 이것을 읽을수 있다.
any([iterator]) instance iterator: Function(value, index)를 충족하는 함수 객체(선택사항) 이 함수는 주어진 함수를 사용하여 값들의 전체 집합을 테스트하기 위한 방법이다. iterator함수가 어떤 요소를 위해 falsenull을 반환하지 않는다면 anytrue를 반환할것이다. 그렇지 않다면 false를 반환할것이다. iterator가 주어지지 않는다면, 요소 자체가 falsenull이 아닌지 테스트할것이다. 당신은 "어느 요소가 false가 아닌지 체크한다"와 같이 이것을 읽을수 있다.
collect(iterator) instance iterator: Function(value, index)를 충족하는 함수 객체 집합내 각각의 요소를 위한 iterator함수를 호출하고 Array로 각각의 결과를 반환한다. 집합내 각각의 요소를 위한 하나의 결과 요소는 같은 순서이다.
detect(iterator) instance iterator: Function(value, index)를 충족하는 함수 객체 집합내 각각의 요소를 위한 iterator함수를 호출하고 true를 반환하는 iterator함수를 야기하는 첫번째 요소를 반환한다. true를 반환하는 요소가 없다면, detectnull을 반환한다.
entries() instance (none) toArray()와 같다.
find(iterator) instance iterator: Function(value, index)를 충족하는 함수 객체 detect()와 같다.
findAll(iterator) instance iterator: Function(value, index)를 충족하는 함수 객체 집합내 각각의 요소를 위한 iterator함수를 호출하고 true로 해석되는 값을 반환하는 iterator함수를 야기하는 모든 요소를 가진 Array을 반환한다. 이 함수는 reject()와는 반대의 함수이다.
grep(pattern [, iterator]) instance pattern: 요소를 일치시키기 위해 사용되는 RegExp객체, iterator: Function(value, index)를 충족하는 함수 객체 집합내 각각의 요소의 문자열 값을 pattern 정규표현식에 대해 테스트한다. 함수는 정규표현식에 대응되는 모든 요소를 포함하는 Array 를 반환할것이다. iterator함수가 주어진다면, Array는 대응되는 각각의 요소를 가진 iterator를 호출한 결과를 포함할것이다.
include(obj) instance obj: 객체 집합내 주어진 객체를 찾도록 시도한다. 객체가 찾아진다면, true를 반환하고 찾지 못한다면 false를 반환한다.
inGroupsOf(number, fillWith) instance number: 그룹별 타이머의 수, fillWith: 빈 공간을 채울 필요가 있는 값 첫번째 인자로 지정된 만큼의 항목을 포함하는 그룹별 collection을 반환. 초기 collection의 항목수가 첫번째 인자로 주어진 숫자로 나누어지지 않는다면, 마지막 그룹의 끝에 빈 항목이 null로 채워지거나 두번째 인자값으로 채워진다. 예를 들면, ['a','b','c','d'].inGroupsOf(3,'?')[ ['a','b','c'] , ['d','?','?'] ]를 생성한다.
inject(initialValue, iterator) instance initialValue: 초기화 값처럼 사용되는 객체, iterator: Function(accumulator, value, index)를 충족하는 함수 객체 iterator함수를 사용하여 집합의 모든 요소를 조합한다. 호출된 iterator는 accumulator인자에서 이전 반복의 결과를 전달한다. 첫번째 반복은 accumulator인자내 initialValue를 가진다. 마지막 결과는 마지막 반환값이다.
invoke(methodName [, arg1 [, arg2 [...]]]) instance methodName: 각각의 요소내에서 호출될 메소드의 이름, arg1..argN: 메소드 호출로 전달될 인자. 집합의 각각의 요소내 methodName에 의해 명시되는 메소드를 호출하는 것은 주어진 인자(arg1에서 argN) 전달하고 Array객체로 결과를 반환한다.
map(iterator) instance iterator: Function(value, index)를 충족하는 함수 객체 collect()과 같다.
max([iterator]) instance iterator: Function(value, index)를 충족하는 함수 객체 집합내 가장 큰 값이나 iterator가 주어진다면 집합내 각각의 요소를 위한 iterator호출의 가장 큰 결과를 반환한다.
member(obj) instance obj: any object include()와 같다.
min([iterator]) instance iterator: Function(value, index)를 충족하는 함수 객체 집합내 가장 작은 값을 가진 요소나 iterator가 주어진다면 집합내 각각의 요소를 위한 iterator호출의 가장 작은 결과를 가진 요소를 반환한다.
partition([iterator]) instance iterator: Function(value, index)를 충족하는 함수 객체 두개의 다른 배열을 포함하는 Array를 반환한다. 첫번째 배열은 true를 반환하는 iterator함수를 야기하는 모든 요소를 포함할것이고 두번째 배열은 남아있는 요소를 포함할것이다. 만약 iterator가 주어지지 않는다면, 첫번째 배열은 true로 해석하는 요소를 포함할것이고 다른 배열은 남아있는 요소를 포함할것이다.
pluck(propertyName) instance propertyName : 각각의 요소로부터 읽어들이는 프라퍼티의 이름. 이것은 요소의 인덱스를 포함할수 있다 집합의 각각의 요소내 propertyName에 의해 명시된 프라퍼티에 값을 가져가고 Array객체로 결과를 반환한다.
reject(iterator) instance iterator: Function(value, index)를 충족하는 함수 객체 집합내 각각의 요소를 위한 iterator함수를 호출하고 false로 해석하는 값을 반환하는 iterator함수를 야기하는 모든 요소를 가진 Array를 반환한다. 이 함수는 findAll()과는 반대되는 함수이다..
select(iterator) instance iterator: Function(value, index)를 충족하는 함수 객체 findAll()과 같다.
sortBy(iterator) instance iterator: Function(value, index)를 충족하는 함수 객체 iterator함수 호출결과를 따르는 정렬된 모든 요소를 가진 Array을 반환.
toArray() instance (none) 집합의 모든 요소를 가지는 Array를 반환.
zip(collection1[, collection2 [, ... collectionN [,transform]]]) instance collection1 .. collectionN: 병합될 목록, transform: Function(value, index)를 충족하는 함수 객체 현재의 집합으로 각각의 주어진 집합을 병합한다. 이 병합 작업은 같은 수의 요소를 가진 새로운 배열을 반환한다. 현재 집합과 각각의 요소가 각각의 병합된 집합으로부터 같은 인덱스를 가진 요소의 배열(이것을 하위 배열이라고 부르자.)이다. transform함수가 주어진다면, 각각의 하위 배열은 반환되기 전에 이 함수에 의해 변형딜것이다. 빠른 예제 : [1,2,3].zip([4,5,6], [7,8,9]).inspect() 는 "[[1,4,7],[2,5,8],[3,6,9] ]" 를 반환한다.

toc

Hash 객체

Hash 객체는 hash구조를 구현한다. 이를테면, Key:Value쌍의 집합.

Hash객체내 각각의 항목은 두개의 요소(첫번째는 key, 두번째는 value)를 가진 배열이다. 각각의 항목은 두개의 프라퍼티(keyvalue)를 가진다.

메소드 종류 인자 상세설명
keys() instance (none) 모든 항목의 key를 가진 Array을 반환
values() instance (none) 모든 항목의 value를 가진 Array을 반환
merge(otherHash) instance otherHash: Hash object hash와 전달된 다른 hash를 조합하고 새로운 결과 hash를 반환
toQueryString() instance (none) 쿼리 문자열처럼 포맷팅된 문자열로 hash의 모든 항목을 반환. 이를테면 'key1=value1&key2=value2&key3=value3'
inspect() instance (none) key:value쌍을 가진 hash의 포맷팅된 문자열 표현을 반환하기 위해 변경(오버라이드)

toc

ObjectRange 클래스

Enumerable으로부터 상속

상위 경계나 하위 경계로 값들의 범위를 표시

프라퍼티 타입 종류 상세설명
start (any) instance 범위의 시작값
end (any) instance 범위의 마지막값
exclusive Boolean instance 경계자체가 범위의 일부인지 판단
메소드 종류 인자 상세설명
[ctor](start, end, exclusive) constructor start: 시작값, end: 마지막값, exclusive: 경계가 범위내 포함되는가.? 하나의 range객체를 생성한다. start 에서 end로 범위를 지정한다. startend가 같은 타입의 객체이고 succ()메소드를 가져야만 한다.
include(searchedValue) instance searchedValue: 검색할 값 주어진 값이 범위내 값인지 체크. truefalse값을 반환한다.

toc

Class 객체

Class 객체는 라이브러리에서 다른 클래스를 선언할때 사용된다. 클래스를 선언할때 이 객체를 사용하는 것은 생성자로 제공되는 initialize()메소드를 지원하기 위한 새로운 클래스를 발생시킨다.

아래의 샘플을 보라.

//declaring the class
var MySampleClass = Class.create();

//defining the rest of the class implementation
MySampleClass.prototype = {

   initialize: function(message) {
		this.message = message;
   },

   showMessage: function(ajaxResponse) {
      alert(this.message);
   }
};	

//now, let's instantiate and use one object
var myTalker = new MySampleClass('hi there.');
myTalker.showMessage(); //displays alert

			
메소드 종류 인자 상세설명
create(*) instance (any) 새로운 클래스를 위한 생성자를 정의

toc

Ajax 객체

이 객체는 AJAX기능을 제공하는 많은 다른 클래스를 위한 root와 명명공간(namespace)처럼 제공한다.

프라퍼티 타입 종류 상세설명
activeRequestCount Number instance 진행중인 AJAX요청의 수.
메소드 종류 인자 상세설명
getTransport() instance (none) 새로운 XMLHttpRequest 객체를 반환

toc

Ajax.Responders 객체

Enumerable 로 부터 상속되었다

이 객체는 Ajax관련 이벤트가 발생할때 호출될 객체의 목록을 보존한다. 예를 들어, 당신이 AJAX작업을 위한 전역 예외 핸들러를 연결하길 원한다면 이 객체를 사용할수 있다.

프라퍼티 타입 종류 상세설명
responders Array instance 객체의 목록은 AJAX이벤트 알림(notifications)을 위해 등록되었다.
메소드 종류 인자 상세설명
register(responderToAdd) instance responderToAdd: 호출될 메소드를 가진 객체. responderToAdd인자를 전달하는 객체는 AJAX이벤트(이를테면, onCreate, onComplete, onException 등등)처럼 명명된 메소드를 포함해야만 한다. 유사한 이벤트가 발생하면, 적절한 이름을 가진 메소드를 포함하는 모든 등록된 객체가 호출되는 메소드를 가질것이다.
unregister(responderToRemove) instance responderToRemove: list로부터 제거될 객체 responderToRemove 인자로 전달되는 객체는 등록된 객체의 list로부터 제거될것이다.
dispatch(callback, request, transport, json) instance callback: 보고되는 AJAX이벤트 이름, request: 이벤트를 책임지는 the Ajax.Request 객체, transport: AJAX호출을 가지는 XMLHttpRequest 객체, json: 응답의 X-JSON 헤더(존재할때만) 등록된 객체의 목록을 통해 실행하는 것은 callback 인자내 결정된 메소드를 가지는 것을 찾는다. 호출되는 각각의 메소드는 다른 3개의 인자를 전달한다. AJAX응답이 몇몇 JSON컨텐츠를 가지는 X-JSON HTTP 헤더를 포함한다면, 이것은 평가되고 json인자로 전달될것이다. 만약 이벤트가 onException라면, transport인자는 대신에 예외를 가질것이고 json은 전달되지 않을것이다.

toc

Ajax.Base 클래스

이 클래스는 Ajax객체내 정의된 다른 대부분의 클래스를 위한 기본(base)클래스처럼 사용된다.

메소드 종류 인자 상세설명
setOptions(options) instance options: AJAX 옵션 AJAX작업을 위해 필요한 옵션 셋팅
responseIsSuccess() instance (none) 만약 AJAX작업이 성공한다면 true를 반환하고, 실패한다면 false를 반환
responseIsFailure() instance (none) responseIsSuccess()와는 반대.

toc

Ajax.Request 클래스

Ajax.Base로 부터 상속

AJAX 작업을 캡슐화

프라퍼티 타입 종류 상세설명
Events Array static AJAX작업중 보고되는 가능한 이벤트/상태의 목록. 목록은 'Uninitialized', 'Loading', 'Loaded', 'Interactive', 그리고 'Complete.'를 포함한다.
transport XMLHttpRequest instance AJAX작업을 가지는 XMLHttpRequest 객체
url String instance 요청에 의해 대상이 되는 URL
메소드 종류 인자 상세설명
[ctor](url, options) constructor url: 꺼내기 위한 url, options: AJAX 옵션 주어진 옵션을 사용하여 주어진 url을 호출할 이 객체의 하나의 인스턴스를 생성. 중요사항: 선택된 url은 브라우저의 보안 셋팅을 위한 대상이 될 가치가 없다. 많은 경우 브라우저는 현재 페이지처럼 같은 호스트로부터가 아니라면 url을 가져오지 않을것이다. 당신은 설정을 피하거나 사용자의 브라우저를 제한하기 위한 로컬 url만을 사용할 것이다.
evalJSON() instance (none) 이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 AJAX응답내 존재하는 X-JSON HTTP헤더의 컨텐츠를 평가하기 위해 내부적으로 호출된다.
evalResponse() instance (none) 이 메소드는 대개 외부적으로 호출되지 않는다. AJAX응답이 text/javascriptContent-type헤더를 가진다면, 응답 몸체는 평가되고 이 메소드는 사용될것이다.
header(name) instance name: HTTP header name 이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 AJAX응답의 HTTP헤더의 컨텐츠를 가져오기 위해 내부적으로 호출된다.
onStateChange() instance (none) 이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 AJAX호출 상태 변경시 객체 자체에 의해 호출된다.
request(url) instance url: url for the AJAX call 이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 생성자를 호출하는 동안 벌써 호출되었다.
respondToReadyState(readyState) instance readyState: 상태 숫자값(1 에서 4) 이 메소드는 대개 외부에서 호출되지 않는다. 이것은 AJAX호출 상태가 변경될때 객체 자체에 의해 호출된다.
setRequestHeaders() instance (none) 이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 HTTP요청을 하는 동안 보내어질 HTTP헤더를 조합하기 위한 객체 스스로에 의해 호출된다.

toc

options 인자 객체

AJAX작업의 중요한 부분은 options 인자이다. 이것은 기대되는 프라퍼티를 가지는 동안 어떠한 객체도 전달될수 있다. 이것은 AJAX호출을 위해 익명 객체를 생성하는 것이 공통적이다.

프라퍼티 타입 디폴트 상세설명
method String 'post' HTTP요청의 메소드
parameters String '' 요청에 전달한 값들의 url형태의 목록
asynchronous Boolean true AJAX호출이 비동기적으로 만들어지는지 표시
postBody String undefined HTTP POST의 경우 요청의 몸체내 전달되는 내용
requestHeaders Array undefined 요청과 함께 전달되기 위한 HTTP헤더의 목록. 이 목록은 많은 수의 항목을 가져야 한다. 나머지 항목은 사용자 정의 헤더의 이름이다. 그리고 다음의 항목은 헤더의 문자열 값이다. 예제 : ['my-header1', 'this is the value', 'my-other-header', 'another value']
onXXXXXXXX Function(XMLHttpRequest, Object) undefined 각각의 이벤트/상태가 AJAX호출이 발생하는 동안 도착할때 호출될 사용자정의 함수. 이 옵션에는 "XXXXXXXX"를 위해 Ajax.Request.Events, 와 HTTP status codes의 상태중에 다양한 대안이 있다. 예를 들어 var myOpts = {onComplete: showResponse, onLoaded: registerLoaded};. 사용되는 함수는 AJAX작업과 평가된 X-JSON응답 HTTP헤더를 포함하는 인자를 가지는 XMLHttpRequest객체를 포함하는 하나의 인자를 받을것이다.
onSuccess Function(XMLHttpRequest, Object) undefined AJAX호출이 성공적으로 완성될때 호출될 사용자정의 함수. 사용되는 함수는 AJAX작업을 가지는 XMLHttpRequest객체를 포함하는 하나의 인자를 받을것이다.
onFailure Function(XMLHttpRequest, Object) undefined AJAX호출이 에러를 가진채 끝날때 호출될 사용자정의 함수. 사용되는 함수는 AJAX작업을 가지는 XMLHttpRequest객체를 포함하는 하나의 인자를 받을것이다.
onException Function(Ajax.Request, exception) undefined 유효하지 않은 응답이나 유효하지 않은 인자와 같이 예외적인 조건이 클라이언트 측 AJAX호출에서 발생했을때 호출될 사용자정의 함수. 사용된 함수는 AJAX작업을 포장하는 Ajax.Request 객체와 exception객체를 포함하는 두개의 인자를 받을것이다.
insertion an Insertion class undefined 새로운 내용이 삽입될 방법을 판단할 클래스. Insertion.Before, Insertion.Top, Insertion.Bottom, 또는 Insertion.After가 될수 있다. Ajax.Updater객체에만 적용한다.
evalScripts Boolean undefined, false 스크립트 블럭이 응답이 도착했을때 평가할지를 판단. Ajax.Updater객체에만 적용 objects.
decay Number undefined, 1 Ajax.PeriodicalUpdater 객체는 받은 응답이 마지막 것과 같을때 비율을 새롭게 하여 연속적인 후퇴를 결정. 예를 들어, 당신이 2를 사용한다면, 새롭게 된것중에 하나가 이전것과 같은 결과를 만든후에, 객체는 다음 refresh를 위한 시간의 두배를 기다릴것이다. 이것은 다시 반복한다면, 객체는 4배를 기다릴것이다. 이것을 후퇴를 피하기 위해 정의되지 않거나 1을 사용하도록 남겨두라.
frequency Number undefined, 2 초단위의 갱신간격(횟수가 아닌), Ajax.PeriodicalUpdater객체에만 적용.

toc

Ajax.Updater 클래스

Ajax.Request로 부터 상속

요청된 url이 당신 페이지의 특정 요소내 직접적으로 삽입하길 원하는 HTML을 반환할때 사용된다. 당신은 url이 도착을 평가할 <script>블럭을 반환할때 이 객체를 사용할수 있다. 스크립트로 작업하기 위해 evalScripts 옵션을 사용하라.

프라퍼티 타입 종류 상세설명
containers Object instance 이 객체는 두개의 프라퍼티(containers.success 는 AJAX호출이 성공할때 사용될것이다. 그리고 AJAX호출이 실패한다면 containers.failure가 사용될것이다.)를 포함한다.
메소드 종류 인자 상세설명
[ctor](container, url, options) constructor container: 이것은 요소의 id, 요소객체 자체, 또는 두개의 프라퍼티(AJAX호출이 성공했을때 사용될 object.success 요소(또는 id), 그리고 AJAX호출이 실패했을때 사용될 object.failure요소(또는 id))를 가지는 객체가 될수 있다. url: 가져오기 위한 url, options: AJAX 옵션 주어진 옵션을 사용하여 주어진 url을 호출할 이 객체의 하나의 인스턴스를 생성.
updateContent() instance (none) 이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 응답을 받았을때 객체 자체에 의해 호출된다. 이것은 HTML로 적절한 요소를 수정하거나 insertion옵션내 전달되는 함수를 호출할것이다. 이 함수는 두개의 인자(수정되기 위한 요소와 응답 텍스트)를 가지고 호출될것이다.

toc

Ajax.PeriodicalUpdater 클래스

Ajax.Base로 부터 상속

이 클래스는 반복적으로 인스턴스화하고 페이지에서 요소를 새롭게 하거나 Ajax.Updater가 수행할수 있는 다른 작업중 어느것을 수행하기 위한 Ajax.Updater객체를 사용한다. 좀더 많은 정보를 위해 Ajax.Updater 참조를 체크하라.

프라퍼티 타입 종류 상세설명
container Object instance 이 값은 Ajax.Updater생성자에 일관적으로 전달될것이다.
url String instance 이 값은 Ajax.Updater의 생성자에 일관적으로 전달될것이다.
frequency Number instance 초단위의 refresh간격. 디폴트는 2초. 이 숫자는 Ajax.Updater 객체를 호출할때 현재 축소(decay)에 의해 곱해질것이다.
decay Number instance 작업을 재-수행할때 적용될 축소(decay)레벨을 유지
updater Ajax.Updater instance 가장 최신에 사용된 Ajax.Updater 객체
timer Object instance 다른 refresh를 위한 시각일때 객체를 알리기 위해 사용되는 자바스크립트 타이머.
메소드 종류 인자 상세설명
[ctor](container, url, options) constructor container:이것은 요소의 id, 요소객체 자체, 또는 두개의 프라퍼티(AJAX호출이 성공할때 사용될 object.success 요소(나 id), AJAX호출이 실패할때 사용할 object.failure 요소(나 id))를 가지는 객체가 될수 있다. url: 가져오기 위한 url, options: AJAX 옵션 주어진 옵션을 사용하여 주어진 url을 호출할 이 객체의 하나의 인스턴스를 생성
start() instance (none) 이 메소드는 대개 외부적으로 호출되지 않는다. 이것의 정기적인 작업 수행을 시작하기 위해 객체 자체에 의해 호출된다.
stop() instance (none) 주기를 가지는 작업 수행을 종료하도록 한다. 종료후, 객체는 onComplete 옵션에 주어진 콜백을 호출할것이다.
updateComplete() instance (none) 이 메소드는 대개 외부적으로 호출되지 않는다. 요청을 완성한 후에 사용되는 Ajax.Updater에 의해 호출된다. 이것은 다음 refresh스케줄링 하기 위해 사용된다.
onTimerEvent() instance (none) 이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 다음 수정을 위한 시각일때 내부적으로 호출된다.

toc

Element 객체

이 객체는 DOM내 요소를 변경하기 위해 몇몇 유틸리티성 함수들을 제공한다.

메소드 종류 인자 상세설명
addClassName(element, className) instance element: element 객체 또는 아이디, className: CSS 클래스명 주어진 class명을 요소의 class명으로 추가
classNames(element) instance element: element 객체 또는 아이디 주어진 element와 관련된 CSS 클래스명을 표시하는 Element.ClassNames 객체를 반환
cleanWhitespace(element) instance element: element 객체 또는 아이디 요소의 자식노드에서 공백을 제거
empty(element) instance element: element 객체 또는 아이디 element태그가 비어있는지(또는 공백만을 가지고 있는지) 표시하는 Boolean값을 반환
getDimensions(element) instance element: element 객체 또는 아이디 element의 면적(dimensions)을 반환. 반환된 값은 두개의 프라퍼티(heightwidth)를 가지는 객체이다.
getHeight(element) instance element: element 객체 또는 아이디 요소의 offsetHeight값을 반환
getStyle(element, cssProperty) instance element: element 객체 또는 아이디, cssProperty : CSS프라퍼티('prop-name' 또는 'propName' 가 작동하는 형태)의 이름 주어진 element내 CSS프라퍼티의 값을 반환하거나 존재하지 않는다면 null 을 반환
hasClassName(element, className) instance element: element 객체 또는 아이디, className: CSS 클래스명 요소가 class명중에 하나로 주어진 class명을 가진다면 true를 반환
hide(element) instance element: element 객체 또는 아이디 style.display'none'로 셋팅하여 각각의 요소를 숨긴다.
makeClipping(element) instance element: element 객체 또는 아이디
makePositioned(element) instance element: element 객체 또는 아이디 element의 style.position'relative'로 변경
remove(element) instance element: element 객체 또는 아이디 문서로 부터 요소를 제거한다.
removeClassName(element, className) instance element: element 객체 또는 아이디, className: CSS 클래스명 요소의 class명으로 부터 주어진 class명을 제거
scrollTo(element) instance element: element 객체 또는 아이디 창을 element위치로 스크롤
setStyle(element, cssPropertyHash) instance element: element 객체 또는 아이디, cssPropertyHash : 적용되기 위한 스타일을 가지는 Hash객체 cssPropertyHash 인자내 값에 따라, 주어진 element내 CSS프라퍼티의 값을 셋팅.
show(element) instance element: element 객체 또는 아이디 style.display''로 다시 셋팅하여 각각의 요소를 보여준다.
toggle(element) instance element: element 객체 또는 아이디 각각의 전달된 요소의 가시성(visibility)을 토글(toggle)한다.
undoClipping(element) instance element: element 객체 또는 아이디
undoPositioned(element) instance element: element 객체 또는 아이디 element의 style.position''으로 초기화
update(element, html) instance element: element 객체 또는 아이디, html: html content 주어진 html인자를 가지는 요소의 내부 html을 대체. 주어진 html이 <script>블럭을 포함한다면, 그것들은 포함되지는 않지만 평가될것이다.
visible(element) instance element: element 객체 또는 아이디 요소가 눈에 보이는지 표시하는 Boolean값을 반환

toc

Element.ClassNames 클래스

Enumerable로 부터 상속

element에 관련된 CSS 클래스명의 collection을 표시

메소드 종류 인자 상세설명
[ctor](element) constructor element: any DOM element 객체 또는 아이디 주어진 element의 CSS 클래스명을 표시하는 Element.ClassNames 객체를 생성
add(className) instance className: CSS 클래스 명 element에 관련된 class명의 리스트에 주어진 CSS 클래스명을 추가
remove(className) instance className: CSS 클래스 명 element에 관련된 class명의 리스트로부터 주어진 CSS 클래스명을 제거
set(className) instance className: CSS 클래스 명 주어진 CSS 클래스명을 가진 element을 결합, element로부터 다른 class명을 제거.

toc

Abstract 객체

이 객체는 라이브러리내 다른 클래스를 위한 root처럼 제공한다. 이것은 어떤 프라퍼티나 메소드도 가지지 않는다. 이 객체에 정의된 클래스는 전통적인 추상 클래스처럼 처리된다.

toc

Abstract.Insertion 클래스

이 클래스는 동적으로 내용물을 추가할 다른 클래스를 위한 기본 클래스처럼 사용된다. 이 클래스는 추상 클래스처럼 사용된다.

메소드 종류 인자 상세설명
[ctor](element, content) constructor element: element 객체 또는 아이디, content: 삽입되는 HTML 동적 내용물 삽입을 도울 객체를 생성
contentFromAnonymousTable() instance (none)
프라퍼티 타입 종류 상세설명
adjacency String static, parameter 내용물이 주어진 요소에 대해 상대적으로 위치할 지점을 명시하는 파라미터. 가능한 값은 'beforeBegin', 'afterBegin', 'beforeEnd', 그리고 'afterEnd'.
element Object instance 삽입이 상대적으로 만들어질 요소객체
content String instance 삽입될 HTML

toc

Insertion 객체

이 객체는 라이브러리내 다른 클래스를 위한 root처럼 제공한다. 이것은 어떠한 프라퍼티나 메소드를 가지지 않는다. 이 객체에 정의된 클래스는 전통적인 추상 클래스처럼 처리된다.

toc

Insertion.Before 클래스

Abstract.Insertion로 부터 상속

요소 앞에 HTML삽입

메소드 종류 인자 상세설명
[ctor](element, content) constructor element: element 객체 또는 아이디, content: 삽입되는 HTML Abstract.Insertion으로 부터 상속. 동적으로 내용물을 삽입하는 것을 돕는 객체를 생성

다음의 코드는

<br/>Hello, <span id="person" style="color:red;">Wiggum. How's it going?</span>

<script> new Insertion.Before('person', 'Chief '); </script>
			

다음처럼 HTML이 변경될것이다.


<br/>Hello, Chief <span id="person" style="color:red;">Wiggum. How's it going?</span>	
			

toc

Insertion.Top 클래스

Abstract.Insertion로 부터 상속

요소아래의 첫번째 자식으로 HTML을 삽입. 이 내용물은 요소의 열기 태그뒤에 위치할것이다.

메소드 종류 인자 상세설명
[ctor](element, content) constructor element: element 객체 또는 아이디, content: 삽입되는 HTML Abstract.Insertion으로부터 상속. 동적으로 내용물을 삽입하는 것을 돕는 객체 생성

다음의 코드는

<br/>Hello, <span id="person" style="color:red;">Wiggum. How's it going?</span>

<script> new Insertion.Top('person', 'Mr. '); </script>
			

다음처럼 HTML이 변경될것이다.

<br/>Hello, <span id="person" style="color:red;">Mr. Wiggum. How's it going?</span>	
			

toc

Insertion.Bottom 클래스

Abstract.Insertion로 부터 상속

요소아래의 마지막 자식으로 HTML삽입. 내용물은 요소의 닫기 태그앞에 위치할것이다.

메소드 종류 인자 상세설명
[ctor](element, content) constructor element: element 객체 또는 아이디, content: 삽입되는 HTML Abstract.Insertion로 부터 상속. 동적으로 내용물을 삽입하는 것을 돕는 객체 생성

다음의 코드는

<br/>Hello, <span id="person" style="color:red;">Wiggum. How's it going?</span>

<script> new Insertion.Bottom('person', " What's up?"); </script>
			

다음처럼 HTML이 변경될것이다.

<br/>Hello, <span id="person" style="color:red;">Wiggum. How's it going? What's up?</span>	
			

toc

Insertion.After 클래스

Abstract.Insertion로 부터 상속

요소의 닫기 태그뒤 HTML삽입

메소드 종류 인자 상세설명
[ctor](element, content) constructor element: element 객체 또는 아이디, content: 삽입되는 HTML Abstract.Insertion으로부터 상속. 동적으로 내용물을 삽입하는 것을 돕는 객체 생성

다음의 코드는

<br/>Hello, <span id="person" style="color:red;">Wiggum. How's it going?</span>

<script> new Insertion.After('person', ' Are you there?'); </script>
			

다음처럼 HTML이 변경될것이다.

<br/>Hello, <span id="person" style="color:red;">Wiggum. How's it going?</span> Are you there?	
			

toc

Field 객체

This object provides some utility functions for working with input fields in forms.

메소드 종류 인자 상세설명
activate(field) instance field: field element 객체 또는 아이디 포커스를 이동하고 텍스트 선택을 지원하는 field내 값을 선택
clear(field) instance field: field element 객체 또는 아이디 field요소로부터 각각 전달된 값을 지움(clear)
disable(field) instance field: field element 객체 또는 아이디 폼 필드 요소를 사용하지 못하도록 만든다. 요소 객체를 반환한다.
enable(field) instance field: field element 객체 또는 아이디 폼 필드 요소를 사용가능하도록 만든다. 요소 객체를 반환한다.
focus(field) instance field: field element 객체 또는 아이디 주어진 폼 field로 입력 포커스 이동
getValue(field) instance field: field element 객체 또는 아이디 필드에 입력되거나 선택된 값을 반환한다.
present(field) instance field: field element 객체 또는 아이디 모든 폼 field가 빈값이 아니라면 true를 반환
select(field) instance field: field element 객체 또는 아이디 텍스트 선택을 지원하는 field내 값을 선택

toc

Form 객체

이 객체는 데이터 항목 폼과 그것들의 입력 field와 작동하기 위한 몇몇 유틸리티성 함수를 제공한다.

메소드 종류 인자 상세설명
serialize(form) instance form: form element 객체 또는 아이디 'field1=value1&field2=value2&field3=value3'처럼 field명과 값의 url형태의 목록을 반환
findFirstElement(form) instance form: form element 객체 또는 아이디 form에서 첫번째로 사용가능한 필드 element를 반환
getElements(form) instance form: form element 객체 또는 아이디 폼내 모든 입력 field를 포함하는 Array 반환
getInputs(form [, typeName [, name]]) instance form: form element 객체 또는 아이디, typeName: input요소의 타입, name: input요소명. 폼내 모든 <input>요소를 포함하는 Array 반환. 선택적으로 목록은 요소의 type이나 name속성에 의해 필터링 될수 있다.
disable(form) instance form: form element 객체 또는 아이디 폼내 모든 입력 field를 사용불가상태로 만들기
enable(form) instance form: form element 객체 또는 아이디 폼내 모든 입력 field를 사용가능하게 만들기
focusFirstElement(form) instance form: form element 객체 또는 아이디 첫번째 가시성을 활성화하고, 폼내 입력 field를 가능하게 하기
reset(form) instance form: form element 객체 또는 아이디 폼을 리셋하기. form객체의 reset()메소드와 같다.

toc

Form.Element 객체

이 객체는 폼요소와 작동하기 위한 몇몇 유틸리티성 함수를 제공한다.

메소드 종류 인자 상세설명
serialize(element) instance element: element 객체 또는 아이디 'elementName=elementValue'처럼 요소의 name=value 짝을 반환
getValue(element) instance element: element 객체 또는 아이디 요소의 값을 반환

toc

Form.Element.Serializers 객체

이 객체는 폼요소의 현재 값을 가져오기 위해 라이브러리 내부적으로 사용되는 몇몇 유틸리티성 함수를 제공한다.

메소드 종류 인자 상세설명
inputSelector(element) instance element: radio 버튼이나 checkbox처럼 checked프라퍼티를 가지는 form요소의 객체 또는 아이디 ['elementName', 'elementValue']처럼 요소의 이름과 값을 가지는 Array을 반환
textarea(element) instance element: textbox, button 또는 password필드처럼 value프라퍼티를 가지는 form요소의 객체 또는 아이디. ['elementName', 'elementValue']처럼 요소의 이름과 값을 가지는 Array를 반환
select(element) instance element: <select> 요소의 객체 또는 아이디 ['elementName', 'selOpt1 selOpt4 selOpt9']처럼 요소의 이름과 모든 선택된 옵션의 값이나 텍스트를 가지는 Array를 반환

toc

Abstract.TimedObserver 클래스

이 클래스는 값이 변경(또는 프라퍼티가 클래스정의를 얻어내는)될때까지 하나의 요소를 모니터링할 다른 클래스를 위한 기본클래스처럼 사용된다. 이 클래스는 추상클래스처럼 사용된다.

하위클래스는 요소의 입력값, style프라퍼티중 하나, 또는 테이블내 row의 수, 또는 당신이 추적하고자 하는 모든것을 모니터링하기 위해 생성될수 있다.

메소드 종류 인자 상세설명
[ctor](element, frequency, callback) constructor element: element 객체 또는 아이디, frequency: 초단위 간격, callback: 요소가 변경될때 호출되는 함수 요소를 모니터링할 객체 생성
getValue() instance, abstract (none) 클래스는 요소에서 모니터링이 되는 현재값이 무엇인지 판단하기 위햔 메소드를 구현해야만 한다.
registerCallback() instance (none) 이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 요소 모니터링릉 시작하기 위한 객체 자체에 의해 호출된다.
onTimerEvent() instance (none) 이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 요소를 체크하기 위해 정기적으로 객체 자체에 의해 호출된다.
Property Type Description
element Object 모니터링되는 요소객체.
frequency Number 이것은 체크사이에 초단위 간격으로 이루어진다.
callback Function(Object, String) 요소가 변경될때마다 호출되기 위한 함수. 이것은 요소객체와 새로운 값을 받을것이다.
lastValue String 요소내 확인되는 마지막 값

toc

Form.Element.Observer 클래스

Abstract.TimedObserver로 부터 상속

폼 입력 요소의 값을 모니터링하는 Abstract.TimedObserver의 구현물. 값 변경을 보고하는 이벤트를 드러내지 않는 요소를 모니터링하고자 할때 이 클래스를 사용하라. 이 경우 당신은 Form.Element.EventObserver 클래스를 대신 사용할수 있다.

메소드 종류 인자 상세설명
[ctor](element, frequency, callback) constructor element: element 객체 또는 아이디, frequency: 초단위 간격, callback: 요소가 변경될때 호출되는 함수 Abstract.TimedObserver으로부터 상속. 요소의 value프라퍼티를 모니터링할 객체를 생성.
getValue() instance (none) 요소의 값을 반환

toc

Form.Observer 클래스

Abstract.TimedObserver로 부터 상속

폼내 데이터 항목 요소의 값이 변경하는지를 모니터링하는 Abstract.TimedObserver의 구현물. 당신이 값 변경을 보고하는 이벤트를 드러내지 않는 요소를 포함하는 폼을 모니터링하고자 할때 이 클래스를 사용하라. 이 경우 당신은 Form.EventObserver 클래스를 대신 사용할수 있다.

메소드 종류 인자 상세설명
[ctor](form, frequency, callback) constructor form: form 객체 또는 아이디, frequency: 초단위 간격, form내 데이터 항목 요소가 변경될때 호출되는 콜백 함수 Abstract.TimedObserver로부터 상속. 변경하기 위한 폼을 모니터링할 객체 생성.
getValue() instance (none) 모든 폼의 데이터의 직렬화를 반환

toc

Abstract.EventObserver 클래스

이 클래스는 요소를 위해 값-변경 이벤트가 발생할때마다 콜백함수를 수행하는 다른 클래스를 위한 기본 클래스처럼 사용된다.

Abstract.EventObserver 타입의 다중 객체는 다른것을 지우지 않고 같은 요소로 묶일수 있다. 콜백은 요소에 할당되는 순서대로 수행될것이다.

트리거 형태의 이벤트는 radio버튼과 checkbox를 위해서는 onclick이고 대개의 textbox와 리스트박스/드랍다운을 위해서는 onchange이다.

메소드 종류 인자 상세설명
[ctor](element, callback) constructor element: element 객체 또는 아이디, callback: function to be called when the event happens 요소를 모니터링할 객체 생성.
getValue() instance, abstract (none) 클래스는 요소에서 모니터링이 되는 현재값이 무엇인지 판단하기 위햔 메소드를 구현해야만 한다.
registerCallback() instance (none) 이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 요소의 이벤트를 자체적으로 묶는 객체에 의해 호출된다.
registerFormCallbacks() instance (none) 이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 폼내 각각의 데이터 항목 요소의 이벤트로 자체적으로 묶기 위한 객체에 의해 호출된다.
onElementEvent() instance (none) 이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 요소의 이벤트로 묶일것이다.
프라퍼티 타입 상세설명
element Object 모니터링되는 요소객체
callback Function(Object, String) 요소가 변경될때마다 호출되기 위한 함수. 이것은 요소객체와 새로운 값을 받을것이다.
lastValue String 요소내 확인되는 마지막 값

toc

Form.Element.EventObserver 클래스

Abstract.EventObserver로 부터 상속

요소내 값 변경을 감지하기 위한 폼 데이터 항목 요소의 적절한 이벤트를 위한 콜백 함수를 수행하는 Abstract.EventObserver의 구현물. 만약 요소가 변경을 보고하는 이벤트를 드러내지 않는다면, 당신은 Form.Element.Observer 클래스를 대신 사용할수 있다.

메소드 종류 인자 상세설명
[ctor](element, callback) constructor element: element 객체 또는 아이디, callback: 이벤트가 발생할때 호출될 함수 Abstract.EventObserver로 부터 상속. 요소의 value프라퍼티를 모니터링할 객체 생성.
getValue() instance (none) 요소의 값 반환

toc

Form.EventObserver 클래스

Abstract.EventObserver로 부터 상속

값이 변결될때 감지하기 위한 요소의 이벤트를 사용하여 폼내 포함되는 어느 데이터 항목 요소에 변경을 모니터링하는 Abstract.EventObserver의 구현물. 만약 폼이 변경을 보고하는 이벤트를 드러내지 않는 요소를 포함한다면, 당신은 Form.Observer 클래스를 대신 사용할수 있다.

메소드 종류 인자 상세설명
[ctor](form, callback) constructor form: form 객체 또는 아이디, callback: form내 데이터 항목 요소가 변경될때 호출되는 함수 Abstract.EventObserver로부터 상속. 변경을 위해 폼을 모니터링할 객체 생성.
getValue() instance (none) 모든 폼의 데이터 직렬화를 반환.

toc

Position 객체 (예비 문서)

이 객체는 요소 위치할당을 작업할때 돕는 수많은 함수를 제공한다.

메소드 종류 인자 상세설명
prepare() instance (none) 스크롤 위치내 변경을 수용하기 위한 deltaXdeltaY 프라퍼티 조정. 페이지 스크롤후 withinIncludingScrolloffset를 호출하기 전에 이 메소드를 호출하는 것을 기억하라.
realOffset(element) instance element: object 요소에 영향을 끼치는 어느 스크롤 offset를 포함하는 요소의 정확한 스크롤 offset를 가진 Array을 반환. 이 결과 배열은 [total_scroll_left, total_scroll_top]과 유사하다.
cumulativeOffset(element) instance element: object 위치가 할당된 부모 요소에 의해 부과된 어느 offset를 포함하는 요소의 정확한 위치가 할당된 offset를 가진 Array을 반환. 결과 배열은 [total_offset_left, total_offset_top]과 유사하다.
within(element, x, y) instance element: object, x 와 y: 위치 조정 만약 주어진 지점이 주어진 요소의 직사각형내 조정이 되는지 테스트
withinIncludingScrolloffsets(element, x, y) instance element: object, x and y: coordinates of a point  
overlap(mode, element) instance mode: 'vertical' or 'horizontal', element: object within()은 이 메소드가 호출되기 전에 호출될 필요가 있다. 이 메소드는 요소에서 겹치는 것을 조정하는 세분화정도를 표현하는 0.0과 1.0사이의 10진수를 반환할것이다. 예를 들면, 만약 요소가 100px를 가지는 정사각형 DIV이고 (300,300)에 위치한다면, within(divSquare, 330, 330); overlap('vertical', divSquare);는 0.70을 반환해야만 한다. 이 값이 의미하는 것은 DIV의 아래쪽 경계에서 70%(100px - 30px = 70px)를 표시하는 지점이라는 것이다. 이해하기 가장 쉬운 방법은 다른 사각형의 위-왼쪽 구석처럼 주어진 쌍을 생각하는 것이다. 숫자값은 겹치는 넓이와 높이의 퍼센트값일 것이다.
clone(source, target) instance source: element 객체 또는 아이디, target: element 객체 또는 아이디 source요소에 대해 똑같이 target요소의 크기를 다시 조정하고 다시 위치를 지정

1.5.0을 위한 이 문서는 여전히 작업중입니다. 이 문서의 업데이트를 계속 지켜봐주십시오.
만약 에러를 발견한다면, 나에게 알려주십시오. 그러면 가능한 한 빨리 그것을 수정할것입니다.
한글 번역에 관련된 부분은 한국어 번역자으로 알려주십시오.

Posted by 1010
반응형

<!--
/******************************************************************************
* prototype 모음
*****************************************************************************/

//-----------------------------------------------------------------------------
// 문자 앞 뒤 공백을 제거 한다.
//-----------------------------------------------------------------------------
String.prototype.trim = function() {
return this.replace(/(^\s*)|(\s*$)/g, "");
}

//-----------------------------------------------------------------------------
// 내용이 있는지 없는지 확인하다.
//
// @return : true(내용 있음) | false(내용 없음)
//-----------------------------------------------------------------------------
String.prototype.notNull = function() {
return (this == null || this.trim() == "") ? false : true;
}

//-----------------------------------------------------------------------------
// 메일의 유효성을 체크 한다.
//
// @return : true(맞는 형식) | false(잘못된 형식)
//-----------------------------------------------------------------------------
String.prototype.mail = function() {
var em = this.trim().match(/^[_\-\.0-9a-zA-Z]{3,}@[-.0-9a-zA-z]{2,}\.[a-zA-Z]{2,4}$/);
return (em) ? true : false;
}

//-----------------------------------------------------------------------------
// 주민번호 체크 XXXXXX-XXXXXXX 형태로 체크
//
// @return : true(맞는 형식) | false(잘못된 형식)
//-----------------------------------------------------------------------------
String.prototype.jumin = function() {
var num = this.trim().onlyNum();
if(num.length == 13) {
num = num.substring(0, 6) + "-" + num.substring(6, 13);
}
else {
return false;
}
num = num.match(/^([0-9]{6})-?([0-9]{7})$/);
if(!num) return false;
var num1 = RegExp.$1;
var num2 = RegExp.$2;
if(!num2.substring(0, 1).match(/^[1-4]{1}$/)) return false;
num = num1 + num2;
var sum = 0;
var last = num.charCodeAt(12) - 0x30;
var bases = "234567892345";
for (i=0; i<12; i++) {
sum += (num.charCodeAt(i) - 0x30) * (bases.charCodeAt(i) - 0x30);
}
var mod = sum % 11;
return ((11 - mod) % 10 == last) ? true : false;
}

//-----------------------------------------------------------------------------
// 사업자번호 체크 XXX-XX-XXXXX 형태로 체크
//
// @return : true(맞는 형식) | false(잘못된 형식)
//-----------------------------------------------------------------------------
String.prototype.biznum = function() {
var num = this.trim().onlyNum();
if(num.length == 10) {
num = num.substring(0, 3) + "-" + num.substring(3, 5) + "-" + num.substring(5, 10);
}
else {
return false;
}
num = num.match(/([0-9]{3})-?([0-9]{2})-?([0-9]{5})/);
if(!num) return false;
num = RegExp.$1 + RegExp.$2 + RegExp.$3;
var cVal = 0;
for (var i=0; i<8; i++) {
var cKeyNum = parseInt(((_tmp = i % 3) == 0) ? 1 : ( _tmp == 1 ) ? 3 : 7);
cVal += (parseFloat(num.substring(i,i+1)) * cKeyNum) % 10;
}
var li_temp = parseFloat(num.substring(i,i+1)) * 5 + '0';
cVal += parseFloat(li_temp.substring(0,1)) + parseFloat(li_temp.substring(1,2));
return (parseInt(num.substring(9,10)) == 10 - (cVal % 10)%10) ? true : false;
}

//-----------------------------------------------------------------------------
// 전화번호 체크 XXX-XXXX-XXXX 형태로 체크
//
// @return : true(맞는 형식) | false(잘못된 형식)
//-----------------------------------------------------------------------------
String.prototype.phone = function() {
var num = this.trim().onlyNum();
if(num.substring(1,2) == "2") {
num = num.substring(0, 2) + "-" + num.substring(2, num.length - 4) + "-" + num.substring(num.length - 4, num.length);
}
else {
num = num.substring(0, 3) + "-" + num.substring(3, num.length - 4) + "-" + num.substring(num.length - 4, num.length);
}
num = num.match(/^0[0-9]{1,2}-[1-9]{1}[0-9]{2,3}-[0-9]{4}$/);
return (num) ? true : false;
}

//-----------------------------------------------------------------------------
// 핸드폰 체크 XXX-XXXX-XXXX 형태로 체크
//
// @return : true(맞는 형식) | false(잘못된 형식)
//-----------------------------------------------------------------------------
String.prototype.mobile = function() {
var num = this.trim().onlyNum();
num = num.substring(0, 3) + "-" + num.substring(3, num.length - 4) + "-" + num.substring(num.length - 4, num.length);
num = num.trim().match(/^01[016789]{1}-[1-9]{1}[0-9]{2,3}-[0-9]{4}$/);
return (num) ? true : false;
}

//-----------------------------------------------------------------------------
// 숫자만 체크
//
// @return : true(맞는 형식) | false(잘못된 형식)
//-----------------------------------------------------------------------------
String.prototype.num = function() {
return (this.trim().match(/^[0-9]+$/)) ? true : false;
}

//-----------------------------------------------------------------------------
// 영어만 체크
//
// @return : true(맞는 형식) | false(잘못된 형식)
//-----------------------------------------------------------------------------
String.prototype.eng = function() {
return (this.trim().match(/^[a-zA-Z]+$/)) ? true : false;
}

//-----------------------------------------------------------------------------
// 영어와 숫자만 체크
//
// @return : true(맞는 형식) | false(잘못된 형식)
//-----------------------------------------------------------------------------
String.prototype.engnum = function() {
return (this.trim().match(/^[0-9a-zA-Z]+$/)) ? true : false;
}

//-----------------------------------------------------------------------------
// 영어와 숫자만 체크
//
// @return : true(맞는 형식) | false(잘못된 형식)
//-----------------------------------------------------------------------------
String.prototype.numeng = function() {
return this.engnum();
}

//-----------------------------------------------------------------------------
// 아이디 체크 영어와 숫자만 체크 첫글자는 영어로 시작
//
// @return : true(맞는 형식) | false(잘못된 형식)
//-----------------------------------------------------------------------------
String.prototype.userid = function() {
return (this.trim().match(/[a-zA-z]{1}[0-9a-zA-Z]+$/)) ? true : false;
}

//-----------------------------------------------------------------------------
// 한글만 체크
//
// @return : true(맞는 형식) | false(잘못된 형식)
//-----------------------------------------------------------------------------
String.prototype.kor = function() {
return (this.trim().match(/^[가-힣]+$/)) ? true : false;
}

//-----------------------------------------------------------------------------
// 숫자와 . - 이외의 문자는 다 뺀다. - 통화량을 숫자로 변환
//
// @return : 숫자
//-----------------------------------------------------------------------------
String.prototype.toNum = function() {
var num = this.trim();
return (this.trim().replace(/[^0-9\.-]/g,""));
}

//-----------------------------------------------------------------------------
// 숫자 이외에는 다 뺀다.
//
// @return : 숫자
//-----------------------------------------------------------------------------
String.prototype.onlyNum = function() {
var num = this.trim();
return (this.trim().replace(/[^0-9]/g,""));
}

//-----------------------------------------------------------------------------
// 숫자만 뺀 나머지 전부
//
// @return : 숫자 이외
//-----------------------------------------------------------------------------
String.prototype.noNum = function() {
var num = this.trim();
return (this.trim().replace(/[0-9]/g,""));
}

//-----------------------------------------------------------------------------
// 숫자에 3자리마다 , 를 찍어서 반환
//
// @return : 통화량
//-----------------------------------------------------------------------------
String.prototype.toMoney = function() {
var num = this.toNum();
var pattern = /(-?[0-9]+)([0-9]{3})/;
while(pattern.test(num)) {
num = num.replace(pattern,"$1,$2");
}
return num;
}

//-----------------------------------------------------------------------------
// String length 반환
//
// @return : int
//-----------------------------------------------------------------------------
String.prototype.getLength = function() {
return this.length;
}

//-----------------------------------------------------------------------------
// String length 반환 한글 2글자 영어 1글자
//
// @return : int
//-----------------------------------------------------------------------------
String.prototype.getByteLength = function() {
var tmplen = 0;
for (var i = 0; i < this.length; i++) {
if (this.charCodeAt(i) > 127)
tmplen += 2;
else
tmplen++;
}
return tmplen;
}

//-----------------------------------------------------------------------------
// 파일 확장자 반환
//
// @return : String
//-----------------------------------------------------------------------------
String.prototype.getExt = function() {
var ext = this.substring(this.lastIndexOf(".") + 1, this.length);
return ext;
}

//-----------------------------------------------------------------------------
// String에 따라서 받침이 있으면 은|이|을 을
// 받침이 없으면 는|가|를 등을 리턴 한다.
// str.josa("을/를") : 구분자는 항상 "/"로
//
//
// @return : 은/는, 이/가 ...
//-----------------------------------------------------------------------------
String.prototype.josa = function(nm) {
var nm1 = nm.trim().substring(0, nm.trim().indexOf("/"));
var nm2 = nm.trim().substring(nm.trim().indexOf("/") + 1, nm.trim().length);
var a = this.substring(this.length - 1, this.length).charCodeAt();
a = a - 44032;
var jongsung = a % 28;
return (jongsung) ? nm1 : nm2;
}


/******************************************************************************
* Form에 관련된 메서드
*
* 1. text, textarea
* required : 값이 없으면 경고
* num : 값에 숫자만 가능
* eng : 값에 영어만 가능
* han : 값에 한글만 가능
* numeng : 값에 숫자와 영어만 가능
* min=value : 최소 value자 이상
* max=value : 최대 value자 이하
* len=value : 정확하게 value자만 가능
* len=start~end : start자에서 end자까지 가능
* userid : 영어 숫자만 가능하고 첫문자는 영어로
* phone=value : value가 ""면 이 필드만 아니면 value가 같은 phone에 관련된 모든 필드 조사
* mobile=value : value가 ""면 이 필드만 아니면 value가 같은 mobile에 관련된 모든 필드 조사
* email=value : value가 ""면 이 필드만 아니면 value가 같은 email에 관련된 모든 필드 조사
* jumin=value : value가 ""면 이 필드만 아니면 value가 같은 jumin에 관련된 모든 필드 조사
* biznum=value : value가 ""면 이 필드만 아니면 value가 같은 biznum에 관련된 모든 필드 조사
* 2. select
* required : 값이 없으면 경고
* 3. radio
* required : 아무것도 선택되지 않으면 경고
* 4. checkbox
* required : 아무것도 선택되지 않으면 경고
* min=value : 최소 value개 이상 가능
* max=value : 최대 value개 이하 가능
* len=value : 정확하게 value개 가능
* len=start~end : start개에서 end개 까지 가능
* 5. file
* required : 아무것도 선택되지 않으면 경고
* allow=value : 확장자가 value 인 파일만 업로드 가능 (allow="gif jpg jpeg png")
* deny=value : 확장자가 value 인 파일은 업로드 불가능
*****************************************************************************/
//-----------------------------------------------------------------------------
// FormUtil Class 생성
//-----------------------------------------------------------------------------
FormUtil = function(obj) {
this.obj = obj;
}

//-----------------------------------------------------------------------------
// 폼 유효성 체크
//
// @return : true | false
//-----------------------------------------------------------------------------
FormUtil.prototype.success = function() {

for(var i = 0; i < this.obj.elements.length; i++) {
var f = this.obj[i];

var fname = (f.getAttribute("FNAME") == null) ? f.name.toUpperCase() : fname = f.getAttribute("FNAME");

// checkbox
if(f.type == "checkbox") {
if(!this.checkbox(f, fname)) {
return false;
}
}
// radio
else if(f.type == "radio") {
if(!this.radio(f, fname)) {
return false;
}
}
else { // text, textarea, password, select
// <input required>
if(f.getAttribute("REQUIRED") != null) {
var ftype = f.type;
var msg = " 입력 하세요";
if(ftype.indexOf("select") >= 0 || ftype == "file") {
msg = " 선택하세요";
}

if(!f.value.notNull()) {
alert(fname + fname.josa("을/를") + msg);
f.focus();
return false;
}
}
// <input num>
if(f.getAttribute("NUM") != null && f.value != "") {
if(!f.value.num()) {
alert(fname + fname.josa("은/는") + " 숫자로만 구성되어야 합니다.");
f.value = "";
f.focus();
return false;
}
}
// <input eng>
if(f.getAttribute("ENG") != null && f.value != "") {
if(!f.value.eng()) {
alert(fname + fname.josa("은/는") + " 영어로만 구성되어야 합니다.");
f.value = "";
f.focus();
return false;
}
}
// <input numeng>
if(f.getAttribute("NUMENG") != null && f.value != "") {
if(!f.value.numeng()) {
alert(fname + fname.josa("은/는") + " 숫자와 영어로만 구성되어야 합니다.");
f.value = "";
f.focus();
return false;
}
}
// <input han>
if(f.getAttribute("HAN") != null && f.value != "") {
if(!f.value.kor()) {
alert(fname + fname.josa("은/는") + " 한글로만 구성되어야 합니다.");
f.value = "";
f.focus();
return false;
}
}
// <input userid>
if(f.getAttribute("USERID") != null && f.value != "") {
if(!f.value.userid()) {
alert(fname + fname.josa("은/는") + " 숫자와 영어로만 구성되어야 하며\n\n첫문자는 반드시 영어로 시작해야 합니다.");
f.value = "";
f.focus();
return false;
}
}
// <input type="file" deny="value">
if(f.getAttribute("DENY") != null && f.type == "file" && f.value != "") {
var ext = f.value.getExt().toLowerCase();
var ext2 = f.getAttribute("DENY").toLowerCase();
if(ext2.indexOf(ext) >= 0) {
alert("확장자가 " + f.getAttribute("DENY").toUpperCase() + " 인 파일은 업로드 하실 수 없습니다.");
return false;
}
}
// <input type="file" deny="value">
if(f.getAttribute("ALLOW") != null && f.type == "file" && f.value != "") {
var ext = f.value.getExt().toLowerCase();
var ext2 = f.getAttribute("ALLOW").toLowerCase();
if(ext2.indexOf(ext) < 0) {
alert("확장자가 " + f.getAttribute("ALLOW").toUpperCase() + " 인 파일만 업로드 가능 합니다.");
return false;
}
}
// <input max="10">
if(f.getAttribute("MAX") != null) {
var tmpLen = f.value.getLength();
if(tmpLen > parseInt(f.getAttribute("MAX"))) {
alert(fname + fname.josa("은/는") + " " + f.getAttribute("MAX") + "자 이하로 입력 하세요.");
f.value = "";
f.focus();
return false;
}
}
// <input min="10">
if(f.getAttribute("MIN") != null) {
var tmpLen = f.value.getLength();
if(tmpLen < parseInt(f.getAttribute("MIN"))) {
alert(fname + fname.josa("은/는") + " " + f.getAttribute("MIN") + "자 이상으로 입력 하세요.");
f.focus();
return false;
}
}
// <input len="10">
if(f.getAttribute("LEN") != null) {
var tmpLen = f.value.getLength();
var val = f.getAttribute("LEN");
if(val.indexOf(val.noNum()) > 0) {
var num1 = val.substring(0, val.indexOf(val.noNum()));
var num2 = val.substring(val.lastIndexOf(val.noNum()) + 1, val.length);
if(tmpLen < parseInt(num1) || tmpLen > parseInt(num2)) {
alert(fname + fname.josa("은/는") + " " + num1 + "자 이상 " + num2 + "자 이하로 입력하세요");
f.focus();
return false;
}
}
else {
if(tmpLen != parseInt(val)) {
alert(fname + fname.josa("은/는") + " " + val + "자리 입니다.");
f.focus();
return false;
}
}
}
}
}

for(var i = 0; i < this.obj.elements.length; i++) {
var f = this.obj[i];
// <input phone="name">
if(f.getAttribute("PHONE") != null) {
var val = "";
if(f.getAttribute("PHONE") == "") {
val = f.value
}
else {
val = this.getValue("PHONE", f.getAttribute("PHONE"));
}
if(!val.phone()) {
alert("올바른 전화번호가 아닙니다.\n\n다시 확인하여 주세요");
f.focus();
return false;
}
}
// <input mobile="name">
if(f.getAttribute("MOBILE") != null) {
var val = "";
if(f.getAttribute("MOBILE") == "") {
val = f.value
}
else {
val = this.getValue("MOBILE", f.getAttribute("MOBILE"));
}
if(!val.mobile()) {
alert("올바른 핸드폰번호가 아닙니다.\n\n다시 확인하여 주세요");
f.focus();
return false;
}
}
// <input jumin="name">
if(f.getAttribute("JUMIN") != null) {
var val = "";
if(f.getAttribute("JUMIN") == "") {
val = f.value
}
else {
val = this.getValue("JUMIN", f.getAttribute("JUMIN"));
}
if(!val.jumin()) {
alert("올바른 주민등록 번호가 아닙니다.\n\n다시 확인하여 주세요");
f.focus();
return false;
}
}
// <input email="name">
if(f.getAttribute("EMAIL") != null) {
var val = "";
if(f.getAttribute("EMAIL") == "") {
val = f.value
}
else {
val = this.getValue("EMAIL", f.getAttribute("EMAIL"));
}
if(!val.mail()) {
alert("유효한 이메일이 아닙니다.\n\n다시 확인하여 주세요");
f.focus();
return false;
}
}
// <input biznum="name">
if(f.getAttribute("BIZNUM") != null) {
var val = "";
if(f.getAttribute("BIZNUM") == "") {
val = f.value
}
else {
val = this.getValue("BIZNUM", f.getAttribute("BIZNUM"));
}
if(!val.bizname()) {
alert("유효한 사업자 등록 번호가 아닙니다.\n\n다시 확인하여 주세요");
f.focus();
return false;
}
}

}

return true;
}

//-----------------------------------------------------------------------------
// Checkbox 일때 유효성 체크
//
// @return : true | false
//-----------------------------------------------------------------------------
FormUtil.prototype.checkbox = function(f, fname) {
var chkObj = eval("this.obj." + f.name);
// 체크박스를 선택하여야 할 때
var c = 0;
var len = chkObj.length;
if(len) {
for(var j = 0; j < len; j++) {
if(chkObj[j].checked) c++;
}
}
else {
if(chkObj.checked) c = 1;
}

if(f.getAttribute("REQUIRED") != null) {
if(c == 0) {
alert(fname + fname.josa("을/를") + " 선택하여 주세요");
return false;
}
}
if(f.getAttribute("MAX") != null) {
var val = f.getAttribute("MAX");
if(c > parseInt(val)) {
alert(fname + fname.josa("은/는") + " 최대 " + val + "개 이하로 선택 하셔야 합니다.");
return false;
}
}
if(f.getAttribute("MIN") != null) {
var val = f.getAttribute("MIN");
if(c < parseInt(val)) {
alert(fname + fname.josa("은/는") + " 최소 " + val + "개 이상 선택 하셔야 합니다.");
return false;
}
}
if(f.getAttribute("LEN") != null) {
var val = f.getAttribute("LEN");
if(val.indexOf(val.noNum()) > 0) {
var num1 = val.substring(0, val.indexOf(val.noNum()));
var num2 = val.substring(val.lastIndexOf(val.noNum()) + 1, val.length);
if(c < parseInt(num1) || c > parseInt(num2)) {
alert(fname + fname.josa("은/는") + " " + num1 + "개 이상 " + num2 + "개 이하로 선택 하셔야 합니다.");
return false;
}
}
else {
if(c != parseInt(val)) {
alert(fname + fname.josa("은/는") + " " + val + "개 선택 하셔야 합니다.");
f.focus();
return false;
}
}
}
return true;
}

//-----------------------------------------------------------------------------
// Radio 유효성 체크
//
// @return : true | false
//-----------------------------------------------------------------------------
FormUtil.prototype.radio = function(f, fname) {
var chkObj = eval("this.obj." + f.name);
if(f.getAttribute("REQUIRED") != null) {
var c = 0;
var len = chkObj.length;
if(len) {
for(var j = 0; j < len; j++) {
if(chkObj[j].checked) c++;
}
}
else {
if(chkObj.checked) c = 1;
}
if(c == 0) {
alert(fname + fname.josa("을/를") + " 선택하여 주세요");
return false;
}
}
return true;
}

//-----------------------------------------------------------------------------
// 체크되어 있는 갯수를 리턴해 준다.
//
// @return : int
//-----------------------------------------------------------------------------
FormUtil.prototype.checked = function(btn) {
var len = btn.length;
var c = 0;
if(len) {
for(var j = 0; j < len; j++) {
if(btn[j].checked) c++;
}
}
else {
if(btn.checked) c = 1;
}
return c;
}

//-----------------------------------------------------------------------------
// 해당 name의 값이 같은 filed를 구한다.
//
// @return : String
//-----------------------------------------------------------------------------
FormUtil.prototype.getValue = function(name, value) {
var val = "";
for(var j = 0; j < this.obj.elements.length; j++) {
if(eval("this.obj[j].getAttribute(\"" + name + "\")") != null && eval("this.obj[j].getAttribute(\"" + name + "\")") == value) {
if(val == "") {
val += this.obj[j].value;
}
else {
val += "@" + this.obj[j].value;
}
}
}
return val;
}
//-->

Posted by 1010
05.JSP2008. 10. 19. 15:42
반응형

50만건이 넘는 데이타를 읽어서 insert 할 일이 생겼는데 보통의 방법으로 하니 톰켓이 계속 죽어 버리는 일이 생겼습니다.

자바 API를 보니 이러한 방법이 있더군요...


 

try {
            StringBuffer query = new StringBuffer();
            query.append("INSERT INTO ABT231 ");
            query.append("(customer_no, item_cd, occur_amt, reason_cd, register_ymd, register_no) ");
            query.append(" VALUES (?, ?, ?, '9', ?, ?) ");

            conn = getConnection();
            conn.setAutoCommit(false);

            pstmt = conn.prepareStatement(query.toString());
            Iterator iter = m_abt231InsertList.iterator();
            int count = 0;

            while( iter.hasNext() ) {
                m_abt231 = (Abt231) iter.next();
                pstmt.setInt(1, m_abt231.getCustomerNo());
                pstmt.setString(2, m_abt231.getItemCd());
                pstmt.setLong(3, m_abt231.getOccurAmt());
                pstmt.setString(4, s_magamCurrentTime);
                pstmt.setInt(5, Integer.parseInt(s_workCd));
                pstmt.addBatch();
                count++;
                if( (count % 10000) == 0){
                    System.out.println(count + "건 처리중");
                    pstmt.executeBatch();
                }
            }

           
pstmt.executeBatch();
            conn.commit();

}

Posted by 1010
05.JSP2008. 10. 19. 15:41
반응형

<%@ page contentType="text/html;charset=EUC-KR"%>
<%
  String protocol = request.getProtocol();
  String serverName = request.getServerName();
  int serverPort = request.getServerPort();
  String remoteAddr = request.getRemoteAddr();
  String remoteHost = request.getRemoteHost();
  String method = request.getMethod();
  StringBuffer requestURL = request.getRequestURL();
  String requestURI = request.getRequestURI();
  String useBrowser = request.getHeader("User-Agent");
  String fileType = request.getHeader("Accept");
 String tt = request.getHeader("referer");

%>
<html>
<body>
<h1>Request Example2</h1>
프로토콜 : <%=protocol%><p>
서버의 이름 : <%=serverName%><p>
서버의 포트 번호 :<%=serverPort%><p>
사용자 컴퓨터의 주소 : <%=remoteAddr%><p>
사용자 컴퓨터의 이름 : <%=remoteHost%><p>
사용 method : <%=method%><p>
요청 경로(URL) : <%=requestURL%><p>
요청 경로(URI) : <%=requestURI%><p>
현재 사용하는 브라우저 : <%=useBrowser%><p>
브라우저가 지원하는 file의 type : <%=fileType%><p>
이전 URL : <%=tt%><p>
</body>

</html>

Posted by 1010
05.JSP2008. 10. 19. 15:40
반응형

CallableStatement
: SQL의 스토어드프로시저(Stored Procedure)를 실행시키기 위해 사용되는 인터페이스 이다.

스토어드프로시저란
: query문을 하나의 파일 형태로 만들거나 데이터베이스에 저장해 놓고 함수처럼 호출해서 사용하는 것임.
 이것을 이용하면 연속되는 query문에 대해서 매우 빠른 성능을 보인다.
 보안적인 장점 역시 가지고 있음.


스토어드프로시저로 값을 받아오려면,
호출하기에 앞서 반드시 CallableStatement인터페이스의 registerOutParameter()메서드를 호출해야 함.
 이 인터페이스는 PreparedStatement 인터페이스로부터 상속 받았기 때문에 setXXX()메서드를 사용할 수 있다.


(CallableStatement 예제)

CallableStatementTest.java
import java.sql.*;

public class CallableStatementTest{

   public static void main(String[] args){

       try{

          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

          Connection con = DriverManager.getConnection("jdbc:odbc:dbdsn", "id", "password");

          CallableStatement cs = con.prepareCall("{call myStoredProcedure(?,?,?)}");

          cs.setInt(1,2);

          cs.registerOutParameter(2, java.sql.Types.VARCHAR);

          cs.registerOutParameter(3, java.sql.Types.INTEGER);

          cs.execute();

          System.out.println("*name : "+ cs.getString(2) +"*age : "+ cs.getInt(3));

          cs.close();

          con.close();

       }catch(Exception e){System.out.println(e);}

   }

}
 
C:\JavaExample\19>javac CallableStatementTest.java

C:\JavaExample\19>java CallableStatementTest

*name : Jabook    *age : 2
 


MS-SQL에서의 스토어드프로시저 myStoredProcedure 작성구문
 
CREATE PROCEDURE  myStoredProcedure

   @age  int

,   @na varchar(20)  OUTPUT

,   @ageo int           OUTPUT

AS
SELECT  @na = name, @ageo = age  FROM mytest

Where age = @age
 


주의 1. Java의 코드에는 SQL의 query문이 들어가 있지 않았음.
 그리고 위에 정리해 놓은 것처럼, SQL서버 자체에 스토어드프로시저를 작성하여 query를 작성해 놓음.
 위에서 골뱅이(@)가 붙은 것들이 매개변수이고 그 중에서도 뒤에 OUTPUT이라고 붙은 것들이 리턴 될 값. 


CallableStatement객체 cs를 생성하여 프로시저를 호출하기 위한 prepareCall()메서드를 사용한다.
 여기서 물음표(?)가 프로시저로 전달되고 받아올 매개변수인 것입니다.


         CallableStatement cs = con.prepareCall("{call myStoredProcedure(?, ?, ?)}");


 setXXX()메서드를 이용하여 프로시저에 사용할 인자값을 넣어주게 됨.
 그리고 리턴되는 값들을 받아야 겠죠. 일반 메서드와 달리 여러 개의 인자값을 받을 수 있음.
 이때 스토어드프로시저에서 넘어오는 값을 얻기 위해서 registerOutParameter()메서드를 이용하여
 반환되는 값들을 셋팅하게 됩니다.
 

         cs.setInt(1,2);
         cs.registerOutParameter(2, java.sql.Types.VARCHAR);
         cs.registerOutParameter(3, java.sql.Types.INTEGER);


반환되는 값을 얻기 위해서는 CallableStatement를 실행한 후 다음과 같이 반환값을 얻어 낼 수 있습니다.

         cs.execute();
         System.out.println("*name : "+ cs.getString(2) +"*age : "+ cs.getInt(3));
 

 CallableStatement인터페이스는 데이터베이스의 스토어드프로시저를 호출하기 위해
prepareCall()메서드를 이용하여 CallableStatement객체를 생성한다.
 그 prepareCall()메서드는 Connection인터페이스의 메서드.
 스토어드프로시저를 실행하기 전에 받아올 값에 대비하기 위해서
registerOutParameter()메서드를 사용하는 주의 할점.



☞ CallableStatement
 데이터베이스의 스토어드프로시저를 실행시키기 위해 사용되는 메서드.

스토어드프로시저를 사용하면 속도, 코드의 독립성, 보안성등의 다양한 이점을 얻을 수 있다.
 


CallableStatement인터페이스 주요 메서드
 
public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException
: 프로시저로 받아온 값을 JDBC타입으로 등록.
 모든 받아온 값은 반드시 이 과정을 거쳐야 합니다.
 대표적인 sqlType을 알아보면 NULL, FOLAT, INTEGER, DATE등이 있습니다.


*PreparedStatement클래스를 상속하므로 getXXX()등, PreparedStatement가 가지고 있는 메서드를 사할수 있음.

Posted by 1010
05.JSP2008. 10. 19. 15:40
반응형
5. JDBC Connection Pooling 을 왜 사용해야 하는가 ?

Pooling 이란 용어는 일반적인 용어입니다. Socket Connection Pooling, Thread
Pooling, Resource Pooling 등 "어떤 자원을 미리 Pool 에 준비해두고 요청시 Pool에
있는 자원을 곧바로 꺼내어 제공하는 기능"인 거죠.

JDBC Connection Pooling 은 JDBC를 이용하여 자바에서 DB연결을 할 때, 미리 Pool에
물리적인 DB 연결을 일정개수 유지하여 두었다가 어플리케이션에서 요구할 때 곧바로
제공해주는 기능을 일컫는 용어입니다. JDBC 연결시에, (DB 종류마다, 그리고 JDBC
Driver의 타입에 따라 약간씩 다르긴 하지만 ) 대략 200-400 ms 가 소요 됩니다. 기껏
0.2 초 0.4 초 밖에 안되는 데 무슨 문제냐 라고 반문할수도 있습니다.

하지만, 위 시간은 하나의 연결을 시도할 때 그러하고, 100 - 200개를 동시에 연결을
시도하면 얘기가 완전히 달라집니다.

아래는 직접 JDBC 드라이버를 이용하여 연결할 때와 JDBC Connection Pooling 을 사용
할 때의 성능 비교 결과입니다.


------------------------------------------------------------------
테스트 환경
LG-IBM 570E Notebook(CPU:???MHz , MEM:320MB)
Windows NT 4.0 Service Pack 6
IBM WebSphere 3.0.2.1 + e-Fixes
IBM HTTP Server 1.3.6.2
IBM UDB DB2 6.1

아래에 첨부한 파일는 자료를 만들때 사용한 JSP소스입니다. (첨부파일참조)

[HttpConn.java] 간단한 Stress Test 프로그램


아래의 수치는 이 문서 이외에는 다른 용도로 사용하시면 안됩니다. 테스트를 저의
개인 노트북에서 측정한 것이고, 또한 테스트 프로그램 역시 직접 만들어한 것인
만큼, 공정성이나 수치에 대한 신뢰를 부여할 수는 없습니다.
그러나 JDBC Connection Pooling 적용 여부에 따른 상대적인 차이를 설명하기에는
충분할 것 같습니다.

테스트 결과

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
매번 직접 JDBC Driver 연결하는 경우
java HttpConn http://localhost/db_jdbc.jsp -c <동시유저수> -n <호출횟수> -s 0

TOTAL( 1,10)  iteration=10 ,  average=249.40 (ms),   TPS=3.93
TOTAL(50,10)  iteration=500 , average=9,149.84 (ms), TPS=4.83
TOTAL(100,10)  iteration=1000 , average=17,550.76 (ms), TPS=5.27
TOTAL(200,10)  iteration=2000 , average=38,479.03 (ms), TPS=4.89
TOTAL(300,10)  iteration=3000 , average=56,601.89 (ms), TPS=5.01

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DB Connection Pooing 을 사용하는 경우
java HttpConn http://localhost/db_pool_cache.jsp -c <동시유저수> -n <호출횟수> -s 0

TOTAL(1,10)  iteration=10 , average=39.00 (ms), TPS=23.26
TOTAL(1,10)  iteration=10 , average=37.10 (ms), TPS=24.33
TOTAL(50,10)  iteration=500 , average=767.36 (ms), TPS=45.27
TOTAL(50,10)  iteration=500 , average=568.76 (ms), TPS=61.26
TOTAL(50,10)  iteration=500 , average=586.51 (ms), TPS=59.79
TOTAL(50,10)  iteration=500 , average=463.78 (ms), TPS=67.02
TOTAL(100,10)  iteration=1000 , average=1,250.07 (ms), TPS=57.32
TOTAL(100,10)  iteration=1000 , average=1,022.75 (ms), TPS=61.22
TOTAL(200,10)  iteration=1462 , average=1,875.68 (ms), TPS=61.99
TOTAL(300,10)  iteration=1824 , average=2,345.42 (ms), TPS=61.51

NOTE: average:평균수행시간, TPS:초당 처리건수
------------------------------------------------------------------

즉, JDBC Driver 를 이용하여 직접 DB연결을 하는 구조는 기껏 1초에 5개의 요청을
처리할 수 있는 능력이 있는 반면, DB Connection Pooling 을 사용할 경우는 초당
60여개의 요청을 처리할 수 있는 것으로 나타났습니다.
12배의 성능향상을 가져온거죠. (이 수치는 H/W기종과 측정방법, 그리고 어플리케이션에
따라 다르게 나오니 이 수치자체에 너무 큰 의미를 두진 마세요)


주의: 흔히 "성능(Performance)"을 나타낼 때, 응답시간을 가지고 얘기하는 경향이
  있습니다. 그러나 응답시간이라는 것은 ActiveUser수가 증가하면 당연히 그에 따라
  느려지게 됩니다. 반면 "단위시간당 처리건수"인 TPS(Transaction Per Second) 혹은
  RPS(Request Per Second)는 ActiveUser를 지속적으로 끌어올려 임계점을 넘어서면,
  특정수치 이상을 올라가지 않습니다. 따라서 성능을 얘기할 땐 평균응답시간이 아니라
  "단위시간당 최대처리건수"를 이야기 하셔야 합니다.
  성능(Performance)의 정의(Definition)은 "단위시간당 최대처리건수"임을 주지하세요.
  성능에 관련한 이론은 아래의 문서를 통해, 함께 연구하시지요.
  [강좌]웹기반시스템하에서의 성능에 대한 이론적 고찰
  http://www.javaservice.net/~java/bbs/read.cgi?m=resource&b=consult&c=r_p&n=1008701211

PS: IBM WebSphere V3 의 경우, Connection 을 가져올 때, JNDI를 사용하게 되는데
   이때 사용되는 DataSource 객체를 매번 initialContext.lookup() 을 통해 가져오게
   되면, 급격한 성능저하가 일어납니다.(NOTE: V4부터는 내부적으로 cache를 사용하여
   성능이 보다 향상되었습니다)
   DataSource를 매 요청시마다 lookup 할 경우 다음과 같은 결과를 가져왔습니다.

   java HttpConn http://localhost/db_pool.jsp -c <동시유저수> -n <호출횟수> -s 0

   TOTAL(1,10)  iteration=10 , average=80.00 (ms), TPS=11.61
   TOTAL(50,10)  iteration=500 , average=2,468.30 (ms), TPS=16.98
   TOTAL(50,10)  iteration=500 , average=2,010.43 (ms), TPS=18.18
   TOTAL(100,10)  iteration=1000 , average=4,377.24 (ms), TPS=18.16
   TOTAL(200,10)  iteration=1937 , average=8,991.89 (ms), TPS=18.12

   TPS 가 18 이니까 DataSource Cache 를 사용할 때 보다 1/3 성능밖에 나오지 않는 거죠.



6. JDBC Connection Pooling 을 사용하여 코딩할 때 고려사항

JDBC Connecting Pooling은 JDBC 1.0 스펙상에 언급되어 있지 않았습니다. 그러다보니
BEA WebLogic, IBM WebSphere, Oracle OAS, Inprise Server, Sun iPlanet 등 어플리케
이션 서버라고 불리는 제품들마다 그 구현방식이 달랐습니다.
인터넷에서 돌아다니는 Hans Bergsten 이 만든 DBConnectionManager.java 도 그렇고,
JDF 에 포함되어 있는 패키지도 그렇고 각자 독특한 방식으로 개발이 되어 있습니다.

JDBC를 이용하여 DB연결하는 대표적인 코딩 예를 들면 다음과 같습니다.

------------------------------------------------------------------
[BEA WebLogic Application Server]

    import java.sql.*;

    // Driver loading needed.
    static {
      try {
        Class.forName("weblogic.jdbc.pool.Driver").newInstance();         
      }
      catch (Exception e) {
        ...
      }
    }

    ......

    Connection conn = null;
    Statement stmt = null;
    try {
      conn = DriverManager.getConnection("jdbc:weblogic:pool:<pool_name>", null);
      stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery("select ....");
      while(rs.next()){
        .....
      }
      rs.close();
    }
    catch(Exception e){
      .....
    }
    finally {
      if ( stmt != null ) try{stmt.close();}catch(Exception e){}
      if ( conn != null ) try{conn.close();}catch(Exception e){}
    }


------------------------------------------------------------------
IBM WebSphere Application Server 3.0.2.x / 3.5.x

    /* IBM WebSphere 3.0.2.x for JDK 1.1.8 */
    //import java.sql.*;
    //import javax.naming.*;
    //import com.ibm.ejs.dbm.jdbcext.*;
    //import com.ibm.db2.jdbc.app.stdext.javax.sql.*;

    /* IBM WebSphere 3.5.x for JDK 1.2.2 */
    import java.sql.*;
    import javax.sql.*;
    import javax.naming.*;

    // DataSource Cache 사용을 위한 ds 객체 static 초기화
    private static DataSource ds = null;
    static {
      try {
        java.util.Hashtable props = new java.util.Hashtable();
        props.put(Context.INITIAL_CONTEXT_FACTORY,
                  "com.ibm.ejs.ns.jndi.CNInitialContextFactory");
        Context ctx = null;
        try {
          ctx = new InitialContext(props);
          ds = (DataSource)ctx.lookup("jdbc/<data_source_name>");
        }
        finally {
          if ( ctx != null ) ctx.close();
        }
      }
      catch (Exception e) {
       ....
      }
    }

    .....  

    Connection conn = null;
    Statement stmt = null;
    try {
      conn = ds.getConnection("userid", "password");
      stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery("select ....");
      while(rs.next()){
        .....
      }
      rs.close();
    }
    catch(Exception e){
      .....
    }
    finally {
      if ( stmt != null ) try{stmt.close();}catch(Exception e){}
      if ( conn != null ) try{conn.close();}catch(Exception e){}
    }

------------------------------------------------------------------
IBM WebSphere Application Server 2.0.x
 
    import java.sql.*;
    import com.ibm.servlet.connmgr.*;


    // ConnMgr Cache 사용을 위한 connMgr 객체 static 초기화

    private static IBMConnMgr connMgr = null;
    private static IBMConnSpec spec = null;
    static {
      try {
        String poolName = "JdbcDb2";  // defined in WebSphere Admin Console
        spec = new IBMJdbcConnSpec(poolName, false, 
              "com.ibm.db2.jdbc.app.DB2Driver",
              "jdbc:db2:<db_name>",   // "jdbc:db2://ip_address:6789/<db_name>",
              "userid","password");
        connMgr = IBMConnMgrUtil.getIBMConnMgr();
      }
      catch(Exception e){
        .....
      }
    }

    .....

    IBMJdbcConn cmConn = null; // "cm" maybe stands for Connection Manager.
    Statement stmt = null;
    try {
      cmConn = (IBMJdbcConn)connMgr.getIBMConnection(spec);   
      Connection conn = jdbcConn.getJdbcConnection();
      stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery("select ....");
      while(rs.next()){
        .....
      }
      rs.close();
    }
    catch(Exception e){
      .....
    }
    finally {
      if ( stmt != null ) try{stmt.close();}catch(Exception e){}
      if ( cmConn != null ) try{cmConn.releaseIBMConnection();}catch(Exception e){}
    }
    // NOTE: DO NOT "conn.close();" !!


------------------------------------------------------------------
Oracle OSDK(Oracle Servlet Development Kit)

    import java.sql.*;
    import oracle.ec.ctx.*;


    .....
   
    oracle.ec.ctx.Trx trx = null;
    Connection conn = null;
    Statement stmt = null;
    try {
      oracle.ec.ctx.TrxCtx ctx = oracle.ec.ctx.TrxCtx.getTrxCtx();
      trx = ctx.getTrx();
      conn = trx.getConnection("<pool_name>");
      stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery("select ....");
      while(rs.next()){
        .....
      }
      rs.close();
    }
    catch(Exception e){
      .....
    }
    finally {
      if ( stmt != null ) try{stmt.close();}catch(Exception e){}
      if ( conn != null ) try{ trx.close(conn,"<pool_name>");}catch(Exception e){}
    }
    // NOTE: DO NOT "conn.close();" !!


------------------------------------------------------------------
Hans Bergsten 의 DBConnectionManager.java

    import java.sql.*;

    .....
   
    db.DBConnectionManager connMgr = null;
    Connection conn = null;
    Statement stmt = null;
    try {
      connMgr = db.DBConnectionManager.getInstance();
      conn = connMgr.getConnection("<pool_name>");
      stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery("select ....");
      while(rs.next()){
        .....
      }
      rs.close();
    }
    catch(Exception e){
      .....
    }
    finally {
      if ( stmt != null ) try{stmt.close();}catch(Exception e){}
      if ( conn != null ) connMgr.freeConnection("<pool_name>", conn);
    }
    // NOTE: DO NOT "conn.close();" !!

------------------------------------------------------------------
JDF 의 DB Connection Pool Framework

    import java.sql.*;
    import com.lgeds.jdf.*;
    import com.lgeds.jdf.db.*;
    import com.lgeds.jdf.db.pool.*;


    private static com.lgeds.jdf.db.pool.JdbcConnSpec spec = null;
    static {
      try {
        com.lgeds.jdf.Config conf = new com.lgeds.jdf.Configuration();
        spec =  new com.lgeds.jdf.db.pool.JdbcConnSpec(
             conf.get("gov.mpb.pbf.db.emp.driver"),
             conf.get("gov.mpb.pbf.db.emp.url"),
             conf.get("gov.mpb.pbf.db.emp.user"),
             conf.get("gov.mpb.pbf.db.emp.password")
          );
      }
      catch(Exception e){
        .....
      }
    }

    .....

    PoolConnection poolConn = null;
    Statement stmt = null;
    try {
      ConnMgr mgr = ConnMgrUtil.getConnMgr();
      poolConn = mgr.getPoolConnection(spec);
      Connection conn = poolConnection.getConnection();
      stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery("select ....");
      while(rs.next()){
        .....
      }
      rs.close();
    }
    catch(Exception e){
      .....
    }
    finally {
      if ( stmt != null ) try{stmt.close();}catch(Exception e){}
      if ( poolConn != null ) poolConn.release();
    }
    // NOTE: DO NOT "conn.close();" !!

------------------------------------------------------------------


여기서 하고픈 얘기는 DB Connection Pool 을 구현하는 방식에 따라서 개발자의 소스도
전부 제 각기 다른 API를 사용해야 한다는 것입니다.
프로젝트를 이곳 저곳 뛰어 본 분은 아시겠지만, 매 프로젝트마나 어플리케이션 서버가
다르고 지난 프로젝트에서 사용된 소스를 새 프로젝트에 그대로 적용하지 못하게 됩니다.
JDBC 관련 API가 다르기 때문이죠.
같은 제품일지라도 버전업이 되면서 API가 변해버리는 경우도 있습니다. 예를 들면,
IBM WebSphere 버전 2.0.x에서 버전 3.0.x로의 전환할 때, DB 연결을 위한 API가
변해버려 기존에 개발해둔 400 여개의 소스를 다 뜯어 고쳐야 하는 것과 같은 상황이
벌어질 수도 있습니다.
닷컴업체에서 특정 패키지 제품을 만들때도 마찬가지 입니다. 자사의 제품이 어떠한
어플리케이션 서버에서 동작하도록 해야 하느냐에 따라 코딩할 API가 달라지니 소스를
매번 변경해야만 하겠고, 특정 어플리케이션 서버에만 동작하게 하려니 마켓시장이
좁아지게 됩니다.
IBM WebSphere, BEA WebLogic 뿐만 아니라 Apache JServ 나 JRun, 혹은 Tomcat 에서도
쉽게 포팅하길 원할 것입니다.

이것을 해결하는 방법은 우리들 "SE(System Engineer)"만의 고유한 "Connection Adapter
클래스"를 만들어서 사용하는 것입니다.

예를 들어 개발자의 소스는 이제 항상 다음과 같은 유형으로 코딩되면 어떻겠습니까 ?


    -----------------------------------------------------------
    .....
    ConnectionResource resource = null;
    Statement stmt = null;
    try {
      resource = new ConnectionResource();
      Connection conn = resource.getConnection();

      stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery("select ....");
      while(rs.next()){
        .....
      }
      rs.close();
    }
    catch(Exception e){
      .....
    }
    finally {
      if ( stmt != null ) try{stmt.close();}catch(Exception e){}
      if ( resource != null ) resource.release();
    }
    // NOTE: DO NOT "conn.close();" !!
    -----------------------------------------------------------



이 때 ConnectionResource 는 다음과 같은 형식으로 누군가 한분이 만들어 두면 되겠죠.

    -----------------------------------------------------------
    import java.sql.*;
    public class ConnectionResource
    {
      private java.sql.Connection conn = null;
      public ConnectionResource() throws Exception {
         ......
         conn =  ..... GET Connection by Connection Pooling API
      }
      public Connection getConnection() throws Exception {
         return conn;
      }
      public void release(){
         // release conn into "Connection Pool"
         .......
      }
    }
    -----------------------------------------------------------



  예를 들어 IBM WebSphere Version 3.0.2.x 의 경우를 든다면 다음과 같이 될 겁니다.

  -----------------------------------------------------------
  package org.jsn.connpool;
  /*
   * ConnectionResource V 1.0
   * JDBC Connection Pool Adapter for IBM WebSphere V 3.0.x/3.5.x
   * Author: WonYoung Lee, javaservice@hanmail.net, 011-898-7904
   * Last Modified : 2000.11.10
   * NOTICS: You can re-distribute or copy this source code freely,
   *         you can NOT remove the above subscriptions.
  */

  /* IBM WebSphere 3.0.2.x for JDK 1.1.8 */
  //import java.sql.*;
  //import javax.naming.*;
  //import com.ibm.ejs.dbm.jdbcext.*;
  //import com.ibm.db2.jdbc.app.stdext.javax.sql.*;

  /* IBM WebSphere 3.5.x for JDK 1.2.2 */
  import java.sql.*;
  import javax.sql.*;
  import javax.naming.*;

  public class ConnectionResource
  {
     private static final String userid = "userid";
     private static final String password = "password"
     private static final String datasource = "jdbc/<data_source_name>";
     private static DataSource ds = null;

     private java.sql.Connection conn = null;

     public ConnectionResource() throws Exception {
       synchronized ( ConnectionResource.class ) {
         if ( ds == null ) {
           java.util.Hashtable props = new java.util.Hashtable();
           props.put(Context.INITIAL_CONTEXT_FACTORY,
              "com.ibm.ejs.ns.jndi.CNInitialContextFactory");
           Context ctx = null;
           try {
             ctx = new InitialContext(props);
             ds = (DataSource)ctx.lookup("jdbc/<data_source_name>");
           }
           finally {
             if ( ctx != null ) ctx.close();
           }
         }
       }
       conn =  ds.getConnection( userid, password );
     }
     public Connection getConnection() throws Exception {
        if ( conn == null ) throw new Exception("Connection is NOT avaiable !!");
        return conn;
     }
     public void release(){
        // release conn into "Connection Pool"
        if ( conn != null ) try { conn.close(); }catch(Excepton e){}
        conn = null;
     }
   }
   -----------------------------------------------------------
         


 
  만약 Hans Bersten 의 DBConnectionManager.java 를 이용한 Connection Pool 이라면
  다음과 같이 만들어 주면 됩니다.

   -----------------------------------------------------------
   package org.jsn.connpool;
   import java.sql.*;
   public class ConnectionResource
   {
      private String poolname = "<pool_name>";
      private Connection conn = null;
      private db.DBConnectionManager connMgr = null;

      public ConnectionResource() throws Exception {
         connMgr = db.DBConnectionManager.getInstance();
         conn =  connMgr.getConnection(poolname);
      }
      public Connection getConnection() throws Exception {
         if ( conn == null ) throw new Exception("Connection is NOT avaiable !!");
         return conn;
      }
      public void release(){
         if ( conn != null ) {
           // Dirty Transaction을 rollback시키는 부분인데, 생략하셔도 됩니다.
           boolean autoCommit = true;
           try{ autoCommit = conn.getAutoCommit(); }catch(Exception e){}
           if ( autoCommit == false ) {
             try { conn.rollback(); }catch(Exception e){}
             try { conn.setAutoCommit(true); }catch(Exception e){}
           }

           connMgr.freeConnection(poolname, conn);
           conn = null;
         }
      }
   }
   -----------------------------------------------------------


  또, Resin 1.2.x 의 경우라면 다음과 같이 될 겁니다.
  -----------------------------------------------------------
  package org.jsn.connpool;
  /*
   * ConnectionResource V 1.0
   * JDBC Connection Pool Adapter for Resin 1.2.x
   * Author: WonYoung Lee, javaservice@hanmail.net, 011-898-7904
   * Last Modified : 2000.10.18
   * NOTICS: You can re-distribute or copy this source code freely,
   *         you can NOT remove the above subscriptions.
  */
  import java.sql.*;
  import javax.sql.*;
  import javax.naming.*;
  public class ConnectionResource
  {
     private static final String datasource = "jdbc/<data_source_name>";
     private static final String userid = "userid";
     private static final String password = "password"
     private static DataSource ds = null;

     private java.sql.Connection conn = null;

     public ConnectionResource() throws Exception {
        synchronized ( ConnectionResource.class ) {
          if ( ds == null ) {
            Context env = (Context) new InitialContext().lookup("java:comp/env");
            ds = (DataSource) env.lookup(datasource);
          }
        }   
        conn =  ds.getConnection( userid, password );
     }
     public Connection getConnection() throws Exception {
        if ( conn == null ) throw new Exception("Connection is NOT avaiable !!");
        return conn;
     }
     public void release(){
        // release conn into "Connection Pool"
        if ( conn != null ) try { conn.close(); }catch(Excepton e){}
        conn = null;
     }
   }
   -----------------------------------------------------------


  Oracle 8i(8.1.6이상)에서 Oracle의 JDBC 2.0 Driver 자체가 제공하는 Connection
  Pool을 이용한다면 다음과 같이 될 겁니다.
  -----------------------------------------------------------
  package org.jsn.connpool;
  /*
   * ConnectionResource V 1.0
   * JDBC Connection Pool Adapter for Oracle JDBC 2.0
   * Author: WonYoung Lee, javaservice@hanmail.net, 011-898-7904
   * Last Modified : 2001.10.29
   * NOTICS: You can re-distribute or copy this source code freely,
   *         but you can NOT remove the above subscriptions.
  */
  import java.sql.*;
  import javax.sql.*;
  import oracle.jdbc.driver.*;
  import oracle.jdbc.pool.*;

  public class ConnectionResource
  {
     private static final String dbUrl = "jdbc:oracle:thin@192.168.0.1:1521:ORCL";
     private static final String userid = "userid";
     private static final String password = "password"
     private static OracleConnectionCacheImpl oraclePool = null;
     private static boolean initialized = false;

     private java.sql.Connection conn = null;

     public ConnectionResource() throws Exception {
        synchronized ( ConnectionResource.class ) {
          if ( initialized == false ) {
            DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver());
            oraclePool = new OracleConnectionCacheImpl();
            oraclePool.setURL(dbUrl);
            oraclePool.setUser(userid);
            oraclePool.setPassword(password);
            oraclePool.setMinLimit(10);
            oraclePool.setMaxLimit(50);
            //oraclePool.setCacheScheme(OracleConnectionCacheImpl.FIXED_WAIT_SCHEME);
            // FIXED_WAIT_SCHEME(default), DYNAMIC_SCHEME, FIXED_RETURN_NULL_SCHEME
            //oraclePool.setStmtCacheSize(0); //default is 0

            initialized = true;
          }
        }   
        conn = oraclePool.getConnection();
     }
     public Connection getConnection() throws Exception {
        if ( conn == null ) throw new Exception("Connection is NOT avaiable !!");
        return conn;
     }
     public void release(){
        // release conn into "Connection Pool"
        if ( conn != null ) try { conn.close(); }catch(Exception e){}
        conn = null;
     }
   }
   -----------------------------------------------------------

  또한 설령 Connection Pool 기능을 지금을 사용치 않더라도 향후에 적용할 계획이
  있다면, 우선은 다음과 같은 Connection Adapter 클래스를 미리 만들어 두고 이를
  사용하는 것이 효과적입니다. 향후에 이 클래스만 고쳐주면 되니까요.
  Oracle Thin Driver를 사용하는 경우입니다.

  -----------------------------------------------------------
  import java.sql.*;
  public class ConnectionResource
  {
     private static final String userid = "userid";
     private static final String password = "password"
     private static final String driver = "oracle.jdbc.driver.OracleDriver"
     private static final String url = "jdbc:oracle:thin@192.168.0.1:1521:ORCL";
     private static boolean initialized = false;

     private java.sql.Connection conn = null;

     public ConnectionResource() throws Exception {
        synchronized ( ConnectionResource.class ) {
          if ( initialized == false ) {
              Class.forName(driver);
              initialized = true;
          }
        }
        conn = DriverManager.getConnection( url, userid, password );
     }
     public Connection getConnection() throws Exception {
        if ( conn == null ) throw new Exception("Connection is NOT avaiable !!");
        return conn;
     }
     public void release(){
        if ( conn != null ) try { conn.close(); }catch(Excepton e){}
        conn = null;
     }
   }
   -----------------------------------------------------------


프로그램의 유형이나, 클래스 이름이야 뭐든 상관없습니다. 위처럼 우리들만의 고유한
"Connection Adapter 클래스"를 만들어서 사용한다는 것이 중요하고, 만약 어플리케이션
서버가 변경된다거나, DB Connection Pooling 방식이 달라지면 해당 ConnectionResource
클래스 내용만 살짝 고쳐주면 개발자의 소스는 전혀 고치지 않아도 될 것입니다.

NOTE: ConnectionResource 클래스를 만들때 주의할 것은 절대 Exception 을 클래스 내부에서
   가로채어 무시하게 하지 말라는 것입니다. 그냥 그대로 throw 가 일어나게 구현하세요.
   이렇게 하셔야만 개발자의 소스에서 "Exception 처리"를 할 수 있게 됩니다.

NOTE2: ConnectionResource 클래스를 만들때 반드시 package 를 선언하도록 하세요.
   IBM WebSphere 3.0.x 의 경우 JSP에서 "서블렛클래스패스"에 걸려 있는 클래스를
   참조할 때, 그 클래스가 default package 즉 package 가 없는 클래스일 경우 참조하지
   못하는 버그가 있습니다. 통상 "Bean"이라 불리는 클래스 역시 조건에 따라 인식하지
   않을 수도 있습니다.
   클래스 다지인 및 설계 상으로 보더라도 package 를 선언하는 것이 바람직합니다.

NOTE3: 위에서  "userid", "password" 등과 같이 명시적으로 프로그램에 박아 넣지
   않고, 파일로 관리하기를 원한다면, 그렇게 하셔도 됩니다.
   JDF의 Configuration Framework 을 참조하세요.


PS: 혹자는 왜 ConnectionResource 의 release() 메소드가 필요하냐고 반문할 수도 있습
   니다. 예를 들어 개발자의 소스가 다음처럼 되도록 해도 되지 않느냐라는 거죠.

    -----------------------------------------------------------
    .....
    Connection conn = null;
    Statement stmt = null;
    try {
      conn = ConnectionResource.getConnection(); // <---- !!!

      stmt = conn.createStatement();
      .....
    }
    catch(Exception e){
      .....
    }
    finally {
      if ( stmt != null ) try{stmt.close();}catch(Exception e){}
      if ( conn != null ) try{conn.close();}catch(Exception e){} // <---- !!!
    }
    -----------------------------------------------------------

  이렇게 하셔도 큰 무리는 없습니다. 그러나, JDBC 2.0 을 지원하는 제품에서만
  conn.close() 를 통해 해당 Connection 을 실제 close() 시키는 것이 아니라 DB Pool에
  반환하게 됩니다. BEA WebLogic 이나 IBM WebSphere 3.0.2.x, 3.5.x 등이 그렇습니다.
  그러나, 자체제작된 대부분의 DB Connection Pool 기능은 Connection 을 DB Pool에
  반환하는 고유한 API를 가지고 있습니다. WebSphere Version 2.0.x 에서는
  cmConn.releaseIBMConnection(), Oracle OSDK 에서는 trx.close(conn, "<pool_name">);
  Hans Bersten 의 DBConnectionManager 의 경우는
  connMgr.freeConnection(poolname, conn); 등등 서로 다릅니다. 이러한 제품들까지
  모두 지원하려면 "release()" 라는 우리들(!)만의 예약된 메소드가 꼭 필요하게 됩니다.

  물론, java.sql.Connection Interface를 implements 한 별도의 MyConnection 을 만들어
  두고, 실제 java.sql.Connection 을 얻은 후 MyConnection의 생성자에 그 reference를
  넣어준 후, 이를 return 시에 넘기도록 하게 할 수 있습니다. 이때, MyConnection의
  close() 함수를 약간 개조하여 DB Connection Pool로 돌아가게 할 수 있으니까요.


PS: 하나 이상의 DB 를 필요로 한다면, 다음과 같은 생성자를 추가로 만들어서 구분케
  할 수도 있습니다.

  -----------------------------------------------------------
  ....
  private String poolname = "default_pool_name";
  private String userid = "scott";
  private String password = "tiger";
  public ConnectionResource() throws Exception {
    initialize();
  }
  public ConnectionResource(String poolname) throws Exception {
    this.poolname = poolname;
    initialize();
  }
  public ConnectionResource(String poolname,String userid, String passwrod)
  throws Exception
  {
    this.poolname = poolname;
    this.userid = userid;
    this.password = password;
    initialize();
  }
  private void initialize() throws Exception {
    ....
  }
  ...
  -----------------------------------------------------------



-------------------------------------------------------------------------------
2001.03.20 추가
2001.10.22 수정
2001.11.09 수정(아래 설명을 추가함)

실 운영 사이트의 장애진단 및 튜닝을 다녀보면, 장애의 원인이 DataBase 연결개수가
지속적으로 증가하고, Connection Pool 에서 더이상 가용한 연결이 남아 있지 않아
발생하는 문제가 의외로 많습니다. 이 상황의 십중팔구는 개발자의 코드에서 Pool로
부터 가져온 DB연결을 사용하고 난 후, 이를 여하한의 Exception 상황에서도 다시
Pool로 돌려보내야 한다는 Rule 를 지키지 않아서 발생한 문제가 태반입니다.
이름만 말하면 누구나 알법한 큼직한 금융/뱅킹사이트의 프로그램소스에서도 마찬가지
입니다.
문제는 분명히 어떤 특정 응용프로그램에서 DB Connection 을 제대로 반환하지 않은
것은 분명한데, 그 "어떤 특정 응용프로그램"이 꼭집어 뭐냐 라는 것을 찾아내기란
정말 쉽지 않습니다. 정말 쉽지 않아요. 1초당 수십개씩의 Request 가 다양하게 들어
오는 상황에서, "netstat -n"으로 보이는 TCP/IP 레벨에서의 DB연결수는 분명히 증가
하고 있는데, 그 수십개 중 어떤 것이 문제를 야기하느냐를 도저히 못찾겠다는 것이지요.
사용자가 아무도 없는 새벽에 하나씩 컨텐츠를 꼭꼭 눌러 본들, 그 문제의 상황은
대부분 정상적인 로직 flow 에서는 나타나지 않고, 어떤 특별한 조건, 혹은 어떤
Exception 이 발생할 때만 나타날 수 있기 때문에, 이런 방법으로는 손발과 눈만 아프게
되곤 합니다.

따라서, 애초 부터, 이러한 상황을 고려하여, 만약, 개발자의 코드에서 실수로 DB연결을
제대로 Pool 에 반환하지 않았을 때, 그 개발자 프로그램 소스의 클래스 이름과 함께
Warnning 성 메세지를 남겨 놓으면, 되지 않겠느냐는 겁니다.

Java 에서는 java.lang.Object 의 finalize() 라는 기막힌 메소드가 있습니다. 해당
Object instance의 reference 가 더이상 그 어떤 Thread 에도 남아 있지 않을 경우
JVM의 GC가 일어날 때 그 Object 의 finalize() 메소드를 꼭 한번 불러주니까요.

계속 반복되는 얘기인데, 아래 글에서 또한번 관련 의미를 찾을 수 있을 것입니다.
Re: DB Connection Pool: Orphan and Idle Timeout
http://www.javaservice.net/~java/bbs/read.cgi?m=devtip&b=servlet&c=r_p&n=1005294960

아래는 이것을 응용하여, Hans Bergsten 의 DBConnectionManager 를 사용하는
ConnectionAdapter 클래스를 만들어 본 샘플입니다. Trace/Debuging 을 위한 몇가지
기능이 첨가되어 있으며, 다른 ConnectionPool을 위한 Connection Adapter 를 만들때도
약간만 수정/응용하여 사용하실 수 있을 것입니다.


/**
* Author : Lee WonYoung, javaservice@hanmail.net
* Date   : 2001.03.20, 2001.10.22
*/

import java.util.*;
import java.sql.*;
import java.io.*;
import java.text.SimpleDateFormat;

public class ConnectionResource
{
    private boolean DEBUG_MODE = true;
    private String DEFAULT_DATASOURCE = "idb";  // default db name
    private long GET_CONNECTION_TIMEOUT = 2000; // wait only 2 seconds if no
                                                // avaiable connection in the pool
    private long WARNNING_MAX_ELAPSED_TIME = 3000;

    private SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd/HHmmss");
    private db.DBConnectionManager manager = null;
    private Connection conn = null;
    private String datasource = DEFAULT_DATASOURCE;
    private String caller = "unknown";
    private long starttime = 0;

    private static int used_conn_count = 0;
    private static Object lock = new Object();

    // detault constructor
    public ConnectionResource()
    {
        manager = db.DBConnectionManager.getInstance();
    }

    // For debugging, get the caller object reference
    public ConnectionResource(Object caller_obj)
    {
        this();
        if ( caller_obj != null )
            caller = caller_obj.getClass().getName();
    }

    public Connection getConnection()  throws Exception
    {
        return getConnection(DEFAULT_DATASOURCE);
    }

    public Connection getConnection(String datasource)  throws Exception
    {
        if ( conn != null ) throw new Exception
            ("You must release the connection first to get connection again !!");

        this.datasource = datasource;
        // CONNECTION_TIMEOUT is very important factor for performance tuning
        conn = manager.getConnection(datasource, GET_CONNECTION_TIMEOUT);
        synchronized( lock ) { ++used_conn_count; }
        starttime = System.currentTimeMillis();
        return conn;
    }

    // you don't have to get "connection reference" as parameter,
    // because we already have the referece as the privae member variable.
    public synchronized void release() throws Exception { 
        if ( conn == null ) return;
        // The following is needed for some DB connection pool.
        boolean mode = true;
        try{
            mode = conn.getAutoCommit();
        }catch(Exception e){}
        if ( mode == false ) {
            try{conn.rollback();}catch(Exception e){}
            try{conn.setAutoCommit(true);}catch(Exception e){}
        }
        manager.freeConnection(datasource, conn);
        conn = null;
        int count = 0;
        synchronized( lock ) { count = --used_conn_count; }
        if ( DEBUG_MODE ) {
            long endtime = System.currentTimeMillis();
            if ( (endtime-starttime) > WARNNING_MAX_ELAPSED_TIME ) {
                System.err.println(df.format(new java.util.Date()) +
                    ":POOL:WARNNING:" + count +
                    ":(" + (endtime-starttime) + "):" +
                    "\t" + caller
                );
            }
        }
    }
    // finalize() method will be called when JVM's GC time.
    public void finalize(){
        // if "conn" is not null, this means developer did not release the "conn".
        if ( conn != null ) {
            System.err.println(df.format(new java.util.Date()) +
                ":POOL:ERROR connection was not released:" +
                used_conn_count + ":\t" + caller
            );
            release();
        }
    }
}

-------------------------------------------------------------------------------

위의 Connection Adaptor 클래스를 Servlet 이나 JSP에서 사용할 때는 다음과 같이
사용할 수 있습니다.


사용법: DB Transaction 처리가 필요치 않을 때...


ConnectionResource resource = null;
Connection conn = null;
Statement stmt = null;
try{
    // For debugging and tracing, I recommand to send caller's reference to
    // the adapter's constructor.
    resource = new ConnectionResource(this); // <--- !!!
    //resource = new ConnectionResource();

    conn = resource.getConnection();
    // or you can use another database name
    //conn = resource.getConnection("other_db");

    stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("select ...");
    while(rs.next()){
        .....
    }
    rs.close();

}
//catch(Exception e){
//    // error handling if you want
//    ....
//}
finally{
    if ( stmt != null ) try{stmt.close();}catch(Exception e){}
    if ( conn != null ) resource.release(); // <--- !!!
}

-------------------------------------------------------------------------------
사용법: Transaction 처리가 필요할 때.

ConnectionResource resource = null;
Connection conn = null;
Statement stmt = null;
try{
    // For debugging and tracing, I recommand to send caller's reference to
    // the adapter's constructor.
    resource = new ConnectionResource(this);
    //resource = new ConnectionResource();

    conn = resource.getConnection();
    // or you can use another database name
    //conn = resource.getConnection("other_db");

    conn.setAutoCommit(false); // <--- !!!

    stmt = conn.createStatement();
    stmt.executeUpdate("update ...");
    stmt.executeUpdate("insert ...");
    stmt.executeUpdate("update ...");
    stmt.executeUpdate("insert ...");
    stmt.executeUpdate("update ...");
   
    int affected = stmt.executeUpdate("update....");
    // depends on your business logic,
    if ( affected == 0 )
        throw new Exception("NoAffectedException");
    else if ( affected > 1 )
        throw new Exception("TooManyAffectedException:" + affected);

    conn.commit(); //<<-- commit() must locate at the last position in the "try{}"
}
catch(Exception e){
    // if error, you MUST rollback
    if ( conn != null ) try{conn.rollback();}catch(Exception e){}

    // another error handling if you want
    ....
    throw e; // <--- throw this exception if you want
}
finally{
    if ( stmt != null ) try{stmt.close();}catch(Exception e){}
    if ( conn != null ) resource.release(); // <-- NOTE: autocommit mode will be
                                            //           initialized
}
-----------------------------------------------------------------

PS: 더 깊이있는 내용을 원하시면 다음 문서들을 참조 하세요...
    JDF 제4탄 - DB Connection Pool
    http://www.javaservice.net/~java/bbs/read.cgi?m=jdf&b=framework&c=r_p&n=945156790

    JDF 제5탄 - DB Connection Resource Framework
    http://www.javaservice.net/~java/bbs/read.cgi?m=jdf&b=framework&c=r_p&n=945335633

    JDF 제6탄 - Transactional Connection Resource Framework
    http://www.javaservice.net/~java/bbs/read.cgi?m=jdf&b=framework&c=r_p&n=945490586


PS: IBM WebSphere의 JDBC Connection Pool 에 관심이 있다면 다음 문서도 꼭 참조
하세요...
    Websphere V3 Connection Pool 사용법
    http://www.javaservice.net/~java/bbs/read.cgi?m=appserver&b=was&c=r_p&n=970209527
    WebSphere V3 DB Connection Recovery 기능 고찰
    http://www.javaservice.net/~java/bbs/read.cgi?m=appserver&b=was&c=r_p&n=967473008

------------------------
NOTE: 2004.04.07 추가
그러나, 2004년 중반을 넘어서는 이 시점에서는, ConnectionResource와 같은 Wapper의
중요성이 별로 높이 평가되지 않는데, 그 이유는 Tomcat 5.0을 비롯한 대부분의 WAS(Web
Application Server)가 자체의 Connection Poolinig기능을 제공하며, 그 사용법은 다음과
같이 JDBC 2.0에 준하여 모두 동일한 형태를 띠고 있기 때문입니다.

InitialContext ctx = new InitialContext();
DataSource ds = (DataSoruce)ctx.lookup("java:comp/env/jdbc/ds");
Connection conn = ds.getConnection();
...
conn.close();

결국 ConnectionResource의 release()류의 메소드는 Vendor별로, JDBC Connection Pool의
종류가 난무하던 3-4년 전에는 어플리케이션코드의 Vendor종속성을 탈피하기 위해 의미를
가졌으나, 지금은 굳이 필요가 없다고 보여 집니다.

단지, caller와 callee의 정보, 즉, 응답시간을 추적한다거나, close() 하지 않은
어플리케이션을 추적하는 의미에서의 가치만 남을 수 있습니다.  (그러나, 이것도,
IBM WebSphere v5의 경우, 개발자가 conn.close() 조차 하지 않을 지라도 자동을 해당
Thread의 request ending시점에 "자동반환"이 일어나게 됩니다.)

---------------------
2005.01.21 추가
JDBC Connection/Statement/ResultSet을 close하지 않은 소스의 위치를 잡아내는 것은
실제 시스템 운영 중에 찾기란 정말 모래사장에서 바늘찾기 같은 것이었습니다.
그러나, 제니퍼(Jennifer2.0)과 같은 APM을 제품을 적용하시면, 운영 중에, 어느 소스의
어느 위치에서 제대로 반환시키지 않았는지를 정확하게 찾아줍니다.
뿐만 아니라, 모든 SQL의 수행통계 및 현재 수행하고 있는 어플리케이션이 어떤 SQL을
수행중인지 실시간으로 확인되니, 성능저하를 보이는 SQL을 튜닝하는 것 등, 많은 부분들이
명확해져 가고 있습니다. 이젠 더이상 위 글과 같은 문서가 필요없는 세상을 기대해 봅니다.

------------------------------------------------------- 
  본 문서는 자유롭게 배포/복사 할 수 있으나 반드시
  이 문서의 저자에 대한 언급을 삭제하시면 안됩니다
================================================
  자바서비스넷 이원영
  E-mail: javaservice@hanmail.net
  PCS:011-898-7904
================================================
Posted by 1010
05.JSP2008. 10. 19. 15:39
반응형
서블렛에서 instance variable 의 공유

1.1 서블렛에서 instance variable 의 공유 - PrintWriter -

  다음과 같은 코드를 생각해 보겠습니다.

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class CountServlet extends HttpServlet {
     private PrintWriter out = null; // <-------------- (1)

     public void doGet(HttpServletRequest req, HttpServletResponse res) 
         throws ServletException, IOException
     {
         res.setContentType("text/html");
         out = res.getWriter();
         for(int i=0;i<20;i++){
             out.println("count= " + (i+1) + "<br>");  // <---- (2)
             out.flush();
             try{Thread.sleep(1000);}catch(Exception e){}
         }
    }
  }

위의 CountServlet.java 를 컴파일하여 돌려 보면, 1초간격으로 일련의 숫자가 올라가는
것이 보일 겁니다.(서블렛엔진의 구현방식에 따라 Buffering 이 되어 20초가 모두 지난
후에서 퍽 나올 수도 있습니다.)
혼자서 단일 Request 를 날려 보면, 아무런 문제가 없겠지만, 이제 브라우져 창을 두개 이상
띄우시고 10초의 시간 차를 두시면서 동시에 호출해 보세요... 이상한 증상이 나타날
겁니다. 먼저 호출한 창에는 10 까지 정도만 나타나고, 10초 뒤에 호출한 창에서는 먼저
호출한 창에서 나타나야할 내용들까지 덤으로 나타나는 것을 목격할 수 있을 겁니다.

이는 서블렛의 각 호출은 Thread 로 동작하여, 따라서, 각 호출은 위의 (1) 에서 선언한
instance variable 들을 공유하기 때문에 나타나는 문제입니다.

위 부분은 다음과 같이 고쳐져야 합니다.

  public class CountServlet extends HttpServlet {
     //private PrintWriter out = null;

     public void doGet(HttpServletRequest req, HttpServletResponse res) 
         throws ServletException, IOException
     {
         PrintWriter out = null; // <--- 이 쪽으로 와야죠 !!!
         res.setContentType("text/html");
         out = res.getWriter();
         for(int i=0;i<20;i++){
             out.println("count= " + (i+1) + "<br>");  // <---- (2)
             out.flush();
             try{Thread.sleep(1000);}catch(Exception e){}
         }
    }
  }

국내 몇몇 Servlet 관련 서적의 일부 예제들이 위와 같은 잘못된 형태로 설명한
소스코드들이 눈에 띕니다. 빠른 시일에 바로 잡아야 할 것입니다.

실제 프로젝트 환경에서 개발된 실무시스템에서도, 그러한 책을 통해 공부하신듯, 동일한
잘못된 코딩을 하고 있는 개발자들이 있습니다. 결과적으로 테스트 환경에서는 나타나지
않더니만, 막상 시스템을 오픈하고나니 고객으로 부터 다음과 같은 소리를 듣습니다.
"내 데이타가 아닌데 남의 데이타가 내 화면에 간혹 나타나요. refresh 를 누르면 또,
제대로 되구요" .....


1.2 서블렛에서 instance variable 의 공유

앞서의 경우와 의미를 같이하는데, 다음과 같이 하면 안된다는 얘기지요.

  public class BadServlet extends HttpServlet {
     private String userid = null;
     private String username = null;
     private int hitcount = 0;

     public void doGet(HttpServletRequest req, HttpServletResponse res) 
         throws ServletException, IOException
     {
         res.setContentType("text/html");
         PrintWriter out = res.getWriter();
         userid = request.getParameter("userid");
         username = request.getParameter("username");
         hitcount = hitcount + 1;
         ....
    }
  }

새로운 매 HTTP 요청마다 userid/username변수는 새롭게 할당됩니다. 문제는 그것이 특정
사용자에 한하여 그러한 것이 아니라, BadServlet의 인스턴스(instance)는 해당
웹컨테이너(Web Container)에 상에서 (예외경우가 있지만) 단 하나만 존재하고, 서로 다른
모든 사용자들의 서로 다른 모든 요청들에 대해서 동일한 userid/username 및 count 변수를
접근하게 됩니다. 따라서, 다음과 같이 메소드 안으로 끌어들여 사용하여야 함을 강조합니다.

  public class BadServlet extends HttpServlet {
     //private String userid = null; // <---- !!
     //private String username = null; // <---- !!
     private int hitcount = 0;

     public void doGet(HttpServletRequest req, HttpServletResponse res) 
         throws ServletException, IOException
     {
         res.setContentType("text/html");
         PrintWriter out = res.getWriter();
         String userid = request.getParameter("userid"); // <---- !!
         String username = request.getParameter("username"); // <---- !!

         //또한, instance 변수에 대한 접근은 적어도 아래처럼 동기화를 고려해야...
         synchronized(this){ hitcount = hitcount + 1; }
         ....
    }
  }


1.3 서블렛에서 instance variable 의 공유  - DataBase Connection -

public class TestServlet extends HttpServlet {
     private final static String drv = "oracle.jdbc.driver.OracleDriver";
     private final static String url = "jdbc:orache:thin@210.220.251.96:1521:ORA8i";
     private final static String user = "scott";
     private final static String password = "tiger";

     private ServletContext context;
     private Connection conn = null;  <--- !!!
     private Statement stmt = null; <------ !!!
     private ResultSet rs = null; <------ !!!

     public void init(ServletConfig config) throws ServletException {
         super.init(config);
         context = config.getServletContext();
         try {
             Class.forName(drv);
         }
         catch (ClassNotFoundException e) {
             throw new ServletException("Unable to load JDBC driver:"+ e.toString());
         }
     }
     public void doGet(HttpServletRequest req, HttpServletResponse res) 
         throws ServletException, IOException, SQLException
     {
         String id = req.getParameter("id");
         conn = DriverManager.getConnection(url,user,password);   ---- (1)
         stmt = conn.createStatement();  ---------- (2)
         rs = stmt.executeQuery("select .... where id = '" + id + "'"); ----- (3)
         while(rs.next()) { ----------- (4)
            ......  --------- (5)
         } 
         rs.close();  -------- (6)
         stmt.close();  ---- (7)
         conn.close();  --- (8)
         .....
    }
  }

  위에서 뭐가 잘못되었죠? 여러가지가 있겠지만, 그 중에 하나가 java.sql.Connection과
  java.sql.Statment, java.sql.ResultSet을 instance variable 로 사용하고 있다는 것입니다.

  이 서블렛은 사용자가 혼자일 경우는 아무런 문제를 야기하지 않습니다. 그러나 여러사람이
  동시에 이 서블렛을 같이 호출해 보면, 이상한 증상이 나타날 것입니다.
  그 이유는 conn, stmt, rs 등과 같은 reference 들을 instance 변수로 선언하여 두었기
  때문에 발생합니다.  서블렛은 Thread로 동작하며 위처럼 instance 변수 영역에 선언해 둔
  reference 들은 doGet(), doPost() 를 수행하면서 각각의 요청들이 동시에 공유하게 됩니다.

  예를 들어, 두개의 요청이 약간의 시간차를 두고 비슷한 순간에 doGet() 안으로 들어왔다고
  가정해 보겠습니다.
  A 라는 요청이 순차적으로 (1), (2), (3) 까지 수행했을 때, B 라는 요청이 곧바로 doGet()
  안으로 들어올 수 있습니다. B 역시 (1), (2), (3) 을 수행하겠죠...
  이제 요청 A 는 (4) 번과 (5) 번을 수행하려 하는데, 가만히 생각해 보면, 요청B 로 인해
  요청A에 의해 할당되었던 conn, stmt, rs 의 reference 들은 바뀌어 버렸습니다.
  결국, 요청 A 는  요청 B 의 결과를 가지고 작업을 하게 됩니다. 반면, 요청 B 는
  요청 A 의 의해 rs.next() 를 이미 수행 해 버렸으므로, rs.next() 의 결과가 이미 close
  되었다는 엉뚱한 결과를 낳고 마는 거죠...
  다른 쉬운 얘기로 설명해 보면, A, B 두사람이 식탁에 앉아서 각자 자신이 준비해 온 사과를
  하나씩 깎아서 식탁 위의 접시에 올려 놓고 나중에 먹어려 하는 것과 동일합니다. A 라는
  사람이 열심히 사과를 깎아 접시에 담아둘 때, B 라는 사람이 들어와서 A가 깎아둔 사과를
  버리고 자신이 깎은 사과를 대신 접시에 담아 둡니다. 이제 A라는 사람은 자신이 깎아서
  담아 두었다고 생각하는 그 사과를 접시에서 먹어버립니다. 곧이어 B라는 사람이 자신의
  사과를 접시에서 먹어려 하니 이미 A 가 먹고 난 후 였습니다. 이는 접시를 두 사람이
  공유하기 때문에 발생하는 문제잖습니까.
  마찬가지로 서블렛의 각 Thread는 instance variable 를 공유하기 때문에 동일한 문제들을
  발생하게 됩니다.

  따라서 최소한 다음처럼 고쳐져야 합니다.

public class TestServlet extends HttpServlet {
     private final static String drv = "...";
     private final static String url = "....";
     private final static String user = "...";
     private final static String password = "...";

     private ServletContext context;

     public void init(ServletConfig config) throws ServletException {
         super.init(config);
         context = config.getServletContext();
         try {
             Class.forName(drv);
         }
         catch (ClassNotFoundException e) {
             throw new ServletException("Unable to load JDBC driver:"+ e.toString());
         }
     }
     public void doGet(HttpServletRequest req, HttpServletResponse res) 
         throws ServletException, IOException, SQLException
     {
         Connection conn = null;  <----- 이곳으로 와야죠..
         Statement stmt = null; <-------
         ResultSet rs = null; <---------

         String id = req.getParameter("id");
         conn = DriverManager.getConnection(url,user,password);
         stmt = conn.createStatement();
         rs = stmt.executeQuery("select ..... where id = '" + id + "'");
         while(rs.next()) {
            ...... 
         } 
         rs.close();
         stmt.close();
         conn.close();
         .....
     }
  }


1.4 JSP에서 Instance Variable 공유

JSP에서 아래처럼 사용하는 경우가 위의 경우와 동일한 instance 변수를 공유하는 경우가
됩니다.
   ---------------------------------------------------------
   <%@ page session=.... import=.... contentType=........ %>
   <%!
       Connection conn = null;
       Statement stmt = null;
       ResultSet rs = null;
       String userid = null;
   %>
   <html><head></head><body>
   <%
       ........
       conn = ...
       stmt = .....

       uesrid = ......
   %>
   </body></html>
   ---------------------------------------------------------

   마찬가지로 위험천만한 일이며, 여러 Thread 에 의해 그 값이 변할 수 있는 변수들은
   <%! ... %> 를 이용하여 선언하시면 안됩니다. 이처럼 instance 변수로 사용할 것은
   다음 처럼, 그 값이 변하지 않는 값이거나, 혹은 공유변수에 대한 특별한 관리를
   하신 상태에서 하셔야 합니다.

   <%!  private static final String USERID = "scott";
        private static final String PASSWORD = "tiger";
   %>

   JSP에서의 이와 같은 잘못된 유형도, 앞선 서블렛의 경우처럼 일부 국내 JSP관련
   서적에서 발견됩니다.  해당 서적의 저자는 가능한 빨리 개정판을 내셔서 시정하셔야
   할 것입니다. 해당 책은 출판사나 책의 유형, 그리고 글자체로 추정건데, 초보자가
   쉽게 선택할 법한 책인 만큼 그 파급력과 영향력이 너무 큰 듯 합니다.

   이와 같은 부분이 실 프로젝트에서 존재할 경우, 대부분 시스템 오픈 첫날 쯤에
   문제를 인식하게 됩니다. Connection reference 가 엎어쳐지므로 Pool 에 반환이
   일어나지 않게 되고, 이는 "connection pool"의 가용한 자원이 부하가 얼마 없음에도
   불구하고 모자라는 현상으로 나타나며, 때론 사용자의 화면에서는 엉뚱한 다른
   사람의 데이타가 나타나거나, SQLException 이 나타납니다.

   NOTE: 어떻게하란 말입니까? 각 호출간에 공유되어서는 안될 변수들은 <%! ...%> 가
   아니라, <% ... %> 내에서 선언하여 사용하란 얘깁니다. JSP가 Pre-compile되어
   Servlet형태로 변환될 때, <%! ... %>는 서블렛의 instance variable로 구성되는 반면,
   <% ... %>는 _jspService() 메소드 내의 method variable로 구성됩니다.



2. 하나의 Connection을 init()에서 미리 연결해 두고 사용하는 경우.

public class TestServlet extends HttpServlet {
     private final static String drv = "oracle.jdbc.driver.OracleDriver";
     private final static String url = "jdbc:orache:thin@210.220.251.96:1521:ORA8i";
     private final static String user = "scott";
     private final static String password = "tiger";

     private ServletContext context;
     private Connection conn = null;  <--- !!!

     public void init(ServletConfig config) throws ServletException {
         super.init(config);
         context = config.getServletContext();
         try {
             Class.forName(drv);
             conn = DriverManager.getConnection(url,user,password);
         }
         catch (ClassNotFoundException e) {
             throw new ServletException("Unable to load JDBC driver:"+ e.toString());
         }
         catch (SQLException e) {
             throw new ServletException("Unable to connect to database:"+ e.toString());
         }
     }
     public void doGet(HttpServletRequest req, HttpServletResponse res) 
         throws ServletException, IOException, SQLException
     {
         Statement stmt = null;
         ResultSet rs = null;
         String id = req.getParameter("id");
         stmt = conn.createStatement();
         rs = stmt.executeQuery("select ..... where id = '" + id + "'");
         while(rs.next()) {
            ...... 
         } 
         rs.close();
         stmt.close();
         .....
     }
     public void destroy() {
         if ( conn != null ) try {conn.close();}catch(Exception e){}
     }    
  }

위는 뭐가 잘못되었을 까요?  서블렛당 하나씩 java.sql.Connection 을 init()에서 미리
맺어 두고 사용하는 구조 입니다.

얼핏 생각하면 아무런 문제가 없을 듯도 합니다. doGet() 내에서 별도의 Statement와
ResultSet 을 사용하고 있으니, 각 Thread는 자신만의 Reference를 갖고 사용하게 되니까요.

이 구조는 크게 세가지의 문제를 안고 있습니다. 하나는 DB 연결자원의 낭비를 가져오며,
두번째로 수많은 동시사용자에 대한 처리한계를 가져오고, 또 마지막으로 insert, update,
delete 와 같이 하나 이상의 SQL문장을 수행하면서 단일의 Transaction 처리를 보장받을
수 없다는 것입니다.

1) DB 자원의 낭비

   위의 구조는 서블렛당 하나씩 java.sql.Connection 을 점유하고 있습니다. 실 프로젝트에서
   보통 서블렛이 몇개나 될까요? 최소한 100 개에서 400개가 넘어 갈 때도 있겠죠?
   그럼 java.sql.Connection에 할당 되어야 할 "DB연결갯수"도 서블렛 갯수 많큼 필요하게
   됩니다. DB 연결 자원은 DB 에서 설정하기 나름이지만, 통상 maximum 을 셋팅하기
   마련입니다. 그러나 아무런 요청이 없을 때도 400 여개의 DB연결이 연결되어 있어야 한다는
   것은 자원의 낭비입니다.
   
2) 대량의 동시 사용자 처리 불가.

   또한, 같은 서블렛에 대해 동시에 100 혹은 그 이상의 요청이 들어온다고 가정해 보겠습
   니다. 그럼 같은 java.sql.Connection 에 대해서 각각의 요청이 conn.createStatement() 를
   호출하게 됩니다.
   문제는 하나의 Connection 에 대해 동시에 Open 할 수 있는 Statement 갯수는 ( 이 역시
   DB 에서 셋팅하기 나름이지만 ) maximum 제한이 있습니다. Oracle 의 경우 Default는 50
   입니다. 만약 이 수치 이상을 동시에 Open 하려고 하면 "maximum open cursor exceed !"
   혹은 "Limit on number of statements exceeded"라는 SQLExceptoin 을 발생하게 됩니다.

   예를 들어 다음과 같은 프로그램을 실행시켜 보세요.

   public class DbTest {
     public static void main(String[] args) throws Exception {
        Class.forName("jdbc driver...");
        Connection conn = DriverManager.getConnection("url...","id","password");
        int i=0;
        while(true) {
           Statement stmt = conn.createStatement();
           System.out.println( (++i) + "- stmt created");
        }
     }
   }

   과연 몇개 까지 conn.createStement() 가 수행될 수 있을까요? 이는 DB에서 설정하기 나름
   입니다. 중요한 것은 그 한계가 있다는 것입니다.
   또한 conn.createStatement() 통해 만들어진 stmt 는 java.sql.Connection 의 자원이기
   때문에 위처럼 stmt 의 reference 가 없어졌다고 해도 GC(Garbage Collection)이 되지
   않습니다.


  3) Transaction 중복현상 발생

  예를 들어 다음과 같은 서비스가 있다고 가정해 보겠습니다.

  public void doGet(HttpServletRequest req, HttpServletResponse res) 
      throws ServletException, IOException, SQLException
  {
      Statement stmt = null;
      String id = req.getParameter("id");
      try {
          conn.setAutoCommit(false);
          stmt = conn.createStatement();
          stmt.executeUpdate("update into XXXX..... where id = " + id + "'");
          stmt.executeUpdate("delete from XXXX..... where id = " + id + "'");
          stmt.executeUpdate(".... where id = " + id + "'");
          stmt.executeUpdate(".... where id = " + id + "'");
          conn.commit();
      }
      catch(Exception e){
          try{conn.rollback();}catch(Exception e){}
      }
      finally {
         if ( stmt != null ) try{stmt.close();}catch(Exception e){}
         conn.setAutoCommit(true);
      }
      .....
  }

  아무런 문제가 없을 듯도 합니다. 그러나 위의 서비스를 동시에 요청하게 되면, 같은
  java.sql.Connection 을 갖고 작업을 하고 있으니 Transaction 이 중첩되게 됩니다.
  왜냐면, conn.commit(), conn.rollback() 과 같이 conn 이라는 Connection 에 대해서
  Transaction 이 관리되기 때문입니다. 요청 A 가 총 4개의 SQL문장 중 3개를 정상적으로
  수행하고 마지막 4번째의 SQL문장을 수행하려 합니다. 이 때 요청 B가 뒤따라 들어와서
  2개의 SQL 문장들을 열심히 수행했습니다.  근데, 요청 A에 의한 마지막 SQL 문장
  수행중에 SQLException 이 발생했습니다. 그렇담 요청 A 는 catch(Exception e) 절로
  분기가 일어나고 conn.rollback() 을 수행하여 이미 수행한 3개의 SQL 수행들을 모두
  rollback 시킵니다. 근데,,, 문제는 요청 B 에 의해 수행된 2개의 SQL문장들도 같이
  싸잡아서 rollback() 되어 버립니다. 왜냐면 같은 conn 객체니까요. 결국, 요청B 는
  영문도 모르고 마지막 2개의 SQL문장만 수행한 결과를 낳고 맙니다.

  따라서 정리하면, Connection, Statement, ResultSet 는 doGet() , doPost() 내에서
  선언되고 사용되어져야 합니다.

  public void doGet(HttpServletRequest req, HttpServletResponse res) 
      throws ServletException, IOException, SQLException
  {
      Connection conn = null;  <----- 이곳으로 와야죠..
      Statement stmt = null; <-------
      ResultSet rs = null; <---------
      .....
  }




3. Exception 이 발생했을 때도 Connection 은 닫혀야 한다 !!

  public void doGet(HttpServletRequest req, HttpServletResponse res) 
       throws ServletException, IOException, SQLException
  {
      String id = req.getParameter("id");

      Connection conn = DriverManager.getConnection("url...","id","password");
      Statement stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery("ssselect * from XXX where id = '" + id + "'");
      while(rs.next()) {
         ...... 
      } 
      rs.close();
      stmt.close();
      conn.close();
      .....
  }

  위에선 뭐가 잘못되었을까요? 네, 사실 특별히 잘못된 것 없습니다. 단지 SQL문장에 오타가
  있다는 것을 제외하곤.... 근데, 과연 그럴까요?
  SQLException 이라는 것은 Runtime 시에 발생합니다. DB 의 조건이 맞지 않는다거나
  개발기간 중에 개발자의 실수로 SQL문장에 위처럼 오타를 적을 수도 있죠.
  문제는 Exception 이 발생하면 마지막 라인들 즉, rs.close(), stmt.close(), conn.close()
  가 수행되지 않는다는 것입니다.
  java.sql.Connection 은 reference 를 잃더라도 JVM(Java Virtual Machine)의 GC(Garbage
  Collection) 대상이 아닙니다. 가뜩이나 모자라는 "DB연결자원"을 특정한 어플리케이션이
  점유하고 놓아 주지 않기 때문에 얼마안가 DB Connection 을 더이상 연결하지 못하는
  사태가 발생합니다.

  따라서 다음처럼 Exception 이 발생하든 발생하지 않든 반드시 java.sql.Connection 을
  close() 하는 로직이 꼭(!) 들어가야 합니다.

  public void doGet(HttpServletRequest req, HttpServletResponse res) 
       throws ServletException, IOException, SQLException
  {
      Connection conn = null;
      Statement stmt = null;
      ResultSet rs = null;
      String id = req.getParameter("id");
      try {
        conn = DriverManager.getConnection("url...","id","password");
        stmt = conn.createStatement();
        rs = stmt.executeQuery("sselect * from XXX where id = '" + id + "'");
        while(rs.next()) {
         ...... 
        }
        rs.close();
        stmt.close();
      }
      finally {
         if ( conn != null ) try {conn.close();}catch(Exception e){}
      }
      .....
  }

  참고로, 실프로젝트의 진단 및 튜닝을 나가보면 처음에는 적절한 응답속도가 나오다가
  일정한 횟수 이상을 호출하고 난 뒤부터 엄청 응답시간이 느려진다면, 십중팔구는 위처럼
  java.sql.Connection 을 닫지 않아서 생기는 문제입니다.
  가용한 모든 Connection 을 연결하여 더이상 연결시킬 Connection 자원을 할당할 수 없을
  때, 대부분 timewait 이 걸리기 때문입니다. 일단 DB관련한 작업이 들어오는 족족
  timewait에 빠질 경우, "어플리케이션서버"에서 동시에 처리할 수 있는 최대 갯수만큼
  호출이 차곡차곡 쌓이는 건 불과 몇분 걸리지 않습니다. 그 뒤부터는 애궂은 dummy.jsp
  조차 호출이 되지 않게 되고,   누군가는 "시스템 또 죽었네요"라며 묘한 웃음을 짓곤
  하겠죠....



4. Connection 뿐만 아니라 Statement, ResultSet 도 반드시 닫혀야 한다 !!

4.1  3번의 예제에서 Connection 의 close() 만 고려하였지 Statement 나 ResultSet 에 대한
  close는 전혀 고려 하지 않고 있습니다. 무슨 문제가 있을까요? Statement 를 닫지 않아도
  Connection 을 닫았으니 Statement 나 ResultSet 은 자동으로 따라서 닫히는 것 아니냐구요?
  천만의 말씀, 만만의 콩깎지입니다.

  만약, DB Connection Pooling 을 사용하지 않고 직접 JDBC Driver 를 이용하여 매번 DB
  연결을 하였다가 끊는 구조라면 문제가 없습니다.
  그러나 DB Connection Pooling 은 이젠 보편화되어 누구나 DB Connection Pooling 을 사용
  해야한다는 것을 알고 있습니다. 그것이 어플리케이션 서버가 제공해 주든, 혹은 작은
  서블렛엔진에서 운영하고 있다면 직접 만들거나, 인터넷으로 돌아다니는 남의 소스를 가져다
  사용하고 있을 겁니다.

  이처럼 DB Connection Pooling 을 사용하고 있을 경우는 Conneciton 이 실제 close()되는
  것이 아니라 Pool에 반환되어 지게 되는데, 결국 reference가 사리지지 않기 때문에 GC시점에
  자동 close되지 않게 됩니다.
  특정 Connection 에서 열어둔 Statement 를  close() 하지 않은채 그냥 반환시켜 놓게 되면,
  언젠가는 그 Connection 은 다음과 같은   SQLException 을 야기할 가능성을 내포하게 됩니다.

  Oracle :
    java.sql.SQLException : ORA-01000: maximum open cursor exceeded !!
                            (최대열기 커서수를 초과했습니다)
  UDB DB2 :
    COM.ibm.db2.jdbc.DB2Exception: [IBM][JDBC 드라이버] CLI0601E  유효하지 않은
      명령문 핸들 또는 명령문이 닫혔습니다. SQLSTATE=S1000
    COM.ibm.db2.jdbc.DB2Exception: [IBM][CLI Driver] CLI0129E  핸들(handle)이
      더이상 없습니다. SQLSTATE=HY014       
    COM.ibm.db2.jdbc.DB2Exception: [IBM][CLI Driver][DB2/NT] SQL0954C  응용프로그램
      힙(heap)에 명령문을 처리하기 위해 사용 가능한 저장영역이 충분하지 않습니다.
      SQLSTATE=57011

  이유는 앞 2)번글에서 이미 언급드렸습니다. 보다 자세한 기술적 내용은 아래의 글을
  참고하세요.
  Connection/Statement 최대 동시 Open 수
  http://www.javaservice.net/~java/bbs/read.cgi?m=devtip&b=jdbc&c=r_p&n=972287002

  따라서 또다시 3번의 소스는 다음과 같은 유형으로 고쳐져야 합니다.

  public void doGet(HttpServletRequest req, HttpServletResponse res) 
       throws ServletException, IOException, SQLException
  {
      Connection conn = null;
      Statement stmt = null;
      ResultSet rs = null;
      String id = req.getParameter("id");
      try {
        conn = ...<getConnection()>...; // (편의상 생략합니다.)
        stmt = conn.createStatement();
        rs = stmt.executeQuery("sselect * from XXX where id = '" + id + "'");
        while(rs.next()) {
         ...... 
        }
        // rs.close();
        // stmt.close();
      }
      finally {
        if ( rs != null ) try {rs.close();}catch(Exception e){}
        if ( stmt != null ) try {stmt.close();}catch(Exception e){} // <-- !!!!
        if ( conn != null ) ...<releaseConnection()>...; // (편의상 생략)

      }
      .....
  }

4.2 사실 위와 같은 구조에서, java.sql.Statement의 쿼리에 의한 ResultSet의 close()에
  대한 것은 그리 중요한 것은 아닙니다. ResultSet은 Statement 가 close() 될 때 함께
  자원이 해제됩니다. 따라서 다음과 같이 하셔도 됩니다.

  public void doGet(HttpServletRequest req, HttpServletResponse res) 
       throws ServletException, IOException, SQLException
  {
      Connection conn = null;
      Statement stmt = null;
      String id = req.getParameter("id");
      try {
        conn = ...<getConnection()>...;
        stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery("sselect * from XXX where id = '" + id + "'");
        while(rs.next()) {
         ...... 
        }
        rs.close(); //<--- !!!
      }
      finally {
        // if ( rs != null ) try {rs.close();}catch(Exception e){}
        if ( stmt != null ) try {stmt.close();}catch(Exception e){}
        if ( conn != null ) ...<releaseConnection()>...;
      }
      .....
  }


4.3  가장 대표적으로 잘못 프로그래밍하고 있는 예를 들라면 다음과 같은 유형입니다.

  Connection conn = null;
  try {
      conn = ...<getConnection()>....;
      Statement stmt = conn.createStatement();
      stmt.executeUpdate("....");  <--- 여기서 SQLException 이 일어나면...
      .....
      .....
      .....  <-- 만약,이쯤에서 NullPointerException 이 일어나면 ?
      .....
      stmt.close(); <-- 이것을 타지 않음 !!!
  }
  finally{
     if ( conn != null ) ...<releaseConnection()>...;
  }


4.4  Statement 가 close() 되지 않는 또 하나의 경우가 다음과 같은 경우입니다.

  Connection conn = null;
  Statement stmt = null;
  try {
    conn = .....
    stmt = conn.createStatement(); // ....(1)
    rs = stmt.executeQuery("select a from ...");
    .....
    rs.close();

    stmt = conn.createStatement(); // ....(2)
    rs = stmt.executeQuery("select b from ...");
    ....
  }
  finally{
    if ( rs != null ) try {rs.close();}catch(Exception e){}
    if ( stmt != null ) try{stmt.close();}catch(Exception e){}
    if ( conn != null ) ....
  }

  즉, 두번 stmt = conn.createStatement() 를 수행함으로써, 먼저 생성된 stmt 는
  (2)번에 의해 그 reference 가 엎어쳐버리게 되어 영원히 close() 되지 않은채
  남아 있게 됩니다.
  이 경우, (2)번 문장을 주석처리하여야 겠지요. 한번 생성된 Statement 로 여러번
  Query 를 수행하면 됩니다.

  Connection conn = null;
  Statement stmt = null;
  try {
    conn = .....
    stmt = conn.createStatement(); // ....(1)
    rs = stmt.executeQuery("select a from ...");
    .....
    rs.close();

    // stmt = conn.createStatement(); // <--- (2) !!!
    rs = stmt.executeQuery("select b from ...");
    ....
  }
  finally{
    if ( rs != null ) try {rs.close();}catch(Exception e){}
    if ( stmt != null ) try{stmt.close();}catch(Exception e){}
    if ( conn != null ) ....
  }


4.5  Statement 뿐만 아니라 PreparedStatement 를 사용할 때로 마찬가지 입니다.
  ....
  PreparedStatement pstmt = conn.prepareStatement("select ....");
  ....
  이렇게 만들어진  pstmt 도 반드시 pstmt.close() 되어야 합니다.

  예를 들면, 다음과 같은 코드를 생각할 수 있습니다.

  Connection conn = null;
  try {
    conn = ...<getConnection()>...;
    PreparedStatement pstmt = conn.prepareStatement("select .... ?...?");
    pstmt.setString(1,"xxxx");
    pstmt.setString(2,"yyyy");
    ResultSet rs = pstmt.executeQuery(); <--- 여기서 SQLException 이 일어나면
    while(rs.next()){
      ....
    }
    rs.close();
    pstmt.close();  <-- 이것을 타지 않음 !!!
  }
  finally{
     if ( conn != null ) ...<releaseConnection()>...;
  }

  따라서 같은 맥락으로 다음과 같이 고쳐져야 합니다.
 
  Connection conn = null;
  PreparedStatement pstmt = null; // <-------- !!
  ResultSet rs = null;
  try {
    conn = ...<getConnection()>...;
    pstmt = conn.prepareStatement("select .... ?...?");
    pstmt.setString(1,"xxxx");
    pstmt.setString(2,"yyyy");
    rs = pstmt.executeQuery(); <--- 여기서 SQLException 이 일어나더라도...
    while(rs.next()){
      ....
    }
    //rs.close();
    //pstmt.close();
  }
  finally{
    if ( rs != null ) try {rs.close();}catch(Exception e){}
    if ( pstmt != null ) try {pstmt.close();}catch(Exception e){} // <-- !!!!
    if ( conn != null ) ...<releaseConnection()>...;
  }


4.6  PreparedStatement 에 관련해서 다음과 같은 경우도 생각할 수 있습니다.

4.6.1 앞서의 4.4에서 Statement를 createStatement() 연거푸 두번 생성하는 것과
  동일하게 PreparedStatement에서도 주의하셔야 합니다. 예를 들면 다음과 같습니다.

  Connection conn = null;
  PreparedStatement pstmt = null;
  ResultSet rs = null;
  try {
    conn = .....
    pstmt = conn.prepareStatement("select a from ..."); // ....(1)
    rs = pstmt.executeQuery();
    .....
    rs.close();

    pstmt = conn.prepareStatement("select b from ..."); // <--- (2) !!!
    rs = pstmt.executeQuery();
    ....
  }
  finally{
    if ( rs != null ) try {rs.close();}catch(Exception e){}
    if ( pstmt != null ) try{pstmt.close();}catch(Exception e){} // <--- (3)
    if ( conn != null ) ...<releaseConnection()>...;
  }

  Statement의 인스턴스는 conn.createStatement() 시에 할당되어 지는 반면,
  PreparedStatement는 conn.prepareStatement("..."); 시에 할당되어 집니다. 위의 경우에서
  설령 마지막 finally 절에서 pstmt.close() 를 하고 있기는 하지만, (1)번에서 할당되어진
  pstmt 는 (2)에서 엎어쳤기 때문에 영원히 close() 되지 않게 됩니다. 따라서, 다음과
  같이 코딩되어야 한다는 것은 자명합니다.

  Connection conn = null;
  PreparedStatement pstmt = null;
  ResultSet rs = null;
  try {
    conn = .....
    pstmt = conn.prepareStatement("select a from ..."); // ....(1)
    rs = pstmt.executeQuery();
    .....
    rs.close();
    pstmt.close(); // <------- !!!!! 이처럼 여기서 먼저 close() 해야지요.

    pstmt = conn.prepareStatement("select b from ..."); // <--- (2)
    rs = pstmt.executeQuery();
    ....
  }
  finally{
    if ( rs != null ) try {rs.close();}catch(Exception e){}
    if ( pstmt != null ) try{pstmt.close();}catch(Exception e){} // <--- (3)
    if ( conn != null ) ...<releaseConnection()>...;
  }

  혹은 다음과 같이 서로 다른 두개의 PreparedStatement를 이용할 수도 있습니다.
 
  Connection conn = null;
  PreparedStatement pstmt1 = null;
  ResultSet rs1 = null;
  PreparedStatement pstmt2 = null;
  ResultSet rs2 = null;
  try {
    conn = .....
    pstmt1 = conn.prepareStatement("select a from ..."); // ....(1)
    rs1 = pstmt1.executeQuery();
    .....
    pstmt2 = conn.prepareStatement("select b from ..."); // <--- (2)
    rs2 = pstmt2.executeQuery();
    ....
  }
  finally{
    if ( rs1 != null ) try {rs1.close();}catch(Exception e){}
    if ( pstmt1 != null ) try{pstmt1.close();}catch(Exception e){} // <--- (3)
    if ( rs2 != null ) try {rs2.close();}catch(Exception e){}
    if ( pstmt2 != null ) try{pstmt2.close();}catch(Exception e){} // <--- (4)
    if ( conn != null ) ...<releaseConnection()>...;
  }


4.6.2 아래는 앞서의 4.6.1과 같은 맥락인데, for loop 안에서 사용된 경우입니다.

  Connection conn = null;
  PreparedStatement pstmt = null;
  try {
    conn = ...<getConnection()>...;
    for(int i=0;i<10;i++){
      pstmt = conn.prepareStatement("update .... ?... where id = ?"); //... (1)
      pstmt.setString(1,"xxxx");
      pstmt.setString(2,"id"+(i+1) );
      int affected = pstmt.executeUpdate();
      if ( affected == 0 ) throw new Exception("NoAffected");
      else if ( affedted > 1 ) throw new Exception("TooManyAffected");
    }
  }
  finally{
     if ( pstmt != null ) try {pstmt.close();}catch(Exception e){} // ...(2)
     if ( conn != null ) ...<releaseConnection()>...;
  }

  이 경우가 실제 프로젝트 performace 튜닝을 가 보면 종종 발견되는 잘못된
  유형 중의 하나입니다. 핵심은 pstmt.prepareStatement("update..."); 문장을
  수행할 때 마다 내부적으로 pstmt 가 새로 할당된다는 것에 있습니다.
  결국, (1)번 문장이 for loop 을 돌면서 9개는 pstmt.close()가 되지 않고, 마지막
  하나의 pstmt 만  finally 절의 (2)번에서 close 되지요...
  따라서 다음처럼 고쳐져야 합니다.

  Connection conn = null;
  PreparedStatement pstmt = null;
  try {
    conn = ...<getConnection()>...;
    pstmt = conn.prepareStatement("update .... ?... where id = ?");
    for(int i=0;i<10;i++){
      pstmt.clearParameters();     
      pstmt.setString(1,"xxxx");
      pstmt.setString(2,"id"+(i+1) );
      int affected = pstmt.executeUpdate();
      if ( affected == 0 ) throw new Exception("NoAffected");
      else if ( affedted > 1 ) throw new Exception("TooManyAffected");
    }
  }
  finally{
     if ( pstmt != null ) try {pstmt.close();}catch(Exception e){}
     if ( conn != null ) ...<releaseConnection()>...;
  }

  PreparedStatement 라는 것이, 한번 파싱하여 동일한 SQL문장을 곧바로 Execution할 수
  있는 장점이 있는 것이고, 궁극적으로 위와 같은 경우에 효과를 극대화 할 수 있는
  것이지요.

  어느 개발자의 소스에서는 위의 경우를 다음과 같이 for loop 안에서 매번
  conn.prepareStatement(...)를 하는 경우를 보았습니다.

  Connection conn = null;
 
  try {
    conn = ...<getConnection()>...;
    for(int i=0;i<10;i++) {
        PreparedStatement pstmt = null;
        try{
            pstmt = conn.prepareStatement("update .... ?... where id = ?");
            pstmt.clearParameters();     
            pstmt.setString(1,"xxxx");
            pstmt.setString(2,"id"+(i+1) );
            int affected = pstmt.executeUpdate();
            if ( affected == 0 ) throw new Exception("NoAffected");
            else if ( affedted > 1 ) throw new Exception("TooManyAffected");
        }
        finally{
            if ( pstmt != null ) try {pstmt.close();}catch(Exception e){}
        }
    }
  }
  finally{
     if ( conn != null ) ...<releaseConnection()>...;
  }

  위 경우는 장애관점에서 보면 사실 별 문제는 없습니다. 적어도 닫을 건 모두 잘 닫고
  있으니까요. 단지 효율성의 문제가 대두될 수 있을 뿐입니다.

4.7 생각해 보면, Statement 나 PreparedStatement 가 close() 되지 않는 유형은
  여러가지가 있습니다. 그러나 열려진 Statement는 반드시 close()되어야 한다라는
  단순한 사실에 조금만 신경쓰시면 어떻게 프로그래밍이 되어야 하는지 쉽게
  감이 오실 겁니다. 단지 신경을 안쓰시니 문제가 되는 것이지요...

  Statement 를 닫지 않는 실수를 한 코드가 400-1000여개의 전 어플리케이션을 통털어
  한두군데에 숨어 있는 경우가 제일 찾아내기 어렵습니다. 한두번 Statement 를
  close 하지 않는다고 하여 곧바로 문제로 나타나지 않기 때문입니다.
  하루나 이틀, 혹은 며칠지나서야, Oracle 의 경우, "maximum open cursor exceed"
  에러를 내게 됩니다. oracle 의 경우, 위와 같은 에러를 conn.createStatement()시에
  발생하므로 (경우에 따라) 큰 문제로 이어지지는 않습니다. 찾아서 고치면 되니까요.

  반면, DB2 의 경우는 메모리가 허용하는 한도까지 지속적인 메모리 증가를 야기합니다.
  급기야 "핸들(handle)이 더이상 없습니다", "응용프로그램 힙(heap)에 명령문을
  처리하기 위해 사용 가능한 저장영역이 충분하지 않습니다", "유효하지 않은 명령문
  핸들 또는 명령문이 닫혔습니다" 등과 같은 에러를 내지만, 여기서 그치는 것이 아니라
  새로운 connection 을 맺는 시점에 SIGSEGV 를 내면 crashing 이 일어납니다.
  java.lang.OutOfMemoryError 가 발생하기 때문이지요.

  Oracle 의 경우도 사실 상황에 따라 심각할 수 있습니다. 예를 들어, 어떤 개발자가
  "maximum open cursor exceed"라는 Oracle SQL 에러 메세지를 만나고는 자신이
  코딩을 잘못한 것은 염두에 두지 않고, 무조건 DBA에게 oraXXX.ini 파일에서
  OPEN_CURSORS 값을 올려달라고 요청하고, DBA는 그 조언(?)을 충실히 받아들여
  Default 50 에서 이를 3000 으로 조정합니다. 여기서 문제는 깊숙히(?) 숨겨집니다.
  close() 안된 Statement 가 3000 회에 도달하지 전까진 아무도 문제를 인식하지
  못하기 때문이죠. 그러나, Statement가 하나씩 close()되지 않은 갯수에 비례하여
  Oracle 엔진의 메모리 사용은 자꾸만 증가하고, 전체적인 성능저하를 야기하지만,
  이를 인식하기란 막상 시스템을 오픈하고 나서 3-4일이 지난 후에 "DB성능이 이상하네,
  응답속도가 느리네" 하면서 또 한번의 "maximum open cursor exceed" 메세지를
  확인하고 난 뒤의 일이 되곤 합니다.

  에러가 없는 정상적인 로직 flow 에서는 대부분 Statement가 잘 닫힐 겁니다. 그러나,
  어떤 이유에서건 아주 드물게 Runtime Exception 이 발생하여 exception throwing으로
  인해 "stmt.close()"를 타지 않는 경우가 제일 무섭지요. 정말 무섭지요...

  Statement, PreparedStatement, CallableStatement 모두 마찬가지 입니다.



5. close() 를 할 땐 제대로 해야 한다!!

5.1 다음과 같은 프로그램 형식을 생각할 수 있습니다.

  Connection conn = null;
  Statement stmt = null;
  ResultSet rs = null;
  try{
     conn = ...<getConnection()>...; //.......(1)
     stmt = conn.createStatement();    //.............(2)
     rs = stmt.executeQuery("select .....");  // .....(3)
     while(rs.next()){
       ......
     }
  }
  finally {
     try {
        rs.close(); //........(4)
        stmt.close(); //......(5)
        ...<releaseConneciton()>...; //......(6)
     }catch(Exception e){}
  }

  위에선 뭐가 잘못되었을까요? 다 제대로 한듯 한데....
  finally 절에서 rs, stmt, conn 을 null check 없이, 그리고 동일한 try{}catch 절로
  실행하고 있습니다.
  예를 들어, (1), (2) 번을 거치면서 conn 과 stmt 객체까지는 제대로 수행되었으나
  (3)번 Query문장을 수행하는 도중에 SQLException 이 발생할 수 있습니다. 그러면,
  finally  절에서 (4) 번 rs.close()를 수행하려 합니다. 그러나, executeQuery()가
  실패 했기 때문에 rs 의 reference 는 null 이므로 rs.close() 시에
  NullPointerException 이 발생합니다.  결국 정작 반드시 수행되어야할 (5)번, (6)번이
  실행되지 않습니다. 따라서 반드시(!) 다음과 같은 형식의 코딩이 되어야 합니다.

  Connection conn = null;
  Statement stmt = null;
  ResultSet rs = null;
  try{
     conn = ...<getConnection()>...;
     stmt = conn.createStatement();
     rs = stmt.executeQuery("select .....");
     while(rs.next()){
       ......
     }
  }
  catch(Exception e){
     ....
  }
  finally {
     if ( rs != null ) try{rs.close();}catch(Exception e){}
     if ( stmt != null ) try{stmt.close();}catch(Exception e){}
     if ( conn != null ) ...<releaseConnection()>...;
  }

같은 맥락으로 PreparedStatement 를 사용할 경우도, 다음과 같은 코딩은 잘못되었습니다.

  Connection conn = null;
  PreparedStatement pstmt = null;
  try{
     conn = ...<getConnection()>...; //.......(1)
     pstmt = conn.prepareStatement("ddelete from EMP where empno=7942"); //...(2)
     int k = pstmt.executeUpdate();  // .....(3)
     ......
  }
  finally {
     try {
        pstmt.close(); //......(4)
        ...<releaseConneciton()>...; //......(5)
     }catch(Exception e){}
  }
  왜냐면, SQL문장에 오타가 있었고, 이는 prepareStatement("ddelete..")시점에 에러가
  발생하여 pstmt 가 여전히 null 인 상태로 finally 절로 분기되기 때문인 것이죠.

5.2.0 앞서 4.2에서도 언급했지만, java.sql.Statement의 executeQuery()에 의한 ResultSet은
  Statement 가 close 될때 자원이 같이 해제되므로 다음과 같이 하여도 그리 문제가 되진
  않습니다.
    
  Connection conn = null;
  Statement stmt = null;
  //ResultSet rs = null;
  try{
     conn = ...<getConnection()>...;
     stmt = conn.createStatement();
     ResultSet rs = stmt.executeQuery("select .....");
     while(rs.next()){
       ......
     }
     rs.close(); // <---- !!!
  }
  catch(Exception e){
     ....
  }
  finally {
     //if ( rs != null ) try{rs.close();}catch(Exception e){}
     if ( stmt != null ) try{stmt.close();}catch(Exception e){}
     if ( conn != null ) ...<releaseConnection()>...;
  }


5.2.1  그러나 PreparedStatement에 의한 ResultSet close()는 얘기가 다를 수 있습니다.
  (2002.06.11 추가 사항)
 
  많은 분들이, "아니 설령 ResultSet를 close하지 않았더라도 Statement/PreparedStatement를
  close하면 함께 ResultSet로 close되는 것 아니냐, JDBC 가이드에서도 그렇다고
  나와 있다, 무슨 개뿔같은 소리냐?" 라구요.

  그러나, 한가지 더 이해하셔야 할 부분은, 웹스피어, 웹로직과 같은 상용 웹어플리케이션
  서버들은 성능향상을 위해 PreparedStatement 및 심지어 Statement에 대한 캐싱기능을
  제공하고  있습니다. pstmt.close() 를 하였다고 하여 정말 해당 PreparedStatement가
  close되는 것이 아니라, 해당 PreparedeStatement가 생겨난 java.sql.Connection당 지정된
  개수까지 웹어플리케이션서버 내부에서 reference가 사라지지 않고 캐시로 남아 있게 됩니다.
  결국, 연관된 ResultSet 역시 close()가 되지 않은 채 남아있게 되는 것이지요. 명시적인
  rs.close()를 타지 않으면, 웹어플리케이션서버의 JVM내부 힙영역 뿐만아니라, 쿼리의 결과로
  데이타베이스에서 임시로 만들어진 메모리데이타가 사라지지 않는 결과를 낳게 됩니다.
  특히 ResultSet이 닫히지 않으면 DB에서의 CURSOR가 사라지지 않습니다.
  또한, CURSOR를 자동으로 닫거나 닫지 않는 등의 옵션은 WAS마다 WAS의 DataSource설정에서
  CORSOR 핸들링에 대한 별도의 옵션을 제공하게 되며 특히 아래 [항목6]에서 다시 언급할
  nested sql query 처리시에 민감한 반응을 하게 됩니다.

  따라서, 앞서의 코딩 방법을 반드시 다음처럼 ResultSet도 close하시기를 다시금 정정하여
  권장 드립니다.

  Connection conn = null;
  PreparedStatement pstmt = null;
  ResultSet rs = null; // <---- !!!
  try{
     conn = ...<getConnection()>...;
     pstmt = conn.prepareStatement("select .....");
     rs = pstmt.executeQuery(); // <----- !!!
     while(rs.next()){
       ......
     }
     //rs.close(); // <---- !!!
  }
  catch(Exception e){
     ....
  }
  finally {
     if ( rs != null ) try{rs.close();}catch(Exception e){} // <---- !!!
     if ( pstmt != null ) try{pstmt.close();}catch(Exception e){}
     if ( conn != null ) ...<releaseConnection()>...;
  }

  PS: 웹어플리케이션서버에서의 PreparedStatement 캐싱기능에 관한 부분은 아래의 글들을
  참조하세요.
  Connection Pool & PreparedStatement Cache Size
  http://www.javaservice.net/~java/bbs/read.cgi?m=appserver&b=was&c=r_p&n=995572195
  WebLogic에서의 PreparedStatement Cache -서정희-
  http://www.javaservice.net/~java/bbs/read.cgi?m=dbms&b=jdbc&c=r_p&n=1023286823



5.3 간혹, 다음과 같은 코딩은 문제를 야기하지 않을 것이라고 생각하는 분들이 많습니다.

finally{
    try{
      if ( stmt != null ) stmt.close();
      if ( conn != null ) conn.close();
    }catch(Exception e){}
}
저명한 많은 책에서도 위처럼 코딩되어 있는 경우를 종종봅니다. 맞습니다. 특별히 문제성이
있어보이지는 않습니다. 그러나, 간혹 웹어플리케이션서버의 Connection Pool과 연계하여
사용할 땐 때론 문제가 될 때도 있습니다. 즉, 만약, stmt.close()시에 Exception이 throw
되면 어떻게 되겠습니까?
아니 무슨 null 체크까지 했는데, 무슨 Exception이 발생하느냐고 반문할 수도 있지만,
오랜 시간이 걸리는 SQL JOB에 빠져 있다가 Connection Pool의 "Orphan Timeout"이 지나
자동으로 해당 Connection을 Pool에 돌려보내거나 혹은 특별한 marking처리를 해 둘 수
있습니다. 이 경우라면 stmt.close()시에 해당 웹어플리케이션서버에 특화된 Exception이
발생하게 됩니다. 그렇게 되면 conn.close()를 타지 못하게 되는 사태가 벌어집니다.
따라서, 앞서 하라고 권장한 형식으로 코딩하세요.


6. Nested (Statemet) SQL Query Issue !!

6.1 아래와 같은 코딩을 생각해 보겠습니다.

  Connection conn = null;
  Statement stmt = null;
  try{
     conn = ...<getConnection()>...;
     stmt = conn.createStatement();
     ResultSet rs = stmt.executeQuery("select deptno ...where id ='"+ id +"'");
     while(rs.next()){
       String deptno = rs.getString("deptno");
       stmt.executeUpdate(
           "update set dept_name = ... where deptno = '"+ deptno +"'"
       );
       ......
     }
     rs.close();
  }
  catch(Exception e){
     ....
  }
  finally {
     if ( stmt != null ) try{stmt.close();}catch(Exception e){}
     if ( conn != null ) ...<releaseConnection()>...;
  }

  위 코드는 사실 실행하자 말자 다음과 같은 에러를 만나게 됩니다.

  DB2 : -99999: [IBM][CLI Driver] CLI0115E 커서 상태가 유효하지 않습니다.
        SQLSTATE=24000
  Oracle :

  에러는 두번째 while(rs.next()) 시에 발생합니다. 왜냐면, Statement가 nested하게
  실행된 executeUpdate() 에 의해 엎어쳐 버렸기 때문입니다. ResultSet 은
  Statement와 밀접하게 관련이 있습니다. ResultSet은 자료를 저장하고 있는 객체가
  아니라, 데이타베이스와 step by step으로 상호 통신하는 Interface 일 뿐이기 때문입니다.
  따라서 위 코드는 다음처럼 바뀌어져야 합니다.

  Connection conn = null;
  Statement stmt1 = null;
  Statement stmt2 = null;
  try{
     conn = ...<getConnection()>...;
     stmt1 = conn.createStatement();
     stmt2 = conn.createStatement();
     ResultSet rs = stmt1.executeQuery("select deptno ...where id ='"+ id +"'");
     while(rs.next()){
       String deptno = rs.getString("deptno");
       stmt2.executeUpdate(
           "update set dept_name = ... where deptno = '"+ deptno +"'"
       );
       ......
     }
     rs.close();
  }
  catch(Exception e){
     ....
  }
  finally {
     if ( stmt1 != null ) try{stmt1.close();}catch(Exception e){}
     if ( stmt2 != null ) try{stmt2.close();}catch(Exception e){}
     if ( conn != null ) ...<releaseConnection()>...;
  }

  즉, ResultSet에 대한 fetch 작업이 아직 남아 있는 상태에서 관련된 Statement를
  또다시 executeQuery()/executeUpdate() 를 하면 안된다는 것입니다.

  PS: IBM WebSphere 환경일 경우, 아래의 글들을 추가로 확인하시기 바랍니다.
  349   Re: Function sequence error  (Version 3.x)
  http://www.javaservice.net/~java/bbs/read.cgi?m=appserver&b=was&c=r_p&n=991154615
  486   WAS4.0x: Function sequence error 해결 
  http://www.javaservice.net/~java/bbs/read.cgi?m=appserver&b=was&c=r_p&n=1015345459



7. executeUpdate() 의 결과를 비즈니스 로직에 맞게 적절히 활용하라.

7.1 아래와 같은 코딩을 생각해 보겠습니다.

  public void someMethod(String empno) throws Exception {
      Connection conn = null;
      Statement stmt = null;
      try{
         conn = ...<getConnection()>...;
         stmt = conn.createStatement();
         stmt.executeUpdate(
             "UPDATE emp SET name='이원영' WHERE empno = '" + empno + "'"
         );
      }
      finally {
         if ( stmt != null ) try{stmt.close();}catch(Exception e){}
         if ( conn != null ) ...<releaseConnection()>...;
      }
  }

  사실 흔히들 이렇게 하십니다. 별로 잘못된 것도 없어보입니다. 근데, 만약
  DB TABLE에 해당 empno 값이 없으면 어떻게 될까요? SQLException 이 발생
  하나요? 그렇지 않죠? 아무런 에러없이 그냥 흘러 내려 옵니다. 그러면, Update를
  하러 들어 왔는데, DB에 Update할 것이 없었다면 어떻게 해야 합니까? 그냥 무시하면
  되나요? 안되죠..  따라서, 다음 처럼, 이러한 상황을 이 메소드를 부른 곳으로
  알려 줘야 합니다.

  public void someMethod(String empno) throws Exception {
      Connection conn = null;
      Statement stmt = null;
      try{
         conn = ...<getConnection()>...;
         stmt = conn.createStatement();
         int affected = stmt.executeUpdate(
             "UPDATE emp SET name='이원영' WHERE empno = '" + empno + "'"
         );
         if ( affected == 0 ) throw new Exception("NoAffectedException");
         else if ( affected > 1 ) throw new Exception("TooManyAffectedException");
      }
      finally {
         if ( stmt != null ) try{stmt.close();}catch(Exception e){}
         if ( conn != null ) ...<releaseConnection()>...;
      }
  }

  물론 이러한 부분들은 해당 비즈니스로직이 뭐냐에 따라서 다릅니다. 그것을 무시케
  하는 것이 비즈니스 로직이었다면 그냥 무시하시면 되지만, MIS 성 어플리케이션의
  대부분은 이처럼 update 나 delete 쿼리의 결과에 따라 적절한 처리를 해 주어야
  할 것입니다.



8. Transaction 처리를 할 땐 세심하게 해야 한다.

단, 아래는 웹어플리케이션서버의 JTA(Java Transaction API)기반의 트렌젝션처리가 아닌,
java.sql.Connection에서의 명시적인 conn.setAutoCommit(false) 모드를 통한 트렌젝션처리에
대해서 언급 하고 있습니다.

8.1 Non-XA JDBC Transaction(명시적인 java.sql.Connection/commit/rollback)

  Connection conn = null;
  Statement stmt = null;
  try{
     conn = ...<getConnection()>...;
     stmt = conn.createStatement();
     stmt.executeUpdate("UPDATE ...."); // -------- (1)
     stmt.executeUpdate("DELETE ...."); // -------- (2)
     stmt.executeUpdate("INSERT ...."); // -------- (3)
  }
  finally {
     if ( stmt != null ) try{stmt.close();}catch(Exception e){}
     if ( conn != null ) ...<releaseConnection()>...;
  }

  위와 같은 코딩은 아무리 비즈니스적 요구가 간소하더라도, 실 프로젝트에서는
  있을 수가 없는 코딩입니다.(JTS/JTA가 아닌 명시적인 Transaction 처리시에..)

  다들 아시겠지만, (1), (2) 번까지는 정상적으로 잘 수행되었는데, (3)번문장을
  수행하면서 SQLException 이 발생하면 어떻게 되나요? (1),(2)은 이미 DB에 반영된
  채로 남아 있게 됩니다. 대부분의 비즈니스로직은 그렇지 않았을 겁니다.
 
  "(1),(2),(3)번이 모두 정상적으로 수행되거나, 하나라도 잘못되면(?) 모두 취소
  되어야 한다"
 
  가 일반적인 비즈니스적 요구사항이었을 겁니다. 따라서, 다음처럼 코딩 되어야
  합니다.

  Connection conn = null;
  Statement stmt = null;
  try{
     conn = ...<getConnection()>...;
     conn.setAutoCommit(false);
     stmt = conn.createStatement();
     stmt.executeUpdate("UPDATE ...."); // -------- (1)
     stmt.executeUpdate("DELETE ...."); // -------- (2)
     stmt.executeUpdate("INSERT ...."); // -------- (3)

     conn.commit(); // <-- 반드시 try{} 블럭의 마지막에 와야 합니다.
  }
  catch(Exception e){
     if ( conn != null ) try{conn.rollback();}catch(Exception ee){}
     // error handling if you want
    
     throw e;  // <--- 필요한 경우, 호출한 곳으로 Exception상황을 알려줄
               //      수도 있습니다
  }
  finally {
     if ( stmt != null ) try{stmt.close();}catch(Exception e){}
     // in some connection pool, you have to reset commit mode to "true"
     if ( conn != null ) ...<releaseConnection()>...;
  }


8.2 auto commit mode 를 "false"로 셋팅하여 명시적인 Transaction 관리를 할 때,
  정말 조심해야 할 부분이 있습니다. 예를 들면 다음과 같은 경우입니다.

  Connection conn = null;
  Statement stmt = null;
  try{
     conn = ...<getConnection()>...;
     conn.setAutoCommit(false);
     stmt = conn.createStatement();
     stmt.executeUpdate("UPDATE ...."); // ----------------------- (1)
     ResultSet rs = stmt.executeQuery("SELECT ename ..."); // ---- (2)
     if ( rs.next() ) {
        conn.commit(); // ------------------- (3)
     }
     else {
        conn.rollback(); // ----------------- (4)
     }
  }
  finally {
     if ( rs != null ) try{rs.close();}catch(Exception e){}
     if ( stmt != null ) try{stmt.close();}catch(Exception e){}
     // in some connection pool, you have to reset commit mode to "true"
     if ( conn != null ) ...<releaseConnection()>...;
  }

  코드가 왜 위처럼 됐는지는 저도 모르겠습니다.  단지 비즈니스가 그러했나보죠..

  문제는 만약, (2)번 executeQuery()문장을 수행하면서 SQLException 이나 기타의
  RuntimeException 이 발생할 때 입니다.
  commit() 이나 rollback()을 타지 않고, finally 절로 건너 뛰어 Statement를
  닫고, connection 은 반환됩니다. 이때, commit() 이나 rollback()이 되지 않은채
  (1)번 UPDATE 문이 수행된채로 남아 있게 됩니다.  이는 DB LOCK을 점유하게
  되고, 경우에 따라 다르겠지만, 다음번 요청시에 DB LOCK으로 인한 hang현상을
  초래할 수도 있습니다.
  일단 한두개의 어플리케이션이 어떠한 이유였든, DB Lock 을 발생시키면, 해당
  DB에 관련된 어플리케이션들이 전부 응답이 없게 됩니다. 이 상황이 조금만
  지속되면, 해당 waiting 을 유발하는 요청들이 어플리케이션서버의 최대 동시
  접속처리수치에 도달하게 되고, 이는 전체 시스템의 hang현상으로 이어지게
  되는 것이죠..


  따라서, 비즈니스 로직이 어떠했든, 반드시 지켜져야할 사항은 다음과 같습니다.

  "conn.setAutoComm(false); 상태에서 한번 실행된 Update성 SQL Query는 이유를
   막론하고 어떠한 경우에도 commit() 이나 rollback() 되어야 한다."

  위의 경우라면 다음처럼 catch 절에서 rollback 시켜주는 부분이 첨가되면 되겠네요.

  Connection conn = null;
  Statement stmt = null;
  try{
     conn = ...<getConnection()>...;
     conn.setAutoCommit(false);
     stmt = conn.createStatement();
     stmt.executeUpdate("UPDATE ....");
     ResultSet rs = stmt.executeQuery("SELECT ename ...");
     if ( rs.next() ) {
        conn.commit();
     }
     else {
        conn.rollback();
     }
  }
  catch(Exception e){  // <---- !!!!!
     if ( conn != null ) try{conn.rollback();}catch(Exception ee){}
     throw e;
  }
  finally {
     if ( rs != null ) try{rs.close();}catch(Exception e){}
     if ( stmt != null ) try{stmt.close();}catch(Exception e){}
     // in some connection pool, you have to reset commit mode to "true"
     if ( conn != null ) ...<releaseConnection()>...;
  }


8.3 모든 경우의 수를 생각하라.

  다음과 같은 경우를 생각해 보겠습니다.

  Connection conn = null;
  Statement stmt = null;
  try{
     conn = ...<getConnection()>...;
     conn.setAutoCommit(false);
     stmt = conn.createStatement();
     stmt.executeUpdate("UPDATE ....");
     String idx = name.substring(3);
     ResultSet rs = stmt.executeQuery("SELECT ename ... where idx=" + idx);
     if ( rs.next() ) {
        .....
     }
     rs.close(); rs = null;

     stmt.executeUpdate("UPDATE ....");
     conn.commit();
  }
  catch(SQLException e){
     if ( conn != null ) try{conn.rollback();}catch(Exception ee){}
     throw e;
  }
  finally {
     if ( rs != null ) try{rs.close();}catch(Exception e){}
     if ( stmt != null ) try{stmt.close();}catch(Exception e){}
     // in some connection pool, you have to reset commit mode to "true"
     if ( conn != null ) ...<releaseConnection()>...;
  }

  잘 찾아 보세요. 어디가 잘못되었습니까? 잘 안보이시죠?

  Connection conn = null;
  Statement stmt = null;
  try{
     conn = ...<getConnection()>...;
     conn.setAutoCommit(false);
     stmt = conn.createStatement();
     stmt.executeUpdate("UPDATE ...."); //---- (1)
     String idx = name.substring(3); //<------ (2) NullPointerExceptoin ?
     ResultSet rs = stmt.executeQuery("SELECT ename ... where idx=" + idx);
     if ( rs.next() ) {
        .....
     }
     rs.close(); rs = null;

     stmt.executeUpdate("UPDATE ....");
     conn.commit();
  }
  catch(SQLException e){ //<------ (3) 이 부분을 탈까?
     if ( conn != null ) try{conn.rollback();}catch(Exception ee){}
     throw e;
  }
  finally {
     if ( rs != null ) try{rs.close();}catch(Exception e){}
     if ( stmt != null ) try{stmt.close();}catch(Exception e){}
     // in some connection pool, you have to reset commit mode to "true"
     if ( conn != null ) ...<releaseConnection()>...;
  }

  위 코드를 보듯, 만약 (1)을 수행 후 (2)번 에서 NullPointerException 이나
  ArrayIndexOutOfBoundException이라도 나면 어떻게 되죠? catch(SQLException ...)에는
  걸리지 않고 곧바로 finally 절로 건너띄어 버리네요. 그럼 (1)에서 update 된 것은
  commit()이나 rollback() 없이 connection 이 반환되네요... ;-)
  어떻게 해야 합니까? SQLException만 잡아서 되는 것이 아니라, catch(Exception ...)과
  같이 모든 Exception 을 catch해 주어야 합니다.


8.4 위 주석문에서도 언급해 두었지만, Hans Bergsteins 의 DBConnectionManager.java
  와 같은 Connection Pool 을 사용할 경우에, 개발자의 코드에서 transaction auto
  commit mode 를 명시적으로 "false"로 한 후, 이를 그냥 pool 에 반환하시면,
  그 다음 사용자가 pool 에서 그 connection 을 사용할 경우, 여전히 transaction
  mode 가 "false"가 된다는 것은 주지하셔야 합니다. 따라서, DBConnectionManger의
  release method를 수정하시든지, 혹은 개발자가 명시적으로 초기화한 후 pool 에
  반환하셔야 합니다. 그렇지 않을 경우, DB Lock 이 발생할 수 있습니다.
  반면, IBM WebSphere 나 BEA WebLogic 과 같인 JDBC 2.0 스펙에 준하는 Connection
  Pool을 사용할 경우는 반환할 당시의 transaction mode 가 무엇이었든 간에,
  pool 에서 꺼내오는 connection 의 transaction mode는 항상 일정합니다.
  (default 값은 엔진의 설정에 따라 달라집니다.)
  그렇다고 commit 시키지 않은 실행된 쿼리가 자동으로 commit/rollback 되는 것은
  아닙니다. 단지 auto commit 모드만 자동으로 초기화 될 뿐입니다.

  PS:WAS의 JTS/JTA 트렌젝션 기반으로 운영될 경우는 명시적으로 commit/rollback되지
   않은 트렌젝션은 자동으로 rollback되거나 commit됩니다. default는 WAS 설정에 따라
   다를 수 있습니다.

  ---------------
  NOTE: 자바서비스컨설팅의 WAS성능관리/모니터링 툴인 제니퍼(Jennifer 2.0)를 적용하면,
  어플리케이션에서 명시적으로 commit/rollback시키지 않고 그대로 반환시킨 어플리케이션의
  소스 위치를 실시간으로 감지하여 알려줍니다. 이를 만약 수작업으로 한다면, 수많은 코드
  중 어디에서 DB lock을 유발 시키는 코드가 숨어있는지를 찾기가 경우에 따라 만만치 않은
  경우가 많습니다.

8.5 XA JDBC Driver, J2EE JTS/JTA
  JDBC 2.0, 표준 javax.sql.DataSource를 통한 JDBC Connection을 사용할 경우에,
  대부분의 상용WAS제품들은 J2EE의 표준 JTS(Java Transaction Service)/JTA(Java Transaction
  API)를 구현하고 있습니다. 특별히, 하나 이상의 데이타베이스에서 2 phase-commit과
  같은 XA Protocol를 지원하고 있지요(사실 WAS에서 2PC가 지원되기 시작한 것은 몇년
  되지 않습니다. 2PC를 사용하려면 반드시 XA-JDBC Driver가 WAS에 설치되어야 합니다)

  샘플 예제는 다음과 같습니다.

    ...
    javax.transaction.UserTransaction tx = null;
    java.sql.Connection conn1 = null;
    java.sql.Statement stmt1 = null;

    java.sql.Connection conn2 = null;
    java.sql.Statement stmt2 = null;
    java.sql.CallableStatement cstmt2 = null;
   
    try {
        javax.naming.InitialContext ctx = new javax.naming.InitialContext();
        tx = (javax.transaction.UserTransaction) ctx.lookup("java:comp/UserTransaction");
        // 트렌젝션 시작
        tx.begin();

        // -------------------------------------------------------------------------
        // A. UDB DB2 7.2 2PC(XA) Test
        // -------------------------------------------------------------------------
        javax.sql.DataSource ds1 =
            (javax.sql.DataSource)ctx.lookup("java:comp/env/jdbc/DB2");
        conn1 = ds1.getConnection();

        stmt1 = conn1.createStatement();
        stmt1.executeUpdate(
            "insert into emp(empno,ename) values(" + empno + ",'Name" + empno + "')"
        );
        stmt1.executeUpdate(
            "update emp set ename = 'LWY" + count + "' where empno = 7934"
        );
        java.sql.ResultSet rs1 = stmt1.executeQuery("select empno,ename from emp");
        while(rs1.next()){
            ...
        }
        rs1.close();
       
        // -------------------------------------------------------------------------
        // B. Oracle 8.1.7 2PC(XA) Test
        // -------------------------------------------------------------------------
        javax.sql.DataSource ds2 =
            (javax.sql.DataSource)ctx.lookup("java:comp/env/jdbc/ORA8i");
        conn2 = ds2.getConnection();
       
        stmt2 = conn2.createStatement();
        stmt2.executeUpdate(
            "update emp set ename = 'LWY" + count + "' where empno = 7934"
        );
        java.sql.ResultSet rs2 = stmt2.executeQuery("select empno,ename from emp");
        while(rs2.next()){
            ...
        }
        rs2.close();


        // -------------------------------------------------------------------------
        // 트렌젝션 commit
        tx.commit();
    }
    catch(Exception e){
        // 트렌젝션 rollback
        if ( tx != null ) try{tx.rollback();}catch(Exception ee){}
        ...
    }
    finally {
        if ( stmt1 != null ) try { stmt1.close();}catch(Exception e){}
        if ( conn1 != null ) try { conn1.close();}catch(Exception e){}

        if ( stmt2 != null ) try { stmt2.close();}catch(Exception e){}
        if ( conn2 != null ) try { conn2.close();}catch(Exception e){}
    }

 

NOTE: 위에서 설명한 하나하나가 제 입장에서 보면 너무나 가슴깊이 다가오는
  문제들입니다. 개발하시는 분의 입장에서 보면, 위의 가이드에 조금 어긋났다고
  뭐그리 문제겠느냐고 반문하실 수 있지만, 수백본의 소스코드 중에 위와 같은 규칙을
  준수하지 않은 코드가  단 하나라도 있다면, 잘 운영되던 시스템이 며칠에 한번씩
  에러를 야기하거나 응답이 느려지고 급기야 hang 현상을 초래하는 결과를 가져 옵니다.
  정말(!) 그렇습니다.

NOTE: 위에서 사용한 코딩 샘플들은 JDBC Connection Pooling 은 전혀 고려치 않고
  설명드렸습니다. 그러했기 때문에 <getConnection()>, <releaseConnection()> 이란
  Pseudo 코드로 설명했던 것입니다.
  반드시 "서블렛 + JDBC 연동시 코딩 고려사항 -제2탄-" 을 읽어 보세요.
  http://www.javaservice.net/~java/bbs/read.cgi?m=devtip&b=servlet&c=r_p&n=968522077


------------------------------------------------------- 
  본 문서는 자유롭게 배포/복사 할 수 있으나 반드시
  이 문서의 저자에 대한 언급을 삭제하시면 안됩니다
================================================
  자바서비스넷 이원영
  E-mail: javaservice@hanmail.net
  PCS:010-6239-6498
================================================
Posted by 1010
05.JSP2008. 10. 19. 15:38
반응형
1 session객체

 

session객체는 세션에 관련된 정보를 핸들하는 객체입니다. 웹서버와 클라이언트간의 세션 데이터를 저장하고 있는 객체죠. 그런데 세션이라는 것이 왜 필요할까요? HTTP프로토콜은 Stateless을 기본으로 합니다. ftp는 지속적인 연결설정이 되어 있는 반면 http는 순간적으로 연결하고 연결설정을 바로 끊어 버립니다. 이것을 개선하기 위해서 나온것이 session이죠. 그래서 Stateless의 극복이라고도 하죠.

 


2 클라이언트의 웹브라우져와 언제까지 세션이 유지될까?
 

클라이언트에서 하나의 jsp파일에 접근하고 그리고 jsp에서 session설정이 true로 되어 있다면 세션이 끝나는 지점은 jsp에서 세션시간설정이 끝났을 때 세션은 마무리되고 그리고 웹브라우져를 닫았다가 다시 오픈하면 즉시 세션이 사라지게 된다.

☞디폴트세션타임은 30분입니다. 


3 세션의 멤버 메서드를 알아볼까요
 

public String getID()

세션이 한번 열리면 고유한 ID를 갖게 됩니다. 이 아이디를 얻겠다는 것이죠

public long getCreationTime()

세션이 처음 생성된 시간을 밀리 초로 계산하여 long형 정수로 리턴합니다. 기준은 70년1월1일 00시 00분 00초입니다.

public long getLastAccessedTime()

클라이언트 요청이 마지막으로 시도된 시간을 밀리초로 반환합니다.

public int getMaxInactiveInterval()

클라이언트의 요구가 없을 때 서버가 현재의 세션을 언제까지 유지할지를 정수로 리턴합니다. 이때 기본 디폴트 세션마감시간은 30분으로 지정되어 있습니다.

public void invalidate()

현재의 세션을 마감해 버립니다. 세션의 속성값들이 사라지는거죠

public boolean isNew()

서버측에서 새로운 session객체를 생성하고 아직 클라이언트에게 세션ID를 할당하지 않은 경우 true를 리턴하고 기존의 세션이 유지되고 있는 상태라면 false를 반환합니다.

public void setMaxInactiveInterval(int seconds)

세션 시간을 설정합니다. 그리고 이 시간이 지나면 당연히 세션은 마감되겠죠(밀리세컨드단위입니다)

 


 

key: 객체를 가리키는 이름

value: 실제 객체

 

session.setAttribute(key, value) => 저장

session.getAttribute(key) => 불러오기


String memberID1 = "ID1";

session.setAttribute("memID", memberID1);

 (key: memID, value: String형 memberID1


ID1이란 값은 memberID1 객체 속에 담긴 정보라고 생각하세요.


로그인 세션의 경우

1. 입력받은 정보(ID, 패스워드)를 DB에서 찾고 유효한지 확인

2. ID, 패스워드와 함께 기타 유저 정보를 받아서 유저 정보 객체(ex:"Info) 저장

3. 그 객체를 다시 세션에 저장(ex: session.setAttribute("Info", Info);

4. 세션이 필요한 페이지는 세션에 저장된 정보를 받아서 알맞게 이용하면 됩니다.  

(ex: Info info = (Info)session.getAttribute("Info"));

 

 

말씀하신 것으로 설명드리면

1. session.getAttribute("memID")  memID라는 이름으로 저장된 객체를 불러오기.

2. session에 아무것도 저장이 안 되있으면 null값을 반환

3. 위와 같이 저장한 경우, String형 memberID1 객체를 불러오게 됩니다.

4. 불러온 객체는 Object형으로 변환되어있기 때문에 다시 형 변환을 시켜줘야 합니다.

ex) (String) <= 요 부분입니다.



EXAMPLE 1:


//세션 등록

session.setAttribute("userId", userId); //왼쪽파라미터는 이름을 명시, 두번째는 값을 저장.
session.setAttribute("passWd", passWd);
session.setAttribute("userName", userName);

session.setAttribute("mgrDiv", mgrDiv);



이는 세션에 적용된 페이지에서

session.getAttribute("userId"); 로 값을 가져옮


//세션 삭제

response.addHeader("Pragma", "No-cache");
response.addHeader("Cache-Control", "no-cache");
response.addDateHeader("Expires", 1);
session.invalidate();


세션 체크ex)

if(session != null && session.getAttribute("userId") != null && !session.getAttribute("userId").equals("")){

   //session에 userId라는 값이 존재할 때

}else{

   //userId를 사용하지 못할 때

}




EXAMPLE 2:

 

getCreationTime()을 사용하려다가 한번 만들어 봤습니다.


<%@ page contentType="text/html;" import="java.util.*,java.text.*" %>

<%
// javax.servlet.http Interface HttpSession


// session Creation / Last Access Time
long logonTime = session.getCreationTime();    //세션이 만들어진 시간
long lastAccessTime = session.getLastAccessedTime();     //최종접속시간

//날짜 타입으로 변환합니다.
SimpleDateFormat sFormat = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss");

Date logonTimeF = new Date(logonTime);
Date lastAccessTimeF = new Date(lastAccessTime);

String logonTimeStr = sFormat.format(logonTimeF);
String lastAccessTimeStr = sFormat.format(lastAccessTimeF);

out.print("LOGON TIME : " + logonTimeStr + "<BR>");
out.print("LAST ACCESS TIME : " + lastAccessTimeStr + "<BR>");
out.print("SESSION MAX INACTIVE INTERVAL : " + (session.getMaxInactiveInterval() / 60) + " MIN <BR>");

//세션타임아웃 시간을 기본 30분에서 40분으로 늘립니다.
session.setMaxInactiveInterval(2400);


// session Attribute
String sName="";
Integer value=new Integer(1004);

session.setAttribute("bigjava", value);
Enumeration attEnum = session.getAttributeNames();

while(attEnum.hasMoreElements()){
        sName=(String)attEnum.nextElement();
        out.print( sName + " : " + session.getAttribute(sName) + "<BR>");
        session.removeAttribute(sName);
}


// session ID
String mySessionID = session.getId();
out.print("SESSION ID : " + mySessionID + "<BR>");

%>


EXAMPLE 3:

 

Q:

[1번 페이지]

session생성 test

id [             ]   확인 <---text box에 값을 넣은 후 확인을 클릭 하면

--------------------------------------------------------------------

웹페이지가 뜨면서   


[2번 페이지]

새로운 세션이 생성되었습니다.

세션ID : ALSJFLAJFLJASDLKJF

세션내용보기 <---링크

-------------------------------------------------------------

2페이지의 세션내용보기 클릭하면 웹페이지가 뜨면서

[3번 페이지]

Attribute id 값 :1234  <--1번페이지 텍스트박스에 넣었던값

isNew():false

세션id:

세션생성시간:

세센마지막접속시간

Session 삭제하기  <------링크

--------------------------------------------------------------------

3페이지의 세션 삭제하기 클릭하면 웹페이지 뜨면서

[4페이지] 

로그인페이지로 <===클릭하면 1페이지

 

A:

---index.jsp---

[%@page language="java" contentType="text/html; charset=euc-kr"%]
[html]
[head]
  [script]
   function idSubmit(){
    document.idForm.action = "test1.jsp";
    document.idForm.submit();
   }
  [/script]
[/head]

[body]

[!-- Header --]
[table width="100%"]
[form name="idForm" method="post"]
    [tr]
        [td]ID : [input type="text" name="id" size="15"]&nbsp;[input type="button" value="확인" onClick="idSubmit()"][/td]
    [/tr]
[/form]
[/table]
[/body]
[/html]

---test1.jsp---

[%@page language="java" contentType="text/html; charset=euc-kr"%]
[html]
[%
 session = request.getSession(true);
 String id = request.getParameter("id");
 request.getSession().setAttribute("id", id);
%]
 [body]
 [h3]Session 생성 [/h3]
 새로운 세션이 생성되었습니다.[BR]
 세션ID : [%=session.getId()%][BR]
 [a href="test2.jsp"]세션내용보기[BR]
 [/body]
[/html]


---test2.jsp---

[%@page language="java" contentType="text/html; charset=euc-kr"%]
[html]
[body]
[h3]Session 정보 [/h3]
Attribute id 값 :[%=(String)request.getSession().getAttribute("id")%][br]
isNew():[%=session.isNew()%][br]
세션ID:[%=session.getId() %][br]
세션생성시간:[%=new java.util.Date(session.getCreationTime()).toString() %][br]
세션마지막접속시간:[%=new java.util.Date(session.getLastAccessedTime()).toString() %][br]
[a href="test3.jsp"]세션삭제하기[/a]
[/body]
[/html]


---test3.jsp---

[%@page language="java" contentType="text/html; charset=euc-kr"%]
[%
session = request.getSession(false);
if(session != null){
 session.invalidate();
}

response.sendRedirect("index.jsp");

%]


session객체는 내장객체를 사용하였고 '['는 '<'로 바꾸어 사용하면 됩니다.

Posted by 1010
05.JSP2008. 10. 19. 15:38
반응형

JSP 페이지를 실행할 때마다 커넥션을 생성해서 사용하게 되면 커넥션을 생성하고 닫는데 시간이 소모되기 때문에 동시 접속자 수가 많은 웹 사이트의 경우 전체 성능을 떨어뜨리는 원인이 된다. 성능문제를 해결하기 위해 사용하는 일반적인 방식으로 커넥션 풀 기법이 있는데, 이 글에서는 자카르타 프로젝트의 DBCP API를 이용하여 커넥션 풀을 사용하는 방법에 대해 살펴보도록 하겠다.

 

 

1. 커넥션 풀이란?

-- 커넥션 풀 기법이란, 데이터베이스와 연결된 커넥션을 미리 만들어서 풀(pool) 속에 저장해 두고 있다가 필요할 때에 커넥션을 풀에서 가져다 쓰고, 다시 풀에 반환하는 기법을 말한다.

 

[그림 1] 커넥션 풀 기법

 

풀 속에 데이터베이스와 연결된 커넥션을 미리 생성해 놓고 있다가, 커넥션이 필요할 경우 풀 속에 미리 생성되어 있는 커넥션을 가져다가 사용하고 다 사용한 커넥션은 다시 풀에 반환한다. 풀에 반환된 커넥션은 다음에 다시 사용된다.

 

◆ 커넥션 풀의 특징

-- 풀 속에 미리 커넥션이 생성되어 있기 때문에 커넥션을 생성하는데 드는 연결 시간이 소비되지 않는다.

-- 커넥션을 계속해서 재사용하기 때문에 생성되는 커넥션 수가 많지 않다.

 

커넥션을 생성하고 닫는데 필요한 시간이 소모되지 않기 때문에 그 만큼 어플리케이션의 실행 속도가 빨라지며, 또한 한번에 생성될 수 있는 커넥션 수를 제어하기 때문에 동시 접속자 수가 몰려도 웹 어플리케이션이 쉽게 다운되지 않는다. 커넥션 풀을 사용하면 전체적인 웹 어플리케이션의 성능 및 처리량이 높아지기 때문에 많은 웹 어플리케이션에서 커넥션 풀을 기본으로 사용하고 있다.

 

 

2. DBCP API의 사용 방법

자카르타 프로젝트의 DBCP API를 사용할 때에는 다음과 같은 과정을 거치면 된다.

 

① DBCP 관련 Jar 파일 및 JDBC 드라이버 Jar 파일 설치하기

② 커넥션 풀 관련 설정 파일 초기화하기

③ 커넥션 풀 관련 드라이버 로딩하기

④ 커넥션 풀로부터 커넥션 사용하기

 

이 네 가지 절차에 대해서 차례대로 살펴보도록 하자.

 

 

2.1 필요한 Jar 파일 복사

DBCP API를 사용하기 위해서는 다음과 같은 라이브러리가 필요하다.

 

- DBCP API 관련 Jar 파일                                                 DBCP 1.2.2        Download

- DBCP API가 사용하는 자카르타 Pool API의 Jar 파일              Pool 1.3           Download 

- Pool API가 사용하는 자카르타 Collection API의 Jar 파일        Collections 3.2  Download

 

이들 라이브러리의 최신 버전은 http://jakarta.apache.org/site/binindex.cgi 에서 다운로드 받을 수 있다.

파일의 압축을 풀면 다음과 같은 Jar 파일들을 발견할 수 있는데, 이들 Jar 파일들을 사용하면 된다.

 

- common-dbcp-1.2.2.jar

- common-pool-1.3.jar

- common-collections-3.2.jar

 

이 파일들을 WEB-INFlib 폴더에 복사해 넣는다.

 

 

2.2 설정 파일 작성하기

DBCP를 사용하는 방법에는 소스 코드 상에서 커넥션 풀을 설정하는 방법과 설정 파일을 통해서 커넥션 풀을 설정하는 방법 두 가지 존재하는데 여기서는 설정 파일을 이용한 커넥션 풀 설정 방법에 대해서 살펴보도록 하겠다.

 

DBCP Pool API에서 사용되는 커넥션 풀 설정 파일의 기본 골격은 다음과 같다.

 

[참고 1] WEB-INFclassespool1.jocl

---------------------------------------------------------------------------------------------------------------------------

01  <object class = "org.apache.common.dbcp.Poolable ConnectionFactory"

02             xmlns = "http://apache.org/xml/xmlsn/jakarta/commons/jocl">

03

04       // DBMS와 연결할 때 사용할 JDBC URL 및 사용자 계정, 암호

05       <object class = "org.apache.commons.dbcp.DriverManagerConnectionFactory">

06             <string value = "jdbc:mysql://localhost:3306/myRoot?.." />

07             <string value = "jspexam" />

08             <string value = "jspex" />

09       </object>

10

11       // 커넥션 풀과 관련된 추가 설정 정보 지정

12       <object class = "org.apache.commons.pool.implGenericObjectPool">

13             <object class = "org.apache.commons.pool.PoolableObjectFactory"  null="true" />

14       </object>

15

16       <object class = "org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory"  null="true" />

17

18       // 커넥션이 유효한지의 여부를 검사할 때 사용할 쿼리. 쿼리를 지정하고 싶은 경우에는

19       // <string value = "SELECT count(*) FROM member" /> 와 같은 코드를 입력해 주면 된다.

20       <string null="true" />

21

22       // 커넥션을 읽기 전용으로 생성할지의 여부를 지정한다.

23       // insert, update, delete 작업이 있다면 false로 지정해 주어야 한다.

24       <boolean value="false" />

25

26       // 커넥션을 자동 커밋 모드로 설정할 경우 true를, 그렇지 않을 경우 false를 지정한다. 일반적으로 true를 사용한다.

27       <boolean value="true" />

28  </object>

---------------------------------------------------------------------------------------------------------------------------

 

[참고1] 설정 파일에서 나머지 부분은 그대로 입력하고 라인 05~09 부분만 알맞게 변경하면 된다.

 

05       <object class = "org.apache.commons.dbcp.DriverManagerConnectionFactory">

06             <string value = "jdbc:mysql://localhost:3306/myRoot?.." />

07             <string value = "jspexam" />

08             <string value = "jspex" />

09       </object>

 

위 코드에는 세 개의 <string> 태그가 사용되는데, 이들 태그는 각각 순서대로 JDBC URF, 데이터베이스 사용자 계정, 암호를 나타낸다. JDBC URL 부분의 값이 길어서 생략해서 표시했는데 다음과 같이 사용할 수 있다.

 

jdbc:mysql://localhost:3306/myRoot?useUnicode=true&amp;characterEncoding=euc-kr

 

*** NOTE

DBCP 커넥션 풀 설정 파일은 XML 문서로 처리된다. XML 문서에서는 엠퍼샌드 기호('&')를 표시할 때 &amp;를 사용해야 하기 때문에 JDBC URL 입력 부분에 useUnicode=true&characterEncoding 대신 useUnicode=true&amp;char...를 사용하였다.

 

하나의 설정 파일은 하나의 커넥션 풀에 해당한다. 새로운 커넥션 풀을 생성하고 싶다면 [참고 1]과 같은 파일을 하나 새롭게 생성하면 된다.

 

 

2.3 설정 파일의 위치

DBCP API는 클래스 패스로부터 설정 파일을 읽어 온다. 따라서 앞서 작성한 커넥션 풀 설정 파일은 클래스 패스에 위치해 있어야 한다. 웹 어플리케이션에서 DBCP API와 관련된 설정 파일의 위치로 가장 좋은 곳은 WEB-INFclasses 폴더이다.

 

 

2.4 커넥션 풀 초기화하기

DBCP API를 통해서 커넥션 풀을 사용하기 위해서는 커넥션 풀과 관련된 JDBC 드라이버를 로딩해 주어야 한다. DBCP API를 사용할 때에 로딩해 주어야 할 JDBC 드라이버는 다음과 같다.

 

- org.apache.commons.dbcp.PoolingDriver  -- DBCP API의 JDBC 드라이버

- DBMS에 연결될 때 사용될 JDBC 드라이버

 

DBCP API를 사용할 때에는 웹 어플리케이션 시작할 때 위에서 언급한 두 가지 형태의 JDBC 드라이버를 로딩하도록 하면 편리하다.

DBCP API와 관련된 JDBC 드라이버를 로딩하는 코드는 다음 [참고 2]와 같다.

 

[참고 2] WEB-INFjdbcdriverDBCPInit.java

---------------------------------------------------------------------------------------------------------------------------

01  package jdbcdriver;

02

03  import javax.servlet.http.HttpServlet;

04  import javax.servlet.ServletConfig;

05  import javax.servlet.ServletException;

06  import java.util.StringTockenizer;

07 

08  public class DBCPInit extends HttpServlet {

09

10       public void init (ServletConfig config) throws ServletException {

11            try {

12                 // DBMS와 연결할 때 사용될 JDBC 드라이버 로딩

13                 String drivers = config.getInitParameter("jdbcdriver");

14                 StringTockenizer st = new StringTokenizer(drivers, ",");

15                 while (st.hasMoreTokens()) {

16                      String jdbcDriver = st.nextToken();

17                      Class.forName(jdbcDriver);

18                 }

19

20                 // DBCP API에서 풀 기능을 제공하기 위해 사용되는 PoolingDriver 로딩

21                 Class.forName("org.apache.commons.dbcp.PoolingDriver");

22

23                 // 톰캣 5.0.19에서는 주석을 그대로 두어도 올바르게 실행되지만 톰캣 5.0.2x 버전부터는

24                 // 주석을 없애고 SAX 파서를 지정해 주어야 올바르게 실행된다.

25                 // System.setProperty("org.xml.sax.driver", "org.apache.crimson.parser.XMLReaderImpl");

26            } catch (Exception ex) {

27                 throw new ServletException(ex);

28            }

29       }

30  }

---------------------------------------------------------------------------------------------------------------------------

 

[컴파일]

C:>cd jakarta-tomcat-5.0.19webappsmyRootWEB-INF

C:..WEB-INF> set PATH=c:j2sdk1.4.2_04bin;%PATH%

C:..WEB-INF> set CLASSPATH=c:jakarta-tomcat-5.0.19commonlibservlet-api.jar;c:jakarta-tomcat-5.0.19commonlibjsp-api.jar;classes

C:..WEB-INF> javac -d classes jdbcdriverDBCPInit.java

 

컴파일에 성공하면 WEB-INFclassesjdbcdriver 폴더에 DBCPInit.class 파일이 생성될 것이다.

WEB-INFweb.xml 파일에 DBCPInit 서블릿 클래스에 대한 설정 정보를 추가함으로써 웹 어플리케이션이 시작될 때 DBCPInit 서블릿 클래스가 시작될 수 있도록 할 수 있다. 예를 들면, 아래와 같은 코드를 web.xml 파일에 추가해 주면 된다.

 

---------------------------------------------------------------------------------------------------------------------------

<servlet>

     <servlet-name>DBCPInit</servlet-name>

     <servlet-class>jdbcdriver.DBCPInit</servlet-class>

     <load-on-startup>1</load-on-startup>

     <init-param>

          <param-name>jdbcdriver</param-name>

          <param-value>com.mysql.jdbc.Driver</param-value>

     <init-param>

</servlet>

---------------------------------------------------------------------------------------------------------------------------

 

위와 같이 코드를 추가해 주면 웹 어플리케이션이 시작할 때 DBCPInit 서블릿 클래스가 자동으로 시작되고 init() 메소드가 호출된다.

 

 

2.5 커넥션 사용하기

커넥션 풀을 위한 JDBC 드라이버 및 DBMS에 연결할 때 사용할 JDBC 드라이버를 로딩하면 커넥션 풀로부터 커넥션을 가져와 사용할 수 있다. 커넥션 풀로부터 커넥션을 가져오는 코드는 별반 다르지 않으며, 다음과 같은 형태의 코드를 사용하면 된다.

Posted by 1010
05.JSP2008. 10. 19. 15:38
반응형

JSP 페이지를 실행할 때마다 커넥션을 생성해서 사용하게 되면 커넥션을 생성하고 닫는데 시간이 소모되기 때문에 동시 접속자 수가 많은 웹 사이트의 경우 전체 성능을 떨어뜨리는 원인이 된다. 성능문제를 해결하기 위해 사용하는 일반적인 방식으로 커넥션 풀 기법이 있는데, 이 글에서는 자카르타 프로젝트의 DBCP API를 이용하여 커넥션 풀을 사용하는 방법에 대해 살펴보도록 하겠다.

 

 

1. 커넥션 풀이란?

-- 커넥션 풀 기법이란, 데이터베이스와 연결된 커넥션을 미리 만들어서 풀(pool) 속에 저장해 두고 있다가 필요할 때에 커넥션을 풀에서 가져다 쓰고, 다시 풀에 반환하는 기법을 말한다.

 

[그림 1] 커넥션 풀 기법

 

풀 속에 데이터베이스와 연결된 커넥션을 미리 생성해 놓고 있다가, 커넥션이 필요할 경우 풀 속에 미리 생성되어 있는 커넥션을 가져다가 사용하고 다 사용한 커넥션은 다시 풀에 반환한다. 풀에 반환된 커넥션은 다음에 다시 사용된다.

 

◆ 커넥션 풀의 특징

-- 풀 속에 미리 커넥션이 생성되어 있기 때문에 커넥션을 생성하는데 드는 연결 시간이 소비되지 않는다.

-- 커넥션을 계속해서 재사용하기 때문에 생성되는 커넥션 수가 많지 않다.

 

커넥션을 생성하고 닫는데 필요한 시간이 소모되지 않기 때문에 그 만큼 어플리케이션의 실행 속도가 빨라지며, 또한 한번에 생성될 수 있는 커넥션 수를 제어하기 때문에 동시 접속자 수가 몰려도 웹 어플리케이션이 쉽게 다운되지 않는다. 커넥션 풀을 사용하면 전체적인 웹 어플리케이션의 성능 및 처리량이 높아지기 때문에 많은 웹 어플리케이션에서 커넥션 풀을 기본으로 사용하고 있다.

 

 

2. DBCP API의 사용 방법

자카르타 프로젝트의 DBCP API를 사용할 때에는 다음과 같은 과정을 거치면 된다.

 

① DBCP 관련 Jar 파일 및 JDBC 드라이버 Jar 파일 설치하기

② 커넥션 풀 관련 설정 파일 초기화하기

③ 커넥션 풀 관련 드라이버 로딩하기

④ 커넥션 풀로부터 커넥션 사용하기

 

이 네 가지 절차에 대해서 차례대로 살펴보도록 하자.

 

 

2.1 필요한 Jar 파일 복사

DBCP API를 사용하기 위해서는 다음과 같은 라이브러리가 필요하다.

 

- DBCP API 관련 Jar 파일                                                 DBCP 1.2.2        Download

- DBCP API가 사용하는 자카르타 Pool API의 Jar 파일              Pool 1.3           Download 

- Pool API가 사용하는 자카르타 Collection API의 Jar 파일        Collections 3.2  Download

 

이들 라이브러리의 최신 버전은 http://jakarta.apache.org/site/binindex.cgi 에서 다운로드 받을 수 있다.

파일의 압축을 풀면 다음과 같은 Jar 파일들을 발견할 수 있는데, 이들 Jar 파일들을 사용하면 된다.

 

- common-dbcp-1.2.2.jar

- common-pool-1.3.jar

- common-collections-3.2.jar

 

이 파일들을 WEB-INFlib 폴더에 복사해 넣는다.

 

 

2.2 설정 파일 작성하기

DBCP를 사용하는 방법에는 소스 코드 상에서 커넥션 풀을 설정하는 방법과 설정 파일을 통해서 커넥션 풀을 설정하는 방법 두 가지 존재하는데 여기서는 설정 파일을 이용한 커넥션 풀 설정 방법에 대해서 살펴보도록 하겠다.

 

DBCP Pool API에서 사용되는 커넥션 풀 설정 파일의 기본 골격은 다음과 같다.

 

[참고 1] WEB-INFclassespool1.jocl

---------------------------------------------------------------------------------------------------------------------------

01  <object class = "org.apache.common.dbcp.Poolable ConnectionFactory"

02             xmlns = "http://apache.org/xml/xmlsn/jakarta/commons/jocl">

03

04       // DBMS와 연결할 때 사용할 JDBC URL 및 사용자 계정, 암호

05       <object class = "org.apache.commons.dbcp.DriverManagerConnectionFactory">

06             <string value = "jdbc:mysql://localhost:3306/myRoot?.." />

07             <string value = "jspexam" />

08             <string value = "jspex" />

09       </object>

10

11       // 커넥션 풀과 관련된 추가 설정 정보 지정

12       <object class = "org.apache.commons.pool.implGenericObjectPool">

13             <object class = "org.apache.commons.pool.PoolableObjectFactory"  null="true" />

14       </object>

15

16       <object class = "org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory"  null="true" />

17

18       // 커넥션이 유효한지의 여부를 검사할 때 사용할 쿼리. 쿼리를 지정하고 싶은 경우에는

19       // <string value = "SELECT count(*) FROM member" /> 와 같은 코드를 입력해 주면 된다.

20       <string null="true" />

21

22       // 커넥션을 읽기 전용으로 생성할지의 여부를 지정한다.

23       // insert, update, delete 작업이 있다면 false로 지정해 주어야 한다.

24       <boolean value="false" />

25

26       // 커넥션을 자동 커밋 모드로 설정할 경우 true를, 그렇지 않을 경우 false를 지정한다. 일반적으로 true를 사용한다.

27       <boolean value="true" />

28  </object>

---------------------------------------------------------------------------------------------------------------------------

 

[참고1] 설정 파일에서 나머지 부분은 그대로 입력하고 라인 05~09 부분만 알맞게 변경하면 된다.

 

05       <object class = "org.apache.commons.dbcp.DriverManagerConnectionFactory">

06             <string value = "jdbc:mysql://localhost:3306/myRoot?.." />

07             <string value = "jspexam" />

08             <string value = "jspex" />

09       </object>

 

위 코드에는 세 개의 <string> 태그가 사용되는데, 이들 태그는 각각 순서대로 JDBC URF, 데이터베이스 사용자 계정, 암호를 나타낸다. JDBC URL 부분의 값이 길어서 생략해서 표시했는데 다음과 같이 사용할 수 있다.

 

jdbc:mysql://localhost:3306/myRoot?useUnicode=true&amp;characterEncoding=euc-kr

 

*** NOTE

DBCP 커넥션 풀 설정 파일은 XML 문서로 처리된다. XML 문서에서는 엠퍼샌드 기호('&')를 표시할 때 &amp;를 사용해야 하기 때문에 JDBC URL 입력 부분에 useUnicode=true&characterEncoding 대신 useUnicode=true&amp;char...를 사용하였다.

 

하나의 설정 파일은 하나의 커넥션 풀에 해당한다. 새로운 커넥션 풀을 생성하고 싶다면 [참고 1]과 같은 파일을 하나 새롭게 생성하면 된다.

 

 

2.3 설정 파일의 위치

DBCP API는 클래스 패스로부터 설정 파일을 읽어 온다. 따라서 앞서 작성한 커넥션 풀 설정 파일은 클래스 패스에 위치해 있어야 한다. 웹 어플리케이션에서 DBCP API와 관련된 설정 파일의 위치로 가장 좋은 곳은 WEB-INFclasses 폴더이다.

 

 

2.4 커넥션 풀 초기화하기

DBCP API를 통해서 커넥션 풀을 사용하기 위해서는 커넥션 풀과 관련된 JDBC 드라이버를 로딩해 주어야 한다. DBCP API를 사용할 때에 로딩해 주어야 할 JDBC 드라이버는 다음과 같다.

 

- org.apache.commons.dbcp.PoolingDriver  -- DBCP API의 JDBC 드라이버

- DBMS에 연결될 때 사용될 JDBC 드라이버

 

DBCP API를 사용할 때에는 웹 어플리케이션 시작할 때 위에서 언급한 두 가지 형태의 JDBC 드라이버를 로딩하도록 하면 편리하다.

DBCP API와 관련된 JDBC 드라이버를 로딩하는 코드는 다음 [참고 2]와 같다.

 

[참고 2] WEB-INFjdbcdriverDBCPInit.java

---------------------------------------------------------------------------------------------------------------------------

01  package jdbcdriver;

02

03  import javax.servlet.http.HttpServlet;

04  import javax.servlet.ServletConfig;

05  import javax.servlet.ServletException;

06  import java.util.StringTockenizer;

07 

08  public class DBCPInit extends HttpServlet {

09

10       public void init (ServletConfig config) throws ServletException {

11            try {

12                 // DBMS와 연결할 때 사용될 JDBC 드라이버 로딩

13                 String drivers = config.getInitParameter("jdbcdriver");

14                 StringTockenizer st = new StringTokenizer(drivers, ",");

15                 while (st.hasMoreTokens()) {

16                      String jdbcDriver = st.nextToken();

17                      Class.forName(jdbcDriver);

18                 }

19

20                 // DBCP API에서 풀 기능을 제공하기 위해 사용되는 PoolingDriver 로딩

21                 Class.forName("org.apache.commons.dbcp.PoolingDriver");

22

23                 // 톰캣 5.0.19에서는 주석을 그대로 두어도 올바르게 실행되지만 톰캣 5.0.2x 버전부터는

24                 // 주석을 없애고 SAX 파서를 지정해 주어야 올바르게 실행된다.

25                 // System.setProperty("org.xml.sax.driver", "org.apache.crimson.parser.XMLReaderImpl");

26            } catch (Exception ex) {

27                 throw new ServletException(ex);

28            }

29       }

30  }

---------------------------------------------------------------------------------------------------------------------------

 

[컴파일]

C:>cd jakarta-tomcat-5.0.19webappsmyRootWEB-INF

C:..WEB-INF> set PATH=c:j2sdk1.4.2_04bin;%PATH%

C:..WEB-INF> set CLASSPATH=c:jakarta-tomcat-5.0.19commonlibservlet-api.jar;c:jakarta-tomcat-5.0.19commonlibjsp-api.jar;classes

C:..WEB-INF> javac -d classes jdbcdriverDBCPInit.java

 

컴파일에 성공하면 WEB-INFclassesjdbcdriver 폴더에 DBCPInit.class 파일이 생성될 것이다.

WEB-INFweb.xml 파일에 DBCPInit 서블릿 클래스에 대한 설정 정보를 추가함으로써 웹 어플리케이션이 시작될 때 DBCPInit 서블릿 클래스가 시작될 수 있도록 할 수 있다. 예를 들면, 아래와 같은 코드를 web.xml 파일에 추가해 주면 된다.

 

---------------------------------------------------------------------------------------------------------------------------

<servlet>

     <servlet-name>DBCPInit</servlet-name>

     <servlet-class>jdbcdriver.DBCPInit</servlet-class>

     <load-on-startup>1</load-on-startup>

     <init-param>

          <param-name>jdbcdriver</param-name>

          <param-value>com.mysql.jdbc.Driver</param-value>

     <init-param>

</servlet>

---------------------------------------------------------------------------------------------------------------------------

 

위와 같이 코드를 추가해 주면 웹 어플리케이션이 시작할 때 DBCPInit 서블릿 클래스가 자동으로 시작되고 init() 메소드가 호출된다.

 

 

2.5 커넥션 사용하기

커넥션 풀을 위한 JDBC 드라이버 및 DBMS에 연결할 때 사용할 JDBC 드라이버를 로딩하면 커넥션 풀로부터 커넥션을 가져와 사용할 수 있다. 커넥션 풀로부터 커넥션을 가져오는 코드는 별반 다르지 않으며, 다음과 같은 형태의 코드를 사용하면 된다.

Posted by 1010
98..Etc/JavaFX2008. 10. 17. 17:10
반응형


Running Draggable JavaFX Applets




The new Drag'able feature in Applet in Java SE 6 update 10 unifies user's browser and desktop experience - The new Plug-In allows you to drag an Applet off from a browser to your desktop and allows your Applet continues to run. In addition to dragging an Applet off from a browser, when user closes the browser, a shortcut can also be created from this Drag'able Applet. The shortcut utilizes Java Web Start technology and allow user to launch the Applet with Java Web Start without opening a web browser. Thus, this feature unifies desktop application deployment via Java Web Start technology, and Applet deployment inside the browser.

Acknowledgments: The sample applications are from Joshua Marinacci and Chuk-Munn Lee.

Expected duration: 60 minutes (excluding homework)


Software Needed


  • JRE 6 update 10 (download)
    • The installation instruction of JRE 6 update 10 is described below.
  • Firefox 3 (download)
    • The installation instruction of JRE 6 update 10 is described below.
  • 4611_javafxdraggableapplets.zip (download)
    • It contains this document and the lab contents
    • Download it and unzip in a directory of your choice

OS platforms you can use

  • Windows
  • Solaris x86, Solaris Sparc
  • Linux
  • Mac OS X

Change Log

  • June 16th, 2008: Created


Lab Exercises


Exercise 1: Download and Install JRE 6 Update 10

You will have to use JRE 6 Update 10 in order to run the StopWatch application leveraging the new Java plug-in architecture.


(1.1) Download JRE 6 Update 10









(1.2) Install JRE 6 Update 10

















(1.3) Verify that JRE 6 update 10 is installed











Exercise 2: Download and Install Firefox 3

You will need either Firefox 3 or IE 7 in order to run StopWatch application.


(2.1) Download Firefox 3





(2.2) Install Firefox 3


          <To do: Include installation of Firefox 3>

(2.3) Verify that Firefox 3 is using JRE 6 Update 10


1. Verify that Firefox 3 is using JRE 6 Update 10 from the browser.
  • In the URL field, type in about:plugins.
  • Make sure you see Java(TM) Platform SE 6 U10 and its Enabled column says Yes.



2. Verify that Firefox 3 is using JRE 6 Update 10 from the Add-ons page. (This is an optional step.)
  • Select Tools from the top-level menu and select Add-ons in the Firefox 3.


  • Make sure you see Java(TM) Platform SE 6 U10 is in enabled state.



Exercise 3: Run StopWatch application


The StopWatch application is compiled version of JavaFX application.  The StopWatch application is provided as part of this hands-on lab zip file and located under <LAB_UNZIPPED_DIRECTORY>/javafxstopwatch/samples/StopWatch directory.

(3.1) Open index.html of the Stopwatch application from local file system


1. Open index.html of the application from the local file system.
  • Within Firefox 3 browser, select File->Open File.



  • Go to <LAB_UNZIPPED_DIRECTORY>/javafxstopwatch/samples/StopWatch directory.
  • Select index.html.
  • Click Open.



(3.2) Observe the stopwatch


1. Click the start button of the stopwatch.



2. Observe that the stopwatch now starts timing.



3. While holding ALT key, drag the stopwatch from the browser to the desktop.


  • Observe that the browser now has the Java logo (instead of the stopwatch) and the stopwatch on the desktop still works.
  • If you want to move the stopwatch around on the desktop, hold ALT key and move it around.
Note: Somehow I could not capture the stopwatch on the desktop.

4. Close the browser.
  • You can close the browser now and the stopwatch on the desktop still works.









(3.3)  Look under the hood of the application


1.  index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Java FX Applets</title>
<style type="text/css">
<!--
body,td,th {
    font-family: Arial, Helvetica, sans-serif;
    color: #CCCCCC;
}
body {
    background-color: #000000;
    margin-left: 20px;
    margin-top: 20px;
    margin-right: 20px;
    margin-bottom: 20px;
}
#content {
    background-color: #3b3b3b;
}
-->
</style></head>
<script src="http://java.com/js/deployJava.js"></script>
<body>
<table width="100%" border="0" cellpadding="0" cellspacing="0" style="max-width:1000px" align="center">
  <tr>
    <td><table width="100%" border="0" cellspacing="0" cellpadding="0">
      <tr>
        <td><img src="header-left.png" width="592" height="147" /></td>
        <td width="100%" background="header-center.png">&nbsp;</td>
        <td><img src="header-right.png" width="19" height="147" /></td>
      </tr>
    </table></td>
  </tr>
   <tr>
    <td colspan=3 align="center">
    <applet width="350" height="350">
        <param name="draggable" value="true">
        <param name="image" value="spinner.gif">
        <param name="boxborder" value="false">
        <param name="centerimage" value="true">
        <param name="boxbgcolor" value="#3b3b3b">
        <param name="boxfgcolor" value="#ffffff">
        <param name="jnlp_href" value="Stopwatch.jnlp">
    </applet>
    </td>
   </tr>
   <tr>
    <td colspan=3 align="center"><h3>Stopwatch</h3>
      <p>Need to keep track of how long it takes to run around your office? How long a coworker is talking to you and won't leave? How fast you wrote that code? Look no further. This Stopwatch applet does all that, and more, all while animating with drop shadows and lighting effects.</p></td>
   </tr>
</table>
</body>
</html>
index.html

2. Stopwatch.jnlp

<?xml version="1.0" encoding="UTF-8"?>
<jnlp href="Stopwatch.jnlp">
  <information>
    <title>Stopwatch</title>
    <vendor>Sun Microsystems</vendor>
    <offline-allowed />
    <shortcut online="false">
        <desktop/>
    </shortcut>
  </information>
  <resources>
    <j2se version="1.6+" href="http://java.sun.com/products/autodl/j2se" />
    <jar href="Widgets.jar" main="true" />
    <extension name="JavaFXRT" href="extensions/javafxrt.jnlp" />
    <extension name="Reprise" href="extensions/Reprise.jnlp" />
    <extension name="Scenario" href="extensions/Scenario.jnlp" />
    <extension name="Swingx-WS" href="extensions/swingx-ws.jnlp" />
  </resources>
  <applet-desc
      name="Stopwatch"
      main-class="widgets.stopwatch.StopwatchApplet"
      width="500"
      height="500">
  </applet-desc>
</jnlp>
Stopwatch.jnlp

Exercise 4: Run Magnifying Glass Draggable Applet


In this exercise, you are going to run magnifuing glass draggable applet.

(4.1) Access the Magnifying Glass Draggable Applet


1. From your browser go to Magnifying Glass Draggable Applet.



2. Drag the magnifying class from the browser to the desktop.
3. Observe that the magnifying glass magnifies the things on the desktop.
4. Closes the browser and observe that the magnifying glass still works.

Exercise 5: Run LiveConnect Draggable Applet


In this exercise, you are going to run LiveConnect draggable applet application.

(4.0) Create a Twitter account


<To do: Add instruction on how to create Twitter account>

(4.1) Access the LiveConnect Applet


1. From your browser, go to LiveConnect.



2. Enter your twitter account username and password.



3. Observe that the picture icon table is being displayed on the left.
4. Drag it from the browser to the desktop.



5. Close the browser.



6. Observe that the LiveConnect applet still works in the desktop.



If you want to close the LiveConnect on the desktop, press ALT key and click x button (upper right corner).

Homework Exercise (for people who are taking Sang Shin's "Java Web Services Programming online course")


<tbd>

                                                                                                                           return to the top




Posted by 1010
98..Etc/Etc...2008. 10. 17. 15:33
반응형
실전 웹 표준 가이드
- 1 -
실전 웹 표준 가이드
The Practice Guide for Development
based on Web Standards
2005.12
한국소프트웨어진흥원
실전 웹 표준 가이드
- 2 -
Web Standard Practice by KIPA
Edited by Seokchan Yun, Jungsik Shin, Hyeonseok Shin, Sungno Lee
Copyright ⓒ 2005 KIPA. All rights reserved.
This book is restricted by the confidential policy of KIPA. Anyone cannot
distribute or copy this book without acceptance of the company.
이 가이드의 내용에 대한 모든 저작권은 한국소프트웨어진흥원에 있으며, 본
원 문서 정책 및 저작권법에 따라 보호 받는 저작물이므로 무단 전재와 복제를
금합니다.
실전 웹 표준 가이드
- 3 -
목차
목차 ························································································································································ 3
그림 목차················································································································································ 7
저자 소개················································································································································ 10
서론 ························································································································································ 11
이 가이드의 목적 ······························································································································· 12
웹 표준에 대한 오해·························································································································· 16
웹 표준이란 무엇인가?······················································································································ 17
웹 표준 스펙 소개 ····························································································································· 19
웹 표준 홈페이지 방법론 ·················································································································· 23
우리 나라 웹 표준 현실 및 과제 ······································································································ 30
실전 XHTML 가이드 ·····················································································36
XTHML 소개········································································································································· 37
XTHML이란 무엇인가? ····················································································································· 37
왜 XTHML을 사용해야 하는가?······································································································· 38
XTHML 문서 구조 ····························································································································· 39
XHTML 일반 문법 준수 ···················································································································· 41
구조적 XHTML 사용 방법···················································································································· 44
잘못 사용하고 있는 태그 ·················································································································· 44
그룹 요소: div, span··························································································································· 46
표제(Heading) ···································································································································· 46
문단(paragraph)································································································································· 46
구문(em, strong, dfn, code, samp, kbd, var, cite, abbr, acronym)······················································ 47
형식을 가지고 있는 컨텐츠 (pre) ····································································································· 48
추가 및 삭제(ins, del) ························································································································ 48
목록 (ul, ol, dl)··································································································································· 48
실전 CSS 레이아웃························································································50
CSS 제대로 사용하기 ···························································································································· 51
CSS 개념 및 소개·································································································································· 53
CSS(Cascading Style Sheet)란 무엇인가? ························································································· 53
CSS 선택자(Selector)························································································································· 54
CSS 선언 방법 ··································································································································· 65
CSS 적용의 체크 포인트 4가지 ········································································································ 66
CSS 레이아웃(LAYOUT) 기초 ··············································································································· 70
실전 웹 표준 가이드
- 4 -
테이블 레이아웃 ································································································································· 70
CSS 레이아웃이란?···························································································································· 70
기본 레이아웃 ···································································································································· 72
컬럼형 레이아웃 ································································································································· 77
목록(List)············································································································································ 81
박스 모델(Box Model)························································································································ 83
테이블(Tables)···································································································································· 90
CSS Hack············································································································································ 93
실전 예제를 통한 CSS 레이아웃 ··········································································································· 95
전체적인 구조와 마크업 ···················································································································· 95
상단 부분(#head) ······························································································································· 97
좌측 영역 (#sub)································································································································ 101
본문 영역 (#body) ····························································································································· 105
하단 영역 (#foot)······························································································································· 107
완료····················································································································································· 109
고급 CSS 레이 아웃 ······························································································································ 110
CSS를 이용한 디자인 팁 ··················································································································· 110
CSS 개발 및 검증 도구 ····················································································································· 115
실전 DOM/Script 가이드 ···············································································122
표준 DOM 기반 개발 ···························································································································· 123
W3C DOM vs. MS DOM···················································································································· 123
DOM 기본 기능 ································································································································· 125
DOM 호환 기능 ································································································································· 128
이벤트(Events) 기능 ··························································································································· 131
XML 기능 ··········································································································································· 133
표준 JAVASCRIPT 사용 방법 ················································································································· 136
ECMAscript vs. Jscript?····················································································································· 136
스크립트 개발시 유의점 ···················································································································· 137
디버깅 및 품질 관리 ······························································································································ 143
기본 디버깅 방법론 ··························································································································· 143
디버깅 도구 이용 ······························································································································· 144
올바른 플러그인(PLUGIN) 사용 ············································································································· 149
외부 객체 이용 방법·························································································································· 149
ActiveX와 대안 Plugin 기술 ············································································································· 152
브라우저 내장 기술 ··························································································································· 156
웹 어플리케이션 표준화 동향 ··········································································································· 158
실전 웹 표준 가이드
- 5 -
실전 표준 웹 프로그래밍··················································································162
표준 MIME 타입 설정··························································································································· 163
Apache에서 설정 방법 ······················································································································· 165
IIS에서 설정 방법 ······························································································································ 167
PHP에서 설정 방법 ··························································································································· 168
Apache Tomcat에서 설정 방법 ·········································································································· 168
Perl/Python 등으로 쓴 CGI·············································································································· 170
표준 문자 인코딩 지정··························································································································· 171
문서에서 지정 ···································································································································· 173
웹 서버 프로그램에서 지정 ··············································································································· 175
참고 문헌················································································································································ 179
실전 웹 표준 개발 프로세스··············································································181
기존 웹 개발 프로세스··························································································································· 182
현재 프로세스 소개(Waterfall 방식)································································································· 182
역할을 중심으로 한 개발 공정 ········································································································· 187
개선된 모델(퍼블리셔 중심) ·············································································································· 192
새로운 개발 프로세스 ···························································································································· 195
기획/분석/회의 ···································································································································· 195
기획자 공정 ········································································································································ 196
퍼블리셔 공정 ···································································································································· 199
디자이너 공정 ···································································································································· 209
프로그래머 공정 ································································································································· 210
맺음말····················································································································································· 213
부록. 웹 표준 브라우저 호환표 ··········································································214
웹 브라우저 현황 ··································································································································· 215
인터넷 익스플로러7 ··························································································································· 215
모질라(Mozilla) 계열 웹브라우저 : 파이어폭스··············································································· 216
오페라 브라우저 ································································································································· 217
사파리 ················································································································································· 218
장애인 웹 접근성 체크 리스트 ·············································································································· 220
HTML 브라우저 호환표 ························································································································ 223
윈도우에서 주요 웹브라우저 별 HTML 지원 내역 ········································································· 223
브라우저별 HTML3/4 지원 일람표 ··································································································· 224
표준 HTML4.01/XHTML 브라우저 호환 차트 ···················································································· 228
실전 웹 표준 가이드
- 6 -
HTML 4.01 ········································································································································· 228
XHTML 1.0········································································································································· 241
XHTML 1.1········································································································································· 241
표준 CSS 브라우저 호환 차트··············································································································· 243
CSS 2.1 Unit ······································································································································· 243
CSS 2.1 Importance···························································································································· 245
CSS 2.1 At-rules ································································································································· 245
CSS 2.1 Selectors ······························································································································· 245
CSS 2.1 Pseudo-classes······················································································································ 246
CSS 2.1 Pseudo-elements ··················································································································· 246
CSS 2.1 Basic properties···················································································································· 246
CSS 2.1 Print properties····················································································································· 261
CSS 2.1 Voice properties···················································································································· 261
CSS 2.1 Conformance ························································································································ 264
CSS 3 Units ········································································································································ 265
CSS 3 At-rules ···································································································································· 268
CSS 3 Selectors ·································································································································· 270
CSS 3 Pseudo-classes························································································································· 270
CSS 3 Pseudo-elements ······················································································································ 272
CSS 3 Basic properties······················································································································· 272
CSS 3 Print properties ······················································································································· 275
표준 DOM 2/3 브라우저 호환 차트 ······································································································ 277
DOM Level 3 Core ····························································································································· 277
DOM Level 2 Events ·························································································································· 281
DOM Level 2 HTML ·························································································································· 283
DOM Level 3 Load and Save ············································································································· 293
DOM Level 2 Style ····························································································································· 294
DOM Level 2 Traversal and Range ··································································································· 300
DOM Level 3 Validation ···················································································································· 301
DOM Level 2 Views ··························································································································· 302
참고 사이트 ············································································································································ 303
각 웹 표준 브라우저별 호환 여부 ···································································································· 303
국내 웹 표준 커뮤니티 ······················································································································ 303
실전 웹 표준 가이드
- 7 -
그림 목차
그림 1 역사상의 웹 브라우저 ······················································································ 11
그림 2 웹 표준에서 구조, 표현, 행동의 분리 ··································································· 13
그림 3 W3C HTML Validator의 실행 모습···································································· 15
그림 4 웹 표준을 제정하는 표준화 기구, 웹 컨소시움(http://w3.org) ·································· 18
그림 5 웹 표준이 정해 지는 순서················································································· 18
그림 6 웹 접근성 평가 도구, KADO-WAH···································································· 23
그림 7 구조적으로 표현한것과 태그로만 표현한 페이지······················································ 24
그림 8 구조와 표현의 분리를 통해 디자인 및 접근성이 확보된 웹 페이지 (1)은 기본 스타일 양식, (2)
는 구조적 마크업을 통한 HTML소스 (3)은 스타일을 걷어 냈을 때 시맨틱 내용만 있는 모습 ······ 27
그림 9 패널 번호를 누르면 내용이 바뀌는 예제 ······························································· 28
그림 10 CSS Zen Garden은 하나의 HTML에 스타일 변경 만으로 다양한 디자인을 선보이고 있다.
··························································································································· 53
그림 11 일반 선택자 개념도 (출처: http://andsite.net)····················································· 55
그림 12 복합 선택자의 종류 (출처: http://andsite.net/)··················································· 56
그림 13 인접 선택자 사용 예제 ··················································································· 59
그림 14. 가상 클래스 선택자 종류 (출처: http://andsite.net/) ··········································· 59
그림 15 동적 수도 클래스 사용 예제············································································· 60
그림 16 동적 선택자 종류 (출처: http://andsite.net/) ····················································· 61
그림 17 focus 수도 클래스 사용 예제 ··········································································· 62
그림 18 :first-child 수도 클래스 사용 예제····································································· 63
그림 19 first-line, first-letter 수도 클래스 사용 예제························································· 64
그림 20 사용자가 스타일을 선택 가능하도록한 표준 기반 예제 ············································ 66
그림 21 W3C CSS Validator ······················································································ 67
그림 22 일반인들에게 표준 웹 브라우저를 홍보하는 BrowseHappy ····································· 69
그림 23웹페이지를 그리드로 바라보고 접근한 것(좌측)과 구성요소로 구분하여 접근한 측면(우측)· 71
그림 24 CSS 박스 모델 ····························································································· 83
그림 25 라운드 박스 표현을 위한 배경 분리 ··································································· 110
실전 웹 표준 가이드
- 8 -
그림 26 Wired.com을 통해 본 CSS 파일 상속 사례 ························································· 112
그림 27 정보통신부의 텍스트, 시각 장애인, 모바일 페이지 ················································· 113
그림 28 스타일 변경으로 레이아웃 변경 사례 (http://PhonoPhunk.phreakin.com) ················ 115
그림 29 드림위버 MX 2004를 통해 본 CSS 레이아웃 기능················································· 116
그림 30 HTML Tidy를 통한 유효성 검사······································································· 121
그림 31 다양한 웹 브라우저를 한번에 띄워 테스트 하는 모습 ············································· 144
그림 32 IE 개발자 툴바를 통한 DOM 스크립트 디버깅 ····················································· 145
그림 33 Venkman을 통한 스크립트 디버깅 ···································································· 146
그림 34 DOM Inspector를 통한 DOM 디버깅 (Firefox 내장) ············································ 147
그림 35 Firefox 자바스크립트 콘솔을 통한 디버깅···························································· 148
그림 36 파이어폭스에서 윈도우 미디어 플레이어 액티브X가 실행되는 모습····························· 154
그림 37 XUL로 개발한 아마존 서비스 브라우저······························································· 155
그림 38 Flex의 서비스 플랫폼 구조 ·············································································· 156
그림 39 Ajax로 구현한 Google Maps··········································································· 157
그림 40 Canvas를 이용한 3D 게임 ·············································································· 158
그림 41 XForm과 WebForm의 관계도·········································································· 160
그림 42 W3C의 웹 어플리케이션 포맷 워킹 그룹 ····························································· 161
그림 43 기존 웹 개발 공정표 ······················································································ 183
그림 44 협업을 이루어 내지 못하는 개발 공정표······························································ 184
그림 45 의존적인 스토리 보드의 전형적인 예·································································· 185
그림 46 디자이너 중심 개발 공정표 ·············································································· 189
그림 47 개발자 중심 개발 공정표················································································· 190
그림 48 기획자 중심 개발 공정표················································································· 191
그림 49 개선된 개발 공정 도표 ··················································································· 193
그림 50 스토리 보드 예제 ·························································································· 197
그림 51 CSS 스타일 가이드 예제 ················································································· 205
그림 52 Opera에 내장된 디버거 ·················································································· 207
그림 53 Firefox Web Developer Extensions을 이용한 디버깅············································· 208
그림 54 다음커뮤니케이션에서 사용하는 UI 가이드라인 ····················································· 209
실전 웹 표준 가이드
- 9 -
그림 55 비지니스 로직 분석도····················································································· 210
그림 56 MVC 모델 설명도 ························································································· 211
그림 57 브라우저 시장 점유율 (2005.10현재) ·································································· 215
실전 웹 표준 가이드
- 10 -
저자 소개
윤석찬 (E-mail) channy@gmail.com (Blog) http://channy.creation.net/blog
신현석 (E-mail) hyeonseok@gmail.com (Blog) http://hyeonseok.com/blog
이성노 (E-mail) eouia0819@gmail.com (Blog) http://eouia0.cafe24.com/blog
신정식 (E-mail) jshin@i18nl10n.com
실전 웹 표준 가이드
- 11 -
서론
1993년 4월 22일 미국 일리노이 대학에서 일단의 학생들이 개발한 모자이크(Mosaic)라는
작은 공개 소프트웨어 웹브라우저는 오늘날 웹이 전 세계에 영향을 끼치게 하는 혁명적인
첫 출발이었다. 이 웹브라우저의 근본 아이디어를 기초로 마이크로소프트와 넷스케이프사
등에서 개발한 유수의 웹브라우저 들이 나와 각축을 벌이고, 이제는 넷스케이프 네비게이
터가 시장 선점에 실패하면서 MS사의 인터넷 익스플로러가 시장 지배적인 위치에 들어서
있다.
브라우저 시장점유 전쟁 동안 서로간의 웹브라우저에 배타적인 기술을 도입하던 나머지
똑 같은 웹페이지가 다르게 보이고 서로에서 구현하지 못하는 기술 때문에 많은 혼란을
겪어 왔다. 이러한 상호 호환 미성숙으로 말미암아 웹기술이 혼란 상태에 있어 왔던 것이
사실이다. 현재에는 이미 마이크로소프트가 IE로 시장 지배력을 넓히고 있는 이 시점인
데다 더 이상 웹브라우저가 신기한 도구이지 않기 때문에, 다양한 인터넷 환경에서 어떠한
웹브라우저가 가장 최적의 구현을 제공하느냐가 관건이 되었다.
그림 1 역사상의 웹 브라우저
그러나 넷스케이프사가 자사의 웹브라우저 소스를 공개 소프트웨어로 전환시키면서 탄생
한 모질라(Mozilla) 재단은 전 세계 개발자들의 노력에 힘입어 경량의 오픈 소스 웹브라
우저인 파이어폭스(Firefox) 1.0을 내 놓으면서, 출시 된지 몇 개월 만에 인터넷 익스플로
러의 브라우저 점유율을 90% 아래로 끌어 내리고 넷스케이프 이후 사상 최초로 10% 점
유율을 바라보고 있다. 노르웨이의 Opera 브라우저는 가볍고, 각종 OS 플랫폼과 표준 호
환성이 뛰어난 기능을 무기로 시장을 개척해 나가고 있다. 뿐만 아니라 유닉스 기반 오픈
소스 프로젝트 KDE(K Desktop Environment)에서 개발한 KHTML 브라우징 엔진은 애
플이 사파리 브라우저에 채택되었고 PDA 및 Embedded Linux 등 소형 기기에 탑재될
수 있는 가능성으로 웹 브라우저의 다양한 엔진 전쟁이 예고 되고 있다.
이러한 현재 상황을 두고 많은 웹 서비스 개발자들이 마치 90년대 중반의 브라우저 전쟁
중에 있었던 비호환성을 고려해야 하는 크로스 브라우징 문제가 다시 대두되는 게 아닌가
염려하고 있다. 즉, 다양한 브라우저 지원이 결국 시간과 비용을 들여야 하는 문제이며 소
수 브라우저에 굳이 비용을 투여할 필요가 있는가 하는 오해가 존재하는 것이다.
본 가이드에서는 현대 웹브라우저들이 과거와는 달리 웹 표준을 준수하고 있고 계속적으
로 이를 지원하기 시작했기 때문에 이를 배우고 따르기만 하면 보다 저렴한 비용으로 홈
실전 웹 표준 가이드
- 12 -
페이지를 구축 및 유지 보수 할 수 있다는 것을 보여 줄 수 있음을 보여 주고자 한다. 또
한, 웹의 근본적인 목표인 기기 및 운영 체제 독립적인 보편적인 웹을 만들 수 있도록 하
고 있다. 전 세계의 많은 웹사이트들이 이미 웹 표준에 기반한 홈페이지 제작 방식을 도입
하고 있으며 이를 통해 매우 효과적인 웹서비스 체계를 갖추기 시작하고 있다.
이 가이드의 목적
1989년 웹(World-wide Web)을 처음 발명한 팀 버너스 리(Tim Berners-Lees)는 CERN
연구소의 수 천명 연구자들이 이기종 OS와 개발 환경에서 정보를 공유할 수 있도록 기종
이나 환경과 상관없이 어떤 컴퓨터에서도 정보 자원에 접근할 수 있는 웹을 만들게 되었
다. 이러한 웹의 근본 취지에는 보편적 디자인(universal design), 보편적 접근(universal
access) 개념이 뿌리내려 있으며 웹을 사용하고 접하는 다양한 환경과 사람들을 위해 공
통적인 정보 소통 통로를 만드는 것은 정보의 가치와 비례하여 중요하다고 하겠다. 이러한
꿈을 이루기 위해 Tim과 CERN은 웹의 발명품을 아무나 사용할 수 있는 무제한으로 특
허를 사용할 수 있도록 하였다.
우리들 중에는 노인, 장애인, 어린이 등의 다양한 계층과 윈도우, 매킨토시, 리눅스 등 다
른 OS, IE와 파이어폭스, 오페라 등 다른 브라우저를 사용하는 사람이 존재한다. 또한, 향
후 TV 브라우저, PDA 등의 다양한 휴대 기기를 사용하는 사람과 시력이 약해서 화면을
확대해 봐야 하는 사람들이 있다. 다양한 사용자들이 어떻게 하면 편하게 웹을 이용할 수
있을까? 어떻게 하면 저비용으로 접근성 문제를 해결할 수 있을지를 고민하여 실마리를
풀어 나가야 한다. 특정 플랫폼의 사용자만이 향유할 수 있는 웹을 만들면 만들수록 더 많
은 정보가 웹으로 쏟아져 나오기 때문에, 장애인, 노인, 외국인, 매킨토시 사용자, 리눅스
사용자는 점점 더 소외 계층으로 전락하여 이른바 정보화의 폐해가 드러나게 되기 때문이
다.
이러한 문제를 해결하기 위한 구체적인 방법은 무엇일까? 본 가이드에서 설명하고자 하는
핵심 요지는 아래에서 말하는 세 가지로 요약 할 수 있다.
미션1. 웹 표준을 지켜라
전 세계적인 웹 기술 표준을 주도하고 있는 W3C의 HTML4.1, XHTML1.0, CSS1/2,
DOM 등의 구현 스펙이 매우 상세하고 이를 지원하는 브라우저들이 계속 늘어 남에 따라
더 이상 웹페이지가 다르게 보이거나 동작하지 않는 현상은 거의 사라지게 되었다. 다만
웹브라우저간 이종 기능이 아직은 상존하고 있고 예전에 개발되어 사용된 오래된 브라우
저 사용자들의 불편함을 고려해 같은 기능이라도 호환 가능하도록 해 주는 표준을 통한
웹페이지 제작이 요구되고 있다.
그러나 이것이 웹브라우저에서 지원하는 버전 호환성 유지(backward compatibility)라는
괴물과 충돌하게 된다. 일반적으로 프로그램을 개발할 때, 버전이 올라가면 갈수록 새로운
기능을 추가하고 이전 기능은 폐기하게 된다. 그러나 사용자의 측면에서는 예전 기능을 계
속 유지해 주어 개발 호환성을 유지해 줄 필요성이 생긴다. 즉, 버전 호환성 유지는 예전
에 사용되는 기능이나 태그를 그대로 사용하도록 해 주는데 이 때 사용된 비표준 문법들
이 계속 확대 재생산 되어 결국 접근성에 심각한 위해를 주게 된다. 여기에는 취약한 우리
나라 웹 생산 시스템의 문제도 있다. 주로 나모 웹 에디터, 드림 위버와 같은 저작 도구에
실전 웹 표준 가이드
- 13 -
의존하여 표준을 무시하고, 그냥 남의 코드를 따다가 적당히 익스플로러에서만 돌려보고
개발을 끝내는 풍토와 그런 정보 가공자들을 계속 양산 하는 교육 시스템에 문제가 있다.
이와 반대로 XHTML 1.x이나 HTML 4.x 표준에 맞추어진 문서는 99% 접근성이 높은
사이트들이다. 기존에 흔히 사용되는 table 구조를 div 바꾸고 font, b 같은 태그들을 스
타일시트(CSS)로 사용하게 되면, HTML 코드 양은 약간 과장해서 반 이하로 줄어든다.
구조와 표현이 엄격히 분리되면, 사이트의 로딩 속도도 빨라지며, 코딩과 유지 보수의 효
율성은 두 배로 늘어난다. 표준을 지킨 사이트에서는 오히려 코드의 양이 줄고 속도가 늘
어나며 재개발 효율성이 증대 된다.
미션2. 구조와 표현, 동작을 분리하라
웹 표준에서 HTML과 함께 중요한 또 다른 요소인 스타일시트(CSS)는 단순히 링크의 색
상, 글자 모양 바꾸는 정도만 할 수 있는 것이 아니고, 문서의 배치, 여백 조정, 색깔, 요
소 자체의 성격 변화, 클래스를 통한 디자인의 일관성 확보, 서로 다른 미디어에 따른 최
적화된 디자인 템플릿 적용 등 이루 말할 수 없이 많은 역할을 할 수 있다.
그림 2 웹 표준에서 구조, 표현, 행동의 분리
HTML 에서는 철저하게 구조화된 마크업만을 사용하고, 모양이나 디자인에 관한 것은
CSS로 완전히 분리함으로써, 구조는 변하지 않은 채 여러 가지 디자인을 적용한다거나,
상황에 따라 쉽게 디자인을 변경하는 것이 가능해진다. 또한, 똑같은 디자인 템플릿에 다
른 내용을 담는 여러 가지 문서를 만드는 것도 가능해진다. 또는 디자인에 전혀 영향을 주
지 않고 문서의 내용을 바꾸는 것이 쉬워지기 때문에 장애인의 접근성에 엄청난 도움을
준다. 예를 들어, 한 개의 HTML 문서에 시각 장애인용 CSS와 텍스트용 CSS 그리고 기
존의 CSS 등 세 개의 스타일시트를 만들어 변경해 줌에 따라 문서의 구조가 내용과 섞이
지 않고 제공 될 수 있다.
우리나라 대부분의 웹사이트들이 문서의 구조적인 요소인 h1, ul, strong, blockquote, cite
등 보다는 font, table, br 등의 요소가 의미적인 내용과 섞여 있어 문서 중에서 도대체 어
실전 웹 표준 가이드
- 14 -
떤 것이 중요한 지, 제목에 해당되는 지, 강조할 것과 인용된 것이 어떤 것이지 하는 것을
이해할 수 없게 된다. 문서의 내용이 구조화 되어 있지 않다는 것은 결국 장애인용 보조
기기, 또는 PDA, TV, 음성 브라우저 등을 통해서도 접근할 수 없거나, 접근했을 때에 바
른 결과를 얻어 낼 수 없다는 이야기가 된다. 디자인 요소가 CSS로 완전히 분리되면, 의
미 있고 구조화된 내용만 남게 되며, 문서의 표현에도 제약 사항이 발생하지 않게 되는 것
이다. 최악의 경우, CSS가 제거되어도 의미를 이해하는 데에는 아무런 문제가 없게 되며
이것이 웹 접근성 문제를 해결하는데도 도움을 준다.
또한, 구조와 표현에서 행동을 분리하는 것도 매우 중요하다. 웹 문서의 내용을 자바 스크
립트를 통해 동적으로 사용하고, 사용자의 반응을 주고 받는 행동(Behavior)도 중요한 부
분으로 인식되고 있다. 이러한 클라이언트 스크립팅을 기본으로하는 동적인 행동 양식이
사실 접근성 및 사용성을 저해하고 및 복잡성을 높이는 요소로 생각되어 왔다. 그러나, 최
근 구조에서 행동 양식을 분리하는 다양한 방법론이 제안되면서 접근성을 해치지 않으면
서 코드를 간단하게 하는 다양한 방법들을 적용할 수 있게 되었다. 자바스크립트를 홈페이
지에 마구 쑤셔 넣는 개발 방식에서 변화할 수 있다는 것이다.
미션3. 최소한의 디버깅을 거쳐라.
W3C에서 제시한 HTML 혹은 XHTML 표준을 지키고, CSS를 통해 구조와 표현을 분리
하였다 하더라도 이것을 검증해 볼 수 있는 방법이 없다면 역시 그 문제 해결이 쉽지 않
을 것이다. 다행히 W3C에서는 이러한 문제를 검증 해주는 유효성 검사(Validation) 도구
들이 제공되고 있다. doctype에 규정된 문서 형식에 따라 유효한 코드가 사용되었는지를
알 수 있게 해준다. (http://validator.w3.org)
HTML과 XHTML 문서뿐만 아니라 CSS 역시 자신이 사용한 표현식과 문법이 제대로
되어 있는지 알려 주는 도구가 존재 한다. 처음 이 검사기를 돌려 보면 수 많은 문제들이
나오게 될 수도 있다. 그러나 대부분의 문제들은 요소를 따옴표 등으로 묶지 않았거나, ?,
& 같은 특수 문자를 특수 코드로 쓰지 않는 등 반복되는 몇 가지 실수를 포함 하고 있으
므로 간단한 수정 만으로 유효성 검사를 통과 할 수 있다.
또한, 문서 안에 들어 있는 요소를 객체화 시켜 사용하는 DOM(Document Object
Method)과 이를 이용하는 자바 스크립트(JavaScript) 등을 사용하는데 있어도 표준 문법
을 사용했는지 확인하는 과정이 필요하다. 오픈소스 브라우저인 Mozilla Firefox의 탑재된
자바 스크립트 디버거 만으로도 인터넷 익스플로러와 공통으로 생기는 문제점을 발견 해
결할 수 있고, 비표준으로 사용된 문법을 판별해 낼 수 있다. 그러나 웹사이트 가공자들이
이러한 디버깅 과정을 빠뜨리고 납품을 하거나 완성하는 경우가 대부분이기 때문에, 웹 사
이트 관리자들이 검수(Quality Assurance) 과정에서 이러한 유효성 통과와 표준 문법 사
용 검증 결과를 첨부하도록 가이드 한다면 보다 좋은 품질을 가진 결과물을 얻을 수 있을
것이다.
실전 웹 표준 가이드
- 15 -
그림 3 W3C HTML Validator의 실행 모습
미션4. 효율적인 웹 개발 방법론을 가져라.
웹을 생산하는 시스템 안에는 웹 기획자와 웹 개발자라는 직군이 함께 존재한다. 웹 생산
공정에서 웹 디자인까지 이들은 삼각 구도를 이루고 있으며, 서로 간의 업무 역할이나 관
심 영역에서 확연한 차이가 드러난다. 따라서 웹사이트를 만드는 이들이 서로 협력하지 않
는 다면 프로젝트는 산으로 가며 따라서 웹사이트는 제대로 된 품질을 지킬 수 없다.
웹사이트를 만드는 일은 기획->디자인->개발이라는 컨베이어 벨트 위에 놓은 물건과 같다.
이게 공장이라면 컨베이어 벨트만 통과하면 완성품이 하나 나오지만, 문제는 이 컨베이어
벨트에 탄 물건은 사용자 테스트나 요구 사항 변경에 따라 이 컨베이어 벨트를 몇 번씩
옮겨진다는 데 있다. 이 과정에서 누가 컨베이어 벨트에 새로 올려 놓았느냐에 따라 서로
간에 피해 의식이 생기게 된다.
서로를 탓할 순 없고 맘속으로만 삭일 수 밖에 없다. 문제를 해결하는 방법은 서로 영역을
나누어 공동 작업을 하는 것이다. 마치 시계의 부품을 각자 작업해서 조립만 될 수 있도록
하는 것이다. 그러기 위해서는 웹 표준을 통한 공정이 매우 생산적이다.
웹 표준에서 말하는 웹은 내용을 담는 구조(HTML, XHTML), 표현(CSS), 양식(자바스크
립트, 서버 측 개발)을 분리시켜 개발하도록 권장하고 있다. 구조는 단순한 HTML로 이
페이지에서 넣고 싶은 내용만을 간추릴 수 있다. 간단한 템플릿을 사용하면 기획자들이 쓰
는 스토리 보드처럼 레이아웃을 만드는 것이 가능하다.
HTML에 표현과 내용을 분리하지 않고 다 집어 넣는 풍토가 바뀌면 기획자와 디자이너,
개발자가 같은 시간에 같은 일을 하는 것이 가능하게 된다. 기획자가 기획안을 넘기고 다
른 기획에 투입되며 디자이너는 디자인만 넘기고 다른 프로젝트에 투입되고, 개발자가 코
딩만 하고 다른 개발을 하게 되는 일이 없어지면 상호간 하나의 팀으로서 같은 일을 같은
시선으로 바라볼 수 있는 것이다.
기획자와 개발자, 그리고 디자이너들은 서로 다른 사고 방식과 생각을 가진 사람들이다.
기획자들은 비즈니스를 생각하고 디자이너들은 시각적인 요소를 더 중시한다. 개발자들은
실전 웹 표준 가이드
- 16 -
그들이 사용하는 기술에 관심이 있는 것은 두말할 나위가 없다.
그럼에도 불구하고 그들을 모두 엮는 것은 웹(Web)이라는 테두리이다. 웹 기획자가 아니
라면 그들이 HTML을 이해할 필요도 없고, DB와 서버를 알 필요도 없다. 따라서 이러한
직군에 근무하는 사람들은 웹에 대한 의미와 인식을 같이하는 공감대를 가질 필요가 있다.
웹 표준에 대한 오해
웹 표준과 웹 접근성을 강조하다 보면 사람들로부터 다음과 같은 질문을 받게 된다. 웹 표
준과 접근성을을 지키는 것이 어떤 혜택을 얻을 수 있는지 알아 본다.
화려하고 세련된 웹페이지를 만들 수 없다?
흔히들 우리나라 웹페이지는 외국보다 역동적이고 화려하게 하는 것을 좋아하기 때문에
접근성을 강조하면 그것을 달성하기 어렵다고들 한다. 그러나 어떠한 접근성 지침에서도
그림이나 멀티미디어 쓰지 말라고 하지 않으며, 그림을 못 보는 사람들을 위해 대체 텍스
트를 함께 넣으라는 것뿐이다. 레이아웃 장식을 위해 그림을 많이 사용하는 경우, CSS의
배경(background)으로 그림을 넣어버리면 가능하며 플래쉬를 이용해 메뉴를 구성 하는
경우, 대체 텍스트 메뉴를 플래쉬를 표현하는 object 사이에 포함시켜 주기만 해도 된다.
접근성 높은 사이트가 온통 텍스트로만 구성된 지루하고, 멋없는 사이트라고 생각하는 것
은 잘못된 편견이다. 접근성 지침에서 결코 디자인과 타협하거나 상충되는 부분은 거의 없
으며, 이미 CSS를 활용한 외국의 사이트들은 접근성이 높으면서도 화려하고, 깔끔한 사이
트가 대부분이다. 우리 나라는 오히려 웹 서비스 가공자들에 대한 재교육 부재와 기존의
비효율적이고 표준을 활용하지 못하는 작업 행태에서 문제가 시작 되는 것이다.
접근성이 높은 사이트는 비용이 훨씬 증가한다?
물론 기존에 접근성을 전혀 고려하지 않고 만든 사이트를 고치려면 상당한 비용이 들어가
는 것이 사실이다. 그러나 대부분의 웹사이트들이 여러 번 리뉴얼이라는 과정을 통해 계속
변경하고 있으며, 이러한 리뉴얼을 시작할 때 처음부터 접근성을 염두해 두고 엄격한 웹
표준에 입각해 개발하면, 결코 비용이 많이 들어가지 않는다.
이 렇게 개발된 접근성이 높은 사이트를 다시 재개발하는데 드는 효율성도 매우 높다. 왜
냐하면, 구조와 표현을 분리하여 만들어져 있으므로, 컨텐츠 담당자는 오로지 구조와 내용
에만 신경을 쓰고, 디자인 담당자는 내용을 표현하기 위한 외양적 디자인에만 관심을 기울
일 수 있기 때문이다. 프로그래머는 이미 HTML과 CSS로 UI가 분리되어 있으므로, 복잡
한 HTML 코드를 이해하고 다뤄야 하는 대신 프로그램 코드에만 신경 쓰면 된다. 즉, 내
용이 바뀌면 디자인까지 다 뜯어고쳐야 한다거나, 디자인이 바뀌면서 내용이 타협을 해야
한다거나 하는 일들이 줄어들게 된다. 그리고 한 번 이렇게 만들어진 사이트를 다른 사람
이 유지 보수를 할 때에도 소스 코드도 훨씬 이해하기가 쉽고 간결해서 완전 재개발 해야
하는 경우가 발생하지 않아 유지 보수 비용도 줄일 수 있다.
특수 계층을 위한 별도의 사이트가 필요하다?
가뜩이나 다수의 논리에 의해 소수는 쉽게 무시되어버리는 우리 나라 사회에서 웹 접근성
실전 웹 표준 가이드
- 17 -
을 이야기하면 효율과 속도를 중시하는 풍조에서 누가 과연 몇 퍼센트나 있을 지 모르는
장애인과 매킨토시, 리눅스 사용자와 비 IE 사용자를 배려할 수 있을 것인가라는 의문을
제기한다. 그리고는 마치 그들을 위해 뭔가 선심이라도 써야 할 듯이 별도의 사이트를 만
들고 비용과 인력을 들여야 할 듯이 말한다. 웹에서 표준안의 사용과 접근성 가이드에 대
한 준수 만으로도 이들 계층들을 위한 별도의 웹사이트는 필요치 않다. 별도의 사이트를
만드는 것이야 말로 오히려 비용을 증가 시켜 효율성을 떨어 뜨리는 것이다.
접 근성이 높은 웹사이트는 결코 이들 특수 계층에게만 좋은 것이 아니다. 사용 편의성이
높아지고, 문서가 분명하며 이해하기 쉽게 되면 아이들이나 노인들에게도 도움이 되며, 이
것을 개선하여 작업하는 웹 사이트 운영자도 편해 진다. 곳곳에 설명 도구(tooltip)들이 생
겨서 일반인들에게도 웹을 친근하게 사용하는 데에 도움이 되며, 그림과 멀티미디어 요소
가 의미있는 대체 텍스트를 달게 하면 검색 엔진이 그림과 멀티미디어를 일반인들이 검색
하는 데에 큰 도움을 준다.
웹 표준이란 무엇인가?
전 세계적인 웹 기술 표준을 주도하고 있는 W3C의 HTML4.0, XHTML, CSS1/2 등의
구현 스펙이 매우 상세하고 이를 지원하는 현대적인 브라우저들이 계속 늘어남에 따라 더
이상 웹페이지가 다르게 보이거나 동작되지 않는 현상은 거의 사라지게 되었다. 옛날 웹브
라우저간 이종 기능이 아직은 상존하고 있기 때문에 오래된 브라우저 사용자들의 불편함
을 고려해 주는 상호 호환성(Cross Browsing)과 최신 웹 표준 기술 적용 그리고 접근성
높은 웹페이지를 통해 향후 표준 기술에 적합하게 만드는 상위 호환성(Forward
Compatibility)가 현재 웹 서비스 제공자들의 공통된 숙제가 되고 있다.
이것은 하위 버전 호환성 유지(Backward Compatibility)와 구분해야 한다. 일반적으로
프로그램을 개발할 때, 버전이 올라가면 갈수록 새로운 기능을 추가하고 이전 기능은 폐기
하게 된다. 그러나 사용자의 측면에서는 예전 기능을 계속 유지해 주어 개발 호환성을 유
지해 줄 필요성이 생긴다. 웹브라우저에서 하위 버전 호환성 유지는 예전에 사용되는 기능
이나 태그를 표준 태그로 치환해 주는 것이다. 이를 통해 대부분의 웹디자이너는 예전 지
식에 따라 웹페이지를 코딩해 주어도 그대로 구현되는 것으로 생각하게 되는 것이다. 그러
나, 하위 버전 호환성 유지는 웹브라우저의 벤더에 따라 지원 가능 정도가 약해 질 뿐만
아니라 웹 표준 기술에 대한 지식 습득을 가로막는 장애가 된다.
이에 반해 상호 호환성은 표준 웹 기술을 채용하여 다른 기종 혹은 플랫폼에 따라 달리
구현되는 기술을 비슷하게 만듦과 동시에 어느 한쪽에 최적화되어 치우치지 않도록 공통
요소를 사용하여 웹페이지를 제작하는 기법을 말하는 것이다. 또한, 지원할 수 없는 다른
웹브라우저를 위한 장치를 만들어 모든 웹브라우저 사용자가 방문했을 때 정보로서의 소
외감을 느끼지 않도록 하는 방법론적 가이드를 의미하는 것이다. 또한, 장기적인 웹 표준
을 지원하는 상위 호환성은 미래에 어떠한 웹 브라우저나 단말 장치가 나오더라도 웹을
이용할 수 있다는 측면에서 매우 중요하다고 하겠다.
웹 표준이 만들어 지는 방법
웹사이트에 적용하는 HTML, CSS, 자바스크립트 같은 것은 어디에서 정해져서 사용되는
것일까? 이 같은 승인된 개방형 인터넷 표준은 즉 World Wide Web Consortium (W3C,
실전 웹 표준 가이드
- 18 -
http://www.w3c.org) 에서 만들어 진다. W3C는 1994년 10월 미국의 MIT 컴퓨터 과
학 연구소(MIT LCS), 정보 수학 유럽 연구 컨소시움(ERCIM), 그리고 일본의 게이오 대
학이 연합하여 만들어진 국제적인 웹 기술 표준 기구이다.
그림 4 웹 표준을 제정하는 표준화 기구, 웹 컨소시움(http://w3.org)
언뜻 보기에는 연구 기관으로만 이루어진 것 같으나 웹과 관련된 510여 개의 국제적인 다
국적 IT 기업체가 참여하여 자사의 하드웨어와 소프트웨어에 웹 표준 기술을 탑재하거나
자사의 기술을 표준화 하고자 하는 치열한 전투장 이기도 하다. W3C의 역할은 정보, 의견
교환, 아이디어 창출, 독립적 사고, 그리고 공동의 이해를 위하여 명세, 가이드 라인, 소프
트웨어, 그리고 도구 및 규칙 등의 표준안을 제정함으로써 웹의 모든 잠재력을 이끌어 내
는 것이다.
웹에 관련한 표준에는 우리가 흔히 말하는 표준(Standard)은 존재하지 않으며, W3C의 토
론을 통해 나온 권고안(Recomendation)이 가장 최상위 이다. 표준의 종류에는 제안된 표
준(Draft), 작업하는 표준(Working Draft, WD), 확정될 권고안(Candidate
Recommendation, RC), 확정된 권고안(Recommendation)이 있다.
그림 5 웹 표준이 정해 지는 순서
권고안을 제정하는 방법은 1) 어떤 기능을 Draft로서 제안하고, 2) 드래프트를 실제로 적
용할 수 있게 기술적인 작업을 하고(Working Draft), 3) 이를 다시 논리 오류가 없는지,
실제 하드웨어에서 지원이 가능한지를 살피고, 4) 정식 권고안이 되기 전에 기업체에 공개
하여 토론을 거친 후(Recommendate Candidation), 5) 마지막으로 권고안
(Recommendation)을 확정한다.
실전 웹 표준 가이드
- 19 -
웹브라우저 중 모질라 파이어폭스, 오페라 등은 문서로서 확정된 권고안(Recomendation)
등 다양한 표준 가운데 확정된 표준을 지원한다. 다시 말해 모질라는 HTML 4.0도 지원하
지만, HTML4.01을 더 잘 지원해 준다. 특히 W3C 전용 브라우저인 Amaya 브라우저가
했던 표준의 기술 지원 시험을 요즘에는 모질라에서 하고 있어 더욱 빠르게 표준 기술이
적용되고 있다. 모질라 계열 제품들의 최신 버전은 XHTML, CSS 1/2를 모두 지원하고
있다. 오페라도 비슷한 정도로 표준을 지원해 주지만, 빠른 속도를 유지하기 위해
MathML 등을 제대로 해석하지 못하기도 한다.
인터넷 익스플로러는 지원하는 표준의 종류만을 보자면, 다른 두 가지 브라우저보다 더 뛰
어나다. 그러나, 지원하는 표준이 권고안(Recomendation)이 아니라는 데 문제가 있다. IE
는 Microsoft가 제안했던 내용만을 지원하는데, 권고안에 자신들이 제안했던 내용이 적고,
권고안 후보나 작업안 또는 기초안에 자신들이 제안한 내용이 많다면 그것을 지원한다. 대
표적인 예가 HTML 4.0과 XHTML 1.0/1.1이다. HTML 4.0은 거의 모든 부분에서 마이
크로소프트의 의견이 반영되어 있다. 그럼에도 불구하고 HTML4.0의 후속 버전인
XHTML 1.0/1.1은 제대로 지원하지 않고 있다. 왜냐 하면, HTML을 모듈화하면서 마이
크로소프트의 의견이 상당 부분 표준에 채택되지 못했기 때문이다. 또한 CSS Level 2(흔
히 CSS2) 지원도 미흡하다. 그러나, 마이크로소프트는 CSS3 표준안에 열심히 참여하고
있다. 웹브라우저가 W3C의 권고안을 지원하는 데는 이러한 복잡한 관계가 얽혀 있다.
이에 반해 모질라 파이어폭스 1.5의 최신 버전은 XTHML 1.0을 모두 지원할 뿐만 아니라
Draft상태에 있는 CSS2.1 전체 기능과 CSS3의 일부 기능을 이미 구현했다. 인터넷 익스
플로러 6.0이 출시된 지 4년 만에 IE팀을 새로 꾸린 마이크로소프트는 IE7 버전에 CSS2
에 대한 지원을 강화하기로 하는 등 표준 지원에 대해 모든 브라우저가 활발히 움직이고
있다.
웹 표준 스펙 소개
지금부터는 W3C에서 제공하는 각종 웹 표준 권고안에 대해 간단하게 살펴본다.
(X)HTML (eXtensible Hypertext Markup Language)
HTML(Hypertext Markup Language) 는 웹페이지를 표시하는데 기본 언어로서 사용된
다. 웹 컨텐츠의 내용은 표준 HTML 포맷으로 적용해야 하며 정보가 독점적인 고유 포맷
으로 제공되는 경우, HTML 포맷도 제공되어야 한다. 브라우저 호환성은 모든 경우에 있
어 고려되어야 하며, 웹사이트는 단일 웹 브라우저에 맞추어 제작되어서는 안되며, 클라이
언트 그룹에 의해 빈번하게 사용되는 웹 브라우저에서 올바르게 작동해야 한다.
최신의 HTML 표준은 4.01이지만 HTML을 XML과 결합한 XHTML이 권고안으로 나와
있다. HTML2/3와 달리 최신 XHTML 표준은 <font>, <b>, <i> 같은 표현 요소들을 배
제하고, 태그를 모두 닫도록 권고하는 등 정확한 문서 규격을 요구하고 있다. 이것은 손으
로 코딩을 하는 게 아니라 점점 전문적인 저작 도구를 사용함에 따라 구조적인 HTML템
플리트를 생성하고 스타일(Cascade Style Sheet, CSS)을 관리함으로서 비 전문 설계자도
웹 페이지를 손쉽게 제작 관리 할 수 있게 해 준다.
실전 웹 표준 가이드
- 20 -
CSS(Cascading Style Sheets)
CSS는 사용자 정의의 디자인 속성, 즉 글꼴, 크기, 색상, 이벤트 등을 지정할 수 있으며
CSS를 사용한 모든 페이지는 기존 버전과의 호환성 되게 어떤 브라우저에서도 내용을 열
람할 수 있다. CSS를 이용하여 설계자는 서로 다른 화면 해상도와 브라우저 상에서, 테이
블 없이도 동일하게 보여질 수 있는 페이지를 생성할 수 있다. 단 IE4.0 이하와 넷스케이
프4 이하의 오래된 웹브라우저에서는 CSS를 지원하지 못한다. CSS를 사용하여 생성한 페
이지와 템플리트는 다양한 브라우저, 화면 해상도 및 액세스 기술을 사용하여 테스트하여
야 하며, 최신 시스템 사용자가 아니더라도 적합한 접근이 보장되어야 한다.
XML(eXtensible Markup Language)
XML(eXtensible Markup Language)은 HTML이나 CSS로서 표현되지 못하는 영역을
DTD를 이용하여 정의하여 사용자 정의의 태그를 생성하여 제작할 수 있는 메타 마크업
언어이다. XML 사용 분야를 검토하여 적절한 용도에 맞게 사용하여야 한다. XML이 고
려되는 애플리케이션은 사용자가 필요한 정보를 얻기 위해 하나 이상의 데이터베이스와
상호 작용할 필요가 있는 경우, 작업이 사용자에게 전달되어 사용자가 자신의 기록 혹은
문서에 액세스할 것이 예상되는 경우, 서로 다른 세트의 데이터가 서로 다른 사용자에게
디스플레이 되어야 하는 경우, 정보 검색 및 디스플레이와 관련하여 사용자 선호 프로파일
을 구축해야 할 필요가 있는 경우, 각 개인이 스타일 시트를 사용하여 다양한 포맷으로 문
서를 갱신해야 할 필요가 있는 경우에 사용 가능하다. XML은 다양한 인터넷 비즈니스 환
경에 손쉽게 적응 가능하여 웹 표준 분야에서 가장 활발한 표준 제정 활동이 이루어 지고
있다.
DOM(Document Object Model)
DOM(Document Object Model)은 웹페이지에 표현되는 모든 속성에 대해 객체화 하여
이를 자유 자재로 사용할 수 있도록 만든 것이다. document, from, window 등 각각의
속성을 객체화 하여 트리 구조로 형상화 하여 이에 대한 이벤트 처리 같은 것이 가능하다.
DOM에는 크게 W3C DOM과 MS DOM이 있는데, IE6.0은 아직 하위 버전 호환성을 위
해 MS DOM을 지원하고 있지만, IE6.0 이전 브라우저를 제외하고는 거의 모든 브라우저
가 표준 W3C DOM을 지원한다.
ECMAScript
자바 스크립트는 W3C 표준으로 제정된 것은 아니다. 또한, 모든 웹 브라우저 사용자가
자바 스크립트를 볼 수 있는 것은 아니다. 특정 방화벽은 자바 스크립트가 통과하는 것을
허용하지 않는다. 그럼에도 자바 스크립트는 DOM이 표준화 되면서 웹 브라우저에 널리
쓰이고 있다. 주의할 점은 클라이언트 측 스크립트는 여러 브라우저에서 폭 넓게 검사되어
야 한다. 핵심 기능은 자바 스크립트에 의해서만 제공되어서는 안 된다. 또 자바 스크립트
는 주석 코드를 사용하여 비 호환성의 웹 브라우저로부터 숨겨져야 한다. 자바 스크립트는
HTML 문서의 Head 내에 위치해야 제대로 동작한다 따라서 문서의 Body 내에 자바 스
크립트를 위치시키는 것은 피해야 한다.
자바스크립트의 경우, 넷스케이프사가 ECMA라는 표준 기구로 제안하여 채택된 바 있어
실전 웹 표준 가이드
- 21 -
ECMA -262 표준안(http://www.ecmainternational.
org/publications/standards/Ecma-262.htm)을 공부하면 된다.
ECMASCript는 IE6.0, Firefox 1.0, Safari 1.0, Opera8에서 거의 100% 지원하고 있다.
웹 표준 목록
웹 표준을 지킨다고 하는 것은 W3C의 표준안을 지킨다는 것을 말한다. W3C의 표준 활
동을 지속적으로 살펴보고 표준 권고안을 공부할 필요가 있는 것이다. 또한 웹 브라우저에
따라 지원 정도가 다르므로 부록에서 제공하는 호환 차트(Web Standard-Broweser
Compatiblity Chart)를 통해 공부 해야 한다. 아래는 웹사이트 개발에 필요한 주요 표준
안들에 대한 목록이다.
.. [HTML 4.01] “HTML 4.01 Recommandation”, David Raggett, Arnaud Le Hors, Ian
Jacobs, http://www.w3.org/TR/1999/REC-html401-19991224 , HTML 4.0의 수정 표
준 (http://www.w3.org/TR/1998/REC-html40-19980424 )
.. [XHTML1.0] “XTHML 1.0 Recommandation”, 26 January 2000, revised 1 August
2002, Steven Pemberton http://www.w3.org/TR/2002/REC-xhtml1-20020801 최신
버전: http://www.w3.org/TR/xhtml1
.. [XHTML 1.1] “ Module-based XHTML”, 31 May 2001, Murray Altheim, Shane
McCarron http://www.w3.org/TR/2001/REC-xhtml11-20010531
.. [CSS1] "CSS, level 1 Recommendation", B. Bos, H. Wium Lie, eds., 17 December 1996,
revised 11 January 1999. CSS1 권고안: http://www.w3.org/TR/1999/REC-CSS1-
19990111 . CSS1 최신 버전: http://www.w3.org/TR/REC-CSS1 .
.. [CSS2.1] "CSS, level 2.1 Draft", Bert Bos, Tantek Celik , Ian Hickson, Hakon, Wium
Lie eds., 12 May 1998. CSS2 드래프트: http://www.w3.org/TR/2005/WD-CSS21-
20050613 . CSS2.1 최신 버전: http://www.w3.org/TR/CSS21.
.. [DOM Level 1, Level 2, Level 3] "Document Object Model (DOM) Level 1,2,3
Recomandation", 최신 버전 http://www.w3.org/DOM/DOMTR
.. [XML] "Extensible Markup Language (XML) 1.0.", T. Bray, J. Paoli, C.M. Sperberg-
McQueen, eds., 10 February 1998. http://www.w3.org/TR/1998/REC-xml-
19980210 .[XML 1.1] XML 1.1 (http://www.w3.org/TR/xml11
.. [HTTP] http://www.w3.org/Protocols/, HTTP 1.0, 1.1을 비롯한 여러 가지 표준 웹
프로토콜에 대한 IETF(http://www.ietf.org) 표준이 있음.
웹에서 쓰이는 표준 중 HTTP등과 같은 프로토콜 표준은 W3C에서 만드는 것이 아니다.
W3C 뿐만 아니라 인터넷에서 사용되는 모든 표준을 RFC라는 문서로 규정하는 IETF도
중요한 표준 기구이다. W3C 표준뿐 아니라 IETF에서 제정하는 표준 가운데 적어도
HTTP와 MIME에 대한 표준은 매우 중요하다. 왜냐하면 우리가 만드는 웹 문서를 인터
넷으로 전달하는 기본적인 방법에 대한 것이기 때문이다.
다행히 이들 웹 표준 문서 중 일부는 W3C 한국사무국(http://w3c.or.kr)을 통해 한국어
번역(http://w3.org/2003/03/Translations/byLanguage?language=ko)을 접할 수 있
다. 또한 이들 중 일부는 한국정보통신표준협회(TTA)의 국내 표준으로 정해진 것도 있다.
.. TTA, TTAS.KO-10.0085, "웹 구축 지침서", 1998-10
.. TTA, TTAS.W3-XHTML1.0, “XHTML 1.0 표준", 2001.12.
실전 웹 표준 가이드
- 22 -
.. TTA, TTAS.W3-DOM "문서 객체 모델 레벨 1", 2003.10.
.. TTA, TTAS.OT-10.0003 "한국형 웹 콘텐츠 접근성 지침", 2004.12
아래는 웹사이트의 접근성을 높이기 위한 표준안들 이다.
.. [WCAG 1.0] Web Content Accessibility Guidelines 1.0, 5 May 1999, Wendy Chisholm,
Gregg Vanderheiden, Ian Jacobs, http://www.w3.org/TR/1999/WAIWEBCONTENT-
19990505
.. [WAI-AUTOOLS] "Authoring Tool Accessibility Guidelines", J. Treviranus, J.
Richards, I. Jacobs, C. McCathieNevile, eds. 저작 도구 접근성 지침에 대한 가장 최신
작업 초안(Working Draft): http://www.w3.org/TR/WAI-AUTOOLS/
.. [WAI-UA-SUPPORT] 이 문서에서는 (보조 기술을 포함하여) 웹 표시 장치들이 여기에서
언급된 접근성 관련 기능을 얼마나 지원하는지에 대해 언급하고 있다. 문서 있는 곳:
http://www.w3.org/WAI/Resources/WAI-UA-Support
.. [WAI-USERAGENT] "User Agent Accessibility Guidelines", J. Gunderson and I.
Jacobs, eds. 접근성이 높은 웹 표시 장치를 설계하기 위한 이 지침에 대한 최신 작업 초
안: http://www.w3.org/TR/WAI-USERAGENT
.. [TECHNIQUES] "Techniques for Web Content Accessibility Guidelines 1.0", W.
Chisholm, G. Vanderheiden, I. Jacobs, eds. 이 문서에서는 "웹 콘텐츠 접근성 지침 1.0"
에서 정의한 체크포인트를 어떻게 구현하는지에 대해 설명하고 있다. 이 기술 문서의 최신
버전: http://www.w3.org/TR/WAI-WEBCONTENT-TECHS
웹 표준 검사 방법
W3C에서는 웹페이지가 표준안에 따라 만들어 졌는지, 접근성에 대한 고려가 이루어 졌는
지 유효성 검사(Validation)에 대한 정보를 제공하고 있다. 개발의 맨 첫 단계에서부터 여
러 가지 검사를 시작하면, 초기에 식별한 접근성 관련 문제점은 더 수정하기 쉽고, 피해
갈 수 있다.
아래는 몇 개의 중요한 유효성 검사 방법으로 제시되는 것이다. 먼저 자동화된 접근성 검
사 도구와 브라우저 유효성 검사 도구(http://validation.w3.org)를 사용한다. 한국어 번
역이 제공되는 http://validator.kldp.net 을 이용하면 유효성 에러에 대한 설명과 해결
을 한국어로 볼수 있다. 이 외에도 CSS 유효성 확인(http://jigsaw.w3.org/cssvalidator/)
페이지와 XML에 대한 유효성 확인
(http://www.stg.brown.edu/service/xmlvalid)를 사용할 수 있다.
이러한 웹 표준 문법에 대한 유효성 확인 도구가 모든 접근성 관련 문제점을 다룰 수는
없다는 점을 유의 해야한다. 예를 들면 링크 텍스트의 의미가 적절한지 여부나, 대체 텍스
트(text equivalent)의 적용 가능성(applicability) 등은 다룰 수 없다. 따라서 W3C의 웹
접근성 체크 리스트를 체크해 볼 필요가 있는데, 한국형 웹 접근성 평가도구인 KADOWAH(
http://www.iabf.or.kr/web/kadowah.asp)라는 소프트웨어를 이용할 수 있다.
이 프로그램은 웹 페이지의 접근성 준수여부를 평가하고 접근성의 오류들을 바로 잡아주
는 수정 과정을 통해서 웹 개발자와 콘텐츠 제작자들에게 장애인들이 웹페이지 접근이 용
이한 웹 사이트를 만들 수 있도록 도와준다.
실전 웹 표준 가이드
- 23 -
그림 6 웹 접근성 평가 도구, KADO-WAH
만약 좀 더 상세하게 접근하고자 한다면 텍스트만 나오는 브라우저 또는 에뮬레이터로 시
험하여 페이지의 레이아웃이 올바른지 살펴 보고 여러 개의 그래픽 브라우저를 써서, 소리
와 그래픽을 모두 받는 설정, 그래픽을 받지 는 설정, 소리를 받지 않는 설정, 마우스를
쓰지 않는 설정, 프레임, 스크립트, 스타일 시트, 애플릿을 사용하지 않는 설정 등을 통해
얼마나 접근도가 좋은지 체크해 볼 필요가 있다. 또한, 최근에 나온 것뿐 아니라 오래된
브라우저를 포함하여 여러 개의 브라우저로 시험해 본다면 더 좋을 것이다.
또한, 음성 브라우저(self-voicing browser), 화면 음성 변환기, 화면 확대 장치, 낮은 해
상도의 화면 등을 써보면 자신의 웹페이지 접근도에서 문제되는 점을 고칠 수 있다. 마지
막으로 철자법과 문법 검사기를 사용한다. 음성 합성기를 통해 페이지를 읽는 사람들은 철
자법이 틀린 단어에 대해서 합성기가 읽어주는 것으로는 무슨 단어인지 추측할 수가 없을
것이다. 문법적인 오류도 없어야 이해하기가 쉽다.
기본적인 접근도 검사가 수행되었다면 문서가 간단 명료하게 작성되었는지 다시 점검한다.
일부 워드 프로세서가 생성해 주는 가독성 통계치같은 것들이 명확성이나 간결성에 대한
좋은 지표로 쓰일 수 있다. 그보다 더 나은 방법은 경험 있는 편집자에게 명료성을 검토해
주도록 부탁하는 것이다. 또한 경험있는 편집자는 특정 언어(단어나 표현)나 아이콘 사용
이 야기할 수도 있는 잠재적으로 민감한 문화적인 문제점을 가려내 문서의 사용자 편의성
(Usability)을 높일 수도 있다.
웹 표준 홈페이지 방법론
우리가 사용하는 HTML의 태그들은 구조(structure)를 나타내는 것과 표현
(presentation)을 나타내는 것으로 분류할 수 있다. 구조를 나타내는 것의 대표적인 것이
H1, H2, UL, DL, OL, LI, LINK, ADDRESS, STRONG, BLOCKQUOTE, CODE, Q,
DIV, P 등이다. 일반적인 브라우저에서는 구조적인 마크업을 사용할 때에 적당하게 모양
실전 웹 표준 가이드
- 24 -
(표현)도 바꾸어 표현해준다. 예를 들면, H1이라는 마크업을 사용하면 보통은 글자 크기가
커지고 두꺼워진다. 그렇다고 해서 H1을 단순히 글자를 키울 목적으로 사용하는 것은 잘
못된 것이다.
H1은 문서의 가장 중요한(또는 가장 상위의) 제목 부분을 표시하라는 “의미”를 가지고
있는 것이지, 그냥 글자를 키울 목적으로 제공되는 것이 아니기 때문이다. 이에 반해 B,
FONT, I, BR 등은 문서의 표시 방법을 결정하는 표현 요소들이다. 즉 이것들은 아무런 의
미는 없지만 단지 시각적으로 표현하는 방법만 결정한다. 예를 들어 B 요소를 사용하면
글자가 두꺼워진다.
초기 HTML이 계속 진보하면서 표현 마크업이 담당하던 모양에 대한 것은 CSS가 담당하
게 되고, 이제 HTML에서 표현 마크업은 점점 쓸모가 없게 되었다. 따라서 1부에서는 문
서 내에 FONT, B, BR 등을 되도록 쓰지 않도록 권고했다. 이런 것들로 표현하고자 하는
모양은 100% CSS를 이용해 훨씬 정교하게 표현할 수 있기 때문이다. 이렇게 HTML은
구조, CSS는 표현이라는 역할 분담을 함으로써, 구조를 고치기 위해 표현 방법을 바꾼다든
지, 표현 방법을 바꾸기 위해 구조를 전부 뜯어고쳐야 할 일이 없어지게 된다.
구조와 표현의 분리
구조를 위한 마크업(structural markup)과 표현을 위한 마크업(presentational markup)
이란 무엇인가? 이 둘을 구분하는 것은 매우 중요하다. 겉으로는 똑같이 보이는 웹페이지
를 만들었더라도 속에 보이는 구조는 천차만별로 다를 수 있고, 이 다른 구조는 다양한 환
경의 사용자에게, 또는 다양한 기기에게, 또는 검색 엔진이나 의미 해석 엔진(semantic
parser)에게 엄청난 차이를 가져다 준다.
그림 7 구조적으로 표현한것과 태그로만 표현한 페이지
위의 그림은 웹 브라우저에 표시된 두 개의 문서를 보여주고 있다. 왼쪽 브라우저와 오른
쪽 브라우저에 표시된 문서의 겉보기 모양은 거의 동일하다. 거의 같은 모양과 내용을 포
함하고 있으나 이 두 페이지가 담고 있는 HTML은 완전히 다르다.
실전 웹 표준 가이드
- 25 -
아마도 흔히 우리가 코딩하는 방식이나 간단하게 나모나 드림위버로 만들어버리면 아래와
같은 html이 만들어질 것이다. 이것은 그림의 왼쪽 화면의 모양과 같다.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="ko">
<head>
<meta http-equiv="content-type" content="text/html; charset=euc-kr">
<title>그냥 표현한 것</title>
</head>
<body>
<br>
<font size="4" color="darkred"><b>1. 서론</b></font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font size="2" color="black">1. 개념
정의</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font size="2" color="black">2.
필요성</font><br>
<font size="4" color="darkred"><b>2. 본론</b></font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font size="2" color="black">2.1 보편적 디자인
원칙</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font size="2" color="black">2.2 접근성
원칙</font><br>
<font size="4" color="darkred"><b>3. 맺음말</b></font><br>
</body>
</html>
이 예제를 보면 계층적인 제목을 나타내기 위해 글꼴을 바꾼 것과 줄 간격, 들여 쓰기 한
것, 그리고 번호를 붙인 것, 불릿 이미지로 동그라미를 붙인 것과 같은 표현 방법
(presentation)들이 내용(contents)과 섞여 있어서 나중에 표현 방법만 살짝 바꾸거나 아
니면 내용만 바꾸거나, 아니면 구조(structure)를 현재의 2단계에서 3단계 체제로 바꾸거
나, 아니면 본론이 없어지고 결론이 바로 나오도록 하려면 번호도 다 바꾸어 주어야 한다.
이와 같이 구조와 표현과 내용이 한데 얽혀 있으면 나중에 소스를 관리하고 수정하기가
매우 어려울 뿐만 아니라, 컴퓨터가 이 문서의 구조를 파악하기도 매우 힘들다. 예를 들어
위의 문서에서 가장 큰문서의 구조는 서론, 본론, 결론의 세 가지 항목으로 이루어졌다고
사람은 알 수 있는데, 컴퓨터는 글자 색깔이 어떻고, 크기가 어떻고 하는 것이 의미가 없
으므로 시각 장애인이 사용하는 음성 브라우저에서도 위와 같은 글자 크기가 어떻고 하는
것은 거의 의미가 없다.
따라서 아래의 HTML 소스와 같이 수정을 해주면, 컴퓨터나 검색 엔진이 문서의 의미적
인 구조를 파악하기가 쉽고, 기계를 통해 문서의 구조에 쉽게 접근할 수 있다. 이것은 그
림7의 오른쪽 화면을 나타낸다.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="ko">
<head>
<meta http-equiv="content-type" content="text/html; charset=euc-kr">
<style type="text/css">
실전 웹 표준 가이드
- 26 -
* { line-height: 138%;}
ol>li {
font-size: 1.2em;
color: darkred;
font-weight: bold;
padding-top: 0.8em;
margin-left: -1em;
}
ul>li {
font-size: 0.7em;
color: black;
font-weight: normal;
margin-left: -2em;
}
</style>
<title>구조적으로 표현한 것</title>
</head>
<body>
<ol>
<li>서론</li>
<ul>
<li>개념 정의</li>
<li>필요성</li>
</ul>
<li>본론</li>
<ul>
<li>보편적 디자인 원칙</li>
<li>접근성 원칙</li>
</ul>
<li>맺음말</li>
</ol>
</body>
</html>
이 HTML 소스는 스타일 지정 부분이 따로 있기 때문에 이 부분만을 바꿈으로써 문서의
구조는 그대로 유지한 채 모양을 자유자재로 바꿀 수가 있고, 심지어 이 스타일 파일만을
여러 벌 만들어 한 벌은 모바일용으로, 한 벌은 음성 브라우저용으로, 한 벌은 그래픽 브
라우저용으로 최적화해서 만들 수도 있다. 그러면, 구조와 내용은 아주 간결하게 놔둔 채
로 표현 방법만 상황에 맞게 여러 가지로 할 수 있게 된다.
이런 경우 인터넷 익스플로러에서는 CSS의 선택자(selector)를 제대로 해석하지 못해 색
깔이나 글자 크기가 제대로 표현되지 않을 수 있다. 그러나 모질라나 오페라와 같은 다른
브라우저에서는 원래 의도한 대로 정확히 보일 것이다. 그럼에도 불구하고 이렇게 쓰는 것
이 font를 이용하여 쓰는 것보다 더 좋은 방법이다.
여기에서 사용된 마크업은 표준에 따라 만든 것이므로 미래에는 인터넷 익스플로러도 이
기능을 지원할 것이고, 설사 이 기능이 지원되지 않는다고 하더라도 문서를 구조적으로 이
해하는 데에 아무런 문제가 없기 때문이다. 이것은 브라우저 이미 언급한 하위 버전 호환
실전 웹 표준 가이드
- 27 -
성뿐만 아니라 향후 미래에 나올 브라우저에 대한 상위 버전 호환성(Forward
Compatibility)로 매우 중요하다는 점이다.
즉, 잠재적으로 스타일시트 기능을 지원하지 않는 어떤 브라우저에서 보더라도, 또는 스타
일 시트를 완전히 제거하더라도 이 문서를 이해하는 데에는 아무런 문제가 없기 때문이다.
HTML에서는 표현과 구조를 나타내는 마크업이 완전하고 명확하게 구분되지는 않았다.
그래서 XML이 나오게 된 것이고, XML은 표현을 위한 마크업이 아예 존재하지 않는다.
XML 문서 내에서는 문서의 구조만을 나타내고 표현을 위한 부분은 CSS, XSL(T) 등으로
아예 따로 떼어내어서 표현해야 한다.
그림 8 구조와 표현의 분리를 통해 디자인 및 접근성이 확보된 웹 페이지 (1)은 기본 스타일 양식, (2)는 구조적
마크업을 통한 HTML소스 (3)은 스타일을 걷어 냈을 때 시맨틱 내용만 있는 모습
구조와 동작(Behavior)의 분리
우리가 흔히 접하는 웹 문서에는 이전에 말한 대로 구조와 표현만 있는 것이 아니다. 바로
사용자 액션에 따른 반응 및 동적인 문서 구조 변경 등 스크립팅(Scripting)이라고 불리우
는 클라이언트 프로그램이 있다. 일반적으로 자바 스크립트(JavaScript) 또는 VBScript
등으로 불리는 이러한 스크립팅을 통한 제어를 동작(Behavior) 이라고 통칭한다. 구조에
서 동작을 분리해 내는 일은 구조에서 표현을 분리해내는 일보다 더 어렵다. 특히, CSS는
선언적인데 반해 스크립트 언어는 그렇지 않기 때문이다.
특히 웹이 문서를 표현 하는 수단으로 여기지기 때문에 웹 문서에서 DHTML이나 DOM
스크립팅 같은 행동 제어를 하는 것에 대해 많은 문제점이 있다고 지적되었다.
.. 사용성: 팝업이나 상태창 메시지, 슬라이딩 메뉴 등은 사용성을 크게 해친다.
.. 접근성: 자바스크립트를 꺼놓았거나 시각 장애인인 경우 접근성이 떨어진다.
.. 복잡성: HTML에 스크립트가 끼어 들어가 코드의 복잡도가 높아진다.
실전 웹 표준 가이드
- 28 -
.. 중복성: CSS에서 스크립트가 하는 전통적인 기능을 수행할 수 있는 데도
이러한 문제점에도 불구하고 스크립트를 통한 DOM 핸들링은 매우 광범위하게 사용되고
있다. 위에서 말한 문제점을 해결 하기 위해서는 구조에서 스크립트를 분리해야 될 필요가
있다.
그림 9 패널 번호를 누르면 내용이 바뀌는 예제
아래 코드는 위와 같이 패널 번호를 누르면 내용이 바뀌는 기능을 구현한 것이다.
<script type="text/javascript">
Function changePanel (id) {
document.getElementById("panel").innerHTML="This is panel"+id;
}
<ul>
<li><a href="#panel1" onClick="changePanel(1);">Panel 1</a></li>
<li><a href="#panel2" onClick="changePanel(2);">Panel 2</a></li>
<li><a href="#panel3" onClick="changePanel(3);">Panel 3</a></li>
</ul>
<div id="panel"> </div>
통상적으로 위와 같이 구현을 하고 나면 panel을 누를 때 마다 나타나는 값에 대한 접근
성이 떨어지게 된다. 또한, 구조 내에 onClick과 같은 이벤트 요소를 넣을 수 밖에 없다.
구조에서 행동을 분리하기 위해서는 우선 구조적인 태그와 함께 반응에 따라 얻어지는 결
과값도 함께 제공한다.
<script src="easytoggle.js"></script>
<p>Select a panel:</p>
<ul>
<li><a href="#panel1" class="toggle">Panel 1</a></li>
<li><a href="#panel2" class="toggle">Panel 2</a></li>
<li><a href="#panel3" class="toggle">Panel 3</a></li>
</ul>
<div id="panel1">This is panel 1</div>
<div id="panel2">This is panel 2</div>
<div id="panel3">This is panel 3</div>
이렇게 제공 한 후에 자바 스크립트에서는 사용자의 이벤트를 감시하고 제어하는 기능을
초기화 하여 사용자가 panel을 누를 때 마다 나타나는 내용을 변화 시켜 주면 된다. 아래
실전 웹 표준 가이드
- 29 -
소스 코드는 그러한 예이다.
/* easytoggle.js, by Simon Willison */
addEvent(window, 'load', et_init); // 이벤트 감시
var et_toggleElements = [];
/* 초기화 */
function et_init() {
var i, link, id, target, first;
first = true;
for (i = 0; (link = document.links[i]); i++) {
if (/\btoggle\b/.exec(link.className)) {
id = link.href.split('#')[1];
target = document.getElementById(id);
et_toggleElements[et_toggleElements.length] = target;
if (first) {
first = false;
} else {
target.style.display = 'none';
}
link.onclick = et_toggle;
}
}
}
// 토글일 경우 디스플레이 변경
function et_toggle(e) {
/* Event handling code adapted from
http://www.quirksmode.org/js/events_properties.html
*/
if (typeof e == 'undefined') {
var e = window.event;
}
var source;
if (typeof e.target != 'undefined') {
source = e.target;
} else if (typeof e.srcElement != 'undefined') {
source = e.srcElement;
} else {
return true;
}
/* For most browsers, targ would now be a link element; Safari
however returns a text node so we need to check the node
type to make sure */
if (source.nodeType == 3) {
source = source.parentNode;
}
var id = source.href.split('#')[1];
var elem;
실전 웹 표준 가이드
- 30 -
for (var i = 0; (elem = et_toggleElements[i]); i++) {
if (elem.id != id) {
elem.style.display = 'none';
} else {
elem.style.display = 'block';
}
}
return false;
}
/* 브라우저별 이벤트 처리*/
function addEvent(obj, evType, fn){
if (obj.addEventListener) {
obj.addEventListener(evType, fn, true);
return true;
} else if (obj.attachEvent) {
var r = obj.attachEvent("on"+evType, fn);
return r;
} else {
return false;
}
}
위의 예에서 사용성을 만족 시키면서도 접근성과 복잡성을 모두 해결한 방법을 간단하게
배웠다. 구조에서 행동을 분리하는 것은 아직 많은 시도가 이루어지고 있지 않은 분야이기
도 하다. 그러나, 현대 웹이 어플리케이션으로 진화함에 따라 문서로 인식되던 웹에서 구
조 요소를 제외하는 것은 무엇보다 중요하게 되었다. 특히, Ajax와 플러그인 등 다양한 웹
어플리케이션 기술에서 어떻게 하면 접근성 높은 상태에서 웹의 특징을 보존할 수 있을
것인가 하는 문제는 향후에도 중요한 이슈가 될 것이다.
우리 나라 웹 표준 현실 및 과제
국내 웹 사이트의 웹 표준 여부를 고려해 보면 현실은 매우 심각하다. 2004년에 공공기관
정보접근성 현황(KIPA 조사 자료)을 조사한 결과는 아래와 같다.
.. 조사 대상: 정부 및 공공기관, 금융기관 웹 사이트 1,000개
.. 조사 기간: 2004년 10월~12월
.. 조사 방법: 조사대상 웹사이트를 윈도즈, 리눅스, 맥킨토시 3종의 운영체제하에서 익스플러
로, 모질라, 사파리를 이용하여 접속 및 정상작동 여부 조사
.. 조사 항목: ① 초기 화면의 정상 작동 여부, ② MS익스플로러 최적화 문구 표기, ③ 글꼴
의 깨짐 없는 내용의 전달, ④ 그림 및 사진 디스플레이 가능, ⑤ 동영상 작동, ⑥ 자료 다
운로드 가능, ⑦ 스크립트 오류 발생 여부, ⑧ 인증여부, ⑨ 인터넷뱅킹 작동여부 등 9개
항목
.. 조사 결과: 전체의 12.3%인 110개 기관 인터넷 익스플러어 최적화 표기, 조사 대상기관의
99.8%가 모질라(리눅스), 사파리(맥킨토시) 부분장애 또는 심각한 장애 발생
웹 표준에따라 홈페이지를 구축하는 분위기가 정립되어 있을 뿐 만 아니라, 정보 접근 문
제에 대한 인식도 매우 저조하기 때문이다. 정보 접근성 문제를 장애인 접근성에 한정되게
실전 웹 표준 가이드
- 31 -
생각하는 것도 문제이다. 정보 접근성 문제를 가지고 있는 대상자는 장애인 뿐만 아니라
소수 운영체제 및 브라우저 사용자, 비 PC 단말기 사용자 (PDA, Phone), 인터넷 환경이
열악한 제3 세계 재한국인, 정보 소외 계층(노인 및 장애인, 농민 및 빈민) 등 다양하기
때문이다. 이는 전 국민이 잠재적인 대상자라고 볼 수 있다.
국내 웹 표준 문제 현황 및 요인
국내 정보 접근성의 주요 문제는 크게 웹 정보 전달 행태 즉, 고기능을 위주(과잉 개인 정
보 및 기능 요구, 스크립트의 무분별한 사용), 고사양을 위주(고해상도 색상 및 플래쉬, 고
사양 PC 위주)의 정보 제공 문제와 웹 정보 가공 행태 즉, 비표준에 따른 웹페이지 가
공 (IE 종속적인 기능)과 과도한 플러그인 기능 사용 (ActiveX)으로 나뉜다.
현황 1. 비표준 웹 페이지 가공
공공기관 웹사이트에서 사용하고 있는 HTML 문서에 사용된 태그들이 90년대 중반에 양
산된 IE용 비표준 태그들을 그대로 채용하고 있는 곳이 많다. 비표준 태그는 IE에서만 지
원 가능하므로 IE 이외의 웹브라우저에서 웹페이지를 제대로 표시할 수 없는 문제를 야기
시키고 있으며, HTML문서를 구성하는 표준 형식을 생략함으로서 브라우저가 글꼴 및 그
림을 제대로 표현 할 수 없는 상태가 되고 있다. HTML 뿐만 아니라 비표준 JavaScript
는 로그인, 회원 가입, 검색, 주소 입력 등 웹페이지 상의 다양한 활동을 제약시키고 있다.
우선 먼저 비표준 태그를 표준 태그로 변환 시키는 전반적인 HTML 리팩토링 작업을 통
해 간단하게 웹사이트 접근성 향상이 가능하다.
현황 2. 과도한 플러그인 사용
전자 정부 사이트를 비롯 공공 기관 웹사이트 온라인 민원 서비스를 이용하기 위해서는
본인 확인을 위해 공인 인증서를 사용하여야 한다. 공인 인증서를 확인하고 처리하는 프로
그램은 웹브라우저에 포함되어 있지 않으므로 별도의 브라우저 플러그인으로 제공하고 있
다. 인증서 플러그인이 Microsoft사의 윈도우즈를 기반으로 하는 ActiveX 기술로만 제작
되어 있어 매킨토시, 리눅스 등 비윈도우즈용 OS에서 온라인 민원 서비스를 이용할 수 없
다.
윈도우즈 사용자라 하더라도 IE이외 모질라, 사파리 웹브라우저 사용자는 MS의 ActiveX
기술을 사용하지 못하므로 접근성에 제약을 받고 있다. 이는 공인 인증에 기반이 되는 정
부 전자 서명 체계는 OS나 브라우저에 관계없이 구현 가능한 기술이나, 예산상의 문제를
들어 타 OS 및 브라우저를 지원하지 않고 있기 때문이다. IE 사용자라도 동일한 기능을
하는 ActiveX 플러그인이 공인 인증 기관 6개, 은행 3~4개 등 10여개의 플러그인이 중복
개발되고 있으며, 해외의 경우 표준 SSL과 간단한 기능의 공통 ActiveX 및 Java Plugin
만으로 인터넷 뱅킹을 구현하여 서비스하고 있다. 뿐만 아니라 민간 부문에서도 우리 나라
ActiveX 사용 비율은 전세계적으로도 가장 높은 편에 속해 있다.
그 밖에, 공공 기관 웹사이트에서 제공하는 인터넷 방송 및 미디어 배포 자료가 모두
Microsoft사에서 제공하는 윈도우즈 미디어(Windows Media) 포맷으로 제공되고 있는데
윈도우즈 미디어 포맷이더라도 비 IE 브라우저에서 재생 될 수 있도록 재생을 위한
HTML 태그를 지원해 주고 있지 않고 있다. 윈도우즈 미디어의 스트리밍 방식을 사용함
실전 웹 표준 가이드
- 32 -
으로서 저속도 사용자나 비윈도우즈 미디어 플레이어 사용자가 접근성에 제약을 받고 있
는 것이다.
리눅스 및 매킨토시에서도 재생 가능한 WAV, MPEG 파일에 대한 지원 및 다운로드가
제공되고 있지 않고 있다. 이러한 현상 들은 공공 기관뿐만 아니라 일반 기업 웹 사이트에
서도 흔히 볼 수 있는 문제이다.
웹 표준 문제 발생 요인
이미 언급한 바 대로 1990년대 중반 소위 브라우저 전쟁기간 동안 인터넷 익스플로러
와 넷스케이프간의 비표준을 기반한 경쟁 이후, 시장이 IE 독점 상태가 되면서 IE
전용 기술만 잔재로 남게 되었다. 2000년에 들어와서 웹 표준 기술이 비약적으로 발전
하였으나, 독점 브라우저인 IE 의 하위 버전 호환 기능(Backward Compatibility) 으로
인해 신 기술에 대한 추가가 잘 되지 못하였다.
뿐만 아니라 표준 기술에 대한 국내 웹디자이너/UI 개발자 등 웹 생산 종사자 재교육 및
자기 개발 부재도 큰 요인이 되었다.
특히, 국내 브로드 밴드 인터넷 환경의 급격한 성장과 공공 부문에서 자체 공인 인증 시스
템으로 인해 플러그인 기술이 광범위하게 도입되었으며 인터넷 산업화로 인한 엔터테인먼
트 인터넷으로 진화하면서 표준 웹 문서 교환이라는 고유의 모습이 잘 지켜지지 못했다.
과다한 홈페이지 구축열로 인해 SI를 통해 고정화된 열악한 국내 웹 생산 시스템 구조 속
에서 웹에 대한 기본 인식 및 개발 방식에 대한 이해 및 교육 부재, 비용과 효율만 중요시
하는 행태 등 공공재로서의 웹을 바라보는 인식이 매우 부족했다고 할 수 있다.
외국의 웹 표준 제도 동향
우리 나라 밖에서는 대부분 웹사이트들이 웹 표준을 채택 하고 있는 반면, 정보 접근이 제
약 받는 다양한 계층을 위한 제도를 가지고 있다.
미국
미국 재활법(The Rehatilitation Act Amendment) 508조는 연방 우편업무를 포함하여 연
방부처나 기구가 전자 및 정보기술을 개발, 조달, 유지, 사용할 대는 지나친 부담(Undue
Burden)이 되지 않는 한 사용하는 기술의 종류에 상관없이 장애를 지닌 연방정부 직원도
비장애인과 동등한 수준으로 정보와 자료에 접근하여 이용할 수 있어야 함을 규정하고 있
다.
동 조항은 연방정부가 준수하는 조항이기 때문에 미 연방 조달시장 진입을 위해서는 필수
적으로 준수하여야 하며, 전자 및 정보기술의 접근성 표준안(Electronic and Information
Technology Accessibility Standards)을 만들어 지침으로 활용(WCAG기반 작성)하고 있
다.
영국
영국은 전자정부를 추진하는 e-Envoy에서 영국 정부의 웹사이트 접근성 준수를 위한 가
이드라인을 제정/공포 하고 있다. 이는 W3C의 WCAG1.0을 기반으로 가이드라인이 작
실전 웹 표준 가이드
- 33 -
성되어 보편적 접근성 보장하고 있으며 시각 장애인 기관인 RNIB(Royal National
Institute for the Blind)에서 웹접근성 인증마크 제도(See it Right) 시행하고 있다.
호주
호주는 W3C WCAG 기준을 활용하여 웹접근성 표준 지침으로 활용하고 있으며, 2001년
NOIE(National Office for the Information Economy)에서 연방 정부 및 기관이 지켜야
할 표준 가이드 제정하고 있다.
국내 웹 표준 제도 소개
2003년 말부터 우리 나라에서도 공공 기관을 시작으로 웹 표준에 대한 인식을 새로이 하
기 시작하여, 전자정부 사업 공개 SW 도입 권고안(2003), 공개 SW 기반 정보 시스템 구
축 사용자 가이드(2004), 행정기관 홈페이지 구축 운영 표준 지침(2005), 행정기관 홈페이
지 평가 지표(2005), 소수 정보통신 환경 사용자 정보 접근성 제약 개선 방안(2005) 등에
정보 접근성, 웹 표준, 웹 접근성에 대한 다양한 가이드라인들이 제정 되었다.
특히, 한국정보 통신 표준 협회(TTA)에 XHTML 1.0 표준(2001.12.), 문서 객체 모델 레
벨 1(2003.10.), 한국형 웹 콘텐츠 접근성 지침(2004.12) 등이 산업 표준으로 제정되기도
했다.
이들 중 많은 공공 기관에서 홈페이지를 구축할 때 표준 지침으로 사용하고 있는 행정 자
치부의 행정 기관 홈페이지 구축 가이드 및 평가 지표를 통해 웹 표준 문제에 대한 요구
사항과 해결 방법을 이 가이드에 기초하여 간단하게 살펴 보도록 한다.
2005년 행정 기관 홈페이지 구축 가이드
본 가이드는 행정자치부 전자정부 본부에서 발간한 홈페이지 구축 가이드 중 일부이다.
지표 항목 준수 방법
6. 개인별 맞춤 서비스
○ 장애인, 노인 등을 위한 웹 접근성 준수
텍스트 버전을 별도로 제공하여 접근성을 높이
기 위한 지침으로서, 표준 기반으로 구조와 표
현을 분리한 후 스타일 변경 만으로도 텍스트
페이지를 구성할 수 있다.
9. 저작권, 개인 정보 보호 등을 위한 고려
○ 장애인, 노인 등 다양한 이용자의 용이한 접근을 확보하기
위해 한국형 웹 콘텐츠 접근성 지침 중 다음 사항을 고려하여
제작
- 그림에 대한 대체 텍스트 제공(지침1), 탭 및 화살표 등
최소 키보드로 접근 가능성 확보(지침5), 각 프레임별 별도 제
목 부여(지침7), 스타일을 제거하더라도 문서 구조를 쉽게 파
악 가능해야 함(지침11) 등
※ 별첨 2「한국형 웹 콘텐츠 접근성 지침」참조
장애인 접근성을 위해 한국형 웹 콘텐츠 접근
성 지침 중 꼭 필요한 사항만을 제시한 것으로
별첨한 지침을 참고하면 도움이 될 것이다.
별첨1. 3. 기술 표준
○ 인터페이스- 브라우저: 익스플로러 6.0 이상(윈도우), 사파
리 1.0(매킨토시) 등에서 작동되어야 하며 리눅스 등 공개 소
지원해야할 웹 브라우저의 버전을 명시한 것으
로 웹 표준에 대한 기술셋이 유사한 주요 주
요 운영 체제의 브라우저를 대상으로 명기하였
실전 웹 표준 가이드
- 34 -
프트웨어 사용자의 웹브라우저에서도 작동되어야 함. (예 모질
라 파이어폭스 1.0)
다.
별첨1. 3. 기술 표준
○ 뷰어 실행 프로그램- 브라우저 : 익스플로러 6.0 이상(윈
도우), 사파리 1.0(매킨토시) 및 리눅스 등 공개소프트웨어 (예
모질라 파이어폭스 1.0)
지원해야할 웹 브라우저의 버전을 명시한 것으
로 웹 표준에 대한 기술셋이 유사한 주요 주
요 운영 체제의 브라우저를 대상으로 명기하였
다.
별첨1. 3. 기술 표준
○ 뷰어 실행 프로그램- 문서 뷰어: MS word viewer 97,
Ms Excel viewer 97, Ms Powerpoint viewer 97, 한글뷰어
2002, OpenOffice, Acrobat PDF Reader
모든 운영 체제와 브라우저에서 지원되고 있는
PDF 뷰어가 추가 되었다.
2005년 행정기관 홈페이지 평가 지표안
본 지표는 행정자치부 전자정부 본부에서 매년 시행하는 홈페이지 평가 지표 중 일부다.
지표 항목 준수 방법
□ 홈페이지 구축성
1. 정보 접근성 (Information Accessibility)
1-1 국제 표준 준수
- 홈페이지가 HTML4.01 또는 XHTML 1.0 표준을 준수하고
있는가
- 디자인 표현을 위해 CSS 1.0 표준을 준수하고 있는가
- 정보 제공을 위해 XML 1.0, XSL 1.0 표준을 준수하고 있는

- 사용자 기능 제공을 위해 W3C 객체모델(DOM) 2.0과
ECMAScript 표준(자바 스크립트)를 준수하고 있는가
* 위의 항목들을 W3C Validator 또는 Venkman등 표준 자
바 스크립트 디버거로 조사하여 오류가 없어야 한다.
국제 웹 표준이 준수되고 있는 지 여부를 명기
하여 유효한 웹 제작이 되도록 하였다. 본 가이
드의 XHTML, CSS, DOM, Javascript 부분을
잘 고려하여 웹 개발을 하면 문제 없이 만들
수 있다.
1-2 브라우저 및 운영 체제 호환성
- 공인 인증 서비스를 제외한 전 페이지가 익스플로러 6.0(윈
도), 모질라 파이어폭스 1.0(리눅스), 사파리 1.0(매킨토시), 에
서 이상 없이 동작 하는가
- 공인 인증 서비스를 제외한 전 페이지가 윈도, 리눅스, 매킨
토시 등 주요 운영 체제에서 이상 없이 동작하는가
지원해야할 웹 브라우저의 버전을 명시한 것으
로 웹 표준에 대한 기술셋이 유사한 주요 주
요 운영 체제의 브라우저를 대상으로 명기하였
다.
공인 인증 서비스를 제외하고 ActiveX같은 종
속적 기능은 배제하거나 대체 기술을 제공하도
록 함을 명기하였다.
1-3 한국형 웹 콘텐츠 접근성 지침 주요 항목 적용
- 모든 비 텍스트 콘텐츠에 대해서 대체 텍스트를 제공하는가
(지침1)
- 탭 및 화살표 등 최소한의 키보드로 홈페이지 네비게인션이
가능한가 (지침5)
- 프레임을 제공하지 않거나 제공 할 경우 각 프레임별 별도
제목을 부여하고 있는가 (지침 7)
- 스타일을 제거하더라도 일렬로 문서 구조를 한눈에 쉽게 파
악 가능한가 (지침 11)
장애인 접근성을 위해 한국형 웹 콘텐츠 접근
성 지침 중 꼭 필요한 사항만을 제시한 것으로
별첨한 지침을 참고하면 도움이 될 것이다.
실전 웹 표준 가이드
- 35 -
* 위의 항목들을 웹접근성 평가 및 수정 도구를 통해 조사하
여 오류가 없어야 한다.
2-2 해상도
- 사용자가 다양한 해상도를 사용하더라도 문서의 내용을 이
해하거나 사용자 기능을 사용할 수 있는가?
- 사용자가 다양한 해상도를 사용할 경우를 대비하여 팝업창
을 아예 사용하지 않거나 사용할 경우, 문서의 내용을 이해
하거나 닫을 수 있는 방법을 제공 하고 있는가?
해상도에 따라 팝업창을 닫을 수 없거나 내용
을 못보는 것을 방지하는 것이 필요하다. 또한,
다양한 해상도에서도 내용을 이해할 수 있도록
레이 아웃을 고정하는 것을 지양 시킨다.
□ 홈페이지 기술 평가
1. 정보 접근성 (Information Accessibility)
1.1. 표준 및 주요 운영 체제 지원
- 주요 운영 체제 및 웹브라우저 지원 여부
- 장애인, 텍스트 브라우저 지원 여부
- Validator.w3.org에 검증하여 에러 여부
- 표준 자바스크립트 디버거로 검증 하에 에러 여부
- 웹 접근성 평가 및 수정 도구로 주요 항목을 검증 하에 에
러 여부
기술 평가를 위한 각종 품질 관리(QA) 항목을
설정 하였다. 이 검증 도구를 통해 손쉽게 웹
표준 준수 여부를 확인 할 수 있다.
3. 성능 (Performance)
1-1. 웹페이지 로딩 속도
- 단위 웹페이지 HTML 크기로 로딩 속도 산출 (페이지 당
70kbyte 이내 권고)
테이블 레이아웃이 아닌 CSS 레이아웃을 이용
함으로서 코드량이 줄기 때문에 웹 페이지
(HTML) 용량를 줄일 수 있다.
4. 유지 보수성 (Maintainability)
1-2 유지 보수 용이성
- 웹페이지를 쉽게 관리할 수 있도록 표현 요소를Cascading
Style Sheet(CSS)로 설계 했는지 유무
- 기본 페이지를 CSS 레이아웃을 통해 제작하여 스타일변경
으로 텍스트, 장애인, 모바일 페이지로 재사용 하고 있는지 여
부.
CSS 레이아웃을 이용하여 유지 보수에 용이하
게 개발 했는지 여부와 스타일 변경만으로 다
양한 별도 웹페이지 기능이 제공 되는지 여부
를 확인한다.
□ 홈페이지 특성 평가
3. 사용성
3.1 W3C 표준을 준수하는 주요 플래폼의 주요 브라우저가 전
페이지 사용 가능한가?
3.2 모든 해상도에서 전 페이지의 내용 확인 및 기능 사용이
가능한가?
W3C 표준과 브라우저 지원, 구조적인 컨텐츠
전달이 가능한가를 확인하고 있다.
4. 내용
4.4 다양한 멀티미디어 자료(동영상, VOD등)을 주요 브라우
저에서 사용 가능 하도록 제공하는가?
4.5 원문이나 제공 자료를 다운로드 할 수 있으며 주요 운영
체제별 뷰어 프로그램을 제공하는가?
동영상 및 문서 자료를 다양한 웹 브라우저에
서도 볼 수 있도록 하고 있으며, 본 가이드의
플러그인 사용 방법 및 웹 서버 설정 방법을
통해 설정 할 수 있다.
실전 웹 표준 가이드
- 36 -
실전 XHTML 가이드
실전 웹 표준 가이드
- 37 -
XTHML 소개
웹이 계속해서 성장, 변화, 성숙하는 것과 마찬가지로, HTML 역시 계속 진화하고 있는
것이다. 표준화 그룹이나 브라우저 회사에서 표준화 작업을 했었지만 HTML의 변화를 막
지는 못했다. 초기 웹은 조잡하고 제대로 된 형태를 이루지 못하다가, 새로운 브라우저 버
전이 출시될 때마다 새로운 태그가 정의되곤 했다.
HTML 3.2는 가장 흔히 쓰이는 태그와 이의 속성을 하나로 묶어 주어 웹 개발이라는 세
계가 어느 정도 안정을 찾는 듯했다. HTML 3.2가 널리 보급되면서 HTML 4.0이 생겨나
게 되었는데 HTML 4.0은 좋으며 간결하고 잘 지원되는 최초의 HTML 표준이다. HTML
4.0은 어떤 태그가 올바른 것인지 말해 줄 뿐 아니라 어떤 태그가 사라져 가고 있는지도
알려 주기 때문에 개발자는 이에 따라 작업해 나가면 된다.
웹 표준화를 맡고 있는 W3C는 HTML 4.0을 표준으로 발표한 바로 직후, 더 큰 모듈성,
유연성, 성능이 필요함을 절감하게 되었다. HTML이 처음 들어 왔을 때 HTML이 이처럼
많은 문서와 브라우저, 미디어를 다룰 것이라고는 아무도 예상하지 못했다. 웹 사용자들의
끝도 없는 요구에 응답하면서 HTML 4.0은 끊임 없이 확장해서 새로운 기술을 수용해야
만 했는데 이를 위해 XTHML이 등장 했다.
XTHML이란 무엇인가?
XHTML은 eXtensible HyperText Markup Language의 약자이다. HTML을 대체하기
위한 목적으로 만들어졌지만 HTML 4.01 규약에 "거의" 준한다. 쉽게 말하자면 XHTML
은 HTML에 비해 일반 HTML에 비해 좀더 명확하고 구조적인 특징을 가지고 있다.
HTML은 정해진 태그 집합만을 사용하는 정적인 마크업 언어라면, XHTML은
XML(Extensible Markup Language: 확장 마크업 언어)로 정의된 단 하나의 집합만을
사용한다.
XML을 사용하면 HTML을 넘어서는 모든 종류의 데이터와 문서를 표현할 수 있다. 다양
한 데이터셋을 만들어 표현 할 수 있는 것이다. 현재의 브라우저에서도 작동하는 혼성 문
서(hybrid documents)를 생성하여, 사용자가 새로운 마크업 태그를 XHTML과 통합할
수도 있다. XSL(Extensible Style Sheets)을 함께 사용하면, 브라우저에 사용자의 새로운
태그를 표시하는 방법도 변경할 수 있다.
XML은 웹이 성장 및 확장할 수 있는 플랫폼이며 XHTML은 XML을 사용하여 HTML
을 혁신한 것으로 XML이 사용되는 모든 새로운 툴에 XHTML을 결합해 준다. 하지만
HTML을 잘 사용한다고 해서 XHTML 역시 잘 사용하리라는 보장은 없다. XHTML이
HTML과 비슷한 사용법을 가지기 위해 노력을 기울이긴 했지만, 이것만 믿고 있다가는
머리 아픈 문제를 많이 만나게 될 것이다. XHTML을 잘 사용하기 위한 유일한 방법은 최
신 버전인 HTML 4.01 표준을 사용해 보면서, XHTML의 모든 세부 사항을 익히는 것이
다.
2000년 1월에 W3C의 공식 표준으로 지정된 이후 HTML의 표준이라하면 XHTML 1.0을
가리킵니다. 당연히 최근의 모든 HTML 브라우저는 XHTML 1.0을 완벽히 지원하고 있
다. 대부분의 브라우저는 일반 HTML을 써도 상관없다. 게다가 HTML 문법이 상당히 느
실전 웹 표준 가이드
- 38 -
슨하기 때문에 어쩌면 XHTML의 딱딱한 규정을 지키는 것이 오히려 번거로울 수도 있다.
그렇다면 왜 굳이 HTML대신 XHTML을 써야 하는 것인가?
왜 XTHML을 사용해야 하는가?
XHTML 1.0으로 전이함으로써 얻는 잇점은 위에서 기술하였다. 이 XHTML로 전이의 몇
가지 일반적인 잇점은 다음과 같다:
호환성 및 확장 가능성
XHTML은 단순히 HTML4를 업그레이드한 것이 아니라 XML 애플리케이션을 가장 폭
넓게 사용하는 웹 페이지에 적용할 수 있다는 데에서 의미를 찾을 수 있다. XML 어플리
케이션이 사용 가능하다는 말은 바로 기계가 이해할 수 있는 언어라는 것이다. 기계가 이
해하려면 우리가 흔히 색상, 글꼴 형식, 레이아웃 등 눈으로 보는 표현적인 요소가 완전히
배제되어 있다는 것이다. HTML4.01 보다 더 표현과 구조가 엄격하게 분리되고 있다는
뜻이다. 다만 브라우저 지원 문제가 걸림돌인데, 인터넷 익스플로러도 XML을 충분히 지
원한다고 보기에 아직 부족한 면을 찾을 수 있다. XHTML은 HTML 문서의 하위 호환성
유지와 함께 더욱 강력하게 확장할 수 있도록 해주는 것이다.
XHTML 1.0 스펙에 무슨 내용이 들어있는지 막상 뚜껑을 열어보면 그 단순함에 당황하게
된다. HTML 4.01 스펙은 389쪽, CSS2 스펙은 338쪽 정도로 책 한권 분량의 문서로 접할
수 있으며, 그 자체로 충분한 레퍼런스 역할을 해준다. 이러한 스펙과 달리 XHTML 1.0은
30쪽 정도밖에 안되므로 지나칠 정도로 단순한 것이 아니냐는 생각을 가질 수도 있으며,
레퍼런스로 삼기에 부실하다는 사람도 많이 있다. HTML4.01 스펙을 참고하여 XML적인
요소를 좀 더 이해 한다면 XHTML 스펙에 대한 이해도를 높힐 수 있다.
유지 비용의 감소 및 재생산성 확대
사실 국내에서 웹 페이지 제작은 "IE를 통해 사용자가 눈으로 보는 것"을 목적으로 만들
어지는 경향이 있다. 따라서 일단 눈으로 보이는 부분만 멀쩡하면 내부적으로 HTML 문
서가 어떻게 구성되어있든 아무도 신경 쓰지 않는다. 이것은 HTML의 재활용과 생산성의
문제이며 장차 나오는 비용의 문제이다. 일반적인 관습대로 작성된 HTML 문서는 내용과
디자인, 문서 구조가 모두 뒤범벅이 되어있다.
디자인을 바꾸려면 일일이 HTML문서를 수정해야 한다. 기존의 HTML 제작 방법으로는
이러한 변화에 대처하기 힘들며, 똑같은 내용이라고 하더라도 모바일 환경을 위해서 따로
만들고, PDA버전을 위해 따로 만들고, 심지어는 같은 PC환경이라도 브라우저 버전별로
따로 만들기도 한다. 뿐만 아니라 장애인용 저속 사용자용 텍스트 버전 심지어 회사의 PR
사이트를 만들면서 영어와 중국어 버전이 각각 필요할 때. 이런 경우에도 각각의 페이지를
다 따로 만들어 주어야 한다. 이는 매우 효율성이 낮은 반복 작업과 막대한 수정 비용을
요구하는 것이다. XHTML과 CSS 기반 사이트는 이러한 수고를 덜고 유지비용이 감소한
다.
경량의 로딩 속도
XHTML 규격을 따르면 저절로 "구조화된" 문서로 만들어진다. 구조화된 문서의 특징은 "
실전 웹 표준 가이드
- 39 -
가독성"이 높아지게 되는데 단지 생성된 코드를 사람이 읽기 편하다는 뜻뿐만 아니라, 다
른 기계나 프로그램도 읽기 수월해 진다. 만약 디자인 부분을 CSS 파일로 분리해낸다면
훨씬 더 간단해진다. 지금까지 만들어온 일반적인 HTML 코드를 보면 아마도 실제 내용
보다 디자인 요소가 차지하는 부분이 더 클 것이다. 문서 내 이러한 디자인 요소들은 파일
의 용량이 키움에 따라, 웹페이지 로딩과 렌더링 속도를 느리게 하고 있다.
실제로 XHTML+CSS 레이아웃으로 첫화면을 개편한 미국 야후!닷컴은 기존과 똑같은 UI
를 유지 하면서도 첫화면 HTML 파일 크기를 1/3 가량 줄었다. ESPN.com의 경우 50kb
의 파일 크기가 감소했고, MSN.com과 Wired.com은 각각 64%, 62% 가량 줄었다.
MSN.com의 경우 하루 940GB의 트래픽 감소 효과를 보았다.
이제 점점 더 많은 사이트들이 테이블을 사용하지 않고 CSS의 배치(layout) 기능을 이용
하여 홈페이지를 재설계 하고 있다. W3C, Web Standards Project, Mozilla, WebAIM와
같이 비영리 사이트나 개인 사이트가 아닌 상업적인 홈페이지도 얼마든지 CSS를 이용해
디자인을 바꿀 수 있다는 실제적인 증거가 곳곳에서 늘어나는 것이다. 미국 야후와 한국
야후, ABC News, Novell: Suse Linux, Chevrolet, Disney Store UK가 그 대열에 동참했
고, ESPN, SitePoint, Max Design, RedHat, Wired News, Opera 등은 오래 전부터 테이
블을 사용하지 않고 설계되어 있었다. Macromedia사의 홈페이지가 테이블을 쓰지 않고
설계가 되을 뿐 아니라 Flash, 드림 위버 등 최근 제품들은 대부분 접근성을 고려한 기능
이 상당히 정교하게 들어가 있다. Adobe사의 홈페이지도 오늘 확인해보니 완벽하진 않
지만 테이블을 배제하고 CSS의 레이아웃 기능을 활용하여 디자인되어 있다. 이러한 추세
는 앞으로도 계속 될 것으로 보인다.
뿐만 아니라 XHTML 사용은 웹표준을 지원하는 모든 현대적인 웹브라우저를 모두 지원
함에 따라 사용자 층을 넓힐 수 있을 뿐 아니라, 검색 엔진이 접근하여 자료를 분석하고
색인 하는 데도 도움을 주므로 좋은 검색 결과를 얻어 미래의 사용자층을 확대할 수도 있
다.
XTHML 문서 구조
올바른 DOCTYPE 사용
대부분의 웹페이지 들이 <html>로 시작하여 <head>와 <body> 태그를 사용하여 웹페이
지를 표현한다. 그러나 웹페이지를 표현 하는 방식을 제대로 표현 하기 위해 웹 브라우저
가 적절한 문서 형태를 표기하도록 할 필요가 있다. 즉 문서의 루트 요소 앞에는 공백 없
이 DOCTYPE 선언이 있어야 하며, 이 선언은 XHTML에 대한 세 DTD(Document
Type Definition) 파일(strict, transitional, frameset) 중 하나를 참조해야 한다.
올바른 문서 형식 선언을 해 주는 것은 다양한 브라우저에 따른 렌더링 차이를 최소화 할
수 있기 때문에 매우 중요하다. HTML 버전에 따라 해석되는 방식이 브라우저에 따라서
도 다르기 때문에 이를 지정해 주는 것은 매우 중요하다.
1) HTML 2.0 표준 문서 형식
<!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN">
2) HTML 3.2 표준 문서 형식
실전 웹 표준 가이드
- 40 -
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
3) HTML 4.01 표준 문서 형식
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
"http://www.w3.org/TR/html4/frameset.dtd">
4) XHTML 1.0 표준 문서 형식
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
5) XHTML 1.1 표준 문서 형식
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
표준 문서 구조
표준 문서 형식(Doctype)을 기반한 웹페이지에 대한 정확한 사용법은 다음과 같다.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko-KR">
<head>
<title> ... </title>
</head>
<body>
...
</body>
</html>
가장 흔히 사용되는 DOCTYPE 코드는 일반 형식(Transitional)과 엄격한 형식(Strict)으
로 나누어 지게 된다. HTML 4.01 Transitional은 예전에 있었거나 없어진 태그도 지원하
며, <font>에 지정된 스타일도 제대로 표현하여 준다. HTML 4.01 Strict은 HTML을 엄
격하게 적용한다. <font> 태그에 적용된 스타일 보다는 CSS파일에서 지정된 스타일을 지
켜 표현 해야 한다. 이러한 DOCTYPE 선언에 차이는 다음과 같다. 만약 웹사이트에
BODY {font-family: Helvetica, sans-serif; font-size: 200%;}와 같은 스타일을 지정한 다
음 서로 다른 DOCTYPE을 지정한 경우 아래와 같이 표현된다.
DOCTYPE을 규정하는 가장 좋은 방법은 Strict 형식을 사용하는 것이다. 이것은 CSS를
통해 모든 HTML 태그의 속성을 모두 자유 자재로 규정할 수 있기 때문이다. 즉, b {fontweight:
normal;} 라고 적는 다면 더 이상 <b>는 굵은체로 표시되지 않는다. 그러나, 아
직 브라우저 호환성 때문에 <embed>나 비표준 태그를 사용해야할 필요가 있으므로 현재
상태에서 가장 최상의 브라우저 호환성을 제공해 주는 문서 형식은 XHTML 1.0
Transitional을 사용하는 것이다.
실전 웹 표준 가이드
- 41 -
XHTML 일반 문법 준수
정확한 문서 구조 준수
문서의 루트 요소는 html이 되어야 하며, 이 html 요소는 XHTML 네임스페이스를 지정
해야 한다.
<html xmlns="http://www.w3.org/1999/xhtml">
표준 문서에는 head, title 및 body 구조 요소가 포함되어야 한다. 프레임 세트 문서에는
head, title 및 frameset 구조 요소가 포함되어야 한다
모든 요소는 완벽하게 중첩되어야 한다.
모든 요소들이 완벽하게 내포(nest) 되어야 하는 것은 필수적이다. 중첩(overlapping)이
부적합(illegal)한 것임에도 불구하고 기존 웹 브라우저들에서 널리 관대하게 사용되었다.
<p>This is a <i>bad example.</p></i>
<p>This is a <i>good example.</i></p>
모든 속성 값은 인용 부호(“나 ‘)로 묶어야 한다.
코드를 생성하거나 XHTML을 정리할 때 코드에서 속성 값을 인용 부호로 묶는다.
<a href=http://sample.com>틀린 경우</A>
<a href="http://sample.com">맞는 경우</a>
모든 요소와 속성은 소문자여야 한다.
XHTML 코드를 생성하거나 정리할 때 태그 및 속성의 대/소문자 환경 설정에 상관 없이
XHTML 코드에서 HTML 요소 및 속성의 이름을 소문자로 강제로 설정해야 한다. 이러
한 차이는 XML은 대소문자를 구별(case-sensitive)하므로 필수적이다. 예를 들어, <li>와
<LI>는 서로 다른 태그들이다
<A HREF="http://sample.com">틀린 경우</A>
<a href="http://sample.com">맞는 경우</a>
모든 요소는 닫아야 한다.
DTD에서 EMPTY로 선언된 경우를 제외하고 모든 요소에는 종료 태그가 포함되어야 한
다. 코드를 생성하거나 XHTML을 정리할 때 코드에 닫기 태그를 삽입한다.
빈 요소에는 종료 태그가 포함되거나 시작 태그가 />로 끝나야 한다. 예를 들어, <br>은
잘못된 것이며 <br></br> 또는 <br/>이 올바른 형식이다. 빈 요소로는 area, base,
basefont, br, col, frame, hr, img, input, isindex, link, meta 및 param이 있다.
또한, XML을 사용할 수 없는 이전 브라우저와의 호환성을 위해 /> 앞에 공백이 있어야
한다(예: <br/>가 아니라 <br />).
실전 웹 표준 가이드
- 42 -
<img src="http://sample.com/wrong.jpg">
<img src="http://sample.com/right.jpg" />
모든 속성값은 속성이 함께 선언되어야 한다.
모든 속성은 최소화되어 표기 되면 안 된다. XML은 속성의 최소화를 지원하지 않는다. 속
성 값의 짝들은 모두 작성되어야 한다.
a, applet, form, frame, iframe, img, map 등의 요소에는 name 속성뿐만 아니라 id 속
성도 있어야 한다. 예를 들어, <a name="intro">Introduction</a>는 잘못된 것이며 <a
id="intro">Introduction</a> 또는 <a id="section1" name="intro">
Introduction</a>.가 맞다.
또한 <td nowrap>은 잘못된 것이며 <td nowrap="nowrap">이 올바른 형식이다. 최소
화될 수 없는 속성으로는 checked, compact, declare, defer, disabled, ismap, multiple,
noresize, noshade, nowrap, readonly 및 selected가 있다.
<option value="wrong" selected>틀린 경우</option>
<option value="right" selected="selected">맞는 경우</option>
참고: HTML 브라우저에서 HTML 4를 지원하지 않는 경우, 부울 속성이 전체 형식으로
표시되면 브라우저에서 이들 속성을 해석하지 못할 수도 있다.
모든 script 및 style 요소에는 type 속성이 포함되어야 한다.
language 속성이 사용되지 않는 HTML 4 이후로는 script 요소의 type 속성을 반드시
지정해야 한다. 코드를 생성하거나 XHTML을 정리할 때 script 요소에서 type 및
language 속성을 설정하고 style 요소에서 type 속성을 설정한다.
<script type="text/javascript” language="javscript"></script>
<style type="text/css"></style>
모든 img 및 area 요소에는 alt 속성이 포함되어야 한다.
코드를 생성하거나 XHTML을 정리할 때 코드에서 이들 속성을 설정하고, 찾을 수 없는
alt 속성을 보고한다.
모든 SCRIPT내의 태그는 Escape 시켜야 한다.
자바 스크립트에서 HTML 태그 쓰기에서 많은 경우 오류를 낸다. 자바스크립트 내에 데
이터는 CDATA 형식으로 간주되기 때문에 HTML태그가 들어가게 되면 오류를 내게 되
어 있다. 예를 들어 아래 예제는 잘못된 방식이다.
<script type="text/javascript">
<!--
// 틀린 표현!
document.write("</P>");
// -->
</script>
실전 웹 표준 가이드
- 43 -
HTML4에서는 SCRIPT내에 데이터 중 시작 태그나 코멘트 부분은 인식이 안되지만 종료
태그는 인식이 되기 때문에 이를 역슬래시로 표시해야 한다.
<script type="text/javascript">
<!.
// 맞는 표현!
document.write("<\/P>");
// -->
</script>
XHTML에서, 스크립트와 스타일 요소들은 #PCDATA 컨텐트를 갖는 것으로 선언된다.
결과적으로, <과 &는 마크업의 시작으로 처리되고, &lt;과 &amp;와 같은 개체(entities)들
은 XML 프로세서(processor)에 의해 각각 <과 &로의 개체 참조로서 인식되므로
CDATA로 마크업 하여 표시하는 게 좋다.
<script type="text/javascript">
<![CDATA[
... <h1>데이터</h1> ...
]]>
</script>
모든 문서 내 URL에서 &를 쓰면 안 된다.
URL에 &가 포함되어 있는 경우 에러를 낼 수 있다. 이것은 &가 XML 엔티티의 시작으
로 인식 하기 때문에 생기는 문제이다. 기존 웹브라우저는 이러한 에러를 복구해 주고 있
지만 유효성 검사기에서는 에러를 내게 된다.
<!.에러! --> <a href="foo.cgi?chapter=1&section=2">...</a>
<!.적합! --> <a href="foo.cgi?chapter=1&amp;section=2">...</a>
HTML 문서 내에서만 &를 &amp;로 바꾸어야 하며 브라우저 주소창이나 이메일 본문에
서는 &를 써야 한다. 웹 서버에서는 &amp;가 아니라 &만을 인식하기 때문이다.
실전 웹 표준 가이드
- 44 -
구조적 XHTML 사용 방법
잘못 사용하고 있는 태그
XHTML에는 컨텐츠의 의미를 나타내는 많은 태그들이 있다. 간단하게는 문단은 나타내
는 <p>부터 사용하는 것을 많이 보지 못했던 <var> 등에 이르기 까지 다양한 태그들이
있다. 그러나 많은 수의 사람들이 이러한 다양한 태그를 사용해서 문서의 메타 데이터를
풍부하게 하기 보다는 <table>만을 사용해서 시각적인 것만을 고려 하여 웹 페이지를 제
작한다.
무분별한 테이블 사용
<table width="640" cellpadding="0" cellspacing="0" border="0">
<tr>
<td height="25" valign="top">
<img src="title_01.gif">
</td>
</tr>
<tr>
<td>
레이아웃에 table element 를 사용하는 이유는 아마도 쉽기 때문일 것이다. 쉽다는
것 보다는 "익숙해서" 가 더 큰 이유일지도 모른다. 대다수의 사람들은 처음부터 아주
당연하게 table 을 사용해 왔고 그렇게 되어 있는 사이트를 더 많이 봤을 것이다.
</td>
</tr>
</table>
보통의 웹사이트에서 위와 같은 코드는 아주 쉽게 찾아 볼 수 있다. <table>은 행과 열이
있는 2차원의 데이터를 표시 하는 데에 사용되는 태그 이다. 그러나 위와 같이 단순히 제
목과 문단을 구분 하는 데에도 표를 사용하는 것을 많이 볼 수 있다. 이와 같은 데이터는
표가 아니기 때문에 <table> 태그를 사용해서는 안되고 의미에 맞는 <h1>이나 <p>와 같
은 태그를 사용해 주어야 한다.
잘못된 위치, 태그, 스크립트 사용
<table cellpadding="0" cellspacing="0">
<form action="/search/" method="get">
<tr>
<td>
<select>
<option>제목</option>
<option>내용</option>
<option>작성자</option>
</select>
</td>
<td>
<input type="text" size="10" class="type-text" />
</td>
실전 웹 표준 가이드
- 45 -
<td>
<a href="javascript:search()"><img src="button_search.gif"></a>
</td>
</tr>
</form>
</table>
<form>을 사용해서 제작하다 보면 디자인상에서 나타나서는 안되는 공백이 생기는 것을
볼 수 있다. 이와 같은 현상을 피하기 위해서 많은 사람들이 <form>태그를 <tr>태그 사
이에 넣는다. 하지만 validator를 이용해 보면 이와 같은 사용은 잘못된 문법 오류라는 것
을 알 수 있다. <form>의 여백을 없애기 위해서 스타일을 사용하면 아주 간단하게 문제를
해결 할 수 있다.
form { margin: 0; }
<form>에 마진을 없앰으로서 간단하게 여백을 없앨 수 있고 위와 같이 <tr>사이에
<form>태그를 넣는 잘못된 xhtml사용을 피할 수 있다.
또한 많은 사람들이 <form>의 서밋을 javascript로 하는 것도 잘못된 xhtml의 사용이다.
<form>의 서밋을 하기 위해서는 <input type="submit">을 사용하면 되고 일반적으로는
이미지를 서밋버튼으로 사용하기 때문에 <input type="image">를 사용하게 된다. 하지만
상당수의 사람들이 이와 같은 방법을 사용하지 않고 <img>태그를 이용해서 이미지 버튼
을 삽입하고 이것에 <a>태그와 javascript를 이용해서 서밋을 하는 방법을 사용한다. 첫
째로, 이 방법은 javascript가 작동하지 않는 상황에서는 서밋이 일어날 수가 없기 때문에
접근성을 아주 떨어뜨리는 방법이다. 그리고 href의 값도 올바른 값이 아니다. href는 하이
퍼텍스트 주소를 값으로 할 수가 있는데 위에서 사용된 "javascript:search()"는 올바른 하
이퍼텍스트 주소가 아니다.
그리고 위의 경우는 단순히 <select>와 텍스트를 입력받는 <input>, 그리고 서밋 버튼으
로 이루어져 있는데 이를 각각<td>안에 넣는 것도 불필요한 <table>의 사용이다. 위의
코드를 간결한 xhtml로 바꾸면 아래와 같다.
<form action="/search/" method="get" onsubmit="validation(this)">
<div class="search">
<select>
<option>제목</option>
<option>내용</option>
<option>작성자</option>
</select>
<input type="text" size="10" class="type-text" />
<inpyt type="image" src="button_search.gif" alt="검색" />
</div>
</form>
불필요한 테이블을 없애고 중앙정렬이나 여백을 없애는 것과 같은 디자인적인 요소를
CSS로 처리 함으로써 아주 간결하고 의미에도 맞는 마크업을 할 수 있다.
XHTML을 작성함에 있어서 가장 중요하게 생각하고 있어야 하는 것은 "의미에 맞는 태
그를 사용"하는 것이다.
실전 웹 표준 가이드
- 46 -
그룹 요소: div, span
페이지를 제작할 때에는 각각의 의미를 갖고 있는 컨텐츠를 묶거나 표시를 해줄 필요가
있다. 이러할 때에 사용하는 태그가 <div>와 <span>이다. <div>가 레이어를 만드는 것
에 사용되는 태그인 것으로 알고 있는 사람이 있을 정도로 많은 사람들이 <table>에 익숙
해져 있는 것이 사실이다. 그리고 <table>을 사용하지 않고 페이지를 제작하는 사람들을
보면 생각의 틀은 바뀌지 않은 채 <table>을 단순히 <div>로 옮기는 식으로 제작을 하는
경우도 있다. 의미에 맞는 태그를 사용해서 페이지를 제작한 다음에는 <div>나 <span>
을 이용해서 단위별로 구분을 해 주어야 한다.
block과 inline
<div>와 <span>은 둘다 그루핑에 사용되는 엘리먼트이지만 <div>는 block이고
<span>은 inline이라는 큰 차이점이 있다. 이 block과 inline은 화면에서 엘리먼트들이
랜더링 되는 기본 모양을 지칭한다. block과 inline은 쉽게 생각하면 이 엘리먼트 뒤에 개
행이 이루어지는지로 구분 할 수 있다. <div>를 이용하면 뒤에 개행이 이루어 지고
<span>을 이용하면 개행이 이루어 지지 않는다.
<div class="name">홍길동</div> <div class="age">24 세</div>
위의 코드를 화면에서 보면 "홍길동" 다음에 줄이 바뀌어서 "24세"라고 나오는 것을 볼 수
있다.
<span class="name">홍길동</span> <span class="age">24 세</span>
하지만 위와 같이 작성을 하게 되면 "홍길동"뒤에 개행이 되지 않고 한줄에 "홍길동 24세"
와 같이 나오는 것을 볼 수 있다.
<div>, <form>, <ul>, <ol>, <li>, <dl>, <dt>, <dd> 등이 block들이고 <a>, <img>,
<select>, <input> 등이 대표적인 inline 엘리먼트들 이다.
표제(Heading)
Heading 태그는 각 부분에서 중요한 역할을 하는 제목들을 표시할 때에 사용하게 된고,
<h1> ~ <h6> 까지 6단계의 heading태그가 있다. 페이지의 한 부분에서 가장 중요한 제
목을 <h1>으로 묶어주게 되고 그 아래의 중요도를 갖는 것은 <h2>, <h3>등을 이용해서
제목을 표기해 주게된다.
주의할 것은 <h1>의 하위 heading은 <h2>여야지 <h3>나 <h4>와 같이 단계를 건너뛰
는 것은 좋지 않다.
문단(paragraph)
<p>태그는 문단을 나타낼 때에 사용한다. 어느 웹스타일 가이드를 보면 브라우져 별로
<p>태그의 간격이 다르기 때문에 <p>태그를 사용하면 안되고 <br />두번을 사용하라는
경우가 있는데 이는 마크업을 비주얼 적인 요소로 잘못 이해한 것이다. 문단은 <p>로 구
분을 하고 간격을 CSS로 제어하게 되면 브라우져와 상관없이 일관된 디자인을 유지할 수
실전 웹 표준 가이드
- 47 -
있다.
<p>를 사용할 때에는 반드시 닫는 태그도 사용해 주어야 한다.
<p> 첫번째 문단
<p> 두번째 문단
<p> 세번째 문단
위와 같이 단락의 경계를 <p>로 구분 하는 것이 아니라 하나의 문단을 <p>와 </p>로
감싸는 식으로 작성을 해야 한다.
<p>첫번째 문단</p>
<p>두번째 문단</p>
<p>세번째 문단</p>
그리고 <p>는 하위에 block요소를 포함 할 수가 없다. 텍스트나 이미지와 같은 inline요
소만을 하위에 포함 할 수 있기 때문에 주의해서 사용해야 한다.
구문(em, strong, dfn, code, samp, kbd, var, cite, abbr, acronym)
강조 (strong, em)
<em>과 <strong>은 문장안에서 강조를 나타낸다. 보통의 브라우져에서 <em>은 이탤릭
으로, <strong>은 볼드체로 나타나게 된다. 문장안에서 중요도가 있을 때에는 이 <em>과
<strong>을 사용해야 하고 단지 이탤릭이나 볼드를 표현하고자 할 때에는 <i>와 <b>를
사용해야 한다. 스크린리터중에는 <em>이나 <strong>태그를 사용하면 그 부분을 큰소리
로 강조해서 읽어주는 제품도 있다.
정의
<dfn>태그는 정의를 나타낼 때에 사용된다.
코드
<code>는 컴퓨터 코드를 나타내는 태그이고 <samp>는 코드의 결과 출력물을 나타낼때
에 사용한다.
값의 표시
<kbd>는 유저의 키보드 입력을 나타내고, <var>는 프로그램에서의 변수를 나타낸다.
<kbd>Enter</kbd>키를 누르세요
출처
<cite>는 인용이나 출처를 밝힐 때에 사용한다.
실전 웹 표준 가이드
- 48 -
축약
<abbr>는 축약어를 나타내고 <acronym>은 두문자어를 나타낸다. 이 두가지는 상당히
혼동하기가 쉬운데 보통 그 약어를 그대로 발음하는 것은 <acronym>을 사용하고 한글자
씩 읽는 것은 <abbr>을 사용한다.
인용(blockquote, q)
다른 인용문을 표시할 때에 사용한다. <blockquote>는 block요소의 인용문이고 <q>는
inline요소의 인용을 나타낸다. 보통 <blockquote>는 인덴트를 해서 보여주게 되고 <q>
는 인용문 앞 뒤로 따옴표를 나타내 준다.
첨자(sup, sub)
위첨자나 아래첨자를 나타내고자 할때 하용한다.
x<sup>2</sup> + 4x + 4 = (x+2)<sup>2</sup>
형식을 가지고 있는 컨텐츠 (pre)
미리 형식을 가지고 있는 내용을 나타내고자 할 때에는 <pre> 태그를 사용한다. 이 태그
를 사용하게되면 공란도 갯수에 맞게 다 나오고 글자폭이 일정한 폰트로 화면에 나오게
된다. 소스 코드등을 나타낼 때에 많이 사용한다. 단, 자동 줄바꿈이 되지 않기 때문에 너
비가 제한 적일 때에는 주의해서 사용해야 한다.
<pre class="code">function menuOn(imgEl)
{
imgEl.src = imgEl.src.replace(&quot;.gif&quot;,
&quot;_on.gif&quot;);
}
function menuOut(imgEl) {
imgEl.src = imgEl.src.replace(&quot;_on.gif&quot;,
&quot;.gif&quot;);
}</pre>
인덴트나 개행을 위해서 다른 태그등을 사용하지 않아도 화면에 그대로 랜더링 되는 것을
볼 수 있다.
추가 및 삭제(ins, del)
문서에 추가된 내용이나 삭제된 내용을 명시할 때에 사용한다.
문서에 <ins>새로 추가</ins>되거나 <del>삭제된 내용</del>을 표시 할 수 있습니다.
보통 <ins>는 밑줄을, <del>은 취소선으로 표현이 된다.
목록 (ul, ol, dl)
리스트에는 <ul>, <ol>, <dl>세가지가 있다.
실전 웹 표준 가이드
- 49 -
Unordered List
<ul>은 하위로 <li> 엘리먼트를 갖게 되고 각 <li>엘리먼트의 앞부분에는 불렛이 나타나
게 된다.
Ordered List
<ol>은 하위로 <li> 엘리먼트를 갖게 되고 각 <li>엘리먼트의 앞부분에는 자동적으로 숫
자가 나오게 된다.
Definition List
<dl>은 하위로 <dt>와 <dd>엘리먼트를 갖게 된다. <dt>는 term을 <dd>는 definition
을 나타낸다.
실전 웹 표준 가이드
- 50 -
실전 CSS 레이아웃
실전 웹 표준 가이드
- 51 -
CSS 제대로 사용하기
현재 대부분의 사이트에서 CSS는 폰트나 링크 스타일에 대한 정의 정도로만 사요이 되고
있다. 이러한 사용도 사이트의 디자인을 효과적으로 관리하고 제작하는 것에 도움이 되고
있지만, CSS의 가장 큰 장점은 문서의 구조와 디자인의 분리에 있다. CSS를 폰트에 대해
서만 제한적으로 사용하게 되면 HTML에 레이아웃 이라든가 배경이미지 같은 디자인 적
인 요소가 많이 들어갈 수 밖에 없다. 여기서는 이러한 디자인 적인 요소를 HTML에서
분리해 냄으로서 얻어질 수 있는 여러가지 장점에 대해서 알아본다.
웹은 초기에 다양한 환경의 사용자들이 환경에 영향을 받지 않으면서 정보나 자료를 서로
쉽게 교환을 할 수 있게 하기 위해서 만들어 졌다. 웹이 처음 만들어질 당시에는 지금과
같은 인터넷이라는 것도 없었고 지역적으로 멀거나 사용하는 컴퓨터 기종이 다를 경우 상
호간에 자료를 교환하는 것이 쉬운일이 아니었다. 이 불편한 상황을 극복하기 위해서 웹이
라는 것이 고안되고 계속 발전을 해서 지금과 같은 엄청난 규모의 정보 전달 매체로 만들
어지게 된 것이다. 자료를 손쉽게 교환하기 위해서 정보를 기록하는 공통된 약속이 필요
했고 이 약속이 발전한 것이 우리들이 현재 사용하고 있는 HTML, XHTML 등 이다.
HTML 의미 바로 알기
HTML은 HyperText Markup Language의 약자 이다. HyperText 는 일반적으로 많이
알고 있는 것 이다. 쉽게 얘기 하자면 링크로 연결되는 문서를 의미 한다. 보통의 종이에
인쇄되어 있는 책들과 비교해 볼 때 HyperText 는 많은 장점을 가지고 있다. 문서들끼리
서로 연결 되어 있기 때문에 참조나 설명이 용이 하고 자신이 원하는 내용으로의 이동이
아주 간편하다. 우리는 HyperText의 장점을 잘 살려서 Web Site 라고 하는 정보의 집합
체이자 효과적인 정보 전달을 할 수 있는 구조적인 문서를 만들어 낼 수 있는 것이다.
HTML에서 한번쯤은 생각해 봐야 하는 것이 HTML은 markup language라는 것이다.
출판이 전산화 되기 전에는 글을 쓰는 사람이 원로글 작성하고 자신의 원고에 표현하고자
하는 내용의 의미과 형식에 대해서 표기를 하였고 이것을 바탕으로 인쇄를 할 활자를 짰
다. 여기서 저자가 원고에 내용의 의미를 표기하는 작업을 "마크업한다(mark it up)." 라고
했다. 즉 마크업이라는 것은 눈으로 보이는 글자 외에 원고에서 특정 부분의 의미가 무엇
인가를 설명하고 그것을 표기하는 것을 말한다. 이 표기는 문서의 표현 형식 - 페이지를
나눈다거나 글씨의 모양을 지정하는 - 일 수도 있고, 특정 부분이 제목이나 문단과 같이
문서내에서 뜻하는 것이 어떠한 것이라는 것의 설명일 수도 있다. 즉, 우리들이 문서를 작
성을 할 때에는 글자 모양외에도 문서가 가지고 있는 정보를 확실하게 전달하기 위해서
겉으로는 보이지 않지만 추가적인 정보를 기술해 주어야 한다.
그러나 보통 HTML 문서를 작업할 때에는 작업자들이 HTML을 markup 하는 용도로
사용하기 보다는 겉으로 어떻게 문서가 보이는 지 만을 나타내기 위해서 사용하고 있다.
사실 더 직설적으로 말하자면 대부분의 HTML 작업자 들은 HTML이 markup이라는 것
을 간과하고 무의식 중에 <table cellpadding="0" cellspacing="0"> 부터 적기 시작한다.
실제로 HTML 작업자에게 "H1 태그가 무엇인가요?" 라고 물어보면 "매우 크고 두꺼운
폰트" 라고 답변하는 사람이 있을 것이다. 그 사람에게 "H2 태그가 무엇인가요?" 라고 질
문을 하게 되면 아마도 "두번째로 크고 두꺼운 폰트" 라는 답변을 하게 될 것이다. 그리고
실전 웹 표준 가이드
- 52 -
"그러한 태그를 사용하신 적이 있습니까?" 라고 물으면 "처음에 배울때에는 사용했었는데
글씨가 두껍고 못생겨서 요즘에는 사용하지 않다." 라고 할 것이다. 물론 완전히 틀린 말
은 아니다. 실제로 이 태그들을 사용해서 페이지를 만들게 되면 크고 두꺼운 글씨들이 나
타나고 그렇게 H1~H6태그를 설명하는 책들도 서점에서 찾아볼 수 있다.
하지만 HTML은 마크업 언어이고 문서의 구조를 나타내는 언어이기 때문에 이러한 답변
보다는 "H1은 해당 부분에서 가장 중요한 타이틀이고 H2는 H1바로 하위의 타이틀을 나
타내고 H3~6 등은 하위 뎁스의 타이틀이다. 그리고 글씨의 모양은 제가 원하는 대로
CSS를 이용해서 조절을 한다." 라는 답변을 해야 - 혹은 알고 있어야 - 프로 HTML 작업
자라고 할 수 있을 것이다. 어느순간부터 대다수의 웹사이트 제작자들은 HTML 태그들이
구조적인 의미를 갖는 다는 것은 잊어 버리고 화면상에서 원하는 대로 보이게 하기 위해
서 HTML언어를 사용하고 있다. 대다수의 사람들이 많은 구조를 나타내는 태그들은 사용
을 안하고 오직 <table>, <img>, <form> 태그들만 이용해서 웹페이지를 제작하고 있는
것이 현실이다.
HTML과 CSS의 관계
HTML은 컨텐츠의 내용과 구조를 표시 한다. 컨텐츠의 내용은 텍스트와 <img> 엘리먼
트 등으로 나타나게 되고 이러한 컨텐츠가 하나의 문단을 이루고 있는지, 인용문인지, 리
스트 형태 인지에 따라서 각각 <p>, <blockquote>, <ul> 등의 의미를 나타내는 엘리먼트
로 표기한다. 그리고 각 컨텐츠들이 페이지에서 어떠한 의미를 갖는지 <div> 엘리먼트와
적절한 id, class 속성으로 표기한다. 이렇게 작성된 markup은 사용자 뿐만이 아니라 검
색엔진과 같이 페이지에서 내용의 의미를 파악하는 기계들도 쉽게 이해 할 수 있는 언어
가 된다. 이렇게 나타내고자 하는 컨텐츠를 의미에 맞게 기술하고 웹페이지로의 접근성을
높일 수 있는 방법으로 markup을 만드는 것이 웹표준의 목적이기도 하다. 그리고 이렇게
제작된 페이지를 어떻게 표현해 내는지에 대한 것은 CSS에서 담당하게 된다.
CSS를 익히고 접근할때 사람들이 가장 흔하게 하는 실수가, CSS라는 것이 기존과는 다른
새로운 것이기 때문에 CSS에만 너무 집중하는 것이다. CSS에 너무 집중을 하게 되면
CSS를 사용하는 원래의 목적에서 멀어지고 컨텐츠의 의미도 제대로 전달하지도 못하고
제작만 더 어렵고 크로스 브라우징도 잘 되지 않는 애물단지의 페이지가 만들어 지게 된
다.
CSS의 가장 큰 목적은 문서의 내용과 문서의 표현을 분리하는 것에 있다. 문서의 내용은
HTML로 작성 하고 문서의 표현은 CSS를 이용해서 나타내는 것이다. CSS에만 너무 촛점
을 맞추다 보면 문서의 내용을 기술하는 HTML을 소흘이 하기 쉽다. CSS를 처음 접할때
CSS를 적용하는 것이 주 목적이 아니라 컨텐츠를 의미에 맞게 기술하기 위한 HTML 작
성을 위해서 CSS를 사용한다는 것을 항상 염두에 두어야 한다.
실전 웹 표준 가이드
- 53 -
CSS 개념 및 소개
CSS(Cascading Style Sheet)란 무엇인가?
CSS 는 구조적으로 짜여진 문서(HTML, XML)에 style (글자, 여백, 레이아웃) 등을 적용
하기 위해서 사용하는 language이다. CSS는 문서의 구조와 디자인을 분리할 수 있게 해
줌으로써 웹 제작이나 유지관리를 간단하게 해 준다. 또한 미디어 (화면, 프린트, 보이스머
신 등) 별로 스타일을 적용 할 수 있기 때문에 각 기기별로 다른 스타일이 적용된 모습을
만들 수 있다.
그림 10 CSS Zen Garden은 하나의 HTML에 스타일 변경 만으로 다양한 디자인을 선보이고 있다.
이러한 특징을 잘 보여주는 사이트로 css zengarden (http://csszengarden.com) 사이트
가 있다. 위의 사이트들은 다 전혀 다른 사이트 같지만 실제적으로는 동일한 사이트이다.
실전 웹 표준 가이드
- 54 -
동일한 HTML을 사용하면서 CSS 만 바꿔서 사이트의 디자인을 다르게 표현한 것이다.
내용의 구조와 디자인이 완벽하게 분리되어 있기 때문에 디자인 요소인 CSS만 바꾸어도
다른 사이트처럼 보이게 할 수 있게 된다.
CSS의 선언
p.text {
margin: 0;
}
CSS의 선언(rule)은 선택자(selector)와 선언부로 이루어져 있다. 위의 rule에서 "p.text"
부분이 바로 selector이고 그 뒤에 나오는 {}안의 내용이 선언부이다. selector에 해당하는
HTML엘리먼트에 선언부에 명시된 것과 같은 스타일을 적용하라는 의미로 되어 있다.
p.text,
span.name {
color: #666;
}
selector들은 ,(comma)를 이용하여 구분할 수 있다. "p.text"와 "span.name"
은 ,(comma)로 구분되어 있다. 이경우 "text"라는 class를 갖는 <p> 엘리먼트와 "name"
이라는 class를 갖는 <span> 엘리먼트는 둘다 폰트의 색이 rgb #666666으로 나타나게
된다.
h1 { font-weight: bold }
h1 { font-size: 3em }
h1 { color: #333 }
h1 { margin: 1.5em 0 1em }
h1 { padding: 0 0 0 8px }
동일한 selector에 서로 다른 선언들이 있을 경우 이를 하나의 셀렉터에 ;(semi-colon)으
로 구분하여 선언 할 수 있다. 위의 선언과 아래의 선언은 동일하다.
h1 {
font-weight: bold;
font-size: 3em;
color: #333;
margin: 1.5em 0 1em;
padding: 0 0 0 8px;
}
CSS 선택자(Selector)
CSS는 속성을 잘 알아서 사용하는 것도 중요하지만 구조화된 문서에 효과적으로 속성을
적용하기 위해서는 selector를 정확히 이해하고 사용해야만 한다. CSS를 풍부하게 사용하
다보면 "내가 만든 CSS class 가 다른 사람의 것과 겹치면 어떻게 하지?", 또는 "CSS
class 가 너무 많아서 복잡하고 이름 정하기가 힘들어." 라는 생각을 하게 된다. 하지만
CSS selector를 잘 알고 능숙하게 사용하게 되면 오히려 이러한 고민들이 보다 구조화된
문서를 제작하는 것에 도움을 주게 된다.
일반 선택자
일반 선택자는 네 가지 종류가 있다.
실전 웹 표준 가이드
- 55 -
그림 11 일반 선택자 개념도 (출처: http://andsite.net)
대부분 한번쯤은 접해 본 타입, 클래스, ID 선택자는 CSS1 에서 채택되었고, 이후 공통
선택자와 다중 클래스가 CSS2 에서 추가되었다. 안타깝게도 윈도용 인터넷 익스플로러
6(IE6/win)는 다중 클래스를 제대로 지원 못해 가장 마지막 클래스만 인식한다.
이 오류가 안타까운 이유는 다중 클래스를 쓸 수 있다면 CSS 에서 반복된 코드를
획기적으로 줄일 수 있기 때문이다. 예를 들어 사이트에 전반적인 색깔을 .maincolor,
.sub-color 로 정하고 폰트 크기를 .main-size, .info-size 로 정한 후에 <p
class="main-color info-size">로 지정하면 두가지 속성을 동시에 적용할 수 있어서
중복된 코드가 필요 없어지기 때문이다. (출처 http://andsite.net/)
* (공용 선택자)
모든 엘리먼트를 선택한다.
* {
margin: 0;
padding: 0;
}
이와 같은 선언을 할 경우 페이지 내의 모든 <h1>, <h2>, <p>, <form>, <blockqoute>
등의 브라우져 기본 마진과 패딩을 갖고 있는 엘리먼트들이 여백이 없어지게 된다.
div.search * {
vertical-align: middle
}
이 경우 div.search안의 모든 엘리먼트가 세로로 가운데 정렬이 되게 된다.
E (타입 선택자)
E엘리먼트를 선택한다. 예를 들어서 "body"와 같이 사용하면 body 엘리먼트를, “div”와
실전 웹 표준 가이드
- 56 -
같이 사용하면 div 엘리먼트를 선택한다.
.E (클래스 선택자)
HTML에서만 사용할 수 있으며, warning이라는 class를 갖고 있는 DIV 엘리먼트를 선
택한다. class는 하나의 페이지에서 여러번 사용할 수 있기 때문에 반적적으로 여러번 나
오는 스타일의 경우 class를 지정해서 정의하여 사용하게 된다.
#E(아이디 선택자)
ID가 myid인 E 엘리먼트를 선택한다. descendant selector와 같이 사용하여 우선순위의
조정에 많이 사용된다. id를 사용하지 않고 class만을 사용하게 되면 다른 페이지나 다른
정의에서 사용된 셀렉터와 겹치게 될 수가 있다. 이를 방지하기 위해서 id를 하나 선언을
하고 descendatd selector를 사용하여 CSS를 정의하면 우선순위를 확실하게 구별할 수
있기 때문에 이러한 염려를 하지 않아도 된다.
복합 선택자
복합 선택자는 크게 세 가지 종류가 있다.
그림 12 복합 선택자의 종류 (출처: http://andsite.net/)
CSS1 에서 복합 선택자가 CSS2 로 오면서 하위 선택자로 바뀌고 자식, 인접 선택자가
추가됐다. 복합 선택자를 잘쓰면 불필요한 클래스의 남발을 막을 수 있다. 예를 들어
#header h1 은 머릿말 부분의 제목이고 #footer h1 은 꼬릿말 부분의 제목으로 각각의
의미가 분명한데, 굳이 <h1 class="header-title">나 <h1 class="footer-title">로 쓸
이유가 없는 것이다.
IE6/win 는 CSS2 에서 추가된 부분은 지원하지 않고, 그나마 지원하던 하위 선택자
역시 공통 선택자로 시작할 경우 첫 공통 선택자를 무시한다 2. 이 오류로 IE6/win 는 *
실전 웹 표준 가이드
- 57 -
html 은 html 로, * * body 는 * body 로 인식하게 되는데, 때때로 IE6/win 의 여러가지
오류들을 고치기 위한 편법으로 쓰인다. (출처: http://andsite.net/)
E F (하위 선택자)
E 엘리먼트의 하위에 있는 F 엘리먼트들을 선택한다. 보통 ID Selector와 함께 사용하여
중복 선언을 피하고자 할때 많이 사용한다. 또한 불필요하게 class를 많이 적어주지 않아
도 많은 하위 엘리먼트를 한번에 선택 할 수 있기 때문에 유용하고 많이 사용한다.
<ul id="list">
<li><a href="list.html?id=34&amp;type=blah">item 34</a></li>
<li><a href="list.html?id=35&amp;type=blah">item 35</a></li>
...
...
<li><a href="list.html?id=99&amp;type=blah">item 99</a></li>
</ul>
위와 같은 코드에서 a 엘리먼트에 스타일을 적용하고자 할 때 일일이 a 엘리먼트에 class
를 기입하지 않아도 아래와 같이 하면 모든 하위 a 엘리먼트에 스타일을 적용 할 수 있다.
ul#list a:link,
ul#list a:visited {
color: #999;
}
ul#list a:hover,
ul#list a:active {
color: #000;
}
E > F (자식 선택자)
E 엘리먼트의 자식 엘리먼트인 F 엘리먼트를 선택한다. descendant selector의 경우 하위
에 있는 모든 F 엘리먼트를 선택하는데 비해 child selector는 바로 하위에 있는 F 엘리먼
트만을 선택해 온다.
사이트 맵과 같은 중첩된 <ul>을 사용할때 유용하게 사용할 수 있다.
<ul class="depth1">
<li>
<a href="about.html>Company</a>
<ul class="depth2">
<li>
<a href="overview.html">Overview</a>
</li>
<li>
<a href="ceo.html">Ceo.html</a>
</li>
</ul>
</li>
</ul>
위의 코드 에서 ul.depth1과 ul.depth2의 <li>에 스타일을 적용할 경우,
ul.depth1 li {
background: #f9f9f9;
border-bottom: 1px solid #ddd;
}
이렇게 정의 하게 되면 ul.depth2의 <li>까지 스티일이 적용 되는 것을 볼 수 있다.
ul.depth1>li {
background: #f9f9f9;
border-bottom: 1px solid #ddd;
}
실전 웹 표준 가이드
- 58 -
이 때, child selector를 사용해 주면 첫번째 뎁스의 <li>만 선택을 해서 스타일을 적용 할
수 있게 된다. IE6에서는 구현되어 있지 않다.
E + F (인접 선택자)
E와 F엘리먼트가 서로 근접해 있는 형제관계(sibling)일 경우를 선택한다. 제목 바로 아래
의 문단에만 특정 스타일을 적용하는 경우와 같이 다른 엘리먼트가 디자인 적으로 영향을
미칠 때에 유용하게 사용할 수 있다. IE6에서는 구현되어 있지 않다.
<h2>브라우져 워</h2>
<p>웹스탠다드를 보다 잘 이해하기 위해서는 브라우져 워에 대해서 짚어볼 필요가
있습니다. 초창기에는 많은 브라우져들이 있었고 그중 사용자가 가장 많은 표준
브라우져는 넷스케이프 네비게이터(이하 NN)였습니다. 그리고 이 시장에
마이크로소프트(이하 MS)가 진입을 했습니다. 초기 windows(win95?) 사용자는
윈도우를 설치 하더라도 … 즉 많은 브라우져가 있었고 IE 에 의한 독점이 이루어지지
않고 서로 시장 점유율을 높이려고 노력하던 시대를 Browser War 라고 합니다.</p>
<h2>브라우져 독점의 폐단과 우리의 웹시장</h2>
<p>우리의 웹시장이 IT 에 대한 지원과 더불어 엄청난 속도로 발전을 했다는 것은
모든 사람이 아는 사실입니다. 그리고 그러한 발전이 양적인 발전이지 질적인 발전은
떨어진 다는 것도 대부분의 사람들이 인식하고 있는 사실입니다. …그리고 약간
비약하자면 이러한 현상에 브라우져의 독점 현상이 일조를 했습니다. 사람들은 MS 의
IE 에서 돌아가는 javascript 를 구현하고 MS 에서 제시하는 방법론을 아무 저항없이
받아 들였습니다.</p>
제목 바로 다음에 나오는 문단의 첫글자를 크게 나타내고자 할 경우 첫번째 글자를
<span>등을 이용해서 따로 선택을 해 주어야 스타일을 적용 할 수 있다. 이럴 경우에 이
셀렉터를 사용하면 별도의 추가 마크업 없이 쉽게 구현 할 수 있다.
h2+p:first-letter {
float: left;
font-size: 2.2em;
}
별도의 코드 없이 타이틀 바로 다음의 "웹" 이라는 글자와 "우"자를 선택하여 스타일을 적
용하면서 다른 문단에는 영향이 없는 것을 볼 수 있다.
실전 웹 표준 가이드
- 59 -
그림 13 인접 선택자 사용 예제
가상 클래스 선택자
그림 14. 가상 클래스 선택자 종류 (출처: http://andsite.net/)
E:first-child (:first-child 수도 클래스)
E 엘리먼트 중에서 맨처음에 나오는 E 엘리먼트를 선택한다. 리스트 등을 디자인 할 때
실전 웹 표준 가이드
- 60 -
유용하게 사용할 수 있다. IE6에서는 구현되어 있지 않다.
E:lang(c) (언어 수도 클래스)
언어가 c 인 E엘리먼트를 선택한다. 문서 안에 한국어, 일본어, 중국어가 섞여 있고 이 글
자들에 각각 다른 스타일을 적용해야 할때 유용하게 사용할 수 있는 셀렉터이다. IE6에서
는 구현되어 있지 않다.
E:link, E:visited (링크 수도 클래스)
링크인 E 엘리먼트와 방문한 E 링크 엘리먼트를 선택한다. HTML 4.01 이나 XHTML 1.0
에서는 a 엘리먼트가 해당된다.
E:active, E:hover, E:focus (동적 수도 클래스)
사용자 액션이 active, hover, focus 인 E 엘리먼트들을 선택한다.
input:hover,
input:focus {
background: #ffe;
}
와 같이 사용하면 input에 마우스 포인터가 오버 되거나 커서가 위치해 있을때의 배경색
을 지정 할 수 있다. 아래를 보면 글을 작성하고 있는 폼의 배경색이 다른 것을 볼 수 있
다.
그림 15 동적 수도 클래스 사용 예제
IE6는 a 엘리먼트에서만 구현 되어 있고, :focus는 구현되어 있지 않다.
실전 웹 표준 가이드
- 61 -
E[foo], E[foo="warning"], E[foo~="warning"], E[lang|="en"] (속성 선택자)
foo라는 속성과 warning이라는 값을 가진 E엘리먼트를 선택한다.
<input type="text" />
<textarea></textarea>
위와 같은 폼 컨트롤의 경우 사이트 전반적으로 일정한 보터를 주는 경우가 있는데 이럴
경우 아래와 같이 손쉽게 스타일을 적용 할 수 있다. IE6에서는 구현되어 있지 않다.
input[type="text"],
textarea {
border: 1px solid #eee;
}
동적 선택자
CSS는 선언적인 특성을 가지고 있기 때문에 문서에 동적으로 스타일을 적용하기는 힘들
지만 pseudo class, pseudo element라는 것을 제공함으로써 몇가지 경우에 있어서는 동
적으로 스타일을 적용 할 수 있다. 첫번째 엘리먼트라든가 첫번째 글자 등을 따로 선택한
다든가 마우스 액션에 따른 스타일을 적용한다든가 하는 것을 이를 이용해서 할 수 있다.
그림 16 동적 선택자 종류 (출처: http://andsite.net/)
:link, :visited, :hover, :active, :focus 수도 클래스
:link, :visited 수도 클래스는 이미 대부분의 사람들이 사용하고 있는 수도 클래스 이다.
바로 링크가 되어 있는 엘리먼트와 방문한 링크를 선택할 수 있는 수도 클래스 인데, 수도
클래스는 이와 같이 순차적으로 적용되는 것이 아니고 특정 조건을 가진 엘리먼트를 선택
해 올 수 있는 기능을 제공한다.
:hover와 :active 수도 클래스는 마우스의 사용과 함께 보다 다양한 스타일 적용을 할 수
있게 해 준다. MSIE에서는 이 수도클래스가 <a>에서만 작동을 해서 링크 스타일 외의 사
용은 많지 않지만 대부분의 브라우져들은 이 수도클래스를 <a>이외의 엘리먼트에도 사용
할 수 있다. 예를 들어서 <tr>에 마우스가 오버되었을때 컬러를 바꾸는 것을 :hover를 이
실전 웹 표준 가이드
- 62 -
용해서 표현이 가능하다.
tr:hover td {
background: #eee;
}
이와같이 하면 마우스가 올라갔을때 배경색이 바뀌는 기능을 javascript를 사용하지 않고
CSS만으로 구현할 수 있다.
이보다 더 유용한 것으로 :focus 수도 클래스가 있다. 이 수도 클래스는 엘리먼트에 포커
스가 이동되어 왔을 때를 선택 할 수 있다. 이를 <input>이나 <select>등에 적용하면 사
용자는 자신의 포커스가 현재 어디에 있는지 화면상에서 확실하게 알 수 있다. 아래의 회
원가입 폼을 보면 현재의 포커스가 이동해 있는 성명 부분의 <input>의 배경 색이 다른
것들과 다른 것을 볼 수 있다.
그림 17 focus 수도 클래스 사용 예제
:first-child 수도 클래스
:first-child 수도 클래스는 첫번째 엘리먼트를 선택해 옴으로써 디자인 적용에 동적인 기
능을 제공한다.
위의 리스트 디자인을 보면 각 항목간에 구분선이 있는 것을 볼 수 있다. <li> 엘리먼트에
border-top 속성을 이용해서 구현을 할 경우 처음 나오는 리스트 항목에도 위에 줄이 생
겨서 원하는 결과를 얻기는 힘들다. 그래서 이와 같은 경우 첫번째 항목에만 특정 class를
적용한다든가 해서 해결을 하게 된다.
실전 웹 표준 가이드
- 63 -
그림 18 :first-child 수도 클래스 사용 예제
하지만 이 리스트가 동적으로 생성되는 것이라면 첫번째 항목과 나머지 항목들을 구분하
기 위해서 서버사이드나 클라이언트 사이드에서 별도의 작업을 해 주어야 한다. 이러한 추
가 작업을 :first-child 수도 클래스를 사용하면 간단히 CSS만으로 구현할 수 있다.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<title>:first-child pseudo class</title>
<style type="text/css">
li {
border-top: 1px solid #999;
padding: 0.2em 0;
}
li:first-child {
border-top: 0 none;
}
</style>
</head>
<body>
<ul>
<li>포스텍 임기홍 교수 이달의 과학기술자상</li>
<li>"노출된 개인정보 즉시 신고하세요"</li>
<li>마침내 선보인 보안이 강화된 「파이폭스 1.5」</li>
<li>러시아 국립광학연구원(SOI) 한국에 온다</li>
<li>여수 거북선사이버해전체험관</li>
</ul>
</body>
</html>
이와 같이 :first-child 수도 클래스를 사용하면 추가적인 로직 작업 없이 HTML과 CSS
만으로 간편하게 원하는 디자인을 적용 할 수 있다. IE6는 아직 구현되어 있지 않다.
실전 웹 표준 가이드
- 64 -
:first-line, :first-letter 수도 클래스
:first-line, :first-letter 수도 엘리먼트는 :first-child 수도 클래스와 비슷한 기능을 가지고
있다. :first-child 수도 클래스가 첫번째 나오는 하위 항목을 선택하는 것과 비슷하
게 :first-line 수도 클래스는 첫번째 라인을, :first-letter 수도 클래스는 첫번째 글자를 선
택할 수 있다. 차이가 있다면 수도 클래스의 경우는 기존에 생성되어 있는 엘리먼트를 선
택해 오지만 수도 엘리먼트의 경우는 코드상에는 별도의 엘리먼트가 없지만 마치 다른 엘
리먼트로 구별 되어 있는 것 같이 해당하는 엘리먼트를 생성해서 선택해 온다.
그림 19 first-line, first-letter 수도 클래스 사용 예제
문단의 첫번째 글자인 "원"자의 클씨 크기를 크게 하고 문단의 첫번째 줄에 밑줄이 그어
져 있다. 이러한 디자인을 적용하기 위해서는 아래와 같은 코드를 작성해서 별도의 클래스
를 적용해 주어야 한다.
<p><span class="first-line"><span class="first-child">원</span>칙은
매사가 순조롭고 편안할 때는 누구나 지킬 수 있다. 그런데</span> 원칙을 원칙이게
하는 것은 어려운 상황, 손해를 볼 것이 예상되는 상황에서도 그것을 지키는 것이다.
앞으로도 나는 원칙을 지키기 위해 어떤 손해를 보게 될지 모른다. 하지만 나의
판단기준과 선택은 크게 달라지지 않을 것이다. - 안철수</p>
그러나, :first-line 수도 엘리먼트와 :first-letter 수도 엘리먼트를 사용하면 위와 같이
<span> 엘리먼트를 삽입한 것과 같은 효과를 CSS만으로 구현 할 수 있다.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<title>:first-letter pseudo element</title>
<style type="text/css">
p {
margin: 3em;
line-height: 1.6em;
font-family: AppleMyungJo, serif;
}
p:first-line {
text-decoration: underline;
}
p:first-letter {
float: left;
font-weight: bold;
실전 웹 표준 가이드
- 65 -
font-size: 3.5em;
}
</style>
</head>
<body>
<p>원칙은 매사가 순조롭고 편안할 때는 누구나 지킬 수 있다. 그런데 원칙을 원칙이게
하는 것은 어려운 상황, 손해를 볼 것이 예상되는 상황에서도 그것을 지키는 것이다.
앞으로도 나는 원칙을 지키기 위해 어떤 손해를 보게 될지 모른다. 하지만 나의
판단기준과 선택은 크게 달라지지 않을 것이다. - 안철수</p>
</body>
</html>
CSS 선언 방법
CSS는 우선순위에 따라서 3가지의 선언 방법이 있다.
외부 선언 (external css)
<link rel="stylesheet" type="text/css" href="myCss.css" />
HTML <head> 엘리먼트에 위와 같이 선언하여 외부에 별도의 파일로 되어 있는 CSS
정의를 불러온다. 여러 HTML 파일이 하나의 CSS 파일을 공유할 수 있어서 표현에 일관
성을 갖게 해 준다. 우선 순위는 가장 낮다.
문서 안에 포함 (embeded css)
<head>
<style type="text/css">
body {
margin: 0;
padding: 0;
}
</style>
</head>
위와 같이 HTML <head> 엘리먼트 안에 <style> 엘리먼트를 사용하여 하나의 문서 안
에서 CSS를 정의 한다.
엘리먼트에 직접 선언 (inline css)
<div style="padding: 10px; border: 1px solid #eee;">
<p>contents</p>
</div>
HTML 엘리먼트에 style 속성을 이용하여 직접 선언하는 방법이다.
사용자 정의 스타일 (user defined css)
가장 우선 순위가 높은 선언으로 웹페이지 제작자가 선언하는 것이 아니라 웹사이트를 이
용하는 사용자가 직접 자신에게 맞는 스타일을 선언하는 방법이다.
실전 웹 표준 가이드
- 66 -
그림 20 사용자가 스타일을 선택 가능하도록한 표준 기반 예제
Opera의 경우 스타일을 author 모드와 user 모드를 선택하여 적용하는 기능을 제공한다.
좌측의 원래 사이트가 사용자의 스타일 재정의에 의해서 완전히 다른 모습으로 보이는 것
을 볼 수 있다. 사용자의 정의가 가장 우선 순위가 높다는 것은 문서의 구조와 디자인을
분리 하여서 개별 사용자가 스스로에게 가장 적합한 형태의 스타일을 선택하여 쉽게 문서
에 접근할 수 있게 하기 위함이다.
CSS 적용의 체크 포인트 4가지
CSS를 이용해서 페이지에 디자인을 적용하기 전에 반드시 지켜야 하는 사항 4가지
실전 웹 표준 가이드
- 67 -
XHTML이 표준 문법이어야 한다.
CSS를 적용하기 전에 반드시 XHTML이 표준 문법인지를 검사해야 한다. XHTML 문법
이 표준이 아니면 제작 시에는 랜더링이 정상적으로 된다고 하더라도 테스트하고 있는 브
라우져가 아닌 다른 브라우져에서는 랜더링이 같게 나올 것이라고 보장 할 수 없게 된다.
XHTML 문법을 확인하는 가장 잘 알려진 방법은 W3C의 Markup Validation
Service(http://validator.w3.org)를 이용하는 것이다.
그림 21 W3C CSS Validator
HTML, XHTML, XML등의 markup문서의 문법을 체크하는 툴로서 markup 문서의
DTD 선언에 기초하여 문법을 검사해 준다. 현재 버젼은 0.7.1로 URL을 직접 입력하는
방법, 파일을 업로드 하는 방법, textarea에 코드를 직접 넣는 방법, 세가지로 문법검사를
할 수 있다.
XHTML 문서가 의미와 구조적으로 구성되어야 한다.
XHTML 문서를 작성할 때에는 표현하고자 하는 컨텐츠에 맞게 태그를 사용하여 문서를
표현해야 한다. 국내의 많은 사이트들은 이러한 컨텐츠의 의미를 나타내어 주는 태그를 사
용하기 보다는 단순히 화면상에서 어떻게 표현되는 지만을 고려하여 제작되어 있는 경우
가 많다.
예를 들어서 문서의 전체적인 내용을 나타내고자 하면 <title>을 사용하게 된다. 많은 사
이트들이 이 <title>에 동일한 내용을 넣고 있는데 이는 잘못된 태그의 사용이고 <title>
에는 해당 페이지의 내용을 간략하게 넣어주어야 한다. 또한 문서의 내용들 중에서 각 제
목에 해당하는 내용은 각 단계에 맞게 <h1>~<h6>를 이용해서 표현을 해 주어야 한다.
이 <h1>~<h6>들은 사용자가 문서의 구조를 파악하는데 많은 도움을 준다. 이 외에도
<ol>, <ul>, <p>, <blockquote>, <ins>, <del> 등과 같은 태그들을 이용해서 컨텐츠가
의미하는 바를 표현해 주어야 한다. 이렇게 의미에 맞는 태그를 적절히 사용해 주게 되면
문서의 스타일을 적용하지 않고 브라우져 기본스타일 만으로도 충분히 가독성 높은 문서
실전 웹 표준 가이드
- 68 -
를 만들 수 있다.
이렇게 의미에 맞는 태그로 문서가 제작이 되면 다음으로는 문서중에서 의미에 따라서 나
눌 수 있는 부분들을 그 의미에 맞게 구분을 해 주어야 한다. 통상 이러한 구분은 <div>,
<span> 태그와 id, class를 부여하는 것으로 구현 되고 이 구분들을 CSS Selector 를 사
용해서 디자인을 적용하게된다.
여기에 추가적으로 <script>, <style>과 같은 태그들은 가능하다면 외부문서로 분리하여
HTML크기를 줄이는 것이 좋다. 문서를 제작 할때에 CSS를 적용하는 것보다는 markup
을 완성도 있게 만드는 것이 무엇보다도 중요하다는 것을 항상 염두해야 한다.
CSS가 표준 문법이어야 한다.
XTHML이 표준 문법이어야 하는 것과 마찬가지로 CSS도 표준 문법을 사용해야 한다. 아
래는 자주 볼 수 있는 잘못 사용된 CSS 문법들이다.
주석구문
CSS의 주석 구문은 아래와 같다.
/* comment */
HTML 주석과 다른 언어들의 한줄 주석은 CSS의 주석 문법이 아니니 사용해서는 안된다.
<!-- wrong CSS comment -->
한줄 주석
// wrong CSS comment
단위표기
CSS의 값들 중에 0을 제외한 모든 값들은 단위를 표기 하여야 한다.
<td style=”padding: 15 20 10 30;”>
많이 볼 수 있는 실수가 위와 같이 단위를 안 적는 것이다. MSIE는 단위가 없으면 pixel
로 해석을 해주어서 많은 사람들이 이와 같은 오류 구문을 사용 하는데 반드시 단위를 기
입해 주고 세미콜론(;)으로 구문의 끝을 표시해 주어야 한다.
<td style=”padding: 15px 20px 10px 30px;”>
잘못된 컬러값 사용
CSS에서 컬러 값을 입력 할때에는 3가지 방법을 사용할 수 있다.
컬러의 이름을 넣는 방법 - color: red;
#rrggbb 방법 - color: #ff0000; (=color: #f00;)
rgb(r,g,b) 방법 - color: rgb(255,0,0); (=color: rgb(100%,0%,0%);)
간혹 color: ff0000; 이나 color=#ff0000 과 같이 표현하는 경우를 볼 수 있는데 잘못된
구문이므로 주의해야 한다.
실전 웹 표준 가이드
- 69 -
CSS를 표준대로 잘 구현한 브라우져를 이용해야 한다.
XHTML과 CSS를 표준 문법으로 작성해도 IE4나 NN4와 같이 CSS가 제대로 구현되지
않은 브라우져를 사용하게 되면 표준대로 랜더링 되지 않는 것이 당연한 일이다. CSS를
사용하여 사이트를 제작할 때에는 표준을 잘 준수하는 브라우져를 이용하고 제작이 끝난
후에 가장 많이 사용되는 메이저 브라우져에 대한 튜닝을 진행하는 것이 효과적이다. CSS
지원이 미약한 브라우져에서 제작을 할 경우 이미 표준대로 랜더링이 되고 있지 않기 때
문에 모든 브라우져에대한 튜닝 작업을 해야 하는 상황이 발생하게 되고 이는 불필요한
자원의 낭비일 수 밖에 없다.
그림 22 일반인들에게 표준 웹 브라우저를 홍보하는 BrowseHappy
Web Standards Project (http://webstandards.org)의 캠페인 사이트인 Browse Happy
(http://browsehappy.com)에서는 Firefox, Mozilla Suite, Opera, Safari 4개의 브라우
져를 표준준수 브라우져로 일반인들에게 추천하고 있다.
실전 웹 표준 가이드
- 70 -
CSS 레이아웃(Layout) 기초
CSS를 이용하여 사이트를 제작 할 때에 가장 먼저 접하게 되는 것이 CSS를 이용한 레이
아웃의 제작이다.
테이블 레이아웃
웹 표준이라고 불리는 XHTML은 HTML 4.01에 기반을 두고 있다. 웹 표준을 담당하는
W3C의 문서를 살펴보면 테이블에 대한 사양을 알 수 있다.
HTML 테이블 모델은 데이타를 행과 열의 셀로 정렬하는 것이 목적이다. 이 데이터에는
텍스트, 스타일이 있는 텍스트, 이미지, 링크, 폼, 폼 필드, 테이블 등이 있다. Tables in
HTML docuemnts
테이블에 이미지나 또다른 테이블이 들어가도 표준에 어긋나지 않는다. 하지만 테이블을
레이아웃의 용도로 쓰지 말 것을 권장하고 있다.
테이블은 비 시각적 미디어에서 랜더링시 문제가 있기 때문에 문서 내용의 레이아웃을
정하는 목적으로 사용하지 않는 편이 좋다. 그리고 테이블에 이미지를 사용한다면,
디자이너의 화면이 사용자의 화면보다 넓을 경우 사용자가 수평으로 스크롤을 해야하는
문제가 발생할 수도 있다. 이런 문제들을 최소화하기 위해서 레이아웃은 테이블보다
스타일쉬트를 사용하는 것이 바람직하다. Tables in HTML docuemnts
인터넷 익스플로러 전용이라고 당당하게 홈페이지에 박아 놓는 우리나라 실정과는 동떨어
진 이야기인게 문제다.
일반적으로 CSS만을 이용해 글이나 그림을 수평으로 정렬하는 것은 쉽지 않다 1. 게다가
75.5%의 점유율을 차지하고 있는 마이크로소프트의 인터넷 익스플로러(IE)는 2 CSS 버그
들로 악평이 높고 언제쯤 이 버그들이 고쳐질지도 알 수가 없다. 그럼에도 불구하고 CSS
를 써야하는 몃가지 이유가 있다.
예전의 테이블을 이용한 레이아웃 디자인은 테이블을 겹쳐서 원하는 위치에 글과 그림을
놓는 방법이었다. 글이나 그림의 간격은 투명 gif 파일로 조정하고, 테이블 속에 테이블이
서너개씩 들어간 것을 쉽게 볼 수 있었다.
이런 이유로 전체적인 데이타량이 늘어나고 구조가 복잡해져서 전송 시간과 페이지 랜더
링 시간이 길어지며 보수와 유지도 힘들어진다. CSS를 이용하면 데이타량과 구조의 문제
에서 해방될 수 있다. 게다가 CSS가 웹표준으로 받아들여지기 때문에 브라우저들이 표준
을 지원할수록 페이지의 랜더링은 최적화되기 마련이다.
CSS 레이아웃이란?
그리드(grid)가 아닌 구성요소의 집합
보통의 테이블을 이용한 퍼블리시에 익숙한 사람이라면 웹페이지의 디자인을 보고 화면을
그리드로 나누는 것을 처음에 시도할 것이다. 하지만 이러한 접근은 웹페이지를 디자인 결
과물로만 바라보는 시각이 강하고 웹의 본연의 목적인 정보 전달의 측면을 간과한 것이다.
실전 웹 표준 가이드
- 71 -
웹페이지를 제작할 때에 가장 먼저 생각해야 하는 것은 화면의 분할이 아니라 웹페이지의
구성요소들과 이 구성요소들의 관계를 정립하는 것이다. 이렇게 구성요소와 구성요소들의
그룹을 확실하게 이해 해야 의미에 맞는 마크업을 이용하여 웹페이지를 퍼블리시 할 수
있게 된다.
그림 23웹페이지를 그리드로 바라보고 접근한 것(좌측)과 구성요소로 구분하여 접근한 측면(우측)
좌측의 경우에는 구성요소들이 서로간의 레이아웃 종속성이 높은 것을 볼 수 있다. 디자인
과 구성요소를 구분하여 생각하기 쉽고 이를 이용하여 보다 접근성 높고 디자인 변경이
쉬운 웹페이지를 제작 할 수 있다.
레이아웃에 사용되는 두가지 속성 position vs. float
CSS의 여러 속성 중에 position 속성과 float 속성을 이용하여 레이아웃을 제작할 수 있
다. position 속성은 단어의 뜻이 말해 주듯이 위치를 지정하여 원하는 위치에 엘리먼트를
배치하는 속성이다. float 속성은 대상 엘리먼트를 띄워서 현재의 위치에서 좌측이나 우측
에 배치하는 속성이다. float 속성은 레이아웃을 위한 속성이라기 보다는 주로 텍스트 안에
이미지를 삽입할 때에 사용되지만 다른 속성들과 함께 레이아웃을 작성하는 곳에 요긴하
게 사용할 수 있다.
position
position은 static, relative, absolute의 세가지 값을 가질 수 있다.
.. static : 기본값.
.. relative : static과 같지만 offset을 지정 할 수 있고 하위 엘리먼트 offset의 기준점이 된
다.
.. absolute : 화면상에서 다른 컨텐츠에 위치에 영향을 미치지 않고 위치 지정이 가능하다.
보통 레이어라고 불리우는 것.
실전 웹 표준 가이드
- 72 -
float
float은 left, right, none의 세가지 값을 가질 수 있다.
.. left : 엘리먼트를 좌측으로 배치함.
.. right : 엘리먼트를 우측으로 배치함.
.. none : float시키지 않음
레이아웃을 작성 할 때에 position을 이용할 것인지, float를 이용할 것인지 선택하는 문제
는 명확한 정답이 있는 것은 아니다. 각 방법들이 장단점을 가지고 있기 때문에 주어진 환
경에 맞게 적절한 속성을 선택할 수 있어야 한다. position은 블록의 크기가 크게 유동적
이지 않고 코드 상에서의 위치에 구애 받지 않고 블록을 위치 시킬때 사용한다. position
을 사용하면 코드상에서 제일 하단에 있는 블록을 페이지의 상단으로 이동 시킬 수 있을
정도로 자유로운 블록의 배치가 가능하다. 이에 반해 float은 지정된 위치에서 좌측 또는
우측으로만 배치가 가능하기 때문에 position과 같이 자유로운 블록 배치는 힘들다. 하지
만 float된 블록의 높이가 유동적으로 변경되어도 레이아웃 조정이 손쉽기 때문에 보통 컬
럼을 사용해야 하는 레이아웃에 사용된다.
기본 레이아웃
국내 웹사이트에서 일반적으로 많이 볼 수 있는 간단한 레이아웃을 position 속성을 이용
해서 제작 한다.
마크업(Markup)
페이지 제작을 위해 먼저 markup을 작성한다. 이 markup작성 단계에서는 디자인이나
CSS를 고려하지 않고 제작을 한다. 페이지를 구성하는 구성요소가 무엇이고 각 구성요소
들의 그룹에 따라서 의미에 맞는 태그와 id, class를 적용하여 markup을 구성한다.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<title>Simple CSS Layout</title>
</head>
<body>
<div id="head">Site Top Area</div>
<hr>
<div id="sub">Site Left Area</div>
<hr>
<div id="body">Main Content Area
</div>
<hr>
<div id="foot">Site Bottom Area</div>
</body>
</html>
실전 웹 표준 가이드
- 73 -
레이아웃 구성을 보기 위해서 상단(#head), 서브(#sub), 내용(#body), 하단(#foot) 만으
로 이루어진 페이지 이다. 제작된 markup을 보면 디자인적인 markup이 전혀 포함되어
있지 않고 단지 영역을 구분지어 주는 div들과 id로만 이루어 진 것을 알 수 있다.
<table>을 이용하여 레이아웃을 작성하게 되면 markup에서 영역이 좌측에 위치 하게 되
는지 우측에 위치하게 되는지 이미 결정지어지게 된다. 하지만 CSS를 이용한 레이아웃에
서는 markup에는 이러한 디자인 적인 정보가 없어서 CSS만을 이용하여 레이아웃을 쉽
게 바꿀 수 있게 된다. 제작된 결과를 브라우져에서 보면 오른쪽 같이 단순히 위에서 아래
로 나열되는 모습을 볼 수 있다.
CSS
markup이 의미에 맞게 작성이 되었으면 CSS를 이용하여 디자인을 적용한다. CSS를 이
용하여 디자인을 적용 할때에 가장 먼저 고려 해야 하는 것은 브라우져 고유의 스타일이
다. 모든 브라우져들은 태그마다 고유의 스타일을 가지고 있다. 예를 들어서 h1은 페이지
에서 가장 중요한 타이틀이기 때문에 가장 큰 글씨를 보여준다든가 ul과 li를 사용하면 li
마다 앞에 불렛(bullet)을 표시한다든가 하는 것이다. 레이아웃을 작성할 때에는 이러한
기본 스타일중에서 body의 기본 스타일을 고려해 주어야 한다. 스타일 없이 HTML문서
를 제작할 경우 화면의 가장자리에 여백이 있는 것을 볼 수 있다. 이 body의 여백을 아래
과 같이 처리한 경우를 쉽게 볼 수 있다.
<body topmragin="0" leftmargin="0" marginheigth="0" marginwidth="0">
하지만 이 속성들은 HTML 4.01 이상의 버젼에서는 사라진 속성이기 때문에 이렇게 사용
해서는 안되고 CSS를 이용해서 처리해 주어야 한다. CSS로는 아래와 같이 하여 화면가장
자리의 여백을 없앨 수 있다.
body {
margin: 0;
실전 웹 표준 가이드
- 74 -
padding: 0;
}
보통은 margin만 사용하면 여백이 없어지지만 여백의 조절을 padding으로 하는 브라우
져가 있기 때문에 두개 다 적용시키는 것이 좋다.
다음으로 각 부분을 구분하는 <hr>은 디자인을 적용하면 화면상에서는 없어져야 하기 때
문에 안보이게 처리를 한다. <hr>같은 엘리먼트는 텍스트 환경에서 각 부분을 구분지어주
는 역할을 하기 때문에 삭제하지는 말고 코드에는 적용을 하고 스타일로 보이지 않게 해
주는 것이 좋다.
hr {
display:none;
}
Site Top Area(#head)는 사이트 로고나 상단 메뉴, 비주얼이 들어가는 영역인데 고정된
높이를 갖는 경우가 많다. #head에는 높이만을 적용하고 화면에서 구분을 할 수 있게 바
탕에 색만 지정을 해 준다.
#head {
height: 170px;
background: #eee;
}
Site Left Area(#sub)는 사이트의 좌측 영역으로 서브네비게이션이나 섹션의 타이틀, 배너,
검색 등이 들어가게 된다. 이 #sub는 비교적으로 높이가 고정적이고 컨텐츠 영역의 좌측
에 항상 위치하기 때문에 고정적으로 absolute position을 사용하여 위치 시킨다.
#sub {
position: absolute;
top: 170px;
left: 0;
width: 160px;
}
여기까지를 적용해 보면 오른쪽과 같다.
#sub에 absolute position을 사용했기 때문에 Site Left Area와 Main Content Area가
겹쳐진 것을 볼 수 있다. absolute position의 경우 화면에서 위치를 차지하지 않기 때문
에 Site Top Area 바로 아래에 Main Content Area가 위치하게 된 것이고 Site Left
Area가 그 위에 겹쳐지게 된 것이다. 보통 레이어라고 일컬어 지는 것이 바로 이
실전 웹 표준 가이드
- 75 -
absolute position을 이용한 block의 다른 이름이다.
Main Content Area는 padding을 써서 간단하게 Site Left Area와 분리할 수 있다. 여기
서 margin을 사용하지 않고 padding을 사용한 이유는 padding을 사용하여 Site Left
Area까지 포함하여 #body에 background 속성을 사용할 수 있게 하기 위함이다.
#body {
padding-left: 170px;
width: 700px;
}
보통의 이러한 2단 레이아웃의 경우 좌측 영역과 컨텐츠 영역 사이에 구분선과 같은 디자
인이 들어가게 되는 Site Left Area는 absolute position을 사용했기 때문에 높이가 유동
적이지 못하고 구분선을 사용할 수가 없다. 그래서 구분선을 background-image를 사용
하여 #body에 적용해 주게 된다. 또한, Site Left Area에 absolute position을 사용했기
때문에 Main Content Area의 높이가 Site Left Area의 높이보다 작을 경우 Site Left
Area가 Site Bottom Area를 덮어버릴 수가 있다. 그래서 Main Content Area가 항상
Site Left Area보다 높게 지정해 준다.
#body {
padding-left: 170px;
width: 700px;
background: url(body.gif) repeat-y 170px 0;
min-height: 400px;
}
마지막으로 Site Bottom Area에 높이와 색을 지정해주면 간단한 레이아웃이 완성된 모습
을 볼 수 있다.
relative와 absolute의 관계
대부분의 사이트가 이 position 속성을 absolute만 사용을 해서 단지 레이어 개념으로만
사용하고 있다. 이 absolute position은 relative position과 같이 사용하면 보다 다양하고
자유로운 위치 조정이 가능해 진다. absolute position을 사용했을때, top, left, right,
bottom의 속성으로 offset을 지정하게 된다. 보통의 경우는 이 absolute position 블록의
실전 웹 표준 가이드
- 76 -
상위에 아무것도 없기 때문에 이 offset이 브라우져의 좌상단을 기준으로 지정이 된다. 하
지만 absolute position 블록의 상위에 relative position 블록이 있으면 이 offset의 기준
이 상위의 relative position 블록의 좌상단이 된다.
<div id="board-list" class="freeboard-item">
<ul id="board-list-item">
<li>
<div class="number">
26
<!-- ArticleSeq: 271 -->
</div>
<div class="title">
<a href="view.jsp?articleSeq=271">자연속 </a>
</div>
<div class="name">
김치홍
</div>
<div class="date">
2005-11-16
</div>
<div class="hits">
22
</div>
</li>
...
...
...
</ul>
</div>
각 <li>에는 div.number, div.title, div.name, div.date, div.hits 블록이 있다.
#board-list-item li {
position: relative;
width: 548px;
border-bottom: 1px solid #EBDDD4;
color: inheret;
}
#board-list li div.number,
#board-list li div.date,
#board-list li div.hits {
top: 7px;
}
#board-list li div.title {
padding-top: 7px;
padding-bottom: 5px;
}
#board-list div.number {
position: absolute;
left: 0;
width: 79px;
text-align: center;
}
#board-list div.title {
margin-left: 90px;
width: 297px;
}
#board-list div.date {
position: absolute;
right: 57px;
width: 92px;
text-align: center;
}
#board-list div.hits {
position: absolute;
right: 0;
width: 57px;
text-align: center;
}
div.freeboard-item div.name {
실전 웹 표준 가이드
- 77 -
position: absolute;
top: 10px;
right: 150px;
width: 55px;
height: 1.5em;
text-align: center;
overflow: hidden;
}
div.freeboard-item div.title {
width: 252px !important;
}
<li>는 relative position이고 하위의 div들은 div.title을 제외하고는 absolute position
이다. 그러면 이 하위의 div들은 브라우져의 좌상단을 기준으로 top과 left같은 offset이
지정되는 것이 아니라 <li>의 좌상단을 기준으로 위치가 지정되게 된다. 따라서 좌상단을
기준으로 정렬 되는 것 처럼 서로 겹치게 되는 것이 아니라 <li>안에서 위치가 결정 되므
로 이와 같은 <li>들을 이용해서 게시판의 리스트 화면을 만들 수도 있다. 단, 이 예에서
div.title은 static position을 사용해서 <li>의 기본적은 크기를 유지해 주어야 하고, 다른
div들은 div.title보다 높이가 높아져서는 안된다.
컬럼형 레이아웃
블로그와 같은 사이트에 볼 수 있는 컬럼형 레이아웃 제작에는 float 속성이 적합하다.
Markup
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<title>Simple CSS Layout</title>
</head>
<body>
<div id="wrapper">
<div id="head">Site Top Area</div>
<hr>
<div id="sub">Site Left Area</div>
<hr>
<div id="body">Main Content Area</div>
<hr>
<div id="sidebar">Side Bar</div>
실전 웹 표준 가이드
- 78 -
<hr>
<div id="foot">Site Bottom Area</div>
</div>
</body>
</html>
float 속성을 이용해서 레이아웃을 작성 할때에는 컬럼전체의 폭을 고정하기 위해서 바깥
쪽에 감싸는 블록 하나를 두어야 한다. 여기서는 #wrapper로 전체 사이트를 감싸 주었다.
겉으로 보기에는 컬럼을 차지하는 Side Bar만 추가되었다. 랜더링된 화면은 이전의 예와
크게 다를 것 없이 수직적으로 해당 섹션들이 나열된 형태인 것을 볼 수 있다.
CSS
기본적인 CSS 설정은 이전에 다루었던 부분과 같다. body의 margin을 없애주고, hr을 보
이지 않게 한다. 그리고 사이트 전체의 폭과 중앙 정렬을 위해서 #wrapper와 body에 스
타일을 적용한다.
#wrapper {
width: 700px;
border: 1px solid #eee;
margin: 20px auto;
}
이렇게 하면 화면의 중앙에 정렬된 모습을 볼 수 있다. 추가적으로 Site Top Area와 Site
Bottom Area를 구분하기 위해서 배경을 넣어준다.
#head {
height: 80px;
background: #eee;
}
#foot {
height: 30px;
background: #eee;
}
float 속성을 이용해서 블록을 배치하는 방법은 아주 간단하다. 단지 폭을 정해주고 좌측
이나 우측에 정렬을 해주면 하나의 블록이 하나의 컬럼을 형성하면서 레이아웃을 작성 할
수 있다. 그리고 #foot에서는 float된 블록들을 clear시켜 주어서 #foot블록과 float된 블
록들이 겹치지 않게 해 준다.
실전 웹 표준 가이드
- 79 -
#sub,
#body,
#sidebar {
float: left;
}
#sub,
#sidebar {
width: 150px;
}
#body {
width: 400px;
height: 450px;
}
#foot {
clear: both;
}
블록이나 엘리먼트를 float할때에는 항상 width나 height를 지정해 주어서 확실한 영역을
차지하도록 하게 하고 float이 끝난 위치 바로 다음에 오는 엘리먼트에서는 clear시켜주어
서 전체 모양이 일그러 지지 않게 주의 해야 한다.
컬럼으로 이루어진 레이아웃에서는 각 컬럼들 사이에 경계선을 넣는 경우가 많다. 하지만
지금과 같은 경우 float된 블록에 border로 경계선을 넣게 되면 원하는 결과가 나오지 않
게 된다. 가장 긴 블록을 기준으로 경계선이 아래까지 내려와야 하는데 float되면 자신이
포함하고 있는 컨텐츠의 높이 만큼만 영역이 확보 되기 때문에 하단까지 border가 생기지
않는다. 그래서 지금과 같은 경우는 #wrapper에 background 속성을 이용해서 경계선을
표현하게 된다.
#wrapper {
background: url(body-col.gif) repeat-y 150px 0;
}
이렇게 하면 3단의 컬럼형 레이아웃이 만들어 진다.
float와 clear
float 속성은 하위의 블록에 영향을 미치기 때문에 이 float 속성을 없애주는 clear 속성을
같이 사용해야 한다. 가장 기본적인 clear 속성의 사용은 float된 블록이나 이미지가 더이
상 하위에 영향을 미치지 않게 하기 위해서 사용한다.
실전 웹 표준 가이드
- 80 -
컨텐츠 이미지에 float 속성을 사용하게 되면 이미지를 원하는 방향에 정렬 할 수 있다 하
지만 컨텐츠의 길이에 따라서 원하지 않는 결과가 나오기도 한다.
왼쪽의 경우 float된 이미지가 하위의 블록에 영향을 미쳐서 페이지 레이아웃이 이상하게
된 것을 볼 수 있다. 이럴때에는 하위블록의 엘리먼트에 clear 속성을 주어서 float된 이
미지의 속성을 없애주면 오른쪽과같이 정상적으로 정렬을 할 수 있다.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Float and Clearing</title>
<style type="text/css">
body {
margin: 0;
padding: 0;
}
#wrapper {
width: 700px;
margin: 20px auto;
}
img {
width: 280px;
height: 200px;
float: left;
margin: 0 1em 1em 0;
}
h2 {
clear: both;
}
</style>
</head>
<body>
<div id="wrapper">
<h2>코뿔소</h2>
<img src="rhinoceros.png" alt="코뿔소">
<p>코뿔소는 말목 포유동물이다.</p>
<h2>악어</h2>
<img src="alligator.png" alt="악어">
<p>악어는 약 2 억 2 천만년 전에 분화한 것으로 알려진 파충류이다. 전세계적으로
23 종이 알려져 있다.</p>
</div>
</body>
</html>
이것은 일반적인 clear의 사용이고, float 속성을 이용해서 레이아웃을 작성하게 되면 아래
와 같은 경우를 접하게 된다.
실전 웹 표준 가이드
- 81 -
<div id="articles">
<ul id="notice">
...
</ul>
<ul id="news">
...
</ul>
<ul id="stats">
...
</ul>
</div>
article은 세개의 하위 리스트를 포함하는 블록이고 하위의 ul은 모두 float를 사용하여 가
로로 배치되어 있다. 이때에 상위 블록인 #articles에 background속성으로 색을 지정해
주면 색이 나타나지 않는 것을 알 수 있다. float된 ul들은 화면상에서 공간을 차지 하지
않기 때문에 #articles가 float된 ul만을 하위에 가지고 있으면 #articles의 높이가 0이 되
어서 마치 배경색이 적용이 안되는 것같이 보이게 된다. 이를 해결하기 위해 과거에는 새
로운 엘리먼트를 추가하거나 content속성을 이용하는 등 여러가지 방법이 있었지만 지금
은 overflow 속성을 이용해는 방법이 가장 좋은 방법으로 여겨지고 있다.
#articles {
width: 700px;
margin: 20px auto;
background: #ddd;
overflow: auto;
}
위와 같이 상위 엘리먼트에 overflow에 auto값을 주게 되면 원하는 배경색이 나오는 것
을 볼 수 있다.
목록(List)
웹사이트 컨텐츠의 절반은 리스트라고 할 수 있을 정도로 리스트는 컨텐츠에서 상당히 많
이 사용되는 형태이다.
세가지 목록
.. ul (unordered list) : 순서가 없는 리스트
.. ol (ordered list) : 순서가 있는 리스트
.. dl (definition list) : term(<dt>), definition(<dd>) 쌍으로 이루어진 리스트
목록의 여백과 모양
list를 나타내는 엘리먼트의 가장 큰 특징은 불렛이나 번호 등이 자동으로 나온다는 것이
다. 그래서 이렇게 자동으로 출력되는 것들의 스타일을 원하는대로 정할 수 있어야 한다.
<dl>은 자동으로 출력되는 것이 없고 단지 <dd>에 기본마진이 있는 것만 신경써서 스타
일을 정의해 주면 된다. <ol>, <ul>은 하나의 <li> 좌측에 기본적으로 여백이 생기고 이
여백에 불렛 등이 나오게 된다. 문제는 이 여백의 조정인데 각 브라우져들 마다 이 여백의
조정이 다르게 구현되어 있다. 예를 들어서 Firefox와 Safari는 padding을 이용해서 이
여백을 조정하게 되는 반면에 Internet Explorer나 Opera 등에서는 margin을 이용해서
이 여백을 조정하게 된다. 그리고 이 불렛이나 숫자의 모양을 직접적으로 제어할 수 있게
되어 있는 list-style 속성도 브라우져별로 차이가 많다. list-style을 위부 이미지 등으로
대체 하여도 정확한 위치를 조절할 수 있는 속성이 없기 때문에 여백의 위치를 조정하게
실전 웹 표준 가이드
- 82 -
되면 이 역시 브라우져 별로 다를 모양으로 나오게 된다. 스펙에는 marker를 이용해서
이 문제를 해결 하는 방법을 제시해 놓고 있지만 실제적으로 많은 브라우져에서 이를 구
현해 놓고 있지 않기 때문에 기존의 list관련된 속성을 이용해서 list에 스타일을 적용하는
문제는 쉬운 일이 아니다.
background 속성을 이용한 bullet의 표시
브라우져 호환성과 list관련된 CSS속성의 특성때문에 이들을 이용해서 list에 디자인을 적
용하기는 힘들고 보통의 경우 background속성을 이용하여 디자인을 적용한다.
background속성을 이용하기 위해서 우선은 브라우져 기본 속성을 초기화 해 준다.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"
/>
<title>Unordered List</title>
<style type="text/css">
ul {
margin: 0;
padding: 0;
list-style: none;
}
</style>
</head>
<body>
<ul>
<li>list item1</li>
<li>list item2</li>
<li>list item3</li>
</ul>
</body>
</html>
이렇게 하면 아무 스타일도 적용되지 않은 세줄의 텍스트와 같이 나오게 된다. 이 <li> 엘
리먼트에 background 속성을 이용해서 불렛디자인을 적용하게 된다.
li {
background: url(bullet.gif) no-repeat 0 0.25em;
padding-left: 15px;
}
실전 웹 표준 가이드
- 83 -
박스 모델(Box Model)
Box model
그림 24 CSS 박스 모델
실전 웹 표준 가이드
- 84 -
위의 그림은 CSS Box model을 한장의 도표로 나타낸 것이다. Box는 컨텐츠 영역(width,
height), 패딩영역(padding), 보더영역(border), 마진영역(margin), offset(top, right,
bottom, left)으로 구성되어 있다. 가장 안쪽의 컨텐츠 영역은 width 속성과 height 속성
으로 그 크기가 결정된다. 그리고 그 밖으로 패딩, 보더, 마진 영역이 있다. 그리고
position 속성과 함께 지정되는 offset이 있게 된다. 실제적으로 화면에서 보이는 영역은
컨텐츠, 패딩, 보더 영역이고 그 외곽의 마진과 offset은 실제적으로 화면상에서 box라고
인식 되어지지는 않는다.
여기서 가장 주의 해야 하는 것은 컨텐츠 영역의 크기이다. 보통 table을 이용해서 작업하
는 것에 익숙한 사람들이 가장 많이 혼동하는 것이 width의 크기를 컨텐츠 영역의 너비
로 인식하지 않고 실제로 눈에 보이는 box의 크기로 인식을 하는 것이다. 즉, width를 실
제로 눈에 보이는 영역인, width + padding + border의 영역으로 인식하는 것이다. 이것
이 CSS2의 box 랜더링과 IE의 box 랜더링이 가장 큰 차이를 보이는 사항이다. CSS2에서
는 width나 height를 컨텐츠가 들어갈 수 있는 영역으로 나타내기 때문에 padding이나
border를 적용하게 되면 눈에 보이는 box의 크기는 커지게 된다.
IE의 DOCTYPE Switching
IE는 box모델을 비롯하여 다른 여러 랜더링 특성이 표준과 다르기 때문에 독특한 방법으
로 표준을 지원하고 있다. IE의 경우 오랫동안 표준과 다른 랜더링을 유지해 왔기 때문에
갑자기 표준을 지원한다고 하여 랜더링 특성을 바꾸게 되면 이미 IE에 맞춰진 수 많은 사
이트들이 IE에서 정상적으로 나오지 않게 될 것이다. 그래서 IE의 trident 엔진은 호환 랜
더링과 표준 랜더링 두개의 랜더링 모드를 지원한다. 호환 랜더링 모드는 IE의 하위버전
호환성을 위해서 이전의 IE랜더링을 유지한 모드이고 표준 랜더링 모드는 W3C의 CSS
스펙에 의거한 랜더링을 해주는 모드이다. 이 호환 랜더링과 표준 랜더링의 선택은 문서에
DOCTYPE을 어떻게 선언하는지에 따라서 달라지게 된다.
HTML과 같은 markup언어는 현재 문서에서 사용되고 있는 엘리먼트나 속성들을 따로
정의하고 그 기준에 따라서 작성하게 된다. 이러한 정의를 document type definition이라
고 하고 markup 문서의 최 상단에 아래와 같은 방식으로 선언을 하게 된다.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
IE는 이 DOCTYPE 선언이 표준대로 선언이 되었는가, 아니면 선언이 되지 않았거나 다
른 DTD를 선언하였는가에 따라서 랜더링 모드를 선택하게된다. 따라서 이 선언을 하지
않거나 다른 DTD를 선언하게 되면 호환 랜더링 모드를 선택하게 되고 box에 padding
이나 border를 적용하게 되면 컨텐츠 영역인 width나 height가 줄어들게 된다. 그러나
이 DOCTYPE선언을 HTML 4.01이나 XHTML 1.0과 같이 W3C의 선언을 정확하게 할
경우 CSS스펙대로 width나 height영역이 변화 없이 컨텐츠의 영역을 나타내게 된다.
또 하나 주의해야 하는 것이 DOCTYPE 선언을 정확히 했다고 하더래도 DOCTYPE 선
언 이전에 어떠한 문자라도 나오게 되면 호환 모드로 랜더링이 되게 된다. 보통은
DOCTYPE 선언 이전에 어떠한 이유로 인해 주석이 나타나게 되면 호환랜더링 모드로 전
환이 되어서 페이지가 원하는 대로 나오지 않는 경우가 많다. DOCTYPE 선언 이전에 서
버사이드 코드가 들어가게 되면 출력되는 문자가 없게 주의해야 한다.
DOCTYPE 선언이 없으면 유효한 HTML문서가 아니기 때문에 반드시 DOCTYPE을 사
실전 웹 표준 가이드
- 85 -
용해야 한다. 하지만 호환성의 문제로 표준 랜더링을 사용하지 않아야 하는 경우가 있는데
이럴 경우에는 역으로 상단에 주석 구문을 추가 해서 호환 랜더링을 사용할 수 있다. 하지
만 이러한 버그 현상은 IE7에서는 이미 수정되었고, 새로 구축되는 사이트의 경우 앞으로
의 호환성에 더 중점을 두어 표준 랜더링을 사용하는 것이 좋다.
중앙 정렬
사이트가 화면의 중앙에 정렬되어야 하는 레이아웃의 경우 <table> 엘리먼트에 고정된 폭
을 지정해 주고 align="center"를 이용해서 정렬 할 수 있었다. 하지만 CSS를 이용한 레
이아웃에서는 이러한 방법으로는 구현이 안되고 margin 속성을 이용해서 동일할 효과를
낼 수 있다.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<title>center alignment</title>
<style type="text/css">
#content {
width: 300px;
padding: 1em;
border: 1px solid #999;
margin: 0 auto;
line-height: 1.5em;
}
</style>
</head>
<body>
<div id="content">
<p>margin 의 auto 값을 이용해서 보다 다양한 레이아웃을 제작 할 수
있다.</p>
</div>
</body>
</html>
폭이 일정한 <div> 엘리먼트에 좌우 margin을 auto로 설정하면 브라우져는 최적의
margin 값을 찾게 되고 <div> 엘리먼트는 화면의 가운데에 정렬이 되게 된다.
IE5 Tuning
IE5는 위와 같이만 하면 중앙정력이 되지 않고 추가적인 속성이 더 필요 하다. IE5에서는
margin: auto가 정상적으로 작동하지 않기 때문에 텍스트 자체를 중앙정렬 해 줄 필요가
있다.
<style type="text/css">
body {
text-align: center;
}
#content {
width: 300px;
padding: 1em;
border: 1px solid #999;
margin: 0 auto;
line-height: 1.5em;
}
</style>
이렇게 하면 box는 가운데 정렬이 되었지만 box안의 텍스트가 모두 가운데 정렬이 된 것
을 볼 수 있다. 이 텍스트 정렬을 기본값으로 돌리기 위해서 #content에 다시 텍스트 정
실전 웹 표준 가이드
- 86 -
렬을 해 준다.
#content {
width: 300px;
padding: 1em;
border: 1px solid #999;
margin: 0 auto;
line-height: 1.5em;
text-align: left;
}
화면 정 중앙에 위치 시키기
<table> 엘리먼트를 이용할 때에는 valign이나 height="100%" 와 같은 속성들을 이용해
서 세로 정렬을 자유롭게 할 수 있지만 CSS에서는 이것이 그렇게 쉽지만은 않다.
vertical-align 속성
CSS의 vertical-align속성은 적용되는 엘리먼트에 따라서 다른 기능을 보인다. 가장 일반
적으로 많이 사용되고 이해하기 쉬운것은 <td> 엘리먼트에 적용되는 것이다. <td>에 적
용된 vertical-align 속성은 HTML의 valign 속성과 같은 기능을 한다. 즉, 셀 안의 컨텐
츠를 셀 높이의 중앙에 위치 시킨다. vertical-align 속성을 <td> 엘리먼트 외의 사용할
수 있는 곳은 inline 엘리먼트이다. inline 엘리먼트의 가장 대표적인 예는 일반 텍스트,
<img>, <input> 엘리먼트 등이다. HTML에서 텍스트를 입력하게 되면 텍스트는 하나의
inline 엘리먼트를 생성하고 그 안에 위치 하게 된다. vertical-align 속성은 이렇게 생성
된 inline 엘리먼트에서의 세로 정렬을 의미한다.
<img> 엘리먼트도 inline 엘리먼트인데 <img> 엘리먼트에 vertical-align 속성의 값을
middle로 지정하면 텍스트 inline 엘리먼트 안에서 세로로 가운데에 정렬이 된 것을 볼
수 있다. 예를 들어서 검색 컨트롤을 만들게 될 때 <select> 엘리먼트와 <input> 엘리먼
트와 텍스트가 가운데로 정렬이 안되서 <table>을 따로 만들어 그 안에 넣고 중앙 정렬을
해본 경험들이 아마 있을 것이다. 이럴때에 유용하게 사용할 수 있는 속성이 verticalalign
속성이다.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<title>inline vertical alignment</title>
<style type="text/css">
body {
font-size: 0.75em;
}
</style>
</head>
<body>
<form action="">
<p>
내용 검색 :
<select>
<option>전체</option>
<option>제목</option>
<option>이름</option>
<option>내용</option>
</select>
<input type="text">
<input type="image" src="btnSearch.gif" alt="검색">
실전 웹 표준 가이드
- 87 -
</p>
</form>
</body>
</html>
vertical-align이 적용되지 않은 좌측은 검색 버튼이 약간 올라갔지만 우측은 같은 선상에
정렬 된 것을 볼 수 있다.
* {
vertical-align: middle;
}
vertical-align 속성은 inline 엘리먼트에 적용되는 속성이기 때문에 가로세로 완전히 중앙
에 블록을 위치 시키기에는 적합하지 않은 속성이다.
position 속성과 negative margin
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<title>inline vertical alignment</title>
<style type="text/css">
#middle {
position: absolute;
top: 50%;
left: 50%;
width: 258px;
height: 250px;
margin: -125px 0 0 -129px;
border: 1px solid #aaa;
}
</style>
</head>
<body>
<div id="middle">
<img src="pages.png" alt="iWork Pages">
</div>
</body>
</html>
화면의 중앙에 위치 시켜야 하기 때문에 absolute position을 사용하고 offset을 50%씩
준다. 그러면 위치시키고자 하는 엘리먼트의 좌상단이 화면의 정 중앙에 오게 될 것이다.
이 상태에서 블록의 크기의 절반 만큼을 margin으로 적용하되 음수로 적용하여 반대로
이동하게 한다. 그러면 위치하고 자 하는 엘리먼트의 정 중앙이 화면의 정중앙과 일치 하
게 된다.
실전 웹 표준 가이드
- 88 -
이 방법은 정확히 화면의 정 중앙에 엘리먼트를 위치 시키고 브라우져 창의 크기를 변화
시켜도 중앙을 유지 하지만 margin값으로 음수를 사용했기 때문에 브라우져의 크기가 엘
리먼트의 크기보다 작아질 경우 화면 밖으로 위치해버리게 되어 엘리먼트의 일부분이 보
이지 않게 된다. 그래서 이 방법을 사용할 때에는 너무 큰 엘리먼트에는 적용하지 않도록
주의 해야 한다.
100%의 높이를 유지하는 레이아웃
사이트 푸터 부분을 브라우져 크기와 상관 없이 항상 하단에 위치 시키고 컨텐츠의 높이
가 브라우져의 높이를 넘어가면 자동으로 스크롤 바가 생기면서 푸터 부분이 브라우져 아
래로 넘어가야 한다. 우선 전체 높이를 유지하기 위해서는 높이가 100%인 블록을 이용하
고 100%를 넘어가면 브라우져 화면 아래로 넘어가게 하기 위해서 height 속성을 이용하
지 않고 min-height 속성을 이용한다.
<div> 엘리먼트를 높이 100%로 유지하기 위해서는 먼저 height에 % 단위로 값을 지정
하는 것의 의미를 파악해야 한다. % 단위로 값을 넣을 때 이 % 값의 기준은 상위 엘리먼
트가 된다. 다시 말해서 상위 엘리먼트의 높이가 100px라면 100%의 높이는 100px가 되
고 50%의 높이는 50px가 된다. 레이아웃을 작성하기 위해서는 <body> 엘리먼트 바로
하위에 100% 높이를 유지하는 <div> 엘리먼트가 와야 한다. 하지만 <div> 엘리먼트에
height: 100%를 적용하여도 높이가 브라우져 높이만큼 유지되지 않는 것을 볼 수 있다.
이 이유는 상위 엘리먼트인 <body>의 높이가 100%가 아니기 때문이며, 마찬가지로
<body> 엘리먼트 상위의 <html> 엘리먼트도 높이가 100%가 아니기 때문이다. 그래서
100% 높이를 이용하고자 할 때에는 <html> 엘리먼트와 <body> 엘리먼트의 높이를 우
선 100%로 고정해 주어야 한다.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
실전 웹 표준 가이드
- 89 -
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"
/>
<title>Full height layout</title>
<style type="text/css">
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#head {
height: 100px;
background: #ddd;
position: relative;
z-index: 1;
}
#body {
min-height: 100%;
margin: -100px 0 -50px;
}
#content-area {
padding: 100px 0 50px;
height: 300px;
}
#foot {
height: 50px;
background: #ddd;
}
</style>
<!--[if IE]>
<style type="text/css">
#body {
height: 100%;
}
</style>
<![endif]-->
</head>
<body>
<div id="head">
head(height 100pixel)
</div>
<div id="body">
<div id="content-area">
content area
</div>
</div>
<div id="foot">
foot(height 50pixel)
</div>
</body>
</html>
화면의 높이를 100%로 확보하고 사이트의 전체 높이를 100%로 유지 하기 위해서
#body에 min-height: 100%를 적용한다. min-height 속성은 최소의 높이를 지정해주는
속성인데 컨텐츠의 높이가 지정된 min-height보다 낮으면 그 값을 유지하고 높이가 넘칠
경우 auto로 높이를 설정해 준다. 이렇게 하면 #body의 높이가 브라우져의 높이와 일치
되지만 IE는 min-height 속성이 구현되어 있지 않기 때문에 다른 방법으로 구현을 해야
한다. IE의 경우 min-height 속성은 구현되어 있지 않지만 height 속성이 이 min-height
속성과 같은 역할을 한다. IE에서는 컨텐츠가 블록의 높이나 너비보다 크게 되면 블록의
크기가 커지는 것을 볼 수 있다. 이와 같은 역할을 해 주는 것이 height이지만 height를
지정할 경우 다른 브라우져에서는 고정된 높이를 갖기 때문에 하나의 속성으로 이 두가지
를 구현 할 수 있는 방법은 없다.
IE는 자체적으로 IE만을 위한 코드를 적용하기 위해서 conditional comment라는 기능을
실전 웹 표준 가이드
- 90 -
제공하고 있다. 코멘트와 같이 표시된 부분이 조건에 따라서 다르게 작동하게 되는 기능을
말한다. 컨디셔널 코멘트는 아래와 같이 사용한다.
<!--[if IE]>
Code for Internet Explorer
<![endif]-->
그냥 보기에는 주석구문이지만 [if IE], [endif] 구문으로 IE에서만 작동하는 코드를 넣을
수 있다. 이 구문에는 not 연산자(!)나 less than 연산자(lt), 버전 표시(IE 5)와 같이 IE의
종류에 따라서 적용되는 코드들을 넣을 수 있다. IE의 경우에는 이 구문을 해석하지만 다
른 브라우져에서는 이 구문은 그냥 주석 구문이기 때문에 건너뛰게 된다. 이 컨디셔널 커
멘트를 이용해서 IE에서는 min-height를 height로 대체하여 작동 될 수 있게 한다.
<style type="text/css">
#body {
height: 100%;
}
</style>
<![endif]-->
위와 같이 하면 IE에서는 min-height 속성은 구현이 안되어 있으므로 무시되고 height:
100%가 적용된다. 다음에는 이미 높이가 확보되어 있는 #head와 #foot을 100% 높이에
서 제외시기키 위해 negative margin을 이용하고 #content-area에서는 padding을 이용
해서 영역을 확보 해 준다.
가장 좌측은 브라우져의 높이가 충분한 경우이고 우측은 브라우져의 높이가 충분하지 않
아서 세로 스크롤 바가 생긴 경우이다. 브라우져 사이즈를 변화시켜 보면 브라우져의 높이
에 따라서 푸터의 위치가 변하는 것을 볼 수 있다.
테이블(Tables)
CSS레이아웃을 적용할 때 사람들이 의도적으로 테이블 사용을 피하는 것을 볼 수 있다.
하지만 이는 잘못된 행동이며 표 형태로 표현해야 하는 데이터의 경우는 당연히 <table>
엘리먼트를 사용해야 한다. 데이터 테이블은 <thead>, <tbody>, <tfoot>, <th>, <td> 등
실전 웹 표준 가이드
- 91 -
다양한 태그를 사용해서 구성하게 되고 이렇게 다양한 태그를 이용해서 제작된 테이블은
접근성도 높아지고 CSS에서도 참조가 쉽위지기 때문에 의미에 맞는 태그를 사용해서 테
이블을 표현하는 것이 중요하다.
테이블에 디자인을 적용할 때 대부분의 사람들은 아래와 같이 cellpadding과 cellspacing
값을 조정한다.
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td>example</td>
</tr>
</table>
cellpadding은 셀 경계면과 컨텐츠 사이의 패딩 영역을 나타내고 cellspacing은 셀간의
간격을 나타낸다. border는 셀 경계선을 나타내고 기본값이 0이므로 생략해도 무방하다.
<table> 엘리먼트에 대부분 기본적으로 적용하는 속성은 다 디자인 적인 요소이고 의미를
나타내는 것이 아니기 때문에 CSS로 처리 하는 것이 더욱 적합하다. cellpadding은 <th>
나 <td> 엘리먼트의 padding으로 제어하고 cellspacing은 border-collapse 속성으로 제
어 한다.
table {
border-collapse: collapse;
}
table th,
table td {
padding: 0;
}
<table> 엘리먼트는 기본적으로 복잡한 width calculation algorithm을 거쳐서 랜더링
되는데 이 알고리즘은 셀안의 컨텐츠와 셀에 지정된 width를 바탕으로 최적의 테이블 레
이아웃을 계산하는 것이다. 대부분 <table>과 <td>에 정확히 width를 지정을 해도 지정
한 대로 width가 나오지 않는 경험을 한 적이 있을 것이고 이때문에 <img
src="blank.gif" width="100"> 을 이용해서 width를 강제로 고정하는 방법도 본적이 있
을 것이다. 이렇게 정확한 폭을 지정하기가 힘들고 복잡한 알고리즘을 거쳐서 랜더링 속도
가 떨어지게 되는데 이를 table-layout이라는 속성을 이용해서 보완 할 수 있다.
table-layout 속성의 기본 값은 auto인데 기본 값일 때에는 테이블이 많이 중첩될 수록
랜더링 속도도 떨어지고 정확한 width 적용이 힘들다. 이 속성의 값을 fixed로 하게 되면
width 계산과정도 없고 정확하게 지정된 값으로 width가 정해지게 된다.
table {
table-layout: fiexd;
}
table-layout: fixed를 사용할때 주의 해야 할 점은 이 속성이 적용된 테이블은 셀의 너비
를 첫번째 줄의 셀의 너비에 맞게 강제로 정해진다는 것이다. 즉, 첫번째 줄의 속성 외의
다른 줄의 width 값은 무시가 되고, 특정 값이 정해 지지 않으면 정해지지 않은 셀의 너
비 만큼 균등하게 나누어서 셀의 너비가 정해진다. 만약에 첫번째 줄에 colspan등을 사용
하여서 모든 셀의 너비를 지정할 수 없을 때에는 <colgroup> 엘리먼트와 <col> 엘리먼
트를 이용해서 너비를 지정해 주게 된다.
<table>
<colgroup>
<col style="width: 150px;">
<col style="width: 100px;" >
<col style="width: 50px;" >
실전 웹 표준 가이드
- 92 -
</colgroup>
<tr>
<td colspan="2">colspan 이 적용 되어서 원하는 너비를 지정할 수
없다.</td>
<td>cell2</td>
</tr>
<tr>
<td style="width: 50px;">이 셀의 너비는 무시된다.</td>
<td style="width: 100px;" >이 셀의 너비는 무시된다.</td>
<td style="width: 150px;" >이 셀의 너비는 무시된다.</td>
</tr>
</table>
마지막 <tr>의 <td>에 너비를 지정 하였지만 table-layout: fixed;가 적용된 상태에서는
첫번째 줄의 너비만을 참조 하기 때문에 150pixel, 100pixel, 50pixel 순으로 너비가 결정
된다.
오른쪽과 같은 데이터는 다른 태그를 사용해서 표현 하는 것 보다 테이블 태그를 사용해
서 표현 하는 것이 좋다.
<table class="data product-data">
<thead>
<tr>
<th colspan="2"><img
src="/Product/img/dataDivision.gif" alt="구분"></th>
<th><img src="/Product/img/dataStandard.gif"
alt="규격치"></th>
</tr>
</thead>
<tbody>
<tr>
실전 웹 표준 가이드
- 93 -
<th colspan="2">외관</th>
<td>노란색</td>
</tr>
<tr>
<th colspan="2">옥탄가</th>
<td>91 이상~94 미만</td>
</tr>
<tr>
<th rowspan="5">증류성상(℃)</th>
<th>10% 유출온도</th>
<td>70 이하</td>
</tr>
<tr>
<th>5% 유출온도</th>
<td>125 이하</td>
</tr>
<tr>
<th>90% 유출온도</th>
<td>175 이하</td>
</tr>
<!-- 중략 -->
<tr>
<th colspan="2">메탄올 함량(무게%)</th>
<td>0.1 이하</td>
</tr>
</tbody>
</table>
CSS Hack
browser issue
HTML이나 CSS는 W3C에서 제정한 표준이다. 그리고 이 표준을 토대로 하여 브라우져
만드는 회사에서 자신의 브라우져에 구현을 하게 된다. 이 과정에서 브라우져 만드는 회사
들이 W3C 의 표준을 완전히 잘 구현을 해 낸다면 별로 문제될 것이 없지만 실제로 브라
우져 만드는 회사들 마다 CSS의 구현 정도에 차이가 있다. Microsoft의 Internet
Explorer 6는 우리가 가장 많이 사용하고 있는 브라우져이지만 출시가 된지 많은 시간이
지나서 CSS 의 구현 정도가 다른 브라우져보다는 미약하다. 그리고 다른 브라우져들 끼리
도 구현된 CSS 스펙이 다르고, 어떠한 브라우져는 스펙을 잘못 구현한 경우도 있다. 가장
좋은 것은 최신의 스펙을 구현한 브라우져를 모든 사람들이 사용하는 것이겠지만 현실적
으로 불가능 하기 때문에 웹사이트를 제가할 경우 반드시 하위버젼 호환성과 브라우져 호
환성을 염두에 두어야 한다.
Browser specific code
CSS hack은 표준은 아니고 브라우져들 간의 CSS 해석 오류나 차이를 이용하여 특정 브
라우져만을 위한 CSS를 만드는 방법이다. 일차적으로는 표준을 준수하여 CSS를 작성을
하고 브라우져들에서 테스트를 해 보고 CSS를 해석하는데 있어서의 차이를 각 브라우져
별로 hack을 사용하여 없애는 것이다. CSS Hack 자체가 고의적으로 에러를 발생시키는
것이라고 볼 수도 있기 때문에 CSS Hack의 사용에 대해서는 아직 논쟁이 많다. 하지만
현재까지 나온 CSS Hack들은 경험적으로 여러번 테스트를 거쳤기 때문에 사용해도 큰
문제가 없고 다양한 브라우져를 지원하기 위해서 어쩔 수 없이 사용해야 하는 경우도 있
다.
실전 웹 표준 가이드
- 94 -
Microsoft Internet Explorer 용 CSS hack
div.ie-hack {
width: 100px;
padding: 20px;
}
* html div.ie-hack {
width: 140px; /* IE width */
}
IE의 경우 표준 DTD 를 사용하여 표준 모드의 랜더링을 사용하지 않으면 padding과
border의 해석이 표준과 다르게 처리된다. 표준에서는 100pixel width에 20px의
padding을 적용하면 화면에서 차지하는 블록의 너비는 140pixel이 되지만 IE 는 여전히
100pixel로 표현 된다. 따라서 표준에 맞게 랜더링이 되게 하기 위해서 IE에서는 width
를 140pixel로 해주어야 한다. "* html E" selector를 사용하게 되면 다른 브라우져들은
html 상위 element가 존재하지 않기 때문에 인식이 안되지만 IE는 인식을 하게 되고 블
록의 크기가 140pixel이 된다.
Microsoft Internet Explorer 5 용 CSS hack
div.ie5-hack {
padding: 20px;
width: 140px;
voice-family: "\"}\"";
voice-family: inherit;
width: 100px; /* IE5 ignore this line */
}
IE6 는 표준 모드와 호환모드 두개의 랜더링 모드를 가지고 있다. 이 것은
<!DOCTYPE>을 선언 하는 것으로 제어가 되는데 <!DOCTYPE> 을 표준으로 선언하게
되면 IE6는 표준 스펙을 따라서 랜더링이 되고 <!DOCTYPE> 선언을 다르게 하거나 하
지 않으면 호환모드로 랜더링이 된다. IE5는 이와 같은 doctype switching을 지원하지 않
기 때문에 표준모드를 사용하게 되면 IE6와 IE5는 서로 다르게 화면을 랜더링 하게 된다.
그래서 표준 모드를 지원 하지 않는 IE5를 위한 CSS hack을 사용해야 하는 경우가 발생
한다. 위의 코드를 이용하게 되면 IE 5는 첫번째 voice-family 선언에서 "}" 을 CSS 선언
의 종료로 인식하고 CSS 선언이 끝난 것으로 해석하게 된고 width는 140pixel이 된다.
반면 다른 현대 브라우져들은 그 다음줄도 인식을 하기 때문에 width는 100pixel이 된다.
이 외에도 CSS Hack은 브라우져 별로 많은 종류가 있다. 하지만 대부분의 브라우져 사용
자들은 최신 버젼으로 자신들의 브라우져를 업데이트 하여 사용하는 빈도가 많기 때문에
다른 브라우져용 hack을 사용하는 경우는 매우 드물다. hack을 사용해야 하는 대상들은
보통 컴퓨터 사용에 익숙하지 않아서 처음 설치되어 있는 IE 브라우져를 그냥 사용하는
사람들이기 때문에 요즘에는 거의 IE용 hack외에는 사용되는 경우가 드물다. 그리고 만약
사용자가 구형 브라우져를 사용하여 CSS가 제대로 해석되지 않다라도 마크업이 완전하면
디자인은 완전하지 않더라도 컨텐츠를 이용하는 데에는 불편이 없기 때문에 충분한 접근
성을 보장 할 수 있다.
실전 웹 표준 가이드
- 95 -
실전 예제를 통한 CSS 레이아웃
지금까지는 간략하고 부분적인 CSS디자인 적용 방법들을 살펴 보았다. 이 장에서는 실제
디자인된 사이트를 분석해 보고 각 단계에서 필요한 부분들을 알아 봄으로써 하나의 완성
된 페이지를 만드는데 필요한 사항들을 살펴 보겠다.
설전 예제로 분석해볼 페이지는 재정경제부의 재경부 안내페이지이다
URL: http://www.mofe.go.kr/about/about_01.php
전체적인 구조와 마크업
전체 페이지 구조를 제작할 때에는 가장 중요한 기준은 화면 구성요소의 의미와 그들 간
의 그룹핑이다. 페이지를 구성하고 있는 요소들의 관계와 그룹핑 데이터가 마크업에 반영
이 되어야 한다. 기존의 테이블을 이용한 레이아웃에서는 이러한 관계와 그룹핑 정보를 마
크업에 넣는 것이 불가능 하지만 CSS와 div를 이용한 레이아웃에서는 이러한 데이터를
포함 시키는 것이 가능하고 이렇게 함으로써 보다 의미에 맞는 마크업을 제작할 수 있게
된다. 재경부의 서브페이지는 크게 4부분으로 구분이 되어 있다.
실전 웹 표준 가이드
- 96 -
.. 사이트의 로고와 상단 메뉴
.. 좌측메뉴
.. 컨텐츠 영역
.. 사이트 하단
각 부분들은 하나의 div 안에 구성되어 있고 각자의 고유한 id를 갖게 된다. 이 id는 해
당 div의 이름이면서도 그 div의 역할과 의미를 표현하는 적절한 것을 선택해야 한다. 예
를 들어서 id="b_e-13" 과 같은 id는 그 id만을 봐서는 무슨 의미 인지 전혀 알 수 없고
코드를 읽는 사람에게 어려움을 주게 되므로 피해야 하고 간결하면서도 의미를 잘 나타내
주는 단어를 선택해야 한다. 이 id는 javascript가 DOM을 통해 엘리먼트에 접근할 때에
나 CSS selector에서 rule을 정의할 때 사용하게 된다.
DTD(Document Type Definition)의 선택
마크업 작성에 있어서 가장 먼저 고려해야 하는 것은 어떠한 DTD를 따라서 페이지를 작
성할 것인가 하는 점이다. DTD는 문서의 작성방법과 여러 태그네임과 속성등을 경정 짓
기 때문에 선택에 있어서 신중을 기할 필요가 있다.
우선은 HTML을 이용할 것인지, XHTML을 이용할 것인지를 정하게 된다. HTML과
XHTML의 가장 큰 차이는 XML의 문법 규칙을 따르게 되는지 그렇지 않는지 이다.
XML문법을 딸게 된다면 XHTML을 사용하게 될 것이고 그렇지 않다면 HTML을 사용
하게 될 것이다. 그리고 그 다음으로는 디자인 적인 요소를 완전히 사용하지 않고 CSS로
대체할 것인지 아닌지를 판단해야 한다. 디자인 적인 요소를 완전히 사용하지 않을 것이라
면 Strict DTD를 사용하고 그렇지 않다면 Transitional DTD를 사용하게 된다.
많은 사람들이 웹표준이라고 하면 당연히 XHTML을 사용해야 하는 것으로 생각하는데
이는 올바른 생각이 아니다. DTD를 선택한다는 것은 정해진 문법 규약을 따르겠다의미이
기 때문에 선택한 DTD에 따라서 표준이거나 비표준이 아니고 반드시 XHTML을 사용할
필요는 없다. 그리고 XHTML을 사용하게 된다면 XML문법을 완벽하게 지켜서 페이지를
제작해야 하기 때문에 만약 그러한 준비가 되어 있지 않은 상황이라면 XHTML을 사용하
는 것 보다는 HTML을 사용하는 것이 더 바람직하다.
그리고 XHTML은 단순히 문법뿐만이 아니라 mime-type도 XML의 것을 따르겠다는 의
미이다. 특히나 XHTML 1.1은 application/xml+xhtml mime-type으로 배포되어야 함에
도 불구하고 많은 사람들이 text/html 로 배포하고 있는 경우가 많다. 이것과 같이 규약
을 정확히 지키지 못하게 된다면 차라리 HTML 4.01 Strict를 사용하고 정확한 문법을 지
키는 것이 훨씬 더 좋은 선택이다.
재정경제부는 XHTML 1.0 Transitional DTD로 제작이 되었다.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr"
/>
<title>재정경제부에 오신 것을 환영한다.</title>
</head>
<body>
<div id="head">
</div>
실전 웹 표준 가이드
- 97 -
<hr />
<div id="sub">
</div>
<hr />
<div id="body">
</div>
<hr />
<div id="foot">
</div>
</body>
</html>
각 부분들은 <hr />을 이용하여 의미적으로 명확하게 구분을 해 준다. 텍스트 브라우져와
같이 완전한 스타일을 볼 수 없는 상황에서 페이지 구분을 명확하게 해 준다. 이 구분은
일반 브라우져에서는 스타일로 보이지 않게 처리 된다.
상단 부분(#head)
상단 부분인 #head에는 사이트 로고와 사이트메뉴, 상단메뉴가 위치하게 된다.
<div id="head">
<h1><a href="/"><img src="/images/nav/logo.gif" alt="재정경제부"
/></a></h1>
<div id="site-menu">
<ul>
<li><a href="http://english.mofe.go.kr/"><img
src="/images/nav/siteMenu01.gif" alt="English" /></a></li>
<li><a href="http://kids.mofe.go.kr/"><img
src="/images/nav/siteMenu02.gif" alt="어린이 홈페이지" /></a></li>
<li><a href="/guide/sitemap.php"><img
src="/images/nav/siteMenu03.gif" alt="사이트맵" /></a></li>
</ul>
</div>
<div id="top-navigation">
<ul class="depth1">
<li class="menu-1"><a
href="/news/news_01_latest.php">재경부뉴스</a>
<ul class="depth2">
<li class="menu-1-1"><a
href="/news/news_01_latest.php">보도자료</a></li>
<li class="menu-1-2"><a
href="http://mofe.news.go.kr/" target="_blank">재경부뉴스 </a></li>
<li class="menu-1-3"><a
href="/news/news_03.php?action=list">언론보도해명</a></li>
<!-- 이하 메뉴 생략 -->
</ul>
</li>
<li class="menu-2"><a href="/lib/">경제정보</a>
<ul class="depth2">
<li class="menu-2-2"><a
href="/lib/lib_02.php?action=list">함께읽고싶은보고서</a></li>
<li class="menu-2-1"><a
href="/lib/lib_01_01.php">간행물</a></li>
<!-- 이하 메뉴 생략 -->
</ul>
</li>
<!-- 메뉴 생략 -->
</ul>
<script type="text/javascript">
initTopNavigation();
</script>
</div>
</div>
사이트 로고는 페이지에서 가장 중요하기도 하고 상단 부분에서도 가장 중요한 부분이기
실전 웹 표준 가이드
- 98 -
때문에 <h1> 태그를 사용하였다. 그리고 나머지 메뉴 부분들은 메뉴의 리스트 이기 때문
에 <ul> 태그를 사용하였고 하나의 메뉴 아이템은 하나의 <li> 태그로 나타내어 진다. 그
리고 그 하위의 메뉴가 있을 경우에는 <li> 안의 메뉴 다음에 <ul>을 이용해서 표기가
되어 있다. 그리고 끝부분에 javascript를 이용하여 전체 메뉴의 효과를 지정해 준다. 이
javascript 부분은 상당히 중요한 역할을 하는 부분이지만 이 글에서 논하기에는 범위를
벗어나는 부분이기 때문에 상세히 다루지는 않겠다. 한가지 특기할 만한 사항은 이
javascript가 현재 text로 되어 있는 메뉴 항목을 이미지로 바꾸어 주는 역할을 한다는 것
이다. 메뉴를 텍스트로 넣고 javascript로 바꾸는 방법을 택한 것은 표준이나 접근성과는
별개의 문제이고 사이트의 유지 관리의 효율성을 위한 것으로 이 역시 이 글에서 다룰 범
위는 아니기 때문에 자세한 언급은 하지 않겠다.
기본 CSS구조
한개의 페이지라면 그렇지 않겠지만 사이트 전체를 CSS를 이용해서 제작하게 되면 CSS
가 상당히 덩치가 커지고 복잡해 지게 된다. 따라서 CSS의 구조와 그에 따른 범위를 명확
히 정하지 않게 되면 차후에 유지관리가 매우 힘들어 지기 때문에 이를 미리 명확하게 규
정지을 필요가 있다.
CSS파일들은 각 파일들의 범위에 따라서 구분을 지어주는 것이 좋다. 물론 전체 CSS파일
이 일 이백줄 내외로 간단하다면야 굳이 파일을 분리할 필요는 없겠지만 사이트가 커지게
되면 하나의 파일로는 관리도 안되고 다른 사람과 협업을 할 때에도 conflict가 많이 발생
하기 때문에 의미와 섹션별로 구분을 해 주는 것이 좋다. 그리고 실제 디자인과는 관련이
없지만 항상 기본적으로 설정해 주어야 하는 파일 같은 것도 따로 구분을 해 주는 것이
좋다. 아래는 재정경제부의 기본 element 설정을 해 주는 base.css 파일이다.
@charset "euc-kr";
/*
* default definition
*/
body {
margin: 0;
padding: 0;
font-size: 0.75em;
line-height: 1.5em;
font-family: Dotum, "돋움", sans-serif;
}
form {
margin: 0;
padding: 0;
}
hr {
display:none;
}
li img {
vertical-align: middle; /* for IE imge margin */
}
p, div, th, td, select {
color: #78777C;
}
a:link, a:visited {
color: #78777C;
text-decoration: none;
}
a:active, a:hover {
text-decoration: underline;
}
img,
input.type-image {
실전 웹 표준 가이드
- 99 -
border: 0 none;
}
input.type-text,
textarea {
border-top: 1px solid #797979;
border-right: 1px solid #D4D1C8;
border-bottom: 1px solid #D4D1C8;
border-left: 1px solid #797979;
background: #fff;
}
input.type-text:hover,
input.type-text:focus,
textarea:hover,
textarea:focus {
background-color: #FFFFCE;
}
input, select, textarea {
vertical-align: middle;
font-size: 1em;
color: #78777C;
}
span.button,
img.button,
a.button {
cursor: pointer;
vertical-align: middle;
}
base.css에서는 <body>엘리먼트나 <form>, <img> 엘리먼트등 기본 설정이 필요한 엘리
먼트들과 폰트정의 등과 같이 사이트 전반에 따라서 설정해 주어야 하는 rule들이 있다.
<form>을 사용하면 공백이 생겨서 <tr> 사이에 넣는 경우가 있는데 이는 HTML상으로
도 오류이기 때문에 잘못된 이용이다. <form>에 기본 여백이 있기 때문인데 이러한 것과
같이 기본 설정이 필요한 것들의 설정들이 포함되어 있다. 이 base.css는 모든 페이지에서
포함해야 하는 파일이다. 실제적으로 지금 디자인작업을 하게되는 파일은 layout.css이고
이 layout.css 상단에서 아래와 같이 base.css를 포함하게 된다.
@charset "euc-kr";
@import url("base.css");
폭이나 높이가 고정되어 있는 경우
페이지의 상단이나 하단과 같이 높이가 고정되어 있는 경우, 그리고 좌측과 같이 너비가
고정되었는 경우와 같이 유동적인 크기를 반영해 줄 필요가 없는 경우에는 position 속성
을 이용해서 위치를 설정해 주기가 수월하다.
우선은 #head의 크기와 배경을 지정하고 하위 엘리먼트에서 absolute position을 사용하
기 위해서 position속성을 relative로 설정해 준다.
#head {
position: relative;
height: 92px;
overflow: hidden;
background: url(/images/nav/head.gif) repeat-x 0 64px;
}
로고가 들어 있는 h1은 absolute position을 사용해서 위치를 설정해 준다.
#head h1 {
position: absolute;
top: 8px;
left: 14px;
margin: 0;
z-index: 5;
}
실전 웹 표준 가이드
- 100 -
<h1>~<h6>까지의 태그에 스타일을 적용할때에는 항상 이 엘리먼트에 기본적으로
margin이 있다는 것을 염두에 두어야 한다. 이것을 정확히 파악하지 못할 경우 "알 수 없
는 이유"로 여백이 발생하여 어려움을 겪을 수 있다. 이것은 다른 <p>나 <ul>과 같은 엘
리먼트에도 적용 된다.
사이트 메뉴는 가로로 배치되어 있는 리스트 이다. 일단은 로고와 같이 absolute position
으로 위치를 지정하고 <li>를 float시켜주어서 가로로 배치하게 된다. <ul>은 대부분의 경
우 커스터마이징 된 불렛을 사용하기 때문에 보통 margin, padding, list-style등을 초기
화 한 후에 디자인을 적용한다.
#site-menu {
position: absolute;
top: 7px;
left: 558px;
width: 170px;
z-index: 2;
}
#site-menu ul {
width: 170px;
margin: 0;
padding: 0;
list-style: none;
}
#site-menu ul li {
float: left;
}
상단 메뉴는 좌측 하단의 그라데이션 부분을 처리하기 위해서 로고 영역부터 사이트 우측
경계까지 넓게 자리 잡고 있다. 그리고 하위의 메뉴들을 위해서 relative position으로 되
어 있다.
#top-navigation {
position: relative;
width: 939px;
height: 91px;
background: url(/images/nav/topNav.gif) no-repeat 0 64px;
}
하위의 메뉴들은 리스트 형태이고 이를 absolute position으로 위치를 잡는다. 그리고 좌
측으로 배열하기 위해서 <li> 엘리먼트를 float 시켜준다.
#top-navigation ul.depth1 {
position: absolute;
top: 24px;
left: 211px;
margin: 0;
padding: 0;
list-style: none;
z-index: 2;
height: 40px;
}
#top-navigation li {
float: left;
}
그 하위의 서브 메뉴는 기본적으로는 탑메뉴와 동일하다. 단, 메뉴의 구동 자체가
javascript로 이루어져 있기 때문에 일부 javascript의 도움을 얻어서 디자인을 적용한 것
이 있다. 각 서브메뉴 항목들을 구분지어주는 사선의 경우 서브 메뉴의 <li>에
background 속성을 이용하여 이미지를 삽입한 것인데 첫번째 <li>는 사선이 없어야 하
기 때문에 이것을 javascript로 처리 하였다. 그리고 각 메뉴별로 위치는 특별한 규칙이
없기 때문에 길이에 따라서 CSS로 정의 하였다.
실전 웹 표준 가이드
- 101 -
#top-navigation ul.depth2 {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
left: 0;
width: 800px;
bottom: -27px;
display:none;
}
#top-navigation ul ul.depth2 li {
background: url(/images/menu/top.gif) no-repeat;
padding-left: 6px;
}
#top-navigation li.menu-1 ul.depth2 {
left: 0;
}
#top-navigation li.menu-2 ul.depth2 {
left: -10px;
}
#top-navigation li.menu-3 ul.depth2 {
left: 135px;
}
#top-navigation li.menu-4 ul.depth2 {
left: 115px;
}
#top-navigation li.menu-5 ul.depth2 {
left: -20px;
}
#top-navigation li.menu-6 ul.depth2 {
left: -165px;
width: 1040px;
}
#top-navigation li.menu-7 ul.depth2 {
left: 190px;
}
좌측 영역 (#sub)
좌측은 페이지의 현재 메뉴명과 서브메뉴, 검색, 외부 링크 영역으로 이루어져 있다.
<div id="sub">
<div id="visual"></div>
<h1><a href="/about/about_01.php"><img
src="/images/nav/heading/about.gif" alt="재경부안내" /></a></h1>
<div id="sub-navigation">
<ul class="depth2">
<li class="menu-7-1"><a
href="/about/about_01.php">인사말</a></li>
<li class="menu-7-2"><a
href="/about/about_02_1.php">부총리/차관</a>
<ul class="depth3">
<li class="menu-7-2-1"><a
href="/about/about_02_1.php">부총리 프로필</a></li>
<li class="menu-7-2-2"><a
href="/about/about_02_2.php">제 1 차관 프로필</a></li>
<!-- 메뉴 항목 생략 -->
</ul>
</li>
<li class="menu-7-3"><a
href="/about/about_03_1.php">재정경제부는</a>
<ul class="depth3">
<li class="menu-7-3-1"><a
href="/about/about_03_1.php">소개</a></li>
<li class="menu-7-3-2"><a
href="/about/about_03_2.php">연혁</a></li>
<!-- 메뉴 항목 생략 -->
실전 웹 표준 가이드
- 102 -
</ul>
</li>
<!-- 메뉴 항목 생략 -->
</ul>
</div>
<script type="text/javascript">
initSubNavigation();
</script>
<form action="/about/man_search.php" method="post" name="membersearch-
form">
<div id="search-member">
<h2><label for="layout-memger-search-name"><img
src="/images/nav/searchMemberH2.gif" alt="직원검색" /></label></h2>
<input id="layout-memger-search-name" name="name"
type="text" class="type-text" />
<input name="image" type="image"
src="/images/nav/btnGo.gif" alt="GO" />
<input type="hidden" name="flag" value="3" />
</div>
</form>
<div id="ext-link">
<div class="link1">
<h2><a href="#ext-link1">실국 홈 바로가기</a></h2>
<div id="ext-link1" class="list">
<ul>
<li class="menu-8"><a
href="/division/off_pm/">정책홍보관리실</a></li>
<li class="menu-9"><a
href="/division/off_tc/">세제실</a></li>
<!-- 메뉴 항목 생략 -->
</ul>
</div>
</div>
<div class="link2">
<h2><a href="#ext-link2">소속기관 바로가기</a></h2>
<div id="ext-link2" class="list">
<ul>
<li><a
href="http://www.publicfund.go.kr/kor_pf/index.html">공적자금관리위원회
</a></li>
<li><a
href="http://www.ntt.go.kr/">국세심판원</a></li>
<!-- 메뉴 항목 생략 -->
</ul>
</div>
</div>
<div class="link3">
<h2><a href="#ext-link3">재경부 소관 공공기관</a></h2>
<div id="ext-link3" class="list">
<ul>
<li><a
href="http://www.shinbo.co.kr">신용보증기금</a></li>
<li><a
href="http://www.komsco.com/">한국조폐공사</a></li>
<!-- 메뉴 항목 생략 -->
</ul>
</div>
</div>
<div class="link4">
<h2><a href="#ext-link4">관련 연구소</a></h2>
<div id="ext-link4" class="list">
<ul>
<li><a
href="http://www.kdi.re.kr/">한국개발연구원</a></li>
<li><a
href="http://www.kiep.go.kr/">대외경제정책연구원</a></li>
<!-- 메뉴 항목 생략 -->
실전 웹 표준 가이드
- 103 -
</ul>
</div>
</div>
<script type="text/javascript">
initExtLink();
</script>
</div>
</div>
좌측 영역에서 가장 중요한 현재 메뉴 타이틀은 <h1> 태그를 사용하였다. 그리고 메뉴들
은 상단과 마찬가지로 중첩된 <ul> 엘리먼트를 사용하였다. 검색 부분에서의 타이틀은 좌
측 영역의 서브격의 타이틀 이기 때문에 <h2> 태그를 사용하였고 <form>과 <label>,
<input>을 이용해서 구성되고 있다. 외부 링크는 링크의 나열이기 때문에 <ul>을 사용하
고 <div> 태그로 각각을 그룹핑해주고 있다. 그리고 javascript로 좌측과 외부 링크 영역
을 제어하고 있기 때문에 <script> 태그가 사용되고 있다.
서브 영역은 absolute position을 이용해서 위치가 정해져 있다.
#sub {
position: absolute;
top: 92px;
left: 0;
width: 209px;
z-index: 5;
}
그리고 비주얼 영역과 타이틀 영역의 크기와 여백을 정해 준다. 비주얼 영역은 처음에는
계획 되었지만 현재는 별 의미가 없는 블록이다. 즉 현재는 신경쓰지 않아도 되는
garbage 코드이다.
#visual {
width: 209px;
height: 121px;
}
#sub h1 {
margin: 33px 0 22px 12px;
}
좌측 메뉴는 여백과 배경 이미지 만으로 구현 되어 있다.
#sub #sub-navigation {
margin: 15px 0 0;
}
#sub #sub-navigation ul.depth2 {
margin: 0;
padding: 0 0 2px;
list-style: none;
background: url(/images/nav/subNavigation.gif) no-repeat 0 100%;
}
#sub #sub-navigation ul.depth3 {
margin: 0 0 0 24px;
padding: 2px 0 3px 4px;
list-style: none;
background: url(/images/menu/subD3.gif) no-repeat 0 100%;
display:none;
}
* html #sub #sub-navigation ul.depth2 li {
height: 1%;
}
* html #sub #sub-navigation ul.depth2 li img {
float: left;
}
마지막 두개의 CSS rule은 앞에도 소개가 되어 있는 IE용 CSS hack이다.
실전 웹 표준 가이드
- 104 -
IE의 hasLayout 속성과 리스트 오류
IE의 랜더링 오류중의 상당수가 hasLayout이라는 속성과 관련이 있다. 보통의 블록들은
hasLayout 속성일 false 인데 이 경우 CSS의 랜더링이 정상적으로 이루어 지지 않는 경
우가 많다. 이때에 해당 블록에 width나 height를 지정해 주게 되면 hasLayout속성이
true로 바뀌게 되고 이렇게 되면 표준대로 랜더링 되는 것을 자주 경험할 수 있다. 여기서
도 li에 height: 1%를 적용함으로써 hasLayout 속성을 true로 바꿔주고 랜더링 오류를
고친 것이다.
그리고 아래의 <img> 엘리먼트를 float시켜준 것은 <li>안에 margin이 없음에도 불구하
고 <li> 엘리먼트 끼리 공간이 생기는 것을 방지하기 위한 것이다. float시키는 방법 외에
도 line-height 속성을 조정하거나 font-size: 1px와 같이 <li>안의 것의 크기를 아주 작
게 만들면 해결이 되곤 한다.
검색 부분은 배경 이미지와 여백의 조정으로 구현 된다.
#search-member {
background: url(/images/nav/searchMember.gif) no-repeat;
padding: 8px 0 13px 15px;
margin: 10px 0 10px 10px;
}
#search-member h2 {
margin: 0 0 10px;
}
외부 링크는 같은 형태의 리스트 4개가 있는 모양인데 클릭이 이루어 지는 부분은 타이틀
인 <h2>로 되어 있고 화면에 나오는 리스트 부분은 <ul>로 되어 있다. 이들 각각은 하나
의 relative position 블록 안에 위치 하게 된다.
#ext-link {
background: #FAF9F2;
padding: 3px 3px 0;
width: 173px;
margin: 5px 10px 0;
overflow: visible;
}
#ext-link h2 {
width: 164px;
font-size: 0.9em;
line-height: 21px;
background: url(/images/nav/extLinkH2.gif) no-repeat;
padding: 2px 0 0 9px;
margin: 0 0 3px;
}
#ext-link div.link1,
#ext-link div.link2,
#ext-link div.link3,
#ext-link div.link4 {
position: relative;
}
이 리스트들은 클릭했을 때에 다른 것들 보다 맨 위에 있어서 리스트 내용 전체가 나와야
하는데 나중에 생성된 블록의 높이가 높기 때문에 현재와 같은 상태에서는 아래의 타이틀
이 리스트 위로 올라오는 것을 볼 수 있다. 이를 해결 하기 위해서 타이틀과 리스트의 zindex를
조절해 준다.
#ext-link div.link1 {
z-index: 7;
}
#ext-link div.link1 div {
z-index: 8;
실전 웹 표준 가이드
- 105 -
}
#ext-link div.link2 {
z-index: 5;
}
#ext-link div.link2 div {
z-index: 6;
}
#ext-link div.link3 {
z-index: 3;
}
#ext-link div.link3 div {
z-index: 4;
}
#ext-link div.link4 {
z-index: 1;
}
#ext-link div.link4 div {
z-index: 2;
}
화면상에서위에 위치하는 것의 z-index는 아래의 것보다 크고 클릭시 나오는 리시트의 zindex는
자신을 포함하는 블록의 z-index보다 커야 한다.
여기까지 되었으면 나머지는 여백과 위치, 색등을 지정해 주면 된다.
#ext-link div.link1 h2 a {
color: #534C41;
}
#ext-link div.link2 h2 a {
color: #676054;
}
#ext-link div.link3 h2 a {
color: #7D7465;
}
#ext-link div.link4 h2 a {
color: #948876;
}
#ext-link div.list {
position: absolute;
top: 21px;
left: 0;
display:none;
background: url(/images/nav/extLinkUl.gif) no-repeat 0 100%;
}
#ext-link div.list ul {
margin: 0;
padding: 5px 9px 2px;
width: 156px;
list-style: none;
}
한가지 특징적인 것은 리스트의 디자인을 나타내기 위해서 이미지를 단 하나만을 사용했
다는 것이다. 원래대로라면 리스트의 아래 부분과 리스트의 중간 부분을 두개로 나누어서
해야 했겠지만 리스트의 길이가 아주 유동적인 것도 아니고 이미지가 복잡하지 않아서 용
량 문제가 별로 심하지 않을 경우 하나의 이미지로 제작하는 것이 HTML도 간소화 해지
고 작업에 있어서의 효율성도 늘어 나게 된다. 그리고 이미지의 갯수가 줄어들기 때문에
서버의 부하도 줄어들게 된다는 장점이 있다.
본문 영역 (#body)
보통의 본문 영역의 경우 좌측 영역과의 구분이라든가 본문 영역의 구분을 위해서 배경이
미지를 사용하게 된다. 그리고 본문 영역은 본문의 길이의 제한이 없어야 되기 때문에 이
배경 이미지는 repeat-y 속성을 이용해서 세로의 구분을 해 주는 경우가 많다. 재정경제
실전 웹 표준 가이드
- 106 -
부 홈페이지 역시 세로의 구분선이 존재 하지만 이에 더에서 emboss와 drop shadow를
이용한 이미지도 구분을 위해서 사용이 되고 있다. 배경이미지는 하나의 div에 하나밖에
사용할 수가 없기 때문에 이와같은 레이아웃을 구현하기 위해서 #body-wrapper라는
div블록을 하나 더 추가 한다.
그리고 #body안에는 오늘의 날짜를 표현해 주는 #current-date와 페이지의 현재 위치를
나타내는 #location, 페이지의 타이틀을 나타내는 h1.content가 모든 페이지에 존재 하게
된다.
<div id="body-wrapper">
<div id="body">
<div id="current-date">2005.12.11 (일)</div>
<div id="location">
<a href="/">HOME</a> :
<a href="/about/about_01.php">재경부안내</a> :
<a href="/about/about_01.php"
class="current">인사말</a>
</div>
<h1 class="content"><img
src="/images/about/heading/greeting.gif" alt="인사말" /></h1>
</div><!-- endof #body -->
</div><!-- endof #body-wrapper -->
#body-wrapper는 세로 구분선을 나타내는 이미지를 repeat-y로 넣는다. 이렇게 하면 실
제적으로는 좌측 영역과 컨텐츠 영역을 모두 포함하면서 세로 구분선을 나타내게 된다.
#body-wrapper {
background: url(/images/nav/bodyWrapper.gif) repeat-y 209px 0;
width: 934px;
margin: 0 0 10px;
}
그리고 그 위에 있는 #body에 drop shadow가 표현된 이미지를 넣고 여백을 조정한다.
#body {
padding: 35px 0 68px 229px;
min-height: 600px;
background: url(/images/nav/news.gif) no-repeat;
}
* html #body {
height: 600px;
}
여기서 주의 해야 할 점은 #body의 최소 높이를 설정하는 것이다. 좌측영역(#sub)을
absolute position을 사용해서 위치 시켰기 때문에 본문 영역이 좌측 영역보다 높이가 낮
아 지게 되면 좌측 영역은 아래 부분이 하단의 푸터 영역을 덮게 된다. 그렇기 때문에 본
문 영역을 좌측 영역보다 항상 높은 위치로 유지 시켜주는 것이 중요하다. 만약 정확한 본
문 영역의 최소 높이를 판단 할 수 없을 때에는 javascript를 이용해서 좌측 영역의 높이
가 본문 영역의 높이보다 높아지게 되는 경우 자동으로 본문 영역이 늘어날 수 있게 해주
는 것이 좋다.
오늘 날짜와 현재 위치는 레이아웃에서 항상 같은 위치에 있기 때문에 absolute position
을 이용하여 위치를 설정한다.
#current-date {
position: absolute;
top: 104px;
left: 212px;
width: 720px;
text-align: right;
실전 웹 표준 가이드
- 107 -
font-weight: bold;
}
#location {
position: absolute;
top: 136px;
left: 212px;
width: 720px;
text-align: right;
line-height: 25px;
font-size: 0.9em;
}
#location a.current {
font-weight: bold;
}
본문의 타이틀은 높이와 여백, 선등을 설정해 주면 된다.
#body h1.content {
height: 18px;
font-size: 14px;
line-height: 40px;
margin: 0 0 12px;
padding: 9px 0 9px 8px;
border-bottom-width: 2px;
border-bottom-style: solid;
}
하단 영역 (#foot)
하단 영역에는 프린트와 탑버튼이 있고 푸터용 로고, 기타링크, 사이트 주소 등이 있다.
<div id="foot">
<div id="page-menu">
<ul>
<li><a href="#head"><img src="/images/nav/btnTop.gif"
alt="Top" /></a></li>
<li><a id="page-print" href="#page-menu"><img
src="/images/nav/btnPrint.gif" alt="Print" /></a></li>
</ul>
</div>
<h1><img src="/images/nav/footLogo.gif" alt="재정경제부" /></h1>
<div id="foot-link">
<ul>
<li><a href="/about/about_07.php"><img
src="/images/nav/footLink01.gif" alt="찾아오시는길" /></a></li>
<li><a href="/guide/privacy.php"><img
src="/images/nav/footLink03.gif" alt="개인정보보호정책" /></a></li>
<li><a href="/guide/copyright.php"><img
src="/images/nav/footLink04.gif" alt="저작권정책" /></a></li>
<li><a href="/guide/"><img
src="/images/nav/footLink05.gif" alt="이용안내" /></a></li>
<li class="email"><a href="/guide/nospam.php"><img
src="/images/nav/footLink06.gif" alt="이메일 무단수집 거부" /></a></li>
<li class="viewer"><a href="/guide/viewer.php"><img
src="/images/nav/footLink07.gif" alt="뷰어다운로드" /></a></li>
</ul>
</div>
<div id="copyright"><img src="/images/nav/footCopyright.gif"
alt="Copyright &copy; 2005 by Ministry of Financial and Economy.
Republic of Korea. All Rights Reserved." /></div>
<address><img src="/images/nav/footAddress.gif" alt="(우) 427-
725 경기도 과천시 관문로 88 번지 정부과천청사 재정경제부 | 대표전화 02-2110-
2332" /><br />
<a href="mailto:forumnet@mofe.go.kr"><img
src="/images/nav/footEmail.gif" alt="Mailto:forumnet@mofe.go.kr"
/></a></address>
</div>
실전 웹 표준 가이드
- 108 -
프린트 버튼과 탑버튼은 컨텐츠 영역의 하단에 위치하고 버튼 리스트 이기 때문에 #foot
맨 위의 list로 표현 된다. 그리고 푸터용 로고는 푸터에서 가장 중요한 제목 이므로 <h1>
을 이용한다. 기타링크는 리스트 이므로 <ul>을 사용하고 사이트 주소는 <address>태그
를 이용한다.
#foot은 #head와 마찬가지로 높이가 고정되어 있으므로 relative position을 사용하면 하
위의 구성 요소들을 위치 잡기가 편리하다.
#foot {
position: relative;
clear: both;
height: 88px;
background: url(/images/nav/foot.gif) repeat-x;
z-index: 0;
}
프린트 버튼과 탑버튼(#page-menu)은 푸터의 영역 밖에 있기 때문에 top offset을 음수
로 지정해 준다. 그리고 다른 가로형 리스트들과 마찬가지로 float을 이용한다.
#page-menu {
position: absolute;
top: -41px;
left: 852px;
}
#page-menu ul {
padding: 0;
margin: 0;
list-style: none;
}
#page-menu li {
float: left;
margin-right: 2px;
}
푸터용 로고는 배경 이미지를 이용하기 위해서 #foot의 좌상단에 꽉 차게 위치를 정하고
#fff로 배경색을 지정하여 가로라인을 가린다. 그리고 안의 <img> 엘리먼트의 여백을 이
용해서 위치를 잡아준다.
#foot h1 {
position: absolute;
top: 0;
left: 0;
margin: 0;
padding: 14px 0 0;
background: #fff;
width: 209px;
}
#foot h1 img {
margin-left: 32px;
}
기타 링크들은 다른 가로형 리스트와 같다.
#foot-link {
padding: 13px 0 6px 209px;
}
#foot-link ul {
padding: 0;
margin: 0;
list-style: none;
height: 17px;
}
#foot-link li {
float: left;
}
실전 웹 표준 가이드
- 109 -
이메일 무단 수집 거부 버튼과 뷰어 다운로드 버튼은 그 위치가 상이 하기 때문에
absolute position을 이용해서 다시 위치를 잡아 준다.
#foot-link li.email {
position: absolute;
top: 22px;
left: 840px;
}
#foot-link li.viewer {
position: absolute;
top: 45px;
left: 840px;
}
나머지 카피라이트 부분과 주소 부분은 여백을 설정해 주는 것으로 간단하게 마무리 할
수 있다.
#copyright,
#foot address {
margin-left: 209px;
}
#copyright img,
#foot address img {
margin-bottom: 3px;
}
완료
이렇게 현재 구현되어 있는 페이지의 스타일을 구간별로 짚어 보면서 제작되어있는 코드
를 살펴 보았다. 사실 CSS디자인이 그 개념을 이해하기 까지는 낯설고 어렵게 느껴질 수
도 있지만 실상 작업을 계속 하다 보면 굉장히 단순하고 반복적인 작업이 많은 것이 사실
이다. 오히려 CSS보다는 XHTML을 구조적으로 작성하고 id, class의 이름을 알아보기 쉽
게 정하는 것이 더 어려운 작업이다. 사실 CSS 레이아웃이나 CSS를 이용해서 디자인을
적용하는 목적 자체가 의미에 맞는 XHTML 제작이라는 것을 생각해 보면 당연한 결과이
기도 하다. 항상 XHTML에 초점을 맞추고 완성도 높은 마크업을 제작할 수 있다면 CSS
를 이용해서 디자인을 적용하는 일은 크게 어렵지 않을 것이다.
실전 웹 표준 가이드
- 110 -
고급 CSS 레이 아웃
CSS를 이용한 디자인 팁
CSS를 이용하면 기존에 우리가 하기 어려웠던 다양한 디자인 효과를 얻을 수 있다. 이 중
몇 가지를 소개해 보고자 한다.
라운드형 박스 디자인
CSS를 이용하여 테이블을 통해 여러 개 파일로 구성해야 하는 디자인도 쉽게 구현이 가
능하다 예를 들어 아래 그림과 같이 제목과 내용이 있는 박스를 디자인 하려면 어떻게 해
야 할까? 대부분 테이블을 떠 올릴 것이다.
그림 25 라운드 박스 표현을 위한 배경 분리
그러나 <div>라는 박스 안에 제목 부분을 <h3>, 목록 부분을 <ul>로 나누어 우선 시맨
틱 마크업을 해보자.
<div class="box">
<h3>Gifts and Special Offers</h3>
<ul>
<li><a href="/purchase/">Purchase Gift Subscription</a></li>
<li><a href="/redeem/">Redeem Gift Subscription</a></li>
<li><a href="/view/">View Purchase History</a></li>
</ul>
</div>
이렇게 한 다음 각각 윗 배경과 아랫 배경 그림을 <h3>과 <div> 속성에 스타일을 지정
하고 표현 하면 테이블로 복잡하게 작성하는 라운드형 박스를 제작할 수 있다.
<style>
.box {
width: 273px;
background: url(img/div-bottom.gif) no-repeat bottom left;
실전 웹 표준 가이드
- 111 -
}
.box h3 {
margin: 0;
padding: 6px 8px 4px 10px;
font-size: 130%;
color: #333;
border-bottom: 1px solid #E0CFAB;
background: url(img/h3-bg.gif) no-repeat top left;
}
.box ul {
margin: 0;
padding: 14px 10px 14px 10px;
list-style: none;
}
.box li {
margin: 0 0 6px;
padding: 0;
}
</style>
이미지의 갯수 줄이기
빠른 로딩, 사용자 친화적인 랜더링)
상속을 고려한 CSS 구조 설계
CSS에서 선언된 속성들은 상속이 가능하다. 즉, 초기에 선언된 내용을 기초로 다양한 선
언들로 재사용 가능한 것이다. 웹 사이트의 메뉴에 따라서 색상을 변경하는 기능을 구현해
보고자 한다. 그러면, 우선 사이트 기본 CSS 파일 ‘default.css’를 작성한다. 여기에는 레
이아웃과 글자 크기에 대한 속성만 정의 한다.
그런 다음 색상 CSS 파일을 ‘color.css’라고 하고 여기에 색상을 정의 한다.
Default.css
h1 {
font-size: 1.4em;
font-weight: bold;
}
Color.css
h1 {
background-color: #f30;
color: #fff;
}
실전 웹 표준 가이드
- 112 -
그림 26 Wired.com을 통해 본 CSS 파일 상속 사례
CSS Switching으로 다양한 페이지 만들기
웹 사이트에서 요구 사항에 보면 하나의 컨텐츠인데도 불구하고 다양한 계층과 단말기를
위한 웹 페이지를 요구하는 경우가 있다. 예를 들어, 유아나 노인을 위해 확대 축소 기능
이 가능한 텍스트 전용 페이지라던지 장애인을 위한 음성 서비스가 포함된 웹페이지, 혹은
모바일 단말기를 위한 모바일 페이지 같은 것들이다.
실전 웹 표준 가이드
- 113 -
그림 27 정보통신부의 텍스트, 시각 장애인, 모바일 페이지
지금까지는 하나의 웹페이지를 만든 다음, 디자인을 변경하여 Copy&Paste 방식의 웹페
이지 과잉 생산을 해왔었다. 이들의 내용은 모두 같아야 하는데도 중복 페이지가 생성되어
관리에 어려움이 있었던 것이 사실이다.
만약 하나의 웹 페이지에 다양한 스타일을 주고 쉽게 변경할 수 있으면 하나의 웹페이지
에서 다양한 요구를 반영할 수 있다. 다국어 홈페이지처럼 내용이 바뀌는 것이 아니라 단
지 디자인이 변경 된다면 더더욱 그렇다.
우선 홈페이지에 다양한 디자인 양식을 아래와 같이 넣는다.
<link rel="stylesheet" type="text/css" href="원본.css"
title="default" />
<link rel="alternate stylesheet" type="text/css" href="텍스트.css"
title="Text" />
<link rel="alternate stylesheet" type="text/css" href="장애인.css"
title="Accessiblity" />
<link rel="alternate stylesheet" type="text/css" href="인쇄용.css"
title="Print" />
<link rel="alternate stylesheet" type="text/css" href="모바일.css"
title="Mobile" />
만약 텍스트 페이지인 경우 레이 아웃은 같지만 이미지가 없는 경우가 된다. 따라서 텍스
트 CSS는 아래와 같은 태그를 넣어 이미지를 없앨 수 있다.
img { display:none; }
그런 다음 자바 스크립트를 이용하여 CSS 자동 변경을 해보고자 한다.
<script type="text/javascript" src="styleswitcher.js"></script>
이렇게 한 다음 페이지 내에 직접 사용자가 클릭할수 있는 링크를 넣고 싶은곳에 레이아
웃 변경 페이지를 넣으면 된다.
<a href="#" onclick="setActiveStyleSheet('Text'); return
false;">텍스트용</a>
<a href="#" onclick="setActiveStyleSheet('Accessiblity'); return
false;">장애인용</a>
<a href="#" onclick="setActiveStyleSheet('Print'); return
false;">인쇄용</a>
<a href="#" onclick="setActiveStyleSheet('Mobile'); return
false;">모바일용</a>
Styleswitcher.js 의 내용은 아래와 같다.
function setActiveStyleSheet(title) {
var i, a, main;
for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
실전 웹 표준 가이드
- 114 -
if(a.getAttribute("rel").indexOf("style") != -1 &&
a.getAttribute("title")) {
a.disabled = true;
if(a.getAttribute("title") == title) a.disabled = false;
}
}
}
function getActiveStyleSheet() {
var i, a;
for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
if(a.getAttribute("rel").indexOf("style") != -1 &&
a.getAttribute("title") && !a.disabled) return
a.getAttribute("title");
}
return null;
}
function getPreferredStyleSheet() {
var i, a;
for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
if(a.getAttribute("rel").indexOf("style") != -1
&& a.getAttribute("rel").indexOf("alt") == -1
&& a.getAttribute("title")
) return a.getAttribute("title");
}
return null;
}
function createCookie(name,value,days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return
c.substring(nameEQ.length,c.length);
}
return null;
}
window.onload = function(e) {
실전 웹 표준 가이드
- 115 -
var cookie = readCookie("style");
var title = cookie ? cookie : getPreferredStyleSheet();
setActiveStyleSheet(title);
}
window.onunload = function(e) {
var title = getActiveStyleSheet();
createCookie("style", title, 365);
}
var cookie = readCookie("style");
var title = cookie ? cookie : getPreferredStyleSheet();
setActiveStyleSheet(title);
동적인 메뉴 레이아웃 구성
CSS 스타일 변경 만으로 레이아웃을 구성하는 각종 항목의 위치를 자유 자재로 변경할
수 있다. 여기서는 가장 알맞은 예제 사이트를 소개한다.
그림 28 스타일 변경으로 레이아웃 변경 사례 (http://PhonoPhunk.phreakin.com)
CSS 개발 및 검증 도구
많은 웹 개발자들이 XHTML/CSS 개발을 메모장에서 하고 있는 경우가 많다. 왜냐하면,
나모 웹에디터나 드림위버 같은 웹 에디터들이 원하지 않는 코드를 생산해 내는 경험 때
문이다. 이로 인해, 코드 생산성이 더 떨어진다고 생각하게 된다. 그러나 아래에 소개할
웹 에디터들은 표준 마크업 및 CSS 레이아웃을 지원하는 것들 이므로 이것들을 이용하면
보다 효율적인 표준 CSS 개발이 가능할 것이다.
또한, CSS 문법을 제대로 사용 했는지 개발 시 확인하고 추후 QA 과정에서 검증할 수 있
는 다양한 툴도 소개한다.
실전 웹 표준 가이드
- 116 -
표준 에디터 소개
드림 위버 8 및 MX2004
드림위버는 대표적인 웹 에디터이다. 드림위버 8 이상 MX2004 버전에서는 표준CSS를 을
거의 완벽하게 지원한다.
또한 간단한 드래그 앤 드롭 워크플로를 통해 RSS 피드와 같은 XML 기반의 데이터를
웹 페이지에 통합할 수 있을 뿐만 아니라, 코드 뷰로 바로 이동하여 XML 및 XSLT를 지
원하는 향상된 코드 힌트 기능을 사용하여 사용자 요구에 맞게 변형 작업을 수행할 수 있
다.
그림 29 드림위버 MX 2004를 통해 본 CSS 레이아웃 기능
모든 CSS 기능이 하나의 패널 세트로 통합되어 CSS를 사용한 작업이 훨씬 수월해졌으며
생산성이 크게 향상되었다. 이 새로운 인터페이스를 사용하면 특정 요소에 적용된 계단식
배열의 스타일을 손쉽게 볼 수 있고 속성이 정의된 위치를 쉽게 파악할 수 있다. 또한 속
성 그리드를 통해 신속하게 편집할 수 있다.
디자인 시 시각적인 보조 도구를 사용하여 CSS 레이아웃 테두리의 외곽선을 표시하거나
CSS 레이아웃의 색상을 지정하여 복잡하게 중첩된 구조를 구분할 수 있고 손쉽게 항목을
선택할 수 있다. CSS 레이아웃을 클릭하면 ID, 패딩, 여백, 테두리 설정과 같은 유용한 툴
팁을 확인할 수 있다.
드림위버는 CSS 미디어 유형을 새롭게 지원하므로 컨텐츠 전달 방법에 관계없이 최종 사
용자가 보게 될 컨텐츠와 동일한 컨텐츠를 볼 수 있다. 또한 스타일 렌더링 툴바를 통해
디자인 뷰로 전환하여 핸드헬드 또는 스크린에서의 인쇄 시 모습이 어떤지 확인할 수 있
다.
정확성이 대폭 향상된 디자인 뷰를 통해 아무리 복잡한 CSS 레이아웃도 대부분의 브라우
저에서 렌더링되도록 할 수 있다. Dreamweaver는 이제 오버플로, 의사(pseudo)-요소 및
실전 웹 표준 가이드
- 117 -
양식 요소와 같은 고급 CSS 기법을 완벽하게 지원한다.
Section 508과 WCAG Priority 1 체크포인트를 위한 통합된 액세스 가능성 평가 도구 이
외에도 Dreamweaver는 현재 WCAG Priority 2 체크포인트를 포함하는 업데이트된 평
가 도구를 통해 CSS 및 액세스 가능성을 모두 지원합니다.
Style Master
http://www.westciv.com/ 에서 다운 받아 사용할 수 있는 CSS Style Master는 매우
훌륭한 CSS 에디터이다.
Top Style Pro
Top Style Pro는 메모장에 길들어져 있는 개발자에게 제격이다. 각종 CSS 표준문법들을
코딩 즉시 알 수 있다. http://www.bradsoft.com 에서 다운로드 받을 수 있다.
실전 웹 표준 가이드
- 118 -
XStandard Editor
XStandard Editor는 XML 에디터이다. XHTML 및 CSS도 지원하며 웹 에디터로 사용할
수도 있다. http://www.xstandard.com 에서 다운받을 수 있다.
CSS Tab Designer
CSS Tab Designer는 <ul>태그를 이용하여 탭 메뉴를 자동으로 만들어 주는 간단한 프로
그램이다. CSS로 다양한 효과를 얻을 수 있는 여러 가지 데모들을 볼 수 있다.
http://www.style-sheets.com 에서 다운로드 받을 수 있다.
실전 웹 표준 가이드
- 119 -
유효성 검증 도구
W3C CSS Validator
W3C의 CSS Validator는 가장 많이 사용하는 CSS 문법 검증 도구 이다. 이를 통해 CSS
오류 등을 알 수 있다. (http://jigsaw.w3.org/css-validator)
Web Developer 확장 기능
파이어폭스에는 Web Developer 확장 기능이라는 것이 있다. 여기서 CSS 문법 오류를
간단하게 체크해 볼 수 있다.
실전 웹 표준 가이드
- 120 -
- 다운로드: http://chrispederick.com/work/webdeveloper/
Web Accessiblity 툴바
웹 접근성 툴바를 통해서도 CSS 문법 오류를 체크해 볼 수 있다.
- 다운로드: http://www.vinfoaxia.com/tools/wat/ko
HTML Tidy
HTML Tidy(http://tidy.sourceforge.net)를 이용하는 방법도 있다. HTML Tidy는
HTML의 문법을 체크하고 잘못된 문법에 대해서는 수정도 가능하게 하는 HTML문법을
위한 도구 이다. 현재는 오픈소스로 관리가 이루어지고 있어서 많은 수의 참가자들이 공동
으로 제작에 참여하고 있다.
이 HTML Tidy를 직접 설치하여 이용할 수도 있겠지만 조금은 번거롭고 누구나 쉽게 할
수 있는 방법은 아니다. 하지만 이 HTML Tidy가 Firefox 확장기능으로 제공되고 있어서
이를 이용하면 손쉽게 HTML, XHTML문법의 유효성을 체크해 볼 수 있다.
실전 웹 표준 가이드
- 121 -
그림 30 HTML Tidy를 통한 유효성 검사
브라우져의 우측 하단에서 validation 결과를 바로 확인 할 수 있고, 소스보기에서 해당하
는 부분과 에러 내용을 살펴볼 수 있다.
실전 웹 표준 가이드
- 122 -
실전 DOM/Script 가이드
실전 웹 표준 가이드
- 123 -
표준 DOM 기반 개발
문서 객체 모델(DOM; Document Object Model)은 HTML내에 들어 있는 요소를 구조
화 객체 모델로 표현하는 형식이다. DOM은 플랫폼/언어 중립적으로 구조화된 문서를 표
현하는 W3C 표준 모델이 기반이 된다.
DOM은 HTML 문서의 요소(Element)를 조작하기 위해 웹 브라우저에서 처음 지원됐다.
DOM은 동적으로 문서의 내용, 구조, 스타일에 접근하고 변경하는 수단이었다. 브라우저
간의 DOM 구현이 호환되지 않음에 따라 W3C에서 DOM 표준 명세를 작성하게 되었다.
DOM은 문서의 기반이 되는 데이터 구조에 제한을 두지 않는다. 잘 구조화된 문서는
DOM을 사용하여 트리 구조(Tree Structure)를 얻어낼 수 있다. 대부분의 XML 해석기와
XSL 처리기는 이러한 트리 구조를 기반으로 개발 되었는데, 이 같은 구현에서는 문서의
전체 내용이 해석되어 메모리 저장되어야 한다. 이 때문에 DOM은 문서 요소가 임의적으
로 접근되고 변경 가능해야 하는 응용프로그램에 가장 적합하다. 한 번 해석 시 단 한 번
의 선택적인 읽기 및 쓰기가 이루어지는 XML 기반 응용프로그램에서 DOM은 메모리에
상당한 부하를 가져 오기도 한다.
현재 널리 사용되고 있는 DOM 표준안은 Level 2이다. 일부 Level 3 명세서 역시 W3C
의 권고안으로 나와 있다.
.. Level 0: DOM이 만들어지기 이전의 모든 벤더 종속적인 DOM을 포함한다. 예:
document.images, document.forms, document.layers, document.all. 이것은 W3C에
의해 공식적으로 출판된 명세가 아니며, 표준화 과정 이전에 있었던 단계에 대한 표현이다.
.. Level 1: DOM 문서에 대한 탐색과 조정에 대한 최초의 표준 명세
.. Level 2: XML 네임스페이스(Namespace) 지원, 필터링된 뷰(view)와 이벤트.
.. Level 3: 6가지 다른 명세로 구성: 1) Core; 2) Load and Save; 3) XPath; 4) Views and
Formatting; 5) Requirements; 6) Validation;
W3C DOM vs. MS DOM
DOM이 처음 구현 된 것은 최초의 브라우저인 Netscape 2 에서이다. 이 때는 문서 내에
들어있는 태그를 그대로 접근하는 방식이었다. 예를 들어 아래와 같은 문서 구조가 있다고
하자.
그러면 위의 각 문서 내 객체들은 다음과 같이 접근한다.
document
img 1 img 2
form
input
실전 웹 표준 가이드
- 124 -
document.images['thefirst'] // name 이 있는 경우
document.images[0]
document.images[1]
document.forms['contactform'] //name 이 있는 경우
document.forms[0].elements['address']
document.forms[0].elements[0]
그러나 이렇게 접근할 수 있는 HTML 태그들은 제한 되어 있다. 예를 들어 <h1>, <p>
등은 접근할 수 없는 것이다. Netscape 4와 IE4 버전이 나올 무렵 좀 더 근본적인 방법으
로 문서 객체에 접근할 수 있는 방법을 따로 내놓았다. 그것이 바로 document.layer와
document.all 이다. 예를 들어, id를 기초로 각 객체를 부르는 방법을 다음과 같이 다르게
사용하게 된 것이다.
<DIV ID="stuff"><IMG NAME="testimage"></DIV>
document.all['stuff'].style.left = 200; // IE 표현
document.all.stuff.style.left = 200; // IE 표현
document.layers['stuff'].left = 200; // Netscape 표현
document.stuff.left = 200; // Netscape 표현
이렇게 자신들이 원하는 형태로 객체 모델을 만들어 퍼트리게 되니 1990년대 중반에는 이
른바 DHTML이라는 기법으로 홈페이지를 만들려면 고도의 브라우저 구현 스펙을 알아야
하는 문제까지 생겼다. 따라서, 브라우저 전쟁 기간 동안 마이크로소프트와 넷스케이프 양
쪽 다 표준 경쟁의 와중에서 비표준 기능을 퍼트리게 된 것에 대한 책임을 피할 수 없다.
어쨌든 브라우저간의 DOM 구현의 차이 때문에 상호 운용성 문제가 생기게 되었다. 이
때문에 MS와 넷스케이프는 DOM Level 1 표준 스펙을 작성하게 되었고, IE5.0 에서는
W3C DOM을 지원하기 시작했다. 그러나, IE가 브라우저 시장에서 독점이 되면서 IE가
W3C DOM을 지원함에도 불구하고 MS DOM이 일반적으로 쓰이게 되었다. 그럼으로 인
해 최근에 나온 파이어폭스나 오페라 등과 같은 표준 호환 브라우저에서 비 표준 DOM
사용에 따라 웹 페이지가 제대로 표시 되지 못하는 문제가 발생하고 있다.
그러나 위와 같은 브라우저 전용 DOM 접근 방식은 W3C DOM에서 아래와 같이 정의한
다. 이는 이미 IE 5.0 이후에 나온 모든 브라우저가 지원하므로 거의 99%의 브라우저가
지원한다고 볼 수 있다.
document.getElementById['stuff'].style.left = 200; // W3C 표준 표현
따라서 일부 몇 가지 DOM 스펙만을 제외하면, 표준 W3C DOM을 사용하는 것이 중요
하다. 만약 웹 개발자가 IE의 MS DOM 확장을 사용한다면 표준 준수에 대한 신뢰성을
잃을 수 있으며, 반대의 경우라면 비표준 확장을 사용하지 않음으로 생기는 기능적 제약
때문에 사용자가 이탈할 수도 있다. 그러나 표준 호환 브라우저가 웹 시장에서 주목할 만
한 점유율을 차지하게 된다면 이 같은 상황이 바뀌게 될 것이며, 비표준 확장을 사용하는
것이 작성자에게 상업적 불이익으로 다가올 것이라는 것에 대해서는 일반적으로 의견이
일치하고 있다.
IE도 W3C DOM을 지원하고 있기 때문에 MS DOM을 사용하지 않고 대체 기능을 사용
하면 충분히 표준 호환 브라우저에서도 서비스를 제공할 수 있다.
실전 웹 표준 가이드
- 125 -
DOM 기본 기능
W3C DOM에서는 HTML 문서를 XML로 바라본다. 즉, 각 문서에 있는 태그들을 노드
(Node)가 있는 트리 구조로 해석해 낼 수 있다고 가정하는 것이다. 각 태그들은 요소 노
드(Element Node)와 텍스트 노드(Text Node)가 있다고 생각하며, 각 요소 노드에 있는
속성 값들은 속성 노드(Atrribute Node)로 인식한다.
예를 들어 아래와 같은 문서 구조가 있다고 하자.
<BODY>
<P ALIGN="right">This is a <B id="dynatext">paragraph</B></P>
</BODY>
위의 문서는 아래와 같은 구조로 표현된다.
객체 접근 방법
Level 0이라고 명명한 과거의 DOM에서 객체에 접근하는 방식은 document.form 과 같
이 HTML 글로벌 네임 스페이스를 바로 선언 하는 것이었다. 그렇지 않으면
document.layer (NS4), document.all(IE4)를 통하는 것이었다. Level 1에서는 이를 위해
다음 두 가지의 객체 접근 방식을 정했다.
.. document.getElementById(aId)
.. document.getElementByTagName(aTagName)
따라서 이전에 썼던 모든 객체 접근법은 위의 방식으로 바꾸어야 한다. 만약
getElementById를 지원하지 않는 IE4의 경우, 아래의 객체 접근 함수를 만들어 사용하면
유용하다.
function getObject(objectId) {
if(document.getElementById && document.getElementById(objectId) {
return document.getElementById(objectId); // check W3C DOM
}
else if (document.all && document.all(objectID) {
return document.all(objectID); // IE4
}
else if (document.layers && document.layers[objectID] {
실전 웹 표준 가이드
- 126 -
return document.layer[objectID]; // NN4
}
else {
return false;
}
}
위의 스크립트를 통해 getObject(objectId)를 이용하여 모든 브라우저의 DOM 객체를 얻
을 수 있다.
객체 사용 방법
DOM 트리 구조 중 각 요소의 컨텐트는 일련의 자식 노드(child node)로 분할되어 있으
며, 각 노드는 단문과 그 자식 요소로 구성되어 있다. 즉, 텍스트를 변경하고자 요소의 노
드를 조정하는 것이 표준적인 방법이다. 노드의 구조 및 지원 메소드는 W3C DOM 레벨
1 권고로 정해져 있다. 이 메소드들은 이미 IE5.0 이상 브라우저에서 모두 지원한다. 따라
서 문제 없이 사용할 수 있다.
예를 들기 앞서서, 우리가 흔히 사용하는 요소 사용 방법중 중에 구성요소의 내용을 바꾸
거나 수정하는 innerText, innerHTML, outerText, outerHTML을 사용하는 것은 원래
잘못된 것이다. 왜냐하면 이는 W3C DOM 표준이 아니고 MS DOM 이기 때문이다. 그러
나, 많은 웹 브라우저들이 만은 지원해 왔기 때문에 일반적으로 사용할 수 있다. 모질라
계열에서는 innerHTML 외에 outerHTML, innerText와 outerText등 다른 메소드는 지
원하지 않기 때문에 사용하는 것을 지양해야 한다. W3C DOM을 이용해서도 이 기능을
구현 할 수 있는 방법이 있다.
innerText와 innerHTML을 W3C DOM으로 구현하는 방법을 통해 객체 사용 방법을 알
아 보도록 하자.
<p ALIGN="right">This is a <span id="dynatext">paragraph</span></p>
위의 dynatext라는 id에 텍스트 내용을 변경하는 예를 통해 DOM에 접근하는 방법을 알
아 보자. 먼저 id dynatext의 요소를 먼저 span_el에 담는다.
<script type="text/javascript">
var span_el = document.getElementById("dynatext");
자식 노드에서 그 이하 특정한 요소를 가지지 않고 텍스트 밖에 없다면 (통상)
element.childNodes[0] 으로서 접근할 수 있는 1차 노드를 가진다. 즉, 우리가
element.innerText을 대체할 방법으로서는 element.childNodes[0].nodeValue 가 사용
할 수 있다.
즉, span_el.innerText = "a brand new bag"을 실현하려면, 다음과 같다.
var new_txt = document.createTextNode("a brand new bag");
span_el.replaceChild(new_txt, span_el.childNodes[0]);
span_el.innerHTML = "a brand <b>new</b> bag" 처럼 HTML 태그가 포함된 문장을
표준적으로 수용하는 방법은 새로운 요소를 만든 후, 이에 3개의 노드를 추가한다. 처음의
텍스트 노드, 자신의 텍스트 노드를 가지는 B 요소, 마지막 텍스트 노드에 각각 내용을 넣
실전 웹 표준 가이드
- 127 -
은 다음 원래 요소에 치환하는 방법이다
var new_el = document.createElement(span_el.nodeName);
new_el.appendChild(document.createTextNode("a brand "));
var bold_el = document.createElement("B");
bold_el.appendChild(document.createTextNode("new"));
new_el.appendChild(bold_el);
new_el.appendChild(document.createTextNode(" bag"));
span_el.parentNode.replaceChild(new_el, span_el);
</script>
DOM객체와 노드 및 그 속성을 조작 하는 방법은 일반적인 W3C DOM 표준을 따른다.
createElement(), createTextNode() 같은 노드 생성 및 접근, nodeName, nodeType,
tagName 같은 노드 정보, childNode, firstChild같은 트리 구조 파악 등은 비교적 표준
이 잘 지켜 지고 있다.
그러나, getAttribute(), removeAttribute() 같은 속성 정의 인터페이스들은 브라우저 마
다 다른 점이 매우 많아서 사용에 주의를 요한다. 이러한 차이점은 부록에 나와 있는
DOM 브라우저 호환 차트를 참고해야 한다.
일반적인 중요 DOM 메소드에 대해서 아래와 같다.
Property/Method Description 비고
childNodes 요소내 모든 노드의 배열을 반환
firstChild 요소내 첫 번째 노드를 반환
getAttribute( aAttributeName ) 특정 속성 값을 반환 오페라 버그
hasAttribute( aAttributeName ) 특정 속성 값이 있는지 여부를 판별. IE지원 안함
hasChildNodes() 자식 노드가 있는지 여부를 판별
lastChild 요소내 마지막 노드를 반환
nextSibling 상위 노드의 다음 자식 노드
nodeName 현재 노드의 이름을 반환
nodeType 현재 노드의 형식을 반환한다. 예를 들어 1번은 요
소 노드, 2번은 속성 노드 3번은 텍스트, 4번은
CDATA, 5번은 참조 엔티티 등.
nodeValue 현재 노드의 값을 반환한다. 노드 값이 텍스트이면
텍스트를, 속성이면 속성값을 기타는 null을 반환한
다.
ownerDocument 현재 노드를 포함하고 있는 문서 객체를 반환
parentNode 현재 노드의 상위 노드를 반환
previousSibling 상위 노드의 이전 자식 노드
removeAttribute( aName ) 노드의 특정 속성을 지운다. IE 버그 있음
실전 웹 표준 가이드
- 128 -
setAttribute( aName, aValue ) 특정 노드의 특정 속성에 대한 값을 설정한다. IE 버그 있음
속성을 읽어 오는 가장 좋은 방법을 예를 들어 보자.
id="test" align="center" style="border: 1px solid #0000cc"
1. x.id 나 x.style 같은 방법으로 먼저 속성을 찾는다.
2. 값이 나오지 않으면 x.getAttribute(“align”)나 x.getAttributeNode(“align”).value 로
찾는다.
3. 그래도 나오지 않으면 다른 속성 인터페이스를 시도하되, attributes[]는 절대 사용하지
않는다.
객체 요소를 다루는 메소드에 있어서도 IE에서만 사용되는 MS DOM 확장 메소드들이 있
다. 이들에 대해서도 사용에 주의를 요하며 이를 대체할 수 있는 W3C DOM을 사용한다.
MS DOM 전용 확장 설명 W3C 대체 표준
applyElement() 다른 상위 노드에 새 노드 생성 appendChild()
clearAttributes() 노드의 모든 속성 삭제 removeAttribute()
mergeAttributes() 특정 속성을 특정 노드에 복사 cloneNode()
removeNode() 노드 삭제 removeChild()
replaceNode() 특정 노드를 다른 노드로 대체 replaceChild()
swapNode() 두 노드를 바꾸기
DOM 호환 기능
DOM Level1과 2에서는 거의 모든 HTML/CSS 객체의 속성을 이용할 수 있다. x를 객
체라고 가정하면 x.className이나 x.id, x.title 등으로 속성을 읽고 쓸 수 있다. 또한,
x.style 등으로 스타일 설정도 가능하다. 그러나, 아직 브라우저 비 호환 DOM 속성들이
많이 남아 있어서 아래 몇 가지 예에서는 브라우저 판별법을 사용해야 될 필요가 있다. 아
래 사항을 알아 두면 웹 개발 시 도움이 될 것이다.
윈도우 위치 파악
DOM을 사용하다 보면 윈도우 위에 각종 DOM 레이어들을 배치 시키고 위치를 잡도록
해야될 필요가 있다. 각 브라우저 마다 윈도우의 크기와 높이 위치를 정하는 방식이 다르
기 때문에 이에 대한 호환 방식을 알아둘 필요가 있다.
Inner width 알기
윈도우나 프레임의 내부 크기를 알아내는 방법이다.
var x,y;
if (self.innerHeight) { // IE 외 모든 브라우저
x = self.innerWidth;
y = self.innerHeight;
실전 웹 표준 가이드
- 129 -
}
else if (document.documentElement &&
document.documentElement.clientHeight) { // Explorer 6 Strict 모드
x = document.documentElement.clientWidth;
y = document.documentElement.clientHeight;
}
else if (document.body) { // 다른 IE 브라우저
x = document.body.clientWidth;
y = document.body.clientHeight;
}
스크롤 위치 파악
페이지가 얼마나 스크롤 됐는지 알아내는 방법이다.
var x,y;
if (self.pageYOffset) { // IE 외 모든 브라우저
x = self.pageXOffset;
y = self.pageYOffset;
}
else if (document.documentElement &&
document.documentElement.scrollTop) {
// Explorer 6 Strict
x = document.documentElement.scrollLeft;
y = document.documentElement.scrollTop;
}
else if (document.body) { // IE 브라우저
x = document.body.scrollLeft;
y = document.body.scrollTop;
}
스타일 가져오기
대부분의 스타일 속성은 x.style을 통해 읽을 수 있지만 인라인(inline) 속성만 사용할 수
있기 때문에 그렇지 않은 스타일 속성을 찾기 어렵다. MS에서는 x.currentStyle이라는 메
소드를 지원하지만 W3C에서는 getComputedStyle()을 사용하므로 브라우저간 호환성
문제가 생긴다.
#test {font-size: 16px;
padding: 10px;
width: 50%;
border-width: 1px;
border-style: solid;
border-color: #cc0000;
}
위와 같은 test라는 클래스의 font-size 속성을 읽어 오려면 다음과 같이 한다.
testProp=getStyle("test","width");
function getStyle(el,styleProp)
{
var x = document.getElementById(el);
실전 웹 표준 가이드
- 130 -
if (x.currentStyle)
var y = x.currentStyle[styleProp];
else if (window.getComputedStyle)
var y =
document.defaultView.getComputedStyle(x,null).getPropertyValue(style
Prop);
return y;
}
DOM에서 pixel 처리
W3C DOM2에서는 style.left 이나 style.top 속성이 돌려주는 값은 CSS의 단위("px"등)
를 포함한다. 그러나, 넷스케이프4의 element.left 나 IE4/5 의 element.style.pixelLeft
는 정수치를 돌려준다. 요소의 왼쪽 혹은 위의 내부 스타일 설정을 정수값으로 읽기 위해
서는 parseInt() 을 사용해 문자 라인에서 정수값을 받는다. 반대로 설정하고자 하면 px과
같은 단위를 꼭 설정해야 한다.
x.style.pixelLeft = x; // IE4/5
x.style.pixelTop = y; // IE4/5
x.style.left = value + "px"; // DOM Level 2
x.style.top = value + "px"; // DOM Level2
W3C DOM과 innerHTML 성능
이미 언급한 바와 같이 W3C의 노드를 생성하는 방법으로 DOM을 생성할 때 실제 브라
우저에서 속도가 많이 느린 것을 경험 할 수 있다. 50x50 정도의 테이블을 그릴 때, W3C
DOM 방식과 HTML 테이블 DOM 방식, innerHTML 방식을 비교하여 실험해 본 결과
innerHTML의 성능이 가장 빠른 것을 알 수 있다. (http://www.quirksmode.org의 실
험 결과)
방식 및 브라우저별 성능 IE5 IE6 Firefox 1.0 Safari1.3 Opera8
W3C DOM1 노드 생성 380 3000 340 330 510
W3C DOM2 노드 생성 330 3000 320 205 340
Table 그리기 방식 3600 9000 290 150 400
innerHTML 방식 100 100 110 100 110
일반적으로 자바스크립트의 수행 속도는 상당히 빨라서 성능에 영향을 주지는 않는다. 다
만 문제되는 경우 위와 같은 DOM을 조작하고 렌더링 하는 부분에서 성능 차이가 나고
있다. 이러한 성능 차이를 볼 수 있는 사이트는 아래와 같다.
1. http://www.oreillynet.com/javascript/2003/05/06/examples/dyn_table_bench
marker_ora.html (Table Benchmarer)
2. http://www.umsu.de/jsperf/ (DOM Performance Test)
3. http://msdn.microsoft.com/library/default.asp?url=/workshop/author/perf/dh
tmlperf.asp (MSDN DHTML Performance)
실전 웹 표준 가이드
- 131 -
이벤트(Events) 기능
MS DOM과 W3C DOM이 극단적으로 차이를 보이는 부분이 바로 이벤트(Events) 부분
이다. 마우스의 클릭, 움직임 등을 파악하여 액션을 구현하는 이벤트 부분은 웹에서 가장
많이 사용되고 있는 부분이기도 하다. IE는 이벤트가 나오면 window.event 를 통해
event 객체를 전달 하는데 반해 파이어폭스는 event 객체를 바로 전달 받는다. 따라서,
이벤트 핸들러를 사용하는데 있어 차이가 발생하게 된다.
<script type="text/javascript">
function handleEvent(aEvent){
// aEvent 가 null 이면 IE 이기 때문에 window.event 를 반환한다.
var myEvent = aEvent ? aEvent : window.event;
}
</script>
<div onclick="handleEvent(event)">Click me!</div>
브라우저 호환 이벤트 캐칭을 위해서는 위의 스크립트가 항상 초기화 되어 있어야 한다.
아래 표즌 MS DOM Event와 W3C Dom Event 의 차이점을 설명한 것이다. 같이 사용
할 수 있는 부분도 있으나 대부분 달리 쓸 수 밖에 없다.
키 이벤트 속성
키 이벤트를 나타내는 속성은 아래와 같다. Keycode가 권장 된다.
MS DOM Event W3C DOM Event 사용 설명
altKey (altLeft) altKey Alt키 사용 여부
shiftKey(shiftLeft) shiftKey Shift키 사용 여부
ctrlKey(ctrlLeft) ctrlKey Ctrl키 사용 여부
keyCode keyCode ASCII코드 값으로 키 인식 (a=65)
마우스 위치 속성
마우스 위치를 나타내는 속성은 다음과 같다. clientX/Y가 권장 된다.
MS DOM Event W3C DOM Event 사용 설명
clientX/Y clientX/Y 윈도우에서 이벤트가 일어난 상대적 x /y좌표 (Safari
는 document 기반으로 측정)
screenX/Y screenX/Y 전체 화면에서 이벤트가 일어나는 위치
offsetX/Y - 마우스 근방에 요소에서 상대적 위치 (모질라에서 작
동 안함)
- PageX/Y 전체 문서에서 상대적 위치 (IE에서 작동 안함)
실전 웹 표준 가이드
- 132 -
위와 같이 표준 지원에 대한 범위가 다르므로 아래와 같은 코드로 마우스의 위치를 파악
할 수 있다.
function getPosition(e)
{
var posx = 0;
var posy = 0;
if (!e) var e = window.event; // 이벤트 검사
if (e.pageX || e.pageY) { // pageX/Y 표준 검사
posx = e.pageX;
posy = e.pageY;
}
else if (e.clientX || e.clientY) { //clientX/Y 표준 검사 Opera
posx = e.clientX;
posy = e.clientY;
if (isIE) { // IE 여부 검사
posx += document.body.scrollLeft;
posy += document.body.scrollTop;
}
}
}
이벤트 핸들러 등록
MS DOM 및 W3C DOM 지원 브라우저 간에 완전히 다른 이벤트 핸들러 인터페이스를
가지고 있다.
MS DOM Event W3C DOM Event 사용 설명
attachEvent() addEventListener() 요소에 이벤트 핸들러 추가
x.addEventListener('click',doSomething,false)
detachEvent() removeEventListner() 요소에서 이벤트 핸들러 삭제
양쪽을 모두 지원할 수 있는 attachEvent 판별 스크립트는 아래와 같다.
function attachEvent (obj, evt, fuc, useCapture) {
if(!useCapture) useCapture=false;
if(obj.addEventListener) { // W3C DOM 지원 브라우저
return obj.addEventListener(evt,fuc,useCapture);
} else if(obj.attachEvent) { // MSDOM 지원 브라우저
return obj.attachEvent(“on”+evt, fnc);
} else { // NN4 나 IE5mac 등 비 호환 브라우저
MyAttachEvent(obj, evt, fnc);
obj[‘on’+evt]=function() { MyFireEvent(obj,evt) };
}
}
function MyAttachEvent(obj, evt, fuc) {
실전 웹 표준 가이드
- 133 -
if(!obj.myEvents) obj.myEvents= {};
if(!obj.myEvents[evt]) obj.myEvents[evt]=[];
var evts = obj.myEvents[evt];
evts[evts.length]=fnc;
}
function MyFireEvent(obj, evt) {
if(!obj )} !obj.myEvents || !obj.myEvents[evt]) return;
var evts = obj.myEvents[evt];
for (var i=0;len=evts.length; i<len;i++) evts[i]();
}
XML 기능
여기에서는 표준 DOM에서 XML을 처리하는 방법을 알아보고자 한다.
XML 데이터 핸들링
W3C DOM의 XML 기능을 가장 잘 탑재하고 있는 것이 바로 모질라 계열 브라우저들이
다. 비표준적인 처리 방식에서 IE와 크게 다른 점은 텍스트 노드에 공백이 들어 있는 경
우 처리 방식이다. XML 노드 사이에 공백이 들어 있는 경우 IE는
XMLNode.childNodes[]속에 공백을 포함하지 않는다.
//XML:
<?xml version="1.0"?>
<myXMLdoc xmlns:myns="http://myfoo.com">
<myns:foo>bar</myns:foo>
</myXMLdoc>
// JavaScript:
var myXMLDoc = getXMLDocument().documentElement;
alert(myXMLDoc.childNodes.length);
위의 예제에서 documentElement를 통해 myXMLDoc에 XML 문서를 로드한 후에 이
를 표시하는 내용이다. Mozilla인 경우 이 자식 노드의 길이에서 공백을 포함하기 때문에
3이 나오지만 IE인 경우에는 1이 나오게 된다.
또한 모든 노드는 nodeType을 가지는데, 요소 노드인 형식1과 문서 노드인 형식 9를 가
질 때, 텍스트 노드를 분리해 내기 위해 텍스트 노드 형식 3과 코멘트 노드 형식 8여부를
아래와 같이 확인해야 한다.
// XML:
<?xml version="1.0"?>
<myXMLdoc xmlns:myns="http://myfoo.com">
<myns:foo>bar</myns:foo>
</myXMLdoc>
// JavaScript:
var myXMLDoc = getXMLDocument().documentElement;
var myChildren = myXMLDoc.childNodes;
실전 웹 표준 가이드
- 134 -
for (var run = 0; run < myChildren.length; run++){
if ( (myChildren[run].nodeType != 3) &&
(myChildren[run].nodeType != 8) ){
// not a text or comment node
}
}
XML data island 처리
IE에서는 XML data islands라는 비표준 기능이 있다. 이것은 HTML 문서내에서 XML을
임베딩 시키는 것인데 <xml>이라는 비표준 태그를 사용하며 다른 브라우저에서는 지원하
지 않는다. XHTML을 사요해서 같은 기능을 구현해 볼 수 있다.
<xml id="xmldataisland">
<foo>bar</foo>
</xml>
방법은 XML 문서를 생성하고 파싱하는 DOM 파서를 사용하는 것인데 모질라에서는
DOMParser라는 구현을 이용한다. IE에서는 ActiveX로 된 Microsoft.XMLDOM에서 이
러한 작업을 처리할 수 있다.
var xmlString = "<xml
id=\"xmldataisland\"><foo>bar</foo></xml>";
var myDocument;
if (document.implementation.createDocument){
// Mozilla 에서 DOMParser 를 이용한다.
var parser = new DOMParser();
myDocument = parser.parseFromString(xmlString, "text/xml");
} else if (window.ActiveXObject){
// IE 에서 XMLDOM 객체를 이용한다.
myDocument = new ActiveXObject("Microsoft.XMLDOM")
myDocument.async="false";
myDocument.loadXML(xmlString);
}
XMLHttpRequest 처리
IE에서는 IE5.0부터 MSXML데이터를 통신으로 처리하기 위해 XMLHTTPRequest라는
객체를 ActiveX Object에 포함해서 비표준으로 제공하고 있다. 이것을 사용하기 위해서는
ActiveXObject(“MSxml2.XMLHTTP) 혹은 ActiveXObject(“Microsofot.XMLHTTP)라
는 객체를 불러서 사용할 수 있다.
그런데 이 기능이 모질라와 사파리 등 다른 브라우저에서 XMLHttpRequest라는 자바스
크립트 객체로 지원하게 됨에 따라 비동기 통신 기능을 하는 표준으로 자리 잡게 되었다.
이른바 Ajax(Asynchronous Javascript and XML)이라는 것으로 잘 알려진 이 기능은 페
이지 내에서 사용자의 데이터를 비동기적으로 받을 수 있도록 할 수 있다는 점에서 획기
적인 기능이라는 평가를 받았다.
실전 웹 표준 가이드
- 135 -
// 객체 판별
var xmlhttp = false;
if (window.XMLHttpRequest) {
myXMLHTTPRequest = new XMLHttpRequest();
} else {
myXMLHTTPRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
// 동기 통신 요청
myXMLHTTPRequest.open("GET", "data.xml", false);
myXMLHTTPRequest.send(null);
var myXMLDocument = myXMLHTTPRequest.responseXML;
//비동기 통신 요청
function xmlLoaded() {
var myXMLDocument = myXMLHTTPRequest.responseXML;
}
function loadXML(){
myXMLHTTPRequest = new XMLHttpRequest();
myXMLHTTPRequest.open("GET", "data.xml", true);
myXMLHTTPRequest.onload = xmlLoaded;
myXMLHTTPRequest.send(null);
}
실전 웹 표준 가이드
- 136 -
표준 JavaScript 사용 방법
XHTML, CSS와 함께 웹 문서에서 가장 많이 사용되는 것이 JavaScript이다. 자바스크립
트는 DOM을 핸들링 할 수 있는 클라이언트 사이드 언어로서 매우 가볍고 쉽지만 개발하
는 데 고려 사항이 매우 많기 때문에 충분한 경험이 필요하다.
자바스크립트는 플래시의 ActionScript, 모질라 확장 기능, 위젯 등 최근의 많은 리치 인
터넷 어플리케이션의 기반 언어가 되고 있으므로 이를 잘 알아 두는 것이 여러 모로 도움
이 된다. 특히 웹 개발에서 자바 스크립트는 매우 중요한 요소이며 브라우저에 따른 호환
성 문제에도 관심을 가져야 한다.
국내 웹사이트 중 대부분의 경우 브라우저에 따른 DOM 핸들링과 자바스크립트 오류로
인해 잘 작동되지 않기 때문이다.
ECMAscript vs. Jscript?
ECMA스크립트(ECMAScript)는 ECMA 인터내셔널의 ECMA-262 기술 명세에 정의된
표준화된 스크립트 프로그래밍 언어이다. 이 언어는 웹 상에서 널리 쓰이며, 흔히 자바스
크립트 혹은 JScript로 간주되지만 두 용어는 특별한 의미 차이가 있다. ECMA스크립트와
자바스크립트, JScript의 관계를 이해하기 위해서는 ECMA스크립트의 역사를 알 필요가
있다.
1996년 3월, 넷스케이프에서 넷스케이프 네비게이터 2.0을 출시하면서 자바스크립트를 지
원하기 시작했다. 웹 페이지 동작을 향상시키는 언어로서 자바스크립트의 성공 때문에 마
이크로소프트가 이와 "적당히" 호환되는 JScript를 개발하는 계기가 되었다. JScript는
1996년 8월 인터넷 익스플로러 3.0에 포함되어 출시되었다.
이에 넷스케이프는 표준화를 위해 자바스크립트 기술 명세를 ECMA 인터내셔널에 제출
하였고, 이 명세에 대한 작업은 ECMA-262의 이름으로 1996년 11월부터 시작됐다.
ECMA-262의 초판은 ECMA 일반 회의에서 1997년 6월 채택됐다.
ECMAScript는 ECMA-262에 의해 표준화된 언어의 이름이다. 자바스크립트와 JScript는
모두 ECMA스크립트와의 호환을 목표로 하면서 ECMA 명세에 포함되지 않는 다른 확장
기능을 제공한다. 1997년 6월과 1998년 6월에 각각 1,2 버전이 발표 되었으며 2000년 7월
자바스크립트 1.5를 기반으로 3 버전(ECMA-327)가 발표되었다. 2004년 6월에
ECMAscript for XML을 포함한 E4X 명세(ECMA-357)이 발표 되었다.
자바스크립트 JScript ECMA스크립트
1.0 (넷스케이프 2.0, 1996년 3월) 1.0 (IE 3.0 - 초기 버전, 1996년 8월)
1.1 (넷스케이프 3.0, 1996년 8월) 2.0 (IE 3.0 - 후기 버전, 1997년 1월)
1.2 (넷스케이프 4.0, 1997년 6월)
1.3 (넷스케이프 4.5, 1998년 10월) 3.0 (IE 4.0, 1997년 10월) 초판 (1997년 6월) / 2판
실전 웹 표준 가이드
- 137 -
(1998년 6월)
1.4 (넷스케이프 서버에만 사용됨) 4.0 (비주얼 스튜디오 6, IE에는 사용되
지 않음)
5.0 (IE 5.0, 1999년 3월)
5.1 (IE 5.01)
1.5 (넷스케이프 6.0, 2000년 11월;
이후 넷스케이프와 모질라 포함)
5.5 (IE 5.5, 2000년 7월) 3판 (1999년 12월)
5.6 (IE 6.0, 2001년 10월)
JScript(ASP.NET; IE에는 포함되지 않
음)
자바스크립트 2.0 (제안) 4판 (진행중)
- 출처: 위키퍼디아(ko.wikiperdia.org)
- 참고: http://www.ecma-international.org/publication/standard/Ecma-357.htm
스크립트 개발시 유의점
브라우저 스니핑
웹 표준 기반 개발은 웹브라우저와 관계 없이 통일된 웹페이지를 제공하는 데 목표가 있
지만 실제로 웹브라우저에 따라 달리 표현하는 부분이 있기 때문에 사용자의 웹브라우저
의 벤더와 버전을 확인하여 이에 따라 적절하게 웹페이지를 표시하거나 대응할 필요가 있
다. 이는 오래된 웹브라우저를 사용하거나 특정 브라우저에서만 동작하는 기능을 제공할
때 특히 그렇다.
1994~2000년도 사이에 나온 브라우저들은 브라우저 시장 경쟁에서 이기기 위한 목적으로
출시된 것들이어서 W3C에서 제정하는 표준을 지키는 브라우저는 아니었다. 브라우저간
비호환성은 웹서비스 발전에 가장 중대한 도전이기 때문에 이를 표준적으로 지원하는 브
라우저의 출현은 필수 불가결한 것이었다. 현재 모질라 1.0 (넷스케이프6) 이상, IE5.5이상
버전의 브라우저들은 W3C의 웹 페이지 표현에 대한 표준인 HTML4.0, CSS1/2, W3C
DOM 시 방식을 지원하고 있다.
크로스 브라우징을 통해 웹페이지를 완벽하게 개발을 하기 위해서는 브라우저의 기능을
동작시에 판별할 수 있어야 한다. 즉, 에러를 일으키지 않고 다양한 방문자들이 폭 넓게
사용해 주기 위한 것이다. 일반적으로 사용되는 방법은 번거럽지만 브라우저를 식별하여
설계 시에 브라우저의 능력에 띠라 웹페이지를 만드는 것이다. 그렇지만, 다양한 브라우저
의 다른 기능을 개발자가 알아서 판단하고 제공한다는 것은 쉬운 일은 아니다. 그러나, 지
금까지 나열된 웹브라우저 차이점을 숙지하여 브라우저에 따라 판별 해 준다면 매우 유용
할 것이다.
다음은 브라우저를 판별하는데 사용하는 몇 가지 방법들이다.
실전 웹 표준 가이드
- 138 -
if (navigator.appName == "Microsoft Internet Explorer") {
document.all(id).style.visibility = "visible";
} else if (navigator.appName == "Netscape") {
if (parseInt(navigator.appVersion) < 5) {
document.layers[id].visibility = "show";
} else {
document.getElementById(id).style.visibility = "visible";
}
}
위의 예에서는 navigator 객체의 appName 이라고 하는 속성 값을 따라 "Microsoft
Internet Explorer" 혹은 "Netscape"를 판별하여 대응하는 코드를 실행하게 된다. 그러나,
Opera와 같이 navigator.appName나 navigator.appVersion의 값을 간단하게 변경할
수 있는 브라우저도 있고 개개의 브라우저를 하나하나 판별해야 하기 때문에 좋은 방법이
라 할 수 없다.
그래서 대부분 객체 기반의 브라우저 판별법을 사용한다. 지원하는 브라우저에 객체모델이
존재하는지 여부를 통해 간단하게 구현 기능을 확인하는 것이다.
if (document.getElementById) { // NS6+, IE 5+, Opera 5+
elm = document.getElementById(id);
}
else if (document.all) { // IE4, Opera
elm = document.all[id];
}
else if (document.layers) { // NN4
elm = document.layers[id];
}
이 예는 document.getElementById이라고 하는 객체를 가지고 있는 브라우저에 대해서
는 같은 코드를 실행한다. document.getElementById 객체는 W3C이 규정되어 있는
DOM의 표준으로 최근 웹브라우저는 대부분 지원하므로 통상 이 방법을 사용해야 한다.
따라서 W3C DOM을 사용하는 표준 웹브라우저에서 다음과 같이 <div id=xxx>…
</div>로 규정된 영역을 이동하는 간단한 스크립트를 생성할 수 있다.
function moveElement(id, x, y){ // W3C DOM Browser
var elm = document.getElementById(id);
if (elm) {
elm.style.left = x + 'px';
elm.style.top = y + 'px';
}
}
Browser sniffing으로 불리는 이러한 방법은 흔히 ECMAScript 함수에 의해 다루어져
아래와 같은 스크립트로 브라우저의 버전과 제품 벤더를 확인할 수도 있다.
// convert all characters to lowercase to simplify testing
var agt=navigator.userAgent.toLowerCase();
// *** BROWSER VERSION ***
실전 웹 표준 가이드
- 139 -
// Note: On IE5, these return 4, so use is_ie5up to detect IE5.
var is_major = parseInt(navigator.appVersion);
var is_minor = parseFloat(navigator.appVersion);
// Note: Opera and WebTV spoof Navigator
var is_nav = ((agt.indexOf('mozilla')!=-1) &&
(agt.indexOf('spoofer')==-1)
&& (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
&& (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1));
var is_nav2 = (is_nav && (is_major == 2));
var is_nav3 = (is_nav && (is_major == 3));
var is_nav4 = (is_nav && (is_major == 4));
var is_nav4up = (is_nav && (is_major >= 4));
var is_navonly = (is_nav && ((agt.indexOf(";nav") != -1) ||
(agt.indexOf("; nav") != -1)) );
var is_nav6 = (is_nav && (is_major == 5));
var is_nav6up = (is_nav && (is_major >= 5));
var is_gecko = (agt.indexOf('gecko') != -1);
var is_ie = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera")
== -1));
var is_ie3 = (is_ie && (is_major < 4));
var is_ie4 = (is_ie && (is_major == 4) && (agt.indexOf("msie 4")!=-
1) );
var is_ie4up = (is_ie && (is_major >= 4));
var is_ie5 = (is_ie && (is_major == 4) && (agt.indexOf("msie
5.0")!=-1) );
var is_ie5_5 = (is_ie && (is_major == 4) && (agt.indexOf("msie
5.5") !=-1));
var is_ie5up = (is_ie && !is_ie3 && !is_ie4);
var is_ie5_5up =(is_ie && !is_ie3 && !is_ie4 && !is_ie5);
var is_ie6 = (is_ie && (is_major == 4) && (agt.indexOf("msie
6.")!=-1) );
var is_ie6up = (is_ie && !is_ie3 && !is_ie4 && !is_ie5
&& !is_ie5_5);
// KNOWN BUG: On AOL4, returns false if IE3 is embedded browser
var is_aol = (agt.indexOf("aol") != -1);
var is_aol3 = (is_aol && is_ie3);
var is_aol4 = (is_aol && is_ie4);
var is_aol5 = (agt.indexOf("aol 5") != -1);
var is_aol6 = (agt.indexOf("aol 6") != -1);
var is_opera = (agt.indexOf("opera") != -1);
var is_opera2=(agt.indexOf("opera 2") != -1 ||
agt.indexOf("opera/2") != -1);
var is_opera3=(agt.indexOf("opera 3") != -1 ||
agt.indexOf("opera/3") != -1);
var is_opera4=(agt.indexOf("opera 4") != -1 ||
agt.indexOf("opera/4") != -1);
var is_opera5=(agt.indexOf("opera 5") != -1 ||
agt.indexOf("opera/5") != -1);
var is_opera5up=(is_opera && !is_opera2 && !is_opera3
&& !is_opera4);
실전 웹 표준 가이드
- 140 -
var is_webtv = (agt.indexOf("webtv") != -1);
var is_TVNavigator = ((agt.indexOf("navio") != -1)
|| (agt.indexOf("navio_aoltv") != -1));
var is_AOLTV = is_TVNavigator;
var is_hotjava = (agt.indexOf("hotjava") != -1);
var is_hotjava3 = (is_hotjava && (is_major == 3));
var is_hotjava3up = (is_hotjava && (is_major >= 3));
코드 작성 시 주의 사항
일반적인 코딩 규칙
자바스크립트를 사용할 때는 <script> 태그에 language="JavaScript"를 속성으로 선언해
사용하는 경우가 있는데 반드시 type="text/javascript"를 사용해 준다. JScript, VBscript
등은 IE에서만 사용하므로 사용하지 않도록 한다. 또한, 텍스트 브라우저나 비 스크립트
브라우저를 위해 NOSCRIPT라는 요소를 사용하여 대체 텍스트나 링크를 제공하거나, 클
라이언트측 스크립트 대신에 서버측 스크립트를 사용해 호환성을 높여 주는 것이 좋다.
<SCRIPT type="text/javascript"><!-- // // --> </SCRIPT>
<NOSCRIPT>
<UL>
<LI><A HREF="choice1.html">Choice1</A></LI>
<LI><A HREF="choice2.html">Choice2</A></LI>
</UL>
</NOSCRIPT>
또한, 내용은 꼭 코멘트를 사용하여 텍스트 브라우저에서도 잘 표현 되도록 해야한다. 코
멘트를 사용할 때는 <!--- -Comment-------> 로 쓰는 것은 잘못된 방법으로 <!--로 시작하
여 -->로 끝내고, 주석 내용 안에는 하이폰(-)이 두개 이상 들어가지 않도록 한다. 즉, <!--
==Comment==-->, <!-- Comment --> 방식이 바른 표현이다.
getYear()의 Y2K 문제
모든 브라우저가 ECMAscript의 기본 함수와 기능을 모두 지원하고있다. 따라서
ECMAScript만으로 스크립트 프로그래밍을 하는 것이 바람직 하다. 하나의 예를 들면, 국
민은행 홈페이지에 비 IE 브라우저로 접속 하면 날짜를 확인할 수 없다는 에러창이 뜬다.
이 에러 창은 날짜를 받는 Jscript 전용 함수를 사용해서 그렇다.
getYear() 라는 함수는 IE인 경우 2005, 비 IE 브라우저인 경우 2005년을 105로 반환한
다. 특히 1998년의 경우는 모두 98로 반환한다. 이런 에러를 없애기 위해서는
ECMAscript Spec에 있는 getFullYear()함수를 사용해야 한다.
속성 입력할 때 주의점
스크립트나 애플릿, 또는 다른 프로그램 객체를 사용하지 않거나 지원하지 않는 경우에도
페이지의 내용을 이해할 수 있어야 한다. 그것이 불가능하다면, 대안적으로 접근 가능한
실전 웹 표준 가이드
- 141 -
페이지에 그들을 대체할만한 정보를 제공하는 것이 좋다.
예를 들면, 스크립트 기능이 꺼져 있거나 지원되지 않을 경우에도 스크립트를 활성화하는
링크가 작동하도록 해야 한다. (예를 들어, 링크의 목적지로 "javascript:"를 쓰지 않아야
한다. href 속성의 값으로 "javascript:"를 쓰는 것은 접근성 지침 위반일 뿐 아니라
HTML 표준 위반이기도 하다. 이런 경우, onClick 등을 사용해야 한다.
<a href="javascript:goURL(here);">틀린 표현</a>
<a href="#" onClick="javascript:goURL(here);">맞는 표현</a>
사용자 form에서 action을 받은 후 나온 결과에 자바스크립트 만을 제공해 자동 전환하
는 결과는 될 수 있으면 사용하지 않는다.
<script> href.location="test.html"; </script> // 나쁜 표현
같은 내용만 담는 것은 권장하지 않으며 만약 한다면, window.href.location 이라고 정확
하게 표현하거나, <meta> 태그의 refresh를 사용하거나 하는 것이 옳다. 또한, 결과에 링
크로 직접 POST 하지 않고 document.form.submit(); 같은 방식을 쓰는 것도 지양해야
한다. 모질라에서는 사용자의 액션이 없는 자동 forum.submit()을 지원하지 않는다.
스크립트 블록 실행
자바스크립트 블록에 실행 스크립트를 넣어 바로 실행하게 하는 것도 올바르지 않은 방법
이다.
// 올바르지 않은 방법
<div id="foo">Loading...</div>
<script type="text/javascript">
document.getElementById("foo").innerHTML = "Done.";
</script>
// 올바른 방법
<body onload="doFinish()">
<div id="foo">Loading...</div>
<script type="text/javascript">
function doFinish() {
var element = document.getElementById("foo");
element.innerHTML = "Done.";
}
</script>
반드시 실행할 함수를 onLoad 함수로 넣어 실행하도록 한다.
Strict 모드에서 document.write()
자바스크립트는 document.write로 HTML 내용을 생성할 수 있다. 그런데 <script>태그
안에 <script>를 생성 할때는 문제가 발생된다. 일반적으로 Transtional 모드에서는 다음
과 같이 할 수 있다.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
실전 웹 표준 가이드
- 142 -
...
<script>
document.write("<script>alert("Hello")</script>")
</script>
Strict 모드에서는 Mozilla의 렌더링 엔진이 이를 허용 하지 않게 때문에 아래와 같이 표
현 해야 한다.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
...
<script>
document.write("<script>alert("Hello")</" + "script>")
</script>
실전 웹 표준 가이드
- 143 -
디버깅 및 품질 관리
지금까지 각종 웹 표준을 알아보고 이에 대한 각 웹 브라우저의 특성과 표준 지원 정도.
올바른 웹페이지 코딩 방법 등을 살펴보았다. 그러나, 이러한 가이드를 충분히 숙지하고
있어도 오류가 나는 것이 웹페이지이다. 가이드를 잘 익히는 것도 중요하지만, 결국 웹 개
발자가 개발 중이나 최종 작업을 마치고 어떤 방식으로 디버깅을 하고 품질 관리(QA)를
하는 가 하는 점도 매우 중요하다. 이 장에서는 최신 디버깅 및 품질 관리 방법을 알아 본
다.
기본 디버깅 방법론
웹 브라우저 기반 디버깅
우선 개발 중 가장 빠르게 해 볼 수 있는 것이 바로 여러 웹브라우저에서 기능을 구현하
여 동작 여부를 체크하는 것이다. IE4.0, IE5.5, IE6.0, Firefox 1.5, Nescape7, Opera8,
Safari1.3, Lynx2.8 등의 브라우저에서 확인해 볼 려면, 아래 링크를 따라가면, 각 웹브라
우저의 예전 버전까지 제공해 준다.
.. 인터넷 익스플로러: http://browsers.evolt.org/?ie/
.. 모질라 파이어폭스: http://browsers.evolt.org/?mozilla/
.. 오페라: http://browsers.evolt.org/?opera/
.. 넷스케이프: http://browsers.evolt.org/?navigator/
.. 사파리: http://browsers.evolt.org/?safari/
.. 링스(Lynx): http://browsers.evolt.org/?lynx/
웹 브라우저를 통한 디버깅에서 가장 쉬운 것은 웹페이지의 간단한 스크립트 오류를 알아
내기 위해서는 파이어폭스에 있는 자바스크립트 콘솔을 이용하는 방법이 있다. 이 콘솔을
이용하면, 표준안에 근접한 방법으로 웹페이지를 디버깅 할 수 있는 장점이 있다. 파이어
폭스는 W3C 표준 DOM과 ECMAscript를 지원하기 때문에 가장 먼저 개발 시 적용해
보고 다른 웹 브라우저로 확인 하는 방법을 이용하면 좋다.
그러나, 각 브라우저 버전별로 DOM, CSS JavaScript Core 등이 조금씩 다르기 때문에
호환성 테스트를 할 때 여러 문제들이 있다. 아래 사이트에서 PC에 동시에 설치할 수 있
는 다양한 버전의 InternetExplorer를 다운로드 받을 수 있다.
http://www.skyzyx.com/downloads/
자동화된 UnitTest를 통해 웹 브라우저별로 한번씩 실행시켜주기만 하면 되니까 편리 하
게 디버깅이 가능하다. 아래 그림은 IE 5.01, 5.5, 6.0, FireFox 1.0에서 자동화된 테스트를
통해 자바스크립트를 테스트 하고 있다.
실전 웹 표준 가이드
- 144 -
그림 31 다양한 웹 브라우저를 한번에 띄워 테스트 하는 모습
디버깅 도구 이용
앞서 언급한 대로 각종 웹브라우저에는 확장 스크립트 디버거들이 있다.
.. Firefox Javascript Debugger : 브라우저 내장
.. Microsoft Script Debugger:
http://msdn.microsoft.com/library/default.asp?url=/library/enus/
sdbug/Html/sdbug_1.asp
.. Internet Explorer Developer Toolbar :
http://www.microsoft.com/downloads/details.aspx?FamilyID=e59c3964-672d-
4511-bb3e-2d5e1db91038&displaylang=en
.. Visual Studio Script Debugger : http://msdn.microsoft.com/vstudio/
.. Venkman Javascript Debugger: http://www.mozilla.org/projects/venkman/
실전 웹 표준 가이드
- 145 -
이러한 스크립트 디버거로 알 수 있는 것은 DOM 요소와 속성 사용에 대한 에러 처리 같
은 것이다. 만약 Javascript 문법에 대해서도 확인하고자 한다면, Strict로 처리한다.
var response = true; var response = false; 라는 코드를 Strict모드로 한 경우 흔히 나
타나는 "redeclaration of var response" 에러의 경우 위의 문법을 아래와 같이 수정해야
에러가 없어진다. var response = true; response = false;
유사한 기능을 하는 IE에서도 MS 스크립트 디버거라는 프로그램이 있다. 기본적으로 자
바스크립트에 에러가 나면 아래와 같은 경고창이 나온다. 여기에는 에러가 생긴 곳
(Breakpoint)의 행과 문자 위치만 나오며 특별한 에러 메시지가 표시되지 않기 때문에 오
류를 찾아내는 것이 쉽지는 않다.
그리고, HTML의 표현상 오류는 소스를 간단히 살펴 봄으로서 해결이 되는 경우가 많다.
그러나 자바스크립트 문법과 DOM의 사용상의 오류는 쉽게 알아내기 힘들다. 따라서 이
러한 경우를 대비하여 디버거를 사용할 수 있다.
IE Developer Toolbar
MS에서 2004년부터 새로운 IE7 버전을 만들기 위해 꾸린 IE팀에서 웹 개발자를 위해 만
든 툴바이다. 이 툴바를 이용하면 DOM Explorer, Validator, Ruler 등 다양한 기능을 이
용할 수 있다.
다운로드: http://www.microsoft.com/downloads/details.aspx?FamilyID=e59c3964-
672d-4511-bb3e-2d5e1db91038&displaylang=en
그림 32 IE 개발자 툴바를 통한 DOM 스크립트 디버깅
Venkman 스크립트 디버거
Mozilla 프로젝트 중에는 자바스크립트 콘솔 및 벤크맨(Venkman)으로 불리는
실전 웹 표준 가이드
- 146 -
JavaScript 디버거가 내장 되어, 스크립트 개발자들에게 이용되고 있다. 이것은 화면 표시
와 콘솔 양쪽에서 조작할 수 있는 디버거이다. 스크립트에서 잘못된 코드로 인해 만들어
지는 종료점(beakpoint)괸리, Call Stack 감시 변수/객체 감시라고 하는 기능을 화면 콘솔
커멘드로 이용 가능하며, 대화형 콘솔에서는 임의의 JavaScript 코드를 실행시킬 수도 있
다. 키보드 쇼트 컷은 기존의 비주얼 디버그 환경에 맞추고 있어 gdb 의 사용자이면 벤크
맨의 break, step, next, finish, frame 및 where 커멘드를 자연스럽게 사용할 수 있다.
이 JavaScript 디버거는 Windows 환경에서의 비주얼 상호 개발 환경이나 다른 대규모
웹 개발도구보다 뛰어나 Mac OS 나 Unix 를 포함해 다른 플랫폼에 대해서는 비주얼 디
버그 환경에서 이 정도까지 포괄적으로 적용 가능하다. 왼쪽의 스크린샷은 벤크맨의 실행
모습이다.
그림 33 Venkman을 통한 스크립트 디버깅
DOM Inspector 검사기
W3C의 표준 권고안인 DOM에 대한 체계적인 구조도와 웹페이지 상의 잘못된 사용 방법
을 알려주는 도구인 DOM Inspector가 모질라에 역시 내장되어 있다. 임의의 웹 문서나
XUL 어플리케이션으로 이용 중 DOM 을 정밀 조사 하거나 수정하거나 하는데 사용할
수가 있는 도구로사, 문서 및 내부의 노드를 다종 다양한 시점에서 보는 볼 수 있는 윈도
우를 이용해 DOM 계층을 탐색할 수 있다. 아래쪽 스크린샷은 전형적인 DOM 정밀 조
사 작업의 모습이다. 이 프로그램은 Firefox에 자체적으로 내장되어 있다. Firefox를 설치
할 때 설치 내용을 묻는 대화 상자에서 고급 사용자 정의로 설치 하고 ‘개발 도구’를 체크
하면 DOM Inspector가 설치 된다.
실전 웹 표준 가이드
- 147 -
그렇지 않더라도 DOM Inspector 확장 기능을 http://update.mozilla.org 에 접속하여
다운로드 받을 수도 있다. 매우 편리한 기능을 가지고 있다.
그림 34 DOM Inspector를 통한 DOM 디버깅 (Firefox 내장)
그 밖에 모질라에서는 IE와 달리 페이지 소스 보기에서 문법을 하이라이트 처리하여 별도
로 확인 할 수 있으며, 캐쉬 관리자, HTTP 헤더 보기를 통해 웹서버와의 통신 과정에서
일어나는 일련의 과정을 모두 디버깅 해 볼 수 있다. 이러한 다양한 디버깅 방법들을 활용
하여 보다 웹 표준에 가까운 웹페이지 구현이 가능하다.
Interactive Shell
자바 스크립트 명령을 실행해 볼 수 있는 흥미로운 프로그램이다. Interactive Shell
(http://www.squarefree.com/shell/)은 Firefox에서 BookMarklet으로 등록해두면 원
하는 페이지에서 Shell을 띄워 DOM inspection을 할 수 있다.
Favelet Suite
HTTP Response Header Viewer, Hidden Field Modifier, DOM Inspector 등 유용한
디버깅 툴을 모아둔 BookMarklet 이다. http://slayeroffice.com/index.php
Firefox 자바스크립트 콘솔
Firefox에는 자체 내장되어 있는 자바 스크립트 콘솔이 있다. 이 콘솔을 이용하면 웹 페이
지내에 에러와 경고를 상세하게 보여 주며 정확한 위치의 소스를 보여 주는 기능 까지 가
지고 있다.
실전 웹 표준 가이드
- 148 -
그림 35 Firefox 자바스크립트 콘솔을 통한 디버깅
실전 웹 표준 가이드
- 149 -
올바른 플러그인(Plugin) 사용
외부 객체 이용 방법
올바른 OBJECT의 사용 방법
Cross browsing에서 가장 난감한 문제에 봉착했다. 바로 Plugin이라는 문제이다. Plugin
이란 HTML상에 특정 어플리케이션의 기능을 실행할 수 있도록 해주는 기술을 말하는
것으로 매크로미디어사의 Flash, 어도비의 Acrobat Reader, 리얼네트웍스의 Real Player,
마이크로소프트의 Windows Media Player 등이 여기에 속한다. 이들은 간단한 실행형
파일만으로도 웹브라우저 내에서 응용 프로그램을 실행할 수 있다.
이는 브라우저 전쟁 당시에 넷스케이프와 마이크로소프트가 각각 NSplugin과 ActiveX라
는 상호 배타적인 기술을 브라우저에 탑재하면서부터 시작되었다. NSplugin은 OS와 관계
없이 제작 실행될 수 있고 Opera나 Sapari 같은 웹브라우저에 채용되는 반면, ActiveX는
IE가 설치된 윈도우즈 환경에서만 실행된다. 당시 넷스케이프는 <embed>, <applet>을
마이크로소프트는 <object>라는 별도의 태그를 만들면서 이 기능을 지원해 왔다. HTML
4.01에서는 object가 표준으로 제정되었기 때문에, object만 사용하면 되지만 예전 NN4버
전과 표준 사용방법에 대해 여전히 논란이 제기되고 있다.
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/sw
flash.cab#version=5,0,0,0" width="366" height="142" id="myFlash">
<param name="movie" value="test.swf">
<param name="quality" value="high">
<param name="swliveconnect" value="true">
</object>
위의 코드는 IE에서 ActiveX를 불러오기 위한 HTML로서 classid는 clsid로 Flash의 고
유 프로그램 식별자이고, codebase는 Flash ActiveX가 설치되지 않은 경우 설치 파일이
위치한 경로를 지정한다. param은 문서 객체 모델에서 자식 노드로서 참고 할수 있는 값
들을 의미한다. Netscape6이나 Opera 4이상 부터는 object를 표준으로 지원하기는 하나
윈도우 미디어 플레이어 등 몇 가지에 국한된다. 또한, classid 같은 식별자를 사용하는 것
이 아니라 mime-type을 기반으로 하기 때문에 응용프로그램을 인식하는 방법이 IE의
object 기술방법과 크게 다르다.
<object type="application/x-shockwave-flash"
data="test.swf" width="366" height="142" id="myFlash">
<param name="movie" value="test.swf">
<param name="quality" value="high">
<param name="swliveconnect" value="true">
<p>You need Flash -- get the latest version from
<a href="http://www.macromedia.com/downloads/">here.</a></p>
</object>
위의 예제는 Mozilla 기반의 웹브라우저에서 flash를 찾아 실행하기 위한 object 의 사용
방법이다. mime-type을 통해 프로그램을 인지하고, IE와 같이 codebase를 통해 자동 설
실전 웹 표준 가이드
- 150 -
치하는 기능을 넣고 있지 않다. 특히, param을 무시하는 웹브라우저가 있기 때문에
data=”..swf” 파일 형식으로도 설정해 주고 있다. object를 사용하는데 있어, 모질라 기
반 브라우저들이 더 표준에 가깝게 기술되고 있으나 워낙 논란이 많고 Plugin이 IE 기반
이 많기 때문에 모두 같이 쓰는 것이 유리하다. 그러나 두 가지 코드를 동시에 사용하는
것은 불가능 하므로 위의 두가지 코드를 지원 여부에 따라 나누어 쓰거나 아예 두가지 정
보를 함께 담는 방법도 있다.
if (window.ActiveXObject) {
// IE ActiveX Code
document.write(“<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-
444553540000">
} else {
// Mozilla based Plugin Code
document.write(“<object type=”application/x-shockwave-flash"..”>
}
<embed>와 <applet>은 지금까지 널리 쓰이긴 하였으나, HTML4.01에서 권고하지 않는
방법으로 되어 될 수 있으면 사용하지 않는 것이 좋다. 그러나 NN4와 같은 브라우저의
버전 호환성 유지 차원에서 필요할 수도 있다. 따라서 자바 애플릿을 불러올 경우에도
object 태그를 사용해야 하며, 아래와 같은 예제를 사용하여 불러온다.
<object classid="java:NervousText.class" width="534" height="50">
<param name="text" value="Java 2 SDK, Standard Edition v1.4">
<p>You need the Java Plugin. Get it from
<a
href="http://java.sun.com/products/plugin/index.html">here.</a>></p>
</object>
위와 같은 방법으로 object 태그의 호환성을 높일 수는 있으나 기본적으로 NSplugin과
ActiveX의 기술적인 호환성 때문에 제일 중요한 목표인 응용프로그램 실행에는 문제가
있다. 이를 해결하기 위해서는 ActiveX 개발자가 NSPlugin API를 참조하여 같은 기능의
Plugin을 개발해 줄 필요가 있다.
또한, 윈도우 환경에서는 ActiveX for Plugin, Plugin for ActiveX 등의 양쪽을 호환할 수
있는 plugin(http://www.iol.ie/~locka/mozilla/mozilla.htm )을 설치하거나, 리눅스
데스크탑 환경에서는 wine (http://www.winehq.org) 같은 윈도우 에뮬레이터를 설치하
여 상호 기술을 사용 가능하다.
외부 객체 특허로 인한 문제 해결
최근 object와 plugin 사용과 관련하여 IE가 다른 업체의 특허를 침해했다는 법원 판결로
인터넷 사용 환경상 변화가 예상되는 가운데 인터넷 표준 언어인 HTML도 특허 논란에
휘말렸다. 2003년 9월 미국 시카고 법원은 지난달 “MS의 IE가 에올라스의 플러그인 기
술 관련 특허를 침해한 것이 인정된다”며 5억2000만달러를 배상하라고 판결했다. 이 소
송의 핵심은 HTML 플러그인 사용에 대한 특허를 UC가 92년도에 받아서 발명만 전담으
로 하는 회사인 이올라스에 94년에 팔았고, 이에 대해 소송을 제기해 W3C HTML 4.01의
object의 구동 방법에 대한 심각한 타격을 입힌 것으로 보인다. MS는 즉각 항소 의지를
밝히는 한편, W3C에 IE를 일부 수정할 뜻을 밝혔다. 이 문제는 IE 뿐만 아니라 모든 웹
실전 웹 표준 가이드
- 151 -
브라우저에 관련된 중요한 사안으로 특허를 피해 나가는 방법으로 아래 제안된 방법을 사
용하도록 권고 하고 있다.
Objec사용을 HTML내에 넣지 않고 JS파일에 넣어 실행하는 방법으로 아래와 같다.
// HTML File
<html>
<body>
<script src="embedControlOuterHTML.js"></script>
</body>
</html>
// embedControlOuterHTML.js
embedControlLocation.outerHTML = '<embed src="examplecontrol">';
아래 예제는 ActiveX 컨트롤에 Parameter 값을 설정하기 위해 createElement를 사용한
것이다.
// HTML File
<html>
<body>
<div id="embedControlLocation">
<script id="elementid" src="embedControl.js"></script>
</div>
</body>
</html>
// embedControl.js
var myObjectElement = document.createElement('<object id="elementid"
classid="clsid:098F2470-BAE0-11CD-B579-08002B30BFEB"></object>');
var myParamElement1 = document.createElement('<PARAM NAME=movie
value="example.avi">');
var myParamElement2 = document.createElement('<Param name=quality
value=high>');
var myParamElement3 = document.createElement('<Param name=bgcolor
value=#FFFFFF>');
myObjectElement.appendChild(myParamElement1);
myObjectElement.appendChild(myParamElement2);
myObjectElement.appendChild(myParamElement3);
embedControlLocation.appendChild(myObjectElement);
그리고, PARAM값을 DATA 객체로 사용할 때는 BASE64로 인코딩 하거나 js파일에 넣
어 document.write를 해야 된다.
- 참고URL
http://msdn.microsoft.com/library/?url=/workshop/author/dhtml/overview/act
ivating_activex.asp
실전 웹 표준 가이드
- 152 -
ActiveX와 대안 Plugin 기술
1995년 넷스케이프가 웹브라우저와 외부 프로그램과의 통신과 좀 더 다이나믹한 인터넷
경험을 제공하기 위해 플러그인(Plugin)이라는 기술을 선보였다. 그러나 마이크로소프트가
인터넷 익스플로러를 시장에 도입하면서 이에 대응하는 액티브X(ActiveX) 기술을 발표하
게 된다. 액티브X는 윈도우의 COM/DCOM 환경에서 인터넷을 자유 자재로 사용할 수
있는 기술 플랫폼으로 인터넷 익스플로러에 임베딩 되어 실행 가능하다. 인터넷 익스플로
러와 윈도우가 브라우저와 운영 체제를 독점하게 됨에 따라 윈도우 환경에서는 자바 애플
릿이나 넷스케이프 플러그인 기술을 대체하게 되었다
인터넷 익스플로러가 웹브라우저 시장 독점 체제를 구축하는 동안 우리 나라에서는 세계
에서도 유래를 찾아 볼 수 없을 정도로 급속한 인터넷 환경이 갖추어 지게 되었다. 이러한
성장의 이면에는 몇 가지 문제점이 발견되었는데 바로 특정 운영 체제와 플랫폼에 종속성
이 심화된 것이다. 웹페이지를 만들 때도 현재의 W3C에서 발표한 웹 표준 스펙을 이용하
지 않고, 당시 넷스케이프와 인터넷 익스플로러에서 경쟁적으로 사용되는 비표준 태그
(Tag)와 마이크로소프트 표준을 기반으로 하는 문서 객체(Document Object Model) 사
용 행태가 현재에도 고쳐지지 않고 있다. 인터넷 익스플로러도 최소한의 W3C 표준을 지
키고 있어 표준을 따르기만 하면, 쉽게 모든 브라우저를 지원하게 된다.
또한, 플러그인(Plugin) 기술 사용에 있어 액티브X 종속성이 더 심화 되어 비 윈도우, 비
IE 환경에서는 사용이 거의 불가능하다는 것이다. 액티브X 종속성은 외국에 비해 우리 나
라의 경우 매우 심각하다. 액티브X 콘트롤을 배포할 때 사용하는 코드사인(Codesign) 인
증서의 경우, 베리사인으로부터 국내에 공급되는 양은 거의 800여개가 된다. 인증서 하나
를 하나의 회사에서 사용한다고 본다면 적어도 800개의 업체에서 800개의 액티브X 콘트
롤이 배포되고 있다는 것을 의미한다. 이는 세계에서 최대 규모이며 적어도 코드사인 인증
서의 경우 세계 최대 시장이라고 들었다. 필자도 윈도우에 최소로 액티브X를 설치 하는
데도 30여개 정도가 설치되어 있다.
왜 액티브X가 문제인가?
액티브X를 우리 나라에서 급속도로 쓸 수 밖에 없었던 이유가 몇 가지가 있다. 첫번째는
초고속 인터넷의 급속한 확대이다. 플러그인이 구동 되기 위해서는 별도의 프로그램을 다
운로드 받아 설치를 해야 하는데 다운로드 크기가 큰 것은 모뎀 수준의 연결 속도에서는
다운로드 받을 때까지 기다릴 수 없는 것이다. 이런 이유로 아직 외국에서는 액티브X 같
은 플러그인 기술을 사용하는 웹사이트가 거의 드물다. 플래쉬와 윈도우 미디어, 리얼 플
레이어 등과 어도비 애크로뱃 리더처럼 설치시 제공하는 플러그인 정도가 대부분이다. 이
에 반해 우리나라는 로그인, 채팅, 파일 첨부, 광고, 카드 결제, 인터넷 뱅킹, 사이버 트레
이딩, 게임, 정부 민원 업무까지 그야말로 쓰이지 않는 곳이 거의 없을 지경이다. 초고속
망 국가로 빨리 진입한 것이 플러그인 들을 부담 없이 사용하게 한 원인이다.
두번째는 웹과 어플리케이션을 구별이 모호한 이유이다. 웹은 정보의 자유로운 공유라는
측면에서 발전 되어 왔는데, 우리 나라에서는 웹을 어플리케이션이 하는 기능의 연장 선상
에서 바라보고 있으며 그에 따라 부가 기능들이 계속적으로 필요로 하게 된 것이다. 소프
트웨어의 모든 기능을 웹이 할 수 있다는 생각에 여러 기능이 덕지덕지 붙어서 결국 웹도
어플리케이션도 아닌 어중간한 웹사이트들이 만들어 지는 것이다.
실전 웹 표준 가이드
- 153 -
세번째는 국가 차원에서의 플러그인 기술 장려를 들 수 있다. 우리 나라에서 플러그인 기
술이 가장 먼저 도입된 것도 인터넷 뱅킹과 공인 인증 기술에 있다. 1999년 당시 128비트
암호화가 탑재된 웹브라우저가 미국 밖으로 수출이 안되고 있는 사이, 우리 나라에서는
128비트 암호화가 가능한 SEED라는 알고리듬을 개발했고 이를 국가 인증 기술로 탑재하
는 과정에서 플러그인 기술을 사용하게 된 것이다. 당시에는 넷스케이프와 인터넷 익스플
로러 양쪽에 모두 포팅 했었으나 브라우저 점유율 확대에 따라 지금은 액티브X만 남게 되
었다. 플러그인은 자신의 PC에 다른 프로그램을 설치하는 것으로 보안 때문에라도 신중하
게 설치 여부를 검토해야 하는 데도 인터넷 뱅킹, 사이버 트레이딩, 공인 인증 등 액티브X
프로그램을 보안 경고창의 “예” 버튼 한번으로 설치했던 경험으로 일반인들에게 거부감
없이 받아들여 지고 있다. 최근 인터넷 익스플로러의 보안 이슈와 악성 플러그인이 범람함
에 따라 좀 더 신중하게 액티브X를 설치하는 사람들이 늘어나고 있기는 하지만.
대안 없는 무분별한 액티브X 사용은 그것이 자랑할만한 독자 기술이였다 하더라도 다시
특정 기술 플랫폼 종속적이 될 수 밖에 없다는 실례를 우라나라 공인 인증 기술에서 찾아
볼 수 있다. 99%가 사용하고 있으니 그것만 지원하는 것이 효율적이라는 생각에는 종속
성이 커짐에 따라 증대하는 관성과 더딘 기술의 진보, 그리고 상상할 수 없는 비용의 증가
를 예고하는 것이다. 얼마 전 윈도우XP 서비스팩2 출시에 따른 액티브X 설치 방법의 변
경으로 인해 생긴 문제 때문에 우리 나라만 서비스팩2 출시를 몇 달 간 연기하고서 우리
나라 모든 웹사이트들이 이 문제에 매달렸던 것만 봐도 알 수 있다. 그래서 운영 체제나
디바이스 플랫폼에 독립적인 데다 오픈 소스이기도 한 모질라 플랫폼에서 제공하는 대안
기술을 주목해야 하는 것이다.
ActiveX Plugin 기술
많은 사람들이 파이어폭스가 액티브X를 지원하면 많은 문제가 해결되는데 왜 그렇게 하지
않는지 의문을 가진다. 액티브X는 윈도우 종속적인 기술이고 모질라는 크로스 플랫폼을
지향하는 특성상 그렇게 할 수가 없다. 그러나 같은 기능을 두 가지로 개발하는 비용을 들
이는데 비해 우선 사용자층이 두터운 윈도우 플랫폼에서 액티브X를 사용할 수 있게 한다
면 또한 윈도우 개발자들도 모질라 플랫폼을 쉽게 가져다 쓸 수 있다면 서로를 이해하고
접근 하는 데 더 용이하지 않을까? 그래서 시작된 것이 바로 Mozilla ActiveX
Project(http://www.iol.ie/~locka/mozilla/mozilla.htm)이다. 이 프로젝트는 성격상
모질라의 공식 프로젝트는 아니지만 자원 봉사로 꾸준히 업데이트 되고 있다.
이 프로젝트의 결과물은 크게 두 가지 부분으로 나누어 진다. 그 첫번째는 액티브X 플러
그인(Plug-in For ActiveX controls) 기술이다. 이것은 기존의 모질라 플러그인 기술을 사
용하여 윈도우에 설치된 액티브X를 감지하고 실행하게 해 주는 플러그인이다. 즉, 파이어
폭스에서 액티브X를 실행할 수 있게 해준다. 이를 위해서는 먼저 인터넷 익스플로러와 파
이어폭스가 플러그인을 인식하는 방법을 맞출 필요가 있다. 똑같이 표준 태그인 <object>
를 사용하고 있지만 그 속성을 인식할 때 인터넷 익스플로러는
classid=”CLSID:XXXX...”, 파이어폭스는 type=”application/x-oleobject” 등과 같은 방
법을 사용한다. 액티브X 플러그인은 일단 classid를 인식하게 해준다. 그리고 clsid에 해
당하는 액티브X를 호스팅(hosting)하여 실행한다. 만약 비표준 자바스크립트나 VBScript
로 액티브X를 제어 하면 제대로 동작하지 않겠지만, 그렇지 않은 경우 대부분 잘 동작한
다.
실전 웹 표준 가이드
- 154 -
이 프로그램은 모든 액티브X가 실행되는 것은 아니다. 기본으로 윈도우 미디어 플레이어
가 실행될 수 있게 만약 실행하고 싶은 액티브X가 있으면 파이어폭스 디렉토리 내에
activex.js 파일에 클래스 ID를 추가해 주어야 한다.
pref("general.useragent.vendorComment", "ax");
pref("security.xpconnect.activex.global.hosting_flags", 9);
pref("security.classID.allowByDefault", false);
pref("capability.policy.default.ClassID.CID6BF52A52-394A-11D3-B153-
00C04F79FAA6", "AllAccess");
pref("capability.policy.default.ClassID.CID22D6F312-B0F6-11D0-94AB-
0080C74C7E95", "AllAccess");
그림 36 파이어폭스에서 윈도우 미디어 플레이어 액티브X가 실행되는 모습
이렇게 하는 이유는 보안상의 문제로 사용자가 실행할 액티브X를 결정할 수 있도록 하기
위해서이다. 아직 테스트 프로젝트이므로 편리한 인터페이스가 필요하다는 생각이 든다.
XPCOM Plugin 기술
액티브X와 모질라를 이어주는 플러그인 기술은 그 자체로서 크로스 플랫폼을 지원하지 않
기 때문에 매우 불안정한 대안이라고 밖에 볼 수 없다. 모질라가 가지고 있는 근본적인 대
안은 앞서 계속해서 다루어 온 대로 XPCOM을 이용하여 모든 플랫폼을 동시에 지원하면
서 XUL, 자바스크립트, CSS 등을 통해 인터넷 어플리케이션(Rich Internet Application)
을 만드는 기술의 확대를 꾀하는 것이다. 예전 플러그인이 수행했던 외부와의 통신 기능도
XML-RPC, SOAP, XMLHTTP 등의 기술로서 이미 해결되었기 때문에 확장 기능 등에서
활용도는 매우 높아지고 있다.
실전 웹 표준 가이드
- 155 -
그림 37 XUL로 개발한 아마존 서비스 브라우저
그러나, 그밖에 외부 기술을 도입하고자 한다면 모질라 내부에 구현해야 한다. XPCOM
Plugin기술은 XPIDL로 정의한 인터페이스를 구현한 플러그인 API와 이를 호출하는
XUL 및 자바스크립트로 구성되어 자유 자재로 구현 가능하다. 각 API의 경우 각 OS별
로 고려하고 컴파일 하는 수고를 제외하고는 크로스 플랫폼에서 훌륭하게 돌아갈 수 있다.
Flash (Flex)
Flex는 Flash라는 클라이언트 플러그인을 무기로 매크로 미디어에서 만든 서버와 클라이
언트의 중간 개념인 미들티어(middle-Tier) 플랫폼이다. FLEX 는 개발자들이 플래시개발
툴(Flash IDE) 없이도 태그로 간단하게 플래시를 만들수 있게 해준다
Flex는 Flash를 대체하는 게 아니라 그 기능의 확장으로서 flash로 FLEX에서 쓰일 컴포
넌트를 개발 하게 될것이다. Flex는 리치 인터넷 어플리케이션(RIA) 나 온라인 프리젠테
이션을 쉽고 간단하게 만들고자 하는 서버쪽 개발자를 위한 맞춤복 같은 솔루션이다.
FLEX 는 쉬운 MXML을 사용하므로 기존의 ASP/JSP/Coldfusion 개발자이 Flash 를
사용하지 않고도 화면구성을 컨트롤 할수 있게 한다
실전 웹 표준 가이드
- 156 -
그림 38 Flex의 서비스 플랫폼 구조
FLEX의 개발 환경은 ASP/JSP/Coldfusion 등 외부 개발 환경을 사용할 수 있다. 즉,
비지니스 로직은 기존과 같이 ASP/JSP/Coldfusion 등이 담당하고, FLEX가 화면표현쪽
을 담당하는 식으로 분리된다. Flex는 Flash로 가는 프로젝트에서 플래시로만 개발 했을때
는 소스가 복잡해지는 것을 막는다. 이에 Flash 개발자는 컴포넌트 만들기에만 집중하고
서버측 개발자는 그 컴포넌트를 사용해 화면 구성을 한다면 상당히 깔끔한 플랫폼이 만들
어질 가능성이 크다.
브라우저 내장 기술
Ajax
Ajax(Asynchronous JavaScript and XML)는 대화식 웹 어플리케이션의 제작을 위해 아
래와 같은 조합을 이용하는 웹 개발 기법이다:
.. 표현 정보를 위한 HTML (또는 XHTML) 과 CSS
.. 동적인 화면 출력 및 표시 정보와의 상호작용을 위한 DOM, 자바스크립트
.. 웹 서버와 비동기적으로 데이터를 교환하고 조작하기 위한 XML, XSLT,
XMLHttpRequest (Ajax 어플리케이션은 XML/XSLT 대신 미리 정의된 HTML 이나 일
반 텍스트, JSON, JSON-RPC를 이용할 수 있다).
DHTML이나 LAMP와 같이 Ajax는 자체가 하나의 특정한 기술을 말하는 것이 아니며,
함께 사용하는 기술의 묶음을 지칭하는 용어이다. 실제로 AFLAX와 같이 사실상 Ajax에
바탕을 두고 있는 유사/복합 기술들이 속속 나타나고 있다.
Ajax 어플리케이션은 실행을 위한 플랫폼으로 위에서 열거한 기술들을 지원하는 웹 브라
우저를 이용한다. 이것을 지원하는 브라우저로는 모질라 파이어폭스, 인터넷 익스플로러,
오페라, 사파리 등이 있다. 단, 오페라는 현재 XSL 포맷팅 객체와 XSLT 변환을 지원하지
실전 웹 표준 가이드
- 157 -
않는다.
그림 39 Ajax로 구현한 Google Maps
기존의 웹 어플리케이션은 폼을 채우고 제출(submit)을 하면, 웹 서버로 요청을 보내도록
한다. 웹 서버는 전송된 내용에 따라서 새로운 웹 페이지로 결과물을 되돌려준다. 이때 둘
사이에 중복되는 HTML 코드로 인해 많은 대역폭이 낭비된다. 게다가 이러한 방식으로는
네이티브 어플리케이션에 비해 고도로 대화형 사용자 인터페이스를 작성하기가 힘들다.
반면에 Ajax 어플리케이션은 필요한 데이터만을 주도록 웹 서버에 요청할 수 있다. 보통
SOAP나 XML 기반의 웹 서비스 언어를 사용하며, 웹 서버의 응답을 처리하기 위해 클라
이언트 쪽에서 자바스크립트를 쓴다. 그 결과로 웹 브라우저와 웹 서버 사이의 교환되는
데이터량이 줄어들기 때문에 어플리케이션의 응답성이 좋아진다. 요청을 주는 수많은 컴퓨
터에서 이 같은 일이 일어나기 때문에, 전체적인 웹 서버 처리량도 줄어들게 된다..
DHTML 어플리케이션과 같이, Ajax 어플리케이션에서는 브라우저마다의 편차를 고려해
서 엄격한 테스트가 이루어져야 한다. 이 기술로써 얻는 이득은 어플리케이션의 속도와 응
답성의 개선이다
Canvas
Canvas는 모질라 게코 렌더링 엔진에 HTML 엘리먼트로 추가된 기능이다. 이 새로운 엘
리먼트는 웹 컨텐츠 제공자가 웹페이지의 원하는 영역에 비트맵 혹은 벡터 그래픽을 그릴
수 있는 스크립트를 이용할 수 있도록 한다. 캔버스 엘리먼트는 웹 애플리케이션 1.0 스펙
의 일부로, 웹 하이퍼텍스트 애플리케이션 기술 워킹 그룹(Web Hypertext Application
Technology Working Group)이 만들었다. WHATWG는 월드 와이드 웹을 통해 풍부한
실전 웹 표준 가이드
- 158 -
애플리케이션을 전달하기 위한 신기술을 개발하는 것을 목표로 하는 그룹이다. 모질라 재
단, 오페라 소프트웨어, 애플 컴퓨터 등이 WHATWG의 회원이다. 캔버스 엘리먼트는 최
초 애플 맥 OS X의 대시보드(Dashboard)에서 이용하기 위해 만들어졌다.
Gecko의 HTML 캔버스 지원에 대해서 이것이 W3C 표준이 아닌 만큼 논쟁의 여지가
있으나, WHATWG는 추후에 이를 표준화하기로 결정하였다. 일반적으로 WHATWG 기
술은 HTML을 더 향상시키는 반면, W3C 표준은 선행적으로 XML을 향한 이전에 필요
한 급진적인 변화의 경향이 있다. 몇몇 사람들은 이로 인해 두 그룹이 충돌할 수 있다고
주장한다. WHATWG의 실용주의적인 접근이 W3C의 광범위하고 복잡한 표준에 맞서 궁
극적으로 웹 개발자들 사이에서 승리를 거둘지에 대한 논쟁이 일어나곤 한다.
그림 40 Canvas를 이용한 3D 게임
모질라 캔버스 구현은 크로스 플랫폼 Cairo 벡터 그래픽 라이브러리를 이용한다. Cairo는
모질라의 SVG(Scalable Vector Graphics)의 렌더링 백엔드로도 쓰이며 추후에 모질라의
그래픽 능력에 힘을 더해줄 계획을 갖고 있다. 작년 Cairo는 Mozilla Public License로
라이선스가 변경되었으며(더불어 LGPL로도), 모질라 재단의 요구에 편의를 도모하기 위
한 것이다. 이 기능을 통해 화려한 데스크탑 효과를 만들기 위해 새로운 캔버스 엘리먼트
와 XUL의 알파 채널 지원을 결합하였다.
웹 어플리케이션 표준화 동향
WHATWG
그간 웹 표준화 기구인 W3C(www.w3.org)를 통해 수 많은 웹 표준들이 제정되었음에도
불구하고 플러그인 기술 즉 웹 어플리케이션 기술에 대한 표준은 만들어 지지 못했다. 표
준은 상호 운용성 및 개방성 측면에서 매우 중요하며 공정한 경쟁을 유도할 수 있는 제도
적 장치이다. 이러한 필요성에 따라 W3C는 작년 4월 웹 어플리케이션에 대한 워크샵을
개최하고 이에 대한 의견을 나누었다. (http://www.w3.org/2004/04/webapps-cdf실전
웹 표준 가이드
- 159 -
ws/)
이 워크샵에서 크게 쟁점은 마이크로소프트와 오페라/모질라 재단 연합이 발표한 웹어플
리케이션 방향에 대한 것이다. 마이크로소프트는 XAML/아발론 등으로 대별되는 롱혼 전
략과 자사가 제안한 CSS3에 대한 이야기만 한 반면, 오페라/모질라 연합은 기존의 웹 표
준 기술을 활용한 중간 단계의 웹 어플리케이션 표준을 빨리 만들자는 제안을 하였다. 이
에 대해 많은 참석자들은 부정적인 반응을 나타냈다. 이런 문제를 다룰 워킹 그룹이 아직
존재하지 않는다는 이유를 달았지만 이미 W3C는 데스크탑 환경에서 웹 표준 문제 보다
는 오히려 모바일 같은 비PC 디바이스에서의 상호 운용성에 관심을 가진 사람들이 많았
으며 그곳에 초점을 두고 있었기 때문이다.
이에 2004년 6월 오페라와 모질라의 Ian Hickson과 David Baron, 애플의 David Hyatt
등이 주축이 되어 W3C와 별도로 표준안을 만들기 위한 웹어플리케이션 기술 워킹 그룹
(Web Hypertext Application Techology Working Group, http://whatwg.org ) 을 조
직하고 활동에 들어갔다. 이 워킹 그룹은 W3C 형식에 준하는 표준안 작업을 한 후, 향후
IETF나 W3C에 기초안(Draft)를 제안할 예정이다.
이 워킹 그룹이 작업 중인 표준안은 크게 세가지 영역으로 나누어져 있다. 그 중 가장 관
심을 끄는 Web Applications 1.0은 어플리케이션 개발을 하기 위해 기존의 HTML을 확
장하는 것이다. 흔히 HTML5라고 불리는 이 표준안은 XUL의 경험을 기초로 복잡한
XML을 사용하기 보다는 기존의 HTML을 확장 하여 UI를 만드는 것을 목표로 하는 것
으로 기존의 파이어폭스 확장 기능보다도 더 쉽게 웹 어플리케이션을 만드는 방법을 제안
할 것이다.
예를 들어 메뉴바를 만들기 위해서 아래와 같이 우리에게 익숙한 HTML태그와 그 확장
태그를 쓰겠다는 것이다.
<menubar>
<li>
<a href="#file">File</a>
<menu id="file">
<li><button type="button" onclick="fnew()">New...</button></li>
<li><button type="button" onclick="fopen()">Open...</button></li>
<li><button type="button" onclick="fsave()"
id="save">Save</button></li>
<li><button type="button" onclick="fsaveas()">Save
as...</button></li>
</menu>
</li>
</menubar>
이 표준안은 XHTML, CSS 같은 기존 표준안과는 연동 하지만, XUL/XAML 과는 독립
적으로 구성하겠다는 뜻을 가지고 있어 웹 표준으로서 기술을 주도하겠다는 생각을 가지
고 있다. Web Forms 2.0은 HTML4.01의 Form 부분의 기능을 확장하는 작업으로 Web
Application에서 사용하는 데이터 입력 및 출력 그리고 추가 등을 위해 기초적으로 필요
한 작업이다. 따라서 이 표준안 작업은 꽤 많이 진척되어 작년 연말까지 거의 완성되게 되
었다.
실전 웹 표준 가이드
- 160 -
W3C에는 이와 유사한 IBM이 제안하여 표준안이 된 XForm이 있다. XForm은 기계들간
의 데이터 교환 표준으로 삼고, WebForm은 사용자 인터페이스에 사용하게 하여 어플리
케이션 개발자들이 이해하기 쉽도록 하자는 것이 이 표준안의 취지이다. 이 표준안이
W3C나 IETF에 받아 들여 진다면 비 마이크로소프트 진영의 브라우저 어플리케이션 개발
에 보다 획기적인 플랫폼이 만들어질 것으로 예상된다.
그림 41 XForm과 WebForm의 관계도
마지막으로 Web Controls 1.0은 새로운 WebForm과 UI에 대한 콘트롤과 외양 표시가
가능하도록 DOM과 CSS의 기존 표준을 확장하는 작업이다. 이 부분은 기존의
DOM/CSS의 객체 사용 방법이 어느 정도 성숙되어 있기 때문에 제일 마지막에 할 작업
이 될 것이다.
표준은 표준으로만 존재하는 것이 아니라 구현 되었을 때 빛을 발하게 된다. 모질라와 오
페라 애플이 만드는 새로운 표준은 웹 개방성과 상호 운용성 문제를 해결 할 수 있는 중
요한 시발점이 될 것이다. 표준이 되더라도 과연 마이크로소프트가 이를 수용할 지 여부는
알 수 없지만 검증된 개발 방법론을 기초로 대안을 제시할 수 있다고 생각한다.
W3C Rich Web Application W/G
Ajax, Web2.0 등 리치 웹 어플리케이션에 대한 관심이 뜨거워 지지 W3C에서도 2005년
9월 워킹 그룹 활동 계획을 시작으로 하여 11월에 두개의 워킹 그룹을 공식적으로 설립하
였다.
Robin Berjon (Expway)가 의장을 맡은 Web APIs Working Group은 AJAX나
XMLHttpRequest 같은 표준 어플리케이션 인터페이스를 표준화 하는 논의를 시작한다.
또한, Art Barstow (Nokia)가 의장을 맡은 Web Application Formats Working Group
은 최근 XUL, XAML, MXML 등 각종 클라이언트 어플리케이션에 사용되는 XML 인터
실전 웹 표준 가이드
- 161 -
페이스 언어와 XBL 등의 표준을 다룬다.
그림 42 W3C의 웹 어플리케이션 포맷 워킹 그룹
W3C에는 유력한 인터넷 브라우저 업체와 기술 업체가 모두 참여 하고 있기 때문에 향후
표준화 움직임에 따라 RIA 시장이 움직을 것으로 예상된다. 따라서, 브라우저 플러그인
대용 기술에 대한 다양한 고민과 표준화의 방향에 따라 움직일 필요가 있다.
실전 웹 표준 가이드
- 162 -
실전 표준 웹 프로그래밍
실전 웹 표준 가이드
- 163 -
표준 MIME 타입 설정
MIME 타입은 인터넷 상의 파일 교환에서 - 메일을 통해서이든 웹을 통해서이든 - 파일
송신자가 수신자에게 '지금 보내는 파일은 이러이러한 형식이다'라고 알려 주기 위해 사용
한다. 파일 수신자가 그 파일을 온전히 해석하도록 하기 위해서 송신지가 꼭 전해 주어야
하는 매우 중요한 정보이므로, 웹 서버 관리자나 웹 개발자들은 올바로 이 정보를 전달하
기 위한 방법을 숙지하고 있어야 한다.
인터넷 익스플로러로 대표되는 몇몇 브라우저는 송신자가 보내는 MIME 타입 정보를 무
시하고, 파일의 첫 부분을 직접 들여다 보고 파일 타입을 스스로 결정한다. 하지만, 이런
방법은 인터넷 표준에 부합하는 것이 아니므로, 모든 웹 클라이언트가 지원하지 않다. 따
라서, 장치 독립적이고, 상호 운용성 있는 웹 사이트를 구축하려면, 웹 서버 관리자와 웹
개발자는 파일 송신 시에 필히 송신하려는 파일에 맞는 MIME 타입을 지정해서 보내야
한다.
웹 서버가 내보내는 MIME 타입을 확인하기 위해서는 HTTP 헤더 엿보기 프로그램이나
엿보기 사이트를 이용할 수 있다. 검색 엔진에서 'HTTP sniffer'라고 치면 이 서비스를 제
공하는 곳이나 프로그램을 쉽게 찾을 수 있다. 예를 들어, SniffURI.org에 가서 HTTP 헤
더의 내용을 알고 싶은 파일의 URL을 치면 그 파일을 제공하는 웹 서버가 내보내는 응답
(response) 내용(HTTP 헤더를 포함한)을 모두 볼 수 있다. 그 가운데에서 Content-
Type으로 시작하는 줄을 보십시오. 아래는 http://www.w3.org/StyleSheets/home.css
를 SniffURI에 치고 얻은 결과 중 일부를 보인 것이다. Content-Type으로 시작하는 줄에
서 text/css라는 값을 서버가 돌려주었다.
HTTP/1.1 200 OK
Date: Mon, 12 Dec 2005 11:53:28 GMT
Server: Apache/1.3.33 (Unix) PHP/4.3.10
P3P: policyref="http://www.w3.org/2001/05/P3P/p3p.xml"
Expires: Mon, 12 Dec 2005 17:53:28 GMT
Last-Modified: Mon, 16 May 2005 15:59:15 GMT
.... 생략 ...
Content-Length: 1545
Content-Type: text/css
MIME 타입을 잘 지정하는 것이 중요한 보기를 두 가지만 들겠다. 국내 유수의 어떤 신
문사 웹 사이트에서는 iframe으로 불러 들이는 html 파일에 'inc'라는 확장자를 붙여 놓
았다. 그런데, 그곳에서 쓰는 웹 서버는 따로 MIME 타입을 설정해 놓지 않은 확장자가
붙은 파일은 모두 application/octet-stream으로 처리하도록 되어 있다. 따라서, inc가 붙
은 파일을 iframe에서 불러 들일 경우 HTTP 표준을 잘 준수하는 브라우저(예를 들어,
firefox)는 파일을 저장하라는 (application/octet-stream은 바이너리 실행 파일로 브라우
저에서 처리할 수 없으므로), 대화 상자가 뜬다.
이 경우 'inc'라는 확장자를 'html'로 바꾸거나 (html이란 확장자는 거의 대부분의 웹 서
버에서 text/html로 이미 설정되어 있다.), 'inc'라는 확장자를 아래에서 설명하는 방법에
따라 'text/html'로 대응시켜 주어야 한다. 또, 어떤 웹 사이트를 firefox로 보면 html 소
실전 웹 표준 가이드
- 164 -
스가 그대로 드러나는 경우가 있다. 이것은 MIME 타입을 지정하지 않은 경우 무조건
'text/plain'으로 처리하도록 웹 서버가 설정되어 있기 때문이다. 이 경우에도 'text/html'
로 모든 웹 클라이언트가 처리하도록 하려면, 써버가 이 파일에 대해 'text/html'이라고
클라이언트에게 알리도록 설정을 고쳐야 한다. 또, 상당수의 국내 웹 서버가 CSS에 대해
MIME type을 지정해 놓지 않아서 application/octet-stream 혹은 text/plain을 서버가
내보내고 있다. 이 역시 text/css로 지정해 두어야 한다.
본래 인터넷 메일을 위해서 개발되었지만(RFC 2045-2049), 그 뒤에 인터넷 메일과 (RFC
2821/2822, RFC 2045-2049)과 웹(HTTP 1.x) 상의 정보 교환에서 공히 쓰이고 있다. 두
경우 모두 'Content-Type'이라는 헤더 필드를 통해 다음과 같이 지정한다. 웹 상에서 파
일 교환을 할 때에는 HTTP 헤더를 통해 그 헤더 필드를 내보내고, 메일에서는 메일 헤더
에 그 헤더 필드를 내보내야 한다. 다음은 몇 가지 보기이다.
Content-Type: type/subtype; param1=value1; param2=value2
MIME 타입 확장자 파라미터 설명 HTTP header
text/html html,
htm
HTML (인코딩은 문서
내부에서 지정)
Content-Type: text/html
text/html html,
htm
charset=EUC-KR HTML (EUC-KR 인코
딩)
Content-Type: text/html;
charset=EUC-KR
text/html html,
htm
charset=UTF-8 HTML (UTF-8 인코
딩)
Content-Type: text/html;
charset=UTF-8
text/css css CSS 스타일시트(인코딩
은 파일 내부에서 지정)
Content-Type: text/css
application/xml xml XML 문서 Content-Type:
application/xml
text/plain txt 일반 텍스트 파일 Content-Type: text/plain
text/rtf rtf Rich Text Format Content-Type: text/rtf
text/javascript js ECMAscript/Javascri
pt
Content-Type:
text/javascript
image/png png PNG 그림 파일 Content-Type: image/png
application/pdf pdf Adobe PDF Content-Type:
application/pdf
application/vnd.
ms-excel
xsl 엑셀 파일 Content-Type:
application/vnd.ms-excel
application/vnd.
sun.xml.writer
sxw 오픈/스타 오피스 워드
프로세서 파일
Content-Type:
application/vnd.sun.xml.
writer
application/octet
-stream
exe 바이너리 실행 패일 Content-Type:
application/octet-stream
실전 웹 표준 가이드
- 165 -
audio/mpeg mp3 mp3 Content-Type:
audio/mpeg
audio/x-mp3 mp3 mp3 Content-Type: audio/xmp3
video/x-mswmv
wmv 윈도우 미디어 비디오 Content-Type: video/xms-
wmv
application/xshockwave-
flash
swf 플래시 Content-Type:
application/x-shockwaveflash
audio/xrealaudio
ra 리얼 미디어 Content-Type: audio/xrealaudio
아직 IANA (인터넷에서 쓰는 여러 가지 번호나 형식 등을 등록하는 곳)에 공식으로 등록
되지 않은 파일 타입에 사용한다. MIME 타입 가운데 'text/*'(application/javascript 등
일부 'application/*'에도)에는 'charset'이란 parameter를 써서 문서에 쓰인 문자 인코딩
(character encoding)을 지정할 수 있다. 이에 대한 자세한 내용은 아래 문자 인코딩 설
정을 참고하면 된다.
Apache에서 설정 방법
Apache 웹 서버에서 MIME 타입을 지정하는 방법에는 몇 가지가 있다. 다음 두 문서를
참고하십시오.
.. http://httpd.apache.org/docs/2.1/mod/mod_mime.html
.. http://httpd.apache.org/docs/1.3/mod/mod_mime.html#addtype
Apache 1.x나 2.x에서 공히 IANA에서 등록된 지 충분한 시간이 지난 (최근에 등록된 경
우에는 아직 Apache에 반영되지 않았을 가능성이 있다.) MIME 타입에 대해서는
mime.types 파일에 모두 나열되어 있으므로, 흔히 쓰이는 확장자를 IANA에 등록된 흔
히 쓰이는 MIME 타입에 대해 쓴다면 특별히 다른 일을 할 필요가 없다. (mime.types의
위치는 써버 설치 방법에 따라 다르다.
/etc/, /etc/httpd/conf, /usr/local/etc/httpd/conf 등에 있을 것이다. Apache의
httpd.conf에서 TypesConfig 디렉티브를 써서 다른 곳에 있도록 지정할 수도 있다.) 하
지만, IANA에 등록되지 않았지만, 흔히 쓰이는 파일 형식 (예를 들어, mp3, Windows
Media, HWP, real audio 등)을 제공하는 경우나 흔히 쓰지 않는 확장자를 사용하는 경우
(위에서 보기로 든 'inc'를 'text/html'에 쓰는 경우)에는 아래에서 설명한 방법에 따라 따
로 지정해 주어야 한다.
서버 전체에서 지정하기
이 방법은 서버 관리자 권한이 있는 경우에만 쓸 수 있다. 두 가지 방법이 있다. 첫째는
'mime.types' (TypesConfig 디렉티브가 가리키는) 파일에 다음과 같은 줄을 더하는 것이
다. (물론, 이미 이런 항목이 있다면 더할 필요가 없겠지요.) Apache 문서에서는 이 중 두
번째 방법을 추천하고 있다.
application/xml xml
실전 웹 표준 가이드
- 166 -
application/xhtml+xml xhtml
application/javascript js
application/ecmascript es
text/css css
video/x-ms-asf asf asx
audio/x-ms-wma wma
video/x-ms-wmv wmv
application/x-pn-realaudio ram rm
application/x-realaudio ra
application/ogg ogg
application/x-hwp hwp
# 보기로 든 모 신문사 웹 서버에는 다음과 같은 설정을 더해 주어야 한다.
text/html inc
두번째는 웹 서버 설정 파일인 httpd.conf에 다음과 같은 줄을 더하는 것이다. 이 경우에
변경 후에 웹 서버를 다시 시작해야 한다. AddType 디렉티브를 써서 더한 내용이
mime.types 파일에 있는 내용보다 더 우선 순위가 높다는 데에 유의해야 한다.
# XML 에는 다른 MIME 타입을 쓸 수도 있지만, application/xml 권장
AddType application/xml .xml
# XHTML 문서에 사용할 수 있는 MIME 타입은 'text/html'을
# 비롯해서 이외에 몇 가지가 더 있음.
AddType application/xhtml+xml .xhtml
# Javascript, ECMAscript
AddType application/javascript .js
AddType application/ecmascript .es
# CSS
AddType text/css .css
# Windows Media format
AddType video/x-ms-asf .asf .asx
AddType audio/x-ms-wma .wma
AddType video/x-ms-wmv .wmv
# Real Media 관련 포맷
AddType application/x-pn-realaudio .ram .rm
AddType application/x-realaudio .ra
AddType application/ogg .ogg
AddType application/x-hwp .hwp
AddType application/octet-stream .rar
# 보기로 든 모 신문사 웹 서버에는 다음과 같은 설정을 더해 주어야 한다.
AddType text/html .inc
웹 사이트 별로 지정하기
AddType을 써서 가상 호스트 별로 서로 다르게 지정할 수 있다.
실전 웹 표준 가이드
- 167 -
디렉토리 별로 지정하기
서버 설정 파일 내에서 Directory로 묶인 부분에서 AddType을 써서 지정하거나, MIME
타입을 더하고자 하는 디렉토리 계층의 최상위 디렉토리에 '.htaccess' 파일을 만들고, 거
기에 AddType 을 써서 더할 수 있다. 후자의 경우에는 서버 관리자 권한이 없는 경우에
도 MIME 타입 설정을 변경할 수 있으므로, 웹 호스팅 서비스를 쓰는 경우에 특히 유용
할 것이다. 단, 이 경우에 서버 관리자가 서버 설정에서 .htaccess 파일에서 FileInfo 관련
값을 변경할 수(AllowOverride) 있도록 설정해 주어야 한다.
기본 MIME 타입 지정
어떤 버전의 Apache 서버의 경우 따로 MIME 타입을 지정하지 않은 확장자에 대해 기
본 MIME 타입(DefaultType)으로 text/plain을 쓰도록 설정되어 있는 경우가 있다. 서
버에서 전송할 모든 파일 타입에 대해 MIME 타입 지정을 해 놓은 경우에는 별 문제가
없지만, 그렇지 않은 경우 바이너리 파일이 브라우저 창에 뿌려지는 일이 생길 수 있다.
이런 일을 방지하려면 DefaultType을 application/octet-stream으로 설정해야 한다. 이
설정은 서버 전체의 설정 파일, 가상 호스트 설정 파일과 디렉토리별 설정 파일
인 .htaccess에서 할 수 있다.
IIS에서 설정 방법
다음은 마이크로소프트 테크넷의 아래 주소에서 가져온 것이다.
http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS
/cd72c0dc-c5b8-42e4-96c2-b3c656f99ead.mspx
웹 서버 전체에 대해 특정 확장자를 갖는 파일에 대해 특정 MIME 타입을 지정하려면 다
음과 같이 한다.
1. IIS 관리자에서 'local computer'를 클릭하고, 다시 '속성'을 선택한다.
2. MIME 타입 단추를 누릅니다
3. '새로 만들기'를 누릅니다.
4. '확장자' 상자에 확장자 이름 (예를 들어, 'css', 'inc', 'hwp')을 입력한다.
5. 'MIME 타입' 상자에 해당 파일의 MIME 타입을 입력한다. 예를 들자면, 'text/css',
'text/html', 'application/x-hwp' 등이다.
6. '확인'을 누릅니다.
7. 웹 써버 전체가 아니라 웹 서버가 호스팅하는 일부 웹 사이트나 일부 디렉토리에 대해
서만 MIME 타입을 더하려면 다음과 같이 한다.
8. IIS 관리자에서 MIME 타입을 더하고자 하는 웹 사이트나 디렉토리를 골라서 오른쪽
마우스 버튼을 누르고, 거기에서 '속성'을 선택한다.
9. HTTP 헤더 탭을 클릭한다.
10. MIME 타입을 클릭한다
11. 새로 만들기를 클릭한다
12. '확장자' 상자에 확장자 이름 (예를 들어, 'foo')을 입력한다.
13. 'MIME 타입' 상자에 해당 파일의 MIME 타입을 입력한다. 예를 들자면, 'text/plain',
'text/html', 'application/x-foo' 등이다. 이미 상위 수준(예를 들어 웹 서버 전체)에서
실전 웹 표준 가이드
- 168 -
정의한 MIME 타입을 더하려고 할 경우 지금 더하는 정의를 어느 수준에서부터 적용할
것인지 정하라는 질문에 답해야 한다.
14. '확인'을 누릅니다.
설정해 놓은 MIME 타입을 제거하기 위해서는 다음과 같이 한다.
1. IIS 관리자에서 MIME 타입을 제거하고자 하는 웹 사이트나 디렉토리를 골라서 오른쪽
마우스 버튼을 누르고, 거기에서 '속성'을 선택한다.
2. HTTP 헤더 탭을 클릭한다.
3. MIME 타입을 클릭한다
4. 등록된 MIME 타입 목록에서 제거하고자 하는 타입을 클릭하고, '제거하기'를 누릅니다.
5. '확인' 단추를 세 번 누릅니다.
PHP에서 설정 방법
CGI에서 사용되는 다양한 프로그램 언어들이 있지만 PHP를 예를 들어 다른 언어에 적용
할 수 있을 것이다. http://kr.php.net/header에서 자세히 설명하고 있는 header() 함수
를 써서 Content-Type을 지정해 주어야 한다.
<?php
// PDF 파일을 전송할 경우
header('Content-type: application/pdf');
// 이름은 'my resume.pdf'
// Content-Disposition 헤더 필드의 filename 파라미터에 쓸 파일 이름
// 중간에 공백이 있을 경우 따옴표로 꼭 묶어야 함.
header('Content-Disposition: attachment; filename="my resume.pdf"');
// 서버 측에 있는 PDF 문서의 이름은 original.pdf
readfile('original.pdf');
?>
<?php
// UTF-8 로 된 text/html 파일을 보낼 때
// 이 경우 이후에 따라 나오는 HTML 파일에서 meta tag 을 써서 문자 인코딩을
// 지정할 필요는 없음. 지정하는 경우에는 header 에서 지정한 값이 우선임을
// 명심할 것. MS IE 는 이 표준을 무시하고, html 파일 내부의 값에 우선 순위를
// 두므로, 브라우저 독립성을 위해서 둘 사이에 모순이 없도록 유의할 것.
header('Content-type: text/html; charset=UTF-8');
....
?>
Apache Tomcat에서 설정 방법
다른 JSP/Servlet container도 비슷한 방식을 사용할 것이다.
실전 웹 표준 가이드
- 169 -
정적 내용물(Static Contents)
conf 디렉토리 아래에 있는 web.xml 파일에 보면 확장자들을 MIME 타입에 대응시켜
놓은 다음과 같은 부분을 볼 수 있다.
<mime-mapping>
<extension>zip</extension>
<mime-type>application/zip</mime-type>
</mime-mapping>
<mime-mapping>
<extension>css</extension>
<mime-type>text/css</mime-type>
</mime-mapping>
Apache에서 배포하는 Tomcat에는 IANA에 등록되지 않은 wma, wmv, rar, hwp 등에
대한 MIME 타입 대응을 해 놓지 않았으므로, 이들에 대해 위와 비슷한 방식으로
web.xml 파일에 추가한 후, 서버를 다시 시작해야 한다. HWP의 경우 application/xhwp로
할 경우 다운로드가 안 될 수도 있다고 한다. 그 경우에는 application/octetstream을
대응시켜야 한다.
<mime-mapping>
<extension>hwp</extension>
<mime-type>application/octet-stream</mime-type>
</mime-mapping>
<mime-mapping>
<extension>wma</extension>
<mime-type>audio/x-ms-wma</mime-type>
</mime-mapping>
동적 내용물(Dynamic Contents)
JSP에서는 다음과 같은 식으로 파일 선두에서 MIME 타입을 지정할 수 있다. 서블렛 엔
진이 생성해서 외부로 전송하는 파일의 문자 인코딩은 @page 디렉티브의 contentType
에서 지정한다. JSP 소스 파일의 인코딩은 pageEncoding으로 지정한다. 따로
pageEncoding을 지정하지 않으면 contentType에서 지정한 인코딩을 JSP 소스 파일 인
코딩으로 가정한다. 반대로 pageEncoding만 지정하면 contentType에서 charset을 지정
하지 않으면 외부로 전송하는 파일의 인코딩도 pageEncoding의 값이 된다.
<%@page contentType="text/css" %>
<%@page contentType="text/plain" %>
<%@page contentType="text/html;charset=UTF-8" %>
<%@page contentType="text/html;charset=EUC-KR" %>
<%@page pageEncoding="EUC-KR" contentType="text/html;charset=UTF-
8" %>
<%@page pageEncoding="UTF-8" contentType="text/html;charset=EUCKR"
%>
3(4)행은 JSP 소스 파일을 UTF-8 (EUC-KR)로 해석하고 HTML 파일도 UTF-8(EUCKR)
로 내보냅니다. 5(6)행은 JSP 소스 파일은 pageEncoding에서 지정한 EUC-KR(UTF-
8)로 해석하고, 외부로 내보내는 HTML 파일은 UTF-8(EUC-KR)로 인코딩한다. 처음 두
실전 웹 표준 가이드
- 170 -
경우에는 서버의 기본 설정 값인 ISO-8859-1을 문자 인코딩 값으로 사용하므로, 그렇지
않은 경우에는 꼭 명시적으로 지정해 주어야 한다.
어느 경우에나 JSP 소스 파일의 실제 인코딩이 JSP 엔진이 생각하는 문자 인코딩과 일치
하도록 주의를 기울여야 한다. 항상 UTF-8을 쓰기를 강력히 권장한다. JSP를 쓸 경우에는
PDF, zip 파일 등 바이너리 파일은 내보낼 수 없고, 오직 text 파일만 내보낼 수 있다. 바
이너리 파일을 내보낼 때에는 servlet을 써야 한다.
Servelet에서는 setContentType을 써서 MIME 타입을 지정할 수 있다.
//response 가 ServletResponse type object 일 때
response.setContentType("text/html; charset=UTF-8");
response.setContentType("text/plain; charset=EUC-KR");
response.setContentType("application/pdf");
response.setContentType("application/x-hwp");
response.setCharacterEncoding("UTF-8"); // Java servlet 2.4 이후에서
Perl/Python 등으로 쓴 CGI
CGI 스크립트에서는 파일의 본체 전송을 시작하기 전에 HTTP 헤더 필드를 차례로
print 문이나 그와 동등한 방법으로 출력해 주면 된다. 단, HTTP 헤더 전송이 다 끝나고,
파일 본체 전송을 시작하기 전에 빈 줄을 하나 넣어 주어야 한다는 사실을 잊지 말아야
한다.
print "Content-Type: text/html; charset=UTF-8\n";
print "Content-Type: application/pdf\n";
print "Content-Type: application/x-hwp\n";
print "Content-Type: application/xhtml+xml\n";
실전 웹 표준 가이드
- 171 -
표준 문자 인코딩 지정
텍스트 형식의 파일(HTML, XML, CSS, Javascript, RTF, 일반 텍스트 등)을 송신하는 서
버는 그 파일의 MIME 타입과 아울러 그 파일이 어떤 문자 인코딩으로 쓰인 것인지를 수
신 측에 알려 주어야 한다. 이 값이 없이는 문서를 수신 측에서 올바로 해석할 수 없기 때
문에 HTML, XML, CSS 문법 검사 프로그램은 이 값이 제대로 설정되지 않은 경우 유효
하지 않은 문서로 간주한다. 문자 인코딩을 수신 측에 알려 주는 방법에는 크게 다음 3가
지가 있다.
.. HTTP 헤더의 Content-Type에 charset parameter를 더해서 지정하는 방법. 아래는 몇몇
보기이다.
Content-Type: text/html; charset=UTF-8
Content-Type: text/html; charset=EUC-KR
Content-Type: text/css; charset=UTF-16LE
Content-Type: text/xml; charset=UTF-8
.. Content-Type: application/javascript; charset=UTF-8
.. 파일 형식 고유의 내부적인 방법. HTML, XML, CSS 등은 이런 방법을 쓸 수 있다.
.. 현재 문서를 참조한(refer to) 문서와의 관계로부터 현재 문서의 인코딩을 결정. 예를 들어,
HTML 문서에서 CSS 파일을 참조한 경우 앞선 두 가지 방법으로 인코딩을 결정할 수 없
을 경우, CSS 파일은 HTML 문서의 인코딩이라고 간주한다. Javascript/ECMAscript나
text/plain처럼 문서 형식에서 두번째 방법을 지원하지 않는 경우에도 (Unicode에 기반
을 둔 몇몇 문자 인코딩은 Byte Order Mark를 써서 이런 경우에도 문서 인코딩을 결정할
수 있기도 한다.) 첫번째 방법을 통한 인코딩 지정이 없으면, 이 방법이 쓰이다.
웹 서버 설정을 변경하여 모든 정적인 문서에 대해 HTTP 헤더로 항상 같은 charset 값
을 내보내도록 하는 것은 좋은 생각이 아닙니다. 왜냐하면, 그렇게 할 경우 HTTP 헤더에
서 지정한 값의 우선 순위가 문서 내부에서 지정한 값보다 더 높아서 개별 문서별로 문자
인코딩을 지정할 수 없기 때문이다. MS IE는 HTTP 표준을 어기고 HTML 문서의 경우,
HTTP 헤더에서 지정한 값보다 문서 내부에서 지정한 값에 더 높은 우선 순위를 부여한
다.
하지만, 대부분의 다른 웹 브라우저는 문서 내부에서 지정한 값과 HTTP에서 지정한 값이
다를 경우 전자를 따릅니다. 따라서, 문서 형식이 제공하는 인코딩 지정 방법을 사용해서
문서 내부에서 지정하는 것이 많은 경우에 더 좋다. 하지만, PHP, CGI, JSP, ASP 등으로
동적으로 생성하는 문서에서는 서버 측 프로그램에서 각 문서 송신에 앞서 HTTP 헤더를
동적으로 변경할 수 있으므로, HTTP 헤더를 통해 문자 인코딩을 지정하는 것이 더 좋다.
단, XML 문서의 경우에는 문서 내부에서 지정하는 것을 권장한다. 또, 대부분의 경우에
HTTP 헤더와 문서 내부 모두에서 지정하는 것은 불필요한다. 하지만, 그렇게 하는 것을
권장하는 의견도 있다. 웹 서버를 통하지 않고 문서를 볼 경우(예를 들어, CD-ROM이나
디스크에 있는 문서를 볼 경우)에 대비하여 문서 내부에서 문자 인코딩을 지정해 놓는 것
은 좋은 생각이다. 그렇게 할 경우에는 두 값이 일치하도록 주의를 기울여야 한다.
한국어 문서를 제공하는 웹 사이트에서 흔히 쓰는 문자 인코딩은 EUC-KR이다. 마이크로
소프트 기반 제품에서는 "ks_c_5601-1987"을 쓰기도 한다만, 이것은 올바른 이름이 아닙
실전 웹 표준 가이드
- 172 -
니다. EUC-KR은 2byte로 표현할 수 있는 한글 음절의 수가 2350자로 제한되어 있다. 따
라서, '똠', '홥', '헿' 등의 글자를 표현하기 위해서는 8byte를 써야 한다.
하지만, KS X 1001 부록 3에서 규정한 이 방법은 mozilla firefox 등 gecko 기반 브라우
저만 지원한다. 따라서, 모든 브라우저에서 현대 한국어의 모든 음절을 불편 없이 쓰기 위
해서는 유니코드에 바탕을 둔 인코딩 방법인 UTF-8, UTF-16LE (LE는 Little Endian. 일
부 Windows 기반 프로그램에서 'Unicode'라고 부르는 인코딩 방법은 실제로는 UTF-
16LE이다), UTF-16BE (BE는 Big Endina) 등을 써야 한다. 몇 년 전과는 달리 UTF-8,
UTF-16 등을 지원하는 문서 편집기(Windows XP에서는 노트 패드나 워드 패드도 지원)
와 웹 저작 도구 (예를 들어, Dreamweaver, Nvu, MS FrontPage 등)를 쉽게 구할 수 있
다.
또한, Oracle, DB2 등 상용 DBMS는 물론이고, MySQL, Postgres 등 open source DB도
UTF-8을 잘 지원하며, Linux의 기본 인코딩도 UTF-8이다. 따라서, UTF-8 (혹은 UTF-16)
을 사용할 것을 강력하게 권고한다.. HTML 문서에 UTF-8을 사용하면 한글 이름을 지닌
파일을 HTML 문서에서 참조할 때 EUC-KR 문서에서 하듯이 한글 부분을 %-escape하
지 않아도 된다.
즉, EUC-KR 문서에서는 'http://www.example.com/%B0%A1%B0%A2.jpg'라고 해야
하지만, UTF-8 문서에서는 'http://www.example.com/가각.jpg'라고 할 수 있다. 이외
에도 한국어가 아닌 다른 언어를 지원하거나 (예를 들어, 한국인을 위한 중국어/일본어/
러시아어 사전이나 언어 교육용 웹 사이트), 장차 해외 시장으로 진출할 때 유니코드 기반
으로 작업하면 훨씬 편리한다.
문자 인코딩 지정에 대한 정보와 유니코드 지원 도구에 대해서는 웹 페이지와 거기에서
언급하고 있는 관련 페이지를 참고하면 된다.
.. http://www.w3.org/International/O-HTTP-charset : HTTP에서 문자 인코딩 지정 방

.. http://www.w3.org/International/O-charset.html : XML과 (X)HTML에서 문자 인코
딩 지정 방법
.. http://www.alanwood.net/unicode/index.html : 유니코드를 지원하는 각종 도구 (편
집기, 워드 프로세서 등), 글꼴, 브라우저 등에 대한 자세한 정보를 얻을 수 있다.
.. convmv
(http://osx.freshmeat.net/projects/convmv/?branch_id=39772&release_id=144059)
: 파일 시스템 인코딩 변환 도구. 리눅스에서 EUC-KR 파일 시스템 인코딩을 쓰고 있다면,
이 도구를 써서 UTF-8로 변환할 수 있다. 이 도구는 파일 이름을 변경하는 도구이다. 파
일 내용의 문자 인코딩 변경은 iconv 등을 쓰거나 위에서 언급한 문서 편집기, 저작 도구
를 사용하십시오.
.. fileiri (http://www.w3.org/2003/06/mod_fileiri/) : Linux/Unix에서 설치된 Apache
2.x용 파일 시스템 인코딩 실시간 변환 모듈. convmv로 파일 시스템 인코딩을 변환하는
대신 사용 가능. 참고 문헌에 있는 '국제화된 도메인 이름과 리소스 식별자 튜토리얼'도 참
고하기 바랍니다.
.. PuTTY (http://www.chiark.greenend.org.uk/~sgtatham/putty/) : Windows용 무료
SSH 클라이언트로 UTF-8을 매우 잘 지원한다. 컬럼비아 대학에서 만든 Kermit95도 잘
지원하지만, 유료이다.
실전 웹 표준 가이드
- 173 -
문서에서 지정
문서 형식에 따른 문자 인코딩의 결정의 우선 순위와 내부에서 지정하는 방법은 다음과
같다.
HTML
HTML의 경우 meta tag을 써서 다음과 같이 문자 인코딩을 내부에서 지정할 수 있다.
이때, 꼭 문자 인코딩을 지정하는 meta 태그가 head의 맨 처음 요소가 되도록 해야 한다.
많은 웹 사이트에서 title 다음에 문자 인코딩을 지정하고 있다.
대부분의 경우 별 문제가 없지만, 매우 미미할지라도 좀더 빠른 웹 페이지 렌더링을 원한
다면 꼭 표준에 따라 문자 인코딩을 지정하는 meta를 head의 맨 처음 요소로 넣으시기
바랍니다. 특히, 문자 인코딩을 지정하는 meta의 위치가 파일 선두에서 지나치게 떨어진
곳에 있을 경우 브라우저가 이 값을 감지하지 못 할 가능성이 높으므로 그렇게 해서는 절
대 안 된다.
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>문서 제목</title>
... 다른 헤더 태그들 : style, script, link 등 ..
</head>
문자 인코딩 결정의 우선 순위는 다음과 같다.
HTTP 헤더를 통해 전송된 Content-Type 필드의 "charset" 파라미터
문서 내부에서 meta로 지정한 값
대부분의 브라우저가 이외에도 참조한 문서의 인코딩 값, 웹 브라우저의 기본값, 인코딩
자동 감지 등의 방법을 채용하고 있다. 하지만, 명시적으로 문자 인코딩을 지정하면, 이런
방법의 구현 여부에 관계 없이 항상 문서가 원하는 방식으로 웹 브라우저나 다른 웹 클라
이언트에 의해 해석될 것이다.
XML
모든 XML 문서는 문서의 최선두에서 다음과 같은 방식으로 문자 인코딩을 선언해야 한
다. 단, 'encoding="UTF-8"' 부분이 없고, 문자 인코딩에 대한 다른 외부 정보가 없는 경
우에는 기본으로 UTF-8을 가정한다.
<?xml version="1.0" encoding="UTF-8"?>
XML 문서가 HTTP를 통해 전송될 경우 문자 인코딩 결정의 우선 순위는 다음과 같다.
HTTP 헤더를 통해 전송된 Content-Type 필드의 "charset" 파라미터. 단, Content-Type
으로 text/xml을 쓰면서 charset 파라미터를 생략하면 US-ASCII가 기본값이 되고, USASCII
범위 밖의 문자를 포함한 모든 XML 문서가 유효하지 않게 되므로, charset을 생
략하지 않도록 주의해야 한다. application/xml을 MIME 타입으로 쓸 경우 이런 문제가
없다.
실전 웹 표준 가이드
- 174 -
BOM(Byte Order Mark) 혹은 문서 최선두의 XML 선언에서 지정한 값
더 자세한 내용은 XML 1.1 규약의 4.3.3과 부록 F를 참고하면된다.
XHTML
원칙적으로 XML과 같지만, 호환성을 위해 meta 태그를 통한 인코딩 선언과 XML을 통
한 인코딩 선언을 같이 써 주어야 한다. 이 경우 두 값은 일치하여야 한다. 일치하지 않을
경우 표준은 XML 선언의 값에 우선 순위를 부여하지만, XHTML을 지원하지 않은 구식
브라우저에서 잘못 해석할 수도 있으므로, 두 값은 꼭 일치시키십시오. 또, meta 태그를
통한 인코딩 선언에서 meta tag을 닫을 때 ">"가 아니라 "/>"를 써야 한다는 점에 유의
하십시오. X(HT)ML에서는 UTF-8이 기본 문자 인코딩이므로, UTF-8을 쓸 경우에는
'encoding="UTF-8"'은 생략 가능한다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="ko" xml:lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"
/>
<title>문서 제목</title>
... 다른 헤더 태그들 : style, script, link 등 ..
</head>
문자 인코딩 결정의 우선 순위는 XML과 같다.
CSS
CSS 문서 내부에서 encoding을 지정하기 위해서는 CSS 파일은 다음과 같이 시작해야
한다. Unicode에 기반한 인코딩 (UTF-8, UTF-16LE, UTF-16BE, UTF-32BE 등)을 쓸 경
우에는 BOM(Byte Order Mark)을 파일 선두에 붙여서 문자 인코딩을 표시할 수도 있다.
@charset="UTF-8"; /* UTF-8 로 지정 */
@charset="EUC-KR"; /* EUC-KR 로 지정 */
문자 인코딩 결정의 우선 순위는 XML과 같다.
.. HTTP 헤더를 통해 전송된 Content-Type 필드의 "charset" 파라미터
.. BOM(Byte Order Mark) 혹은 @charset를 써서 CSS의 최선두에서 지정한 값
.. CSS 문서를 참조하는 HTML 문서에서 <link charset="">로 지정한 값
.. CSS 문서를 참조하는 HTML/XML 문서의 문자 인코딩
.. UTF-8로 가정
실전 웹 표준 가이드
- 175 -
웹 서버 프로그램에서 지정
Apache 서버
MIME 타입 지정과 마찬가지로 DefautlCharset 디렉티브를 써서 기본값을 지정할 수 있
다. 하지만, 이 값은 웹 서버 전체에 대해서는 지정하지 않는 것이 좋다. 특정 디렉토리나
특정 가상 호스트에서 제공되는 모든 정적인 텍스트 문서가 이 기본값을 문자 인코딩으로
사용하는 특수한 경우에만 이 값을 지정하는 것을 고려해 볼 수 있다. 또, 웹 서버 관리자
가 이 값을 설정해 놓았고, 일반 사용자나 가상 호스트 사용자가 자신의 웹 영역에 있는
모든 정적인 문서에 대해 다른 값을 일관되게 쓰고 싶다면, .htacces에서 이 값을 지정할
수 있다.
DefaultCharset UTF-8
AddType을 써서 확장자를 MIME 타입에 대응시킨 것과 마찬가지로 AddCharset을
써서 확장자를 문자 인코딩에 대응시킬 수 있다. 이 대응에 대해서는 다음 문서를 참고하
십시오.
.. http://httpd.apache.org/docs/2.1/mod/mod_mime.html#addcharset
.. http://httpd.apache.org/docs/1.3/mod/mod_mime.html#addcharset
AddCharset UTF-8 .utf8
AddCharset EUC-KR .euckr
AddCharset EUC-JP .eucjp
AddCharset ISO-8859-1 .iso88591
AddCharset GB2312 .gb2312
AddCharset UTF-16LE .utf16le
AddCharset UTF-32BE .utf32be
Apache가 송신하는 문서는 복수의 확장자를 가질 수 있으며, Apache 서버는 복수의 확
장자에 대응하는 MIME 타입, 문자 인코딩을 찾아 HTTP 헤더의 Content-Type 필드의
값으로 내보낸다. 예를 들어, "test.html.utf8.ko"란 파일은 다음과 같은 HTTP 헤더를 가
지고 (다른 헤더 필드는 생략) 송신된다. 복수의 확장자가 붙는 순서는 중요하지 않다.
"test.html.ko.utf8"이나 "test.ko.utf8.html" 파일도 아래와 같은 HTTP 헤더를 가지고 송
신된다.
Content-Type: text/html; charset=UTF-8
Content-Language: ko
위의 보기에서 AddLanguage 디렉티브를 써서 확장자 'ko'를 언어 코드 'ko'에 대응시켰
다고 가정했다.
JSP/Java servlet
동적 문서의 경우에는 MIME 타입 설정에서 설명한 방식으로 문자 인코딩을 지정할 수
있다. 혹은, setLocale을 사용하고, 다음처럼 locale-encoding-mapping-list에 locale에
대응하는 인코딩을 지정하는 방법도 있다고 한다. 아래와 같은 설정이 서버 설정 파일에
있을 때, setLocale("ko")는 문자 인코딩을 'UTF-8'로 만들고, setLocale("ja")는 'Shift_JIS'
로 만듭니다. 또, JSTL의 지역화 관련 태그를 쓸 때에도 locale이 암묵적으로 설정되는 경
우가 있으므로 주의해야 한다. 하지만, 이런 경우에도 page 디렉티브에서 contentType으
실전 웹 표준 가이드
- 176 -
로 지정한 값이 우선권을 가집니다. 일부 옛 버전(JSTL 1.0)에서는 이 우선 순위가 바뀌어
있었지만, 최신 버전에서는 고쳐졌다. 옛 버전을 써야 하는 경우라면, 문자 인코딩을 지정
한 직후 (암묵적으로 문자 인코딩을 바꿀 가능성이 있는 JSTL 태그를 쓰기 전에)
ServletResponse.flushBuffer를 써서 버퍼를 비워주면 된다.
<locale-encoding-mapping-list>
<locale-encoding-mapping>
<locale>ko</locale>
<encoding>UTF-8</encoding>
</locale-encoding-mapping>
<locale-encoding-mapping>
<locale>ja</locale>
<encoding>Shift_JIS</encoding>
</locale-encoding-mapping>
</locale-encoding-mapping-list>
JSP 2.0에서는 deployment descriptor에서 다음과 같이 JSP 소스 코드 인코딩을 지정할
수도 있다. 이렇게 지정한 경우 소스 파일 내의 page 디렉티브로 지정한 값보다 우선 순
위가 높다는데에 유의하십시오.
<jsp-property-group>
<page-encoding>UTF-8</page-encoding>
</jsp-property-group>
HTML form을 통해 POST로 전달되는 파라미터의 문자 인코딩은 또다른 방법으로 지정
해야 한다. ServletRequest object의 characterEncoding property를 지정할 수 있다. JSP
에서는 이 방법 이외에 JSTL의 <fmt:requestEncoding>를 써서 지정할 수도 있다.
단, 이 경우에도 Apache tomcat5 등을 비롯한 JSP container는 GET으로 넘어온 파라미
터를 해석할 때 이 값을 쓰지 않다. 이 문제를 해결하기 위해서는 server.xml 파일에서
useBodyEncodingForURI를 true로 설정해야 한다. Tomcat container의 경우
URIEncoding이나 QueryStringEncoding을 쓰는 방법도 있다. UTF-8을 항상 쓴다면 이
값을 UTF-8로 설정하는 방법도 고려할 수 있다.
더 자세한 내용은 http://issues.apache.org/bugzilla/show_bug.cgi?id=23929 혹은
http://java.sun.com/developer/technicalArticles/Intl/MultilingualJSP/index.html
를 참고하면 된다.
JSP 파일에서 디렉티브를 파일 선두에 사용할 때에는 원하지 않는 빈 줄이 생성되어 전송
되는 파일의 선두에 들어가지 않도록 주의해야 한다. 복수의 디렉티브를 쓸 경우에는 아래
처럼 뒤에 오는 디렉티브가 앞에 오는 디렉티브의 후미와 같은 줄에 오도록 해야 한다. 이
렇게 해야만 파일 선두에 공백 없이 와야하는 XML 선언문이나 DTD 선언 등이 수신 측
에 제대로 인식이 된다. 혹은 DTD나 XML 선언문을 page 디렉티브보다 먼저 쓰는 방법
도 있다.
<%@ page pageEncoding="UTF-8"
contentType="text/html; charset=UTF-8"
import="java.io.*, java.net.*" %><%@
taglib prefix="my"
uri="http://jakarta.apache.org/tomcat/jsp2-exampletaglib"%><!
DOCTYPE html
실전 웹 표준 가이드
- 177 -
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko" lang="ko">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html charset=UTF-
8" />
<title><%= application.getServerInfo() %></title>
</head>
<body>
.....
</body>
</html>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ page pagecontentType="text/html charset=UTF-8"
import="java.io.*, java.net.*" %>
<%@ taglib prefix="my"
uri="http://jakarta.apache.org/tomcat/jsp2-example-taglib"%>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko" lang="ko">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html charset=UTF-
8" />
<title><%= application.getServerInfo() %></title>
</head>
<body>
<% request.setCharacterEncoding("UTF-8");
response.flushBuffer();
String names[];
names = request.getParameterValues("name");
%>
</body>
</html>
IIS and ASP
http://www.w3.org/International/O-HTTP-charset에 있는 내용을 참고하였다. 정적
인 문서에 대해서 문자 인코딩을 지정하고자 한다면, MIME 타입 지정과 같은 방법을 쓰
면서 각 MIME 타입에 대응하는 확장자에 대해서 'text/html;charset=UTF-8'(예를 들어,
html/htm에 대해서)과 같은 식으로 charset parameter를 더해 주십시오. 이 때, 공백을
넣지 않도록 주의해야 한다.
ASP로 만드는 동적인 문서의 출력 인코딩은 response.Charset으로 다음처럼 지정할 수
있다. response.Codepage는 ASP 소스 문서의 인코딩을 지정하는데 쓰이다. (65001은
UTF-8, 949는 확장 완성형)
<% response.Charset= "UTF-8" %>
실전 웹 표준 가이드
- 178 -
<% response.CodePage=65001 %>
<% response.CodePage=949 %>
ASP.Net의 경우에는 설정 파일(Machine.config나 Web.config)의 globalization 요소에
서 responseEncoding (출력 인코딩), fileEncoding (asp 소스 파일 인코딩),
requestEncoding (get/post request의 문자 인코딩) 등을 설정할 수 있다.
PHP
PHP의 경우 MIME 타입 설정에서 설명한 대로 header() 함수를 써서 Content-Type
헤더 필드를 내보낼 때에 "charset" 파라미터를 같이 써 주면 문자 인코딩을 지정할 수
있다.
실전 웹 표준 가이드
- 179 -
참고 문헌
1. W3C 의 HTTP 표준 관련 자료 모음 (http://www.w3.org/Protocols) : HTTP 1.0, HTTP 1.1
등에 대한 랑크 포함
2. HTML 4.01 표준(http://www.w3.org/TR/html401/) : 5.2에서 문자 인코딩 선언법과 결정 방
법을 다루고 있다. 부록 B.2에서 URI 에 대해 언급하고 있지만, RFC 3987에서 이와 약간 다른 방
식을 표준으로 지정하였음에 유의하십시오.
3. CSS(http://www.w3.org/Style/CSS/)
4. CSS 2.1 표준(http://www.w3.org/TR/CSS21/) : 4.4에서 문자 인코딩 선언법과 결정 방법을
다루고 있다.
5. XML 1.1 표준(http://www.w3.org/TR/xml11) : 부록 F 와 4.3.3에서 문자 인코딩 선언법과 클
라이언트에서 어떻게 문자 인코딩을 알아 내는지 다루고 있다.
6. RFC 2616 (http://ietf.org/rfc/rfc2616.txt?number=2616) : HTTP 1.1
7. 자세한 MIME 타입 목록(http://www.utoronto.ca/webdocs/HTMLdocs/Book/Book-
3ed/appb/mimetype.html): 1997년판으로 낡았음.
8. IANA MIME 타입 목록 (http://www.iana.org/assignments/media-types/) : application/*
타입만 포함
9. 또다른 MIME 타입 목록 (http://www.webmaster-toolkit.com/mime-types.shtml) : 규범적
인 것은 아님
10. RFC 2045(http://www.faqs.org/rfcs/rfc2045.html) : RFC 2045에서 2049까지 문서에서
MIME 의 기본을 정의한다.
11. IANA charset registry(http://www.iana.org/assignments/character-sets) : EUC-KR 이
preferrred MIME 이름으로 등록되어 있음. 하지만, 앞으로 만드는 모든 한국어 문서는 UTF-8이
나 UTF-16 사용이 바람직한다.
12. http://web-sniffer.net : HTTP Sniffer
13. http://sniffuri.org : 또다른 HTTP sniffer
14. Apache 2.x MIME 타입 설정 방법
(http://httpd.apache.org/docs/2.1/mod/mod_mime.html)
15. Apache 1.x MIME 타입 설정
(http://httpd.apache.org/docs/1.3/mod/mod_mime.html#addtype)
16. Apache 2.x 문서 (http://httpd.apache.org/docs/2.1/) : AllowOverride, MIME, htaccess,
DefaultCharset 등의 키워드를 치면 Apache 2.x 서버의 해당 항목에 대한 자세한 설명을 볼 수
있음.
17. Apache 1.x 문서 (http://httpd.apache.org/docs/1.3/) : AllowOverride, MIME, htaccess,
DefaultCharset 등의 키워드를 치면 Apache 1.x 서버의 해당 항목에 대한 자세한 설명을 볼 수
있음.
18. Windows Media File MIME
Types(http://msdn.microsoft.com/library/default.asp?url=/library/enus/
dnwmt/html/mime.asp): 여러 가지 웹 서버에서 Windows Media 파일을 위한 MIME 타
입 설정법. 다른 파일 형식에도 응용할 수 있다.
19. W3C 국제화 워킹 그룹 (http://www.w3.org/International/) : 웹의 국제화 관련 풍부한 자료
를 구할 수 있음.
20. 문자 인코딩 지정 방법 튜토리얼(http://www.w3.org/International/tutorials/tutorial-char실전
웹 표준 가이드
- 180 -
enc/)
21. 문자 인코딩 지정 방법 (http://www.w3.org/International/O-HTTP-charset) : 간략한 설명
22. RFC 3987 (http://www.ietf.org/rfc/rfc3987) : IRI (국제화된 리소스 식별자)를 규정한 RFC.
HTML 4.01의 B.2와는 약간 다른 방법이 표준으로 채택되었음에 유의.
23. 국제화된 도메인 이름과 리소스 식별자(IRI)(http://www.w3.org/International/articles/idnand-
iri/ : IDN 과 IRI 에 대한 여러 가지 정보. RFC 3986(URI), RFC 3987(IRI), Apache 2.x 용
fileiri 모듈을 비롯한 여러 자료에 대한 링크가 있음
24. RFC 3023 (XML Media type)(http://www.ietf.org/rfc/rfc3023.txt)
25. XHTML media type(http://www.w3.org/TR/2002/NOTE-xhtml-media-types-20020801/)
26. Javascript/ECMAscript MIME type(http://www.ietf.org/internet-drafts/draft-hoehrmannscript-
types-03.txt)
27. XHTML 호환성 지침(http://www.w3.org/TR/2002/REC-xhtml1-20020801/#guidelines)
28. Unicode 용어집(http://www.unicode.org/glossary)
29. JSP 를 이용한 다국어 지원 웹 사이트 개발 튜토리얼
(http://java.sun.com/developer/technicalArticles/Intl/MultilingualJSP/index.html) : JSP
개발자라면 꼭 읽어야 할 문서이다.
30. Java Server Page 표준 (http://java.sun.com/products/jsp/reference/api/index.html) : JSP
1.1, 1.2, 2.0의 표준 문서를 구할 수 있다. JSP 2.0의 4장에서 문자 인코딩에 대해서 자세히 다루고
있다.
31. JSP 를 이용한 웹 사이트의 국제화
(http://java.sun.com/developer/technicalArticles/Programming/jspwebsites/index.html)
32. Java 국제화(http://java.sun.com/j2se/corejava/intl/index.jsp)
33. IBM web sphere 에서 문자 인코딩 지정 방법(http://www-
306.ibm.com/software/globalization/j2ee/encoding.jsp)
34.
실전 웹 표준 가이드
- 181 -
실전 웹 표준 개발 프로세스
실전 웹 표준 가이드
- 182 -
기존 웹 개발 프로세스
일반적으로 웹 개발 프로젝트란 웹의 다양한 기술을 바탕으로 브라우저 상에서 이용할 수
있는 문서 혹은 서비스를 기획, 개발하는 일련의 작업과정을 가리킨다. 이전에는 주로
Internet Explorer나 Mozilla같은 데스크탑 브라우저 클라이언트 상에서 동작하는 것만을
목표로 했으나, 기술이 발달하면서 데스크탑 브라우저 이외에도 모바일 및 유비쿼터스 환
경에서의 이용, 여러 프로그램 및 기계장치에서의 입,출력 데이터 포맷 등 다양한 용도로
의 활용이 요구되고 있다. 이러한 다양한 욕구를 충족시키기에는 기존의 데스크탑 브라우
저 중심의 개발 개념/기술/환경은 부족함이 있으며 이에 따라 새로이 웹 표준화의 중요
성이 강조되고 있다.
그러나 실무현장에서는 업무종사자들이 아직 기존의 낡은 개발방법론을 따르고 있어 웹
표준화를 준수하는데 구조적인 문제가 발생할 수 있다. 즉, 단순히 (x)HTML이나 CSS등
의 웹 표준 기술이나, 웹 접근성 등에 대한 이해가 있다 하더라도, 기존의 개발 프로세스
상에서는 이를 적용시키기가 어려울 뿐더러 오히려 기회비용의 증가로 인해 작업효율성이
떨어지게 되어 웹 표준을 거부하는 현상도 발생하게 된다. 따라서 웹 표준화를 따르기 위
해서는 기존의 방식보다 개선되고 발전된 새로운 개발 방법론을 채택할 필요가 있다. 그러
나 일부 대형 사업장 및 전문 업체만이 이 분야에 대해 관심을 가지고 자신들의 상황에
맞추어 실무에 적용하고 있을 뿐, 우리나라의 대부분의 웹 개발 관련 업체들의 영세성이나
후진성 때문에 이에 대한 체계적인 접근 및 고민은 전무하다고 해도 과언이 아니다.
이에 이 문서에서는 기존 방법론의 문제점을 확인하고 웹 표준화를 준수하기 위해 필요한
새로운 방법론을 제시하고자 한다.
주의 : 이 문서에서 소개 및 제시되는 모든 개발 방법론들은 모든 경우에 반드시 맞아
떨어지는 방법론이라 할 수는 없다. 그러한 방법론은 존재하지 않는다, 개인, 조직,
기업은 저마다 고유한 특성과 환경을 가지고 있어서, 일률적으로 한가지 방법이 최선의
선택일 수는 없다. 따라서 이 문서는 어디까지나 자신들의 고유한 방법론을 개발하기
위한 참고용으로만 활용되기 바란다.
현재 프로세스 소개(Waterfall 방식)
이전에 사용하던 일반적인 웹 개발 업무의 흐름이다. 대략적으로 살펴보자면, 다음과 같은
순서를 따른다.
1. 기획자가 기획작업을 거쳐 스토리보드를 산출해내면
2. 디자이너가 이미지 편집 프로그램을 이용해 필요한 이미지를 생산해 낸 후,
3. 코더가 적절히 구획된 테이블 안에 해당 이미지와 컨텐트들을 배치한 HTML
코드를 생산해내고,
4. 프로그래머가 산출된 코드를 받아 웹 프로그래밍 언어와 조합하여 프로그램이
적용된 최종 결과를 완성한다.
기존의 프로세스의 특징이라면, 이른바 선형 개발 과정을 따르기 때문에, 컨베이어 벨트처
럼 밀어내기식 개발을 하게 된다. 마치 폭포처럼 보인다 해서 폭포수(Waterfall) 방법론이
라고 불리우기도 한다.
실전 웹 표준 가이드
- 183 -
그림 43 기존 웹 개발 공정표
이 방식은 각 프로세스별 단계 파악이 용이하고, 비교적 작업이 정형화되어 대단한 기술이
나 능력을 요구하지 않는 특징이 있다. 그러나, 웹 표준화를 준수하는 데 있어 이러한 기
존 방법론은 구조적인 문제에 봉착하게 된다.
문제점(1) 병목현상
기존 프로세스의 중요한 문제점 중 첫번째는, 밀어내기식 선형 작업 진행에 의해 필연적으
로 발생하는 자원관리의 비효율성과 병목현상을 들 수 있다.
디자이너가 디자인을 완성하기 전까지는 HTML 코드를 생산해낼 수 없다. HTML 코드가
생산되지 않으면 프로그래머는 프로그램 개발을 진행할 수 없다. 기존 프로세스 방식을 따
랐을 때의 일반적인 상황이다.
예를 들어보자.
실전 웹 표준 가이드
- 184 -
전체 개발 기간으로 30일을 산정한 웹 사이트 개발 프로젝트가 있다. 프로젝트 매니저가
주의깊게 프로젝트를 검토한 결과, 기획단계에 10인-일 단위가, 디자인 단계에 10인-일 단
위가, 개발 단계에 10인-일 단위가 필요하다는 결론을 내렸다. 이에 따라 인력이 이 프로
젝트에 적절히 투입된다. (실제로는, 기획자가 스토리보드를 완성할 때까지 프로젝트의 규
모를 추산해내지 못하는 경우도 허다하다.)
그림 44 협업을 이루어 내지 못하는 개발 공정표
대개의 경우 위의 그림처럼 프로젝트 일정은 밀어내기식 순차진행을 보이게 된다. 이전 단
계의 작업이 어느정도 끝나야 다음 단계의 작업을 시작할 수 있다.
기획단계에서 스토리보드를 작성해내고 디자이너가 디자인을 만들어 HTML 코드를 생산
해줄 때까지 프로그래머는 약 20일간 할 일이 없게 된다. 물론 어느 단계에서 예상 외의
지연상황이 발생하게 되면 후속 단계들도 그만큼 늦어지게 된다. 선행 단계에서의 지연 누
적은 후속 단계로 갈 수록 일정 준수에 대한 부담으로 쌓이게 되며, 대개의 경우 가장 마
지막 단계에 속하는 프로그래머들이 프로그래밍에 착수할 때 즈음에는 작업을 위한 충분
한 일정을 확보하지 못한 채 프로젝트 종료일정의 압박을 받으며 작업해야 한다.
이러한 문제점을 해결하기 위해 일반적으로 쉽게 취할 수 있는 방법 중 한가지는, 자신의
작업 단계가 가능할 때까지, 해당 인력을 다른 프로젝트에 할당하는 것이다. 그러나 이 방
법은 이론만큼 효율적이지는 못하다. 어떠한 실무자도 두 개의 프로젝트에 50%씩 투입되
기 보다는 하나의 프로젝트에 100% 투입되기를 원한다. 만약 계획대로 일정이 지켜진다
하더라도 아무런 준비없이 다른 프로젝트의 중간단계를 바로 시작할 수 없기 때문이다. 게
다가 이 방법은 병목현상에 대해 아무런 효과를 볼 수 없다. 일정은 언제나 계획보다 지연
되기 마련이다. 프로젝트 기간의 대부분 동안 다른 프로젝트 개발에 투입되어 있다가 원래
프로젝트로 돌아와 며칠 남지 않은 마감을 앞에 두고 개발을 시작해야하는 프로그래머의
입장을 상상해보라.
해결 방법 중 또다른 한가지는, 선행단계의 일정을 단축시키는 것이다. 스토리보드가 빨리
나오면 그만큼 디자인이 빨리 완성된다. 디자인이 빨리 나오면 그만큼 코딩이 앞당겨진다.
코딩이 앞당겨지면 프로그래밍도 그만큼 앞당겨 진다. 그런 믿음으로 관리자들은 언제나
실무자들의 일정을 닥달하게 된다. 그러나 이것은 곧잘 무리한 공정 단축으로 이어지게 되
며, 선행 단계에서 충분히 검토되고 완성되어야 할 작업들을 빠트리게 되는 핑계가 된다.
결국 잦은 변경과 수정으로 인해 작업진행이 체계적이지 못하게 되고, 원래 일정보다 오히
려 더 지연되는 결과를 초래하거나 혹은 불완전한 결과물을 만들어내는 요인이 된다.
실전 웹 표준 가이드
- 185 -
문제점(2) 스토리보드
스토리보드란 원래 시나리오의 흐름(스토리)을 기술하는 유스케이스 모델링 기법의 일종이
다. 그러나 현재 국내의 일반적인 웹 개발 스토리보드란 작업지시명세서 및 페이퍼 시뮬레
이션의 성격이 더 강하다. 기획이란 이렇다는 특정한 법칙이 있는 것은 아니니, 스토리보
드를 이용한다는 그 자체가 문제가 되는 것은 아니다.
일반적인 스토리보드는 다음 그림들과 같다.
그림 45 의존적인 스토리 보드의 전형적인 예
실전 웹 표준 가이드
- 186 -
실제 현장에서 사용되는 스토리보드 문서들의 형태는 대략 이와 같으며, 주로 웹페이지의
외형과 컨텐츠, 동작 기능에 대해 기술하고 있다.
문제는 스토리보드에 지나치게 의존적인 작업형태라는 점이다. 기획단계에서 인터뷰/회의
를 통해 대강의 흐름과 요구사항을 확인한다 하여도 그 결과가 스토리보드에 반영되어 확
정되기 전까지 다른 사람들은 설계에 들어갈 수 없다. 관행상 혹은 일정상이라는 이유로
기획자들은 스토리보드만을 산출해낸다. 예를 들어 DBA가 DB 스키마 설계를 하려 해도,
어떤 객체들과 어떤 기능, 어떤 속성들이 있을지 사전 정리가 안되어 있기 때문에 설계가
힘들어진다. 메인 프로그래머가 전체 시스템에 대한 프레임워크를 적용하려 해도 비즈니스
로직이 명확히 정의되지 않았기 때문에 스토리보드의 완성을 기다려야만 한다. 디자이너
역시 디자인 지시사항이 스토리보드에 명시되어 있기 때문에 스토리보드 없이 디자인은
불가능하다.
스토리보드가 산출되어야 디자이너는 스토리보드에 따라 디자인을 시작할 수 있고, 프로그
래머들은 스토리보드를 보고 전체적인 프로세스 플로우와 비즈니스 로직을 뽑아낼 수 있
으며, DBA는 DB설계에 필요한 요소들을 잡아낼 수 있다. 심지어 이러한 이유로, 스토리
보드가 완성되고 나서야 프로젝트의 정확한 규모, 일정, 소요인력등이 결정되기도 한다.
선형 순차 개발 방법론의 디자인->코딩->프로그래밍이라는 구조상 이를 해결할 수 있는
방법은 그다지 다양하지 못하다. 애초에 프로그램 설계를 먼저 한다 하더라도 실제 코딩
결과물이 산출되지 않는 한, 프로그래머로서는 설계와 대략적인 프레임워크는 만들 수 있
어도, 실제 인터페이스 개발은 불가능하기 때문이다.
실질적으로 스토리보드 외의 레퍼런스를 만들기 어려운 현실 상, 상세하고 내용이 많을 수
록 좋은 스토리보드로 평가받게 된다. 이는 또다른 문제점을 야기시키는데, 스토리보드가
상세하면 상세할 수록, 디자이너와 프로그래머들의 스토리보드 의존도가 높아진다는 점이
다. 스토리보드 의존도가 높아지면 높아질 수록, 더욱 더 상세한 스토리보드를 기획자에게
요구하게 된다. 이 무한루프는 기획자들의 가장 큰 고민거리이며, 기획자들이 프로젝트 일
정 내내 파워포인트를 붙잡고 몇백장씩의 세세한 스토리보드를 그려내는 일에만 몰두하게
만드는 원인이다. 그러나 아무리 뛰어난 기획자라 해도 완벽한 스토리보드를 그려내기란
거의 불가능하다.
다음 발언은 스토리보드 의존도가 심화된 상태의 현장에서의 흔히 발견되는 모습이라 할
수 있다.
“스토리보드에는 그에 대한 지시사항이 없는 걸요” - 아주 기본적인 에러확인 로직을
스토리보드에 없다는 이유만으로 개발하지 않은 프로그래머의 반문
“저는 스토리보드에 그려진 대로 그린 것 뿐인데요...” . 디자인이 참신하지 못하다는
지적을 받은 디자이너의 변명
“어째서 스토리보드에 있는 그대로 하지 않았지?” . 발전적 창의성을 적용한
프로그래머/디자이너를 인정하지 않는 기획자의 질책
디자인 지시서 / 설계 지시서로 스토리보드의 역할이 고정되어 있는 한 이러한 문제점을
해결하기는 힘들다.
실전 웹 표준 가이드
- 187 -
문제점(3) 구조화의 어려움
앞서 언급한 문제점들은 웹 표준화 패러다임과는 크게 관련없어 보일 수도 있다. 웹 표준
화를 위한 문제점이라기 보다는, 개발 방법론 자체의 후진성에 기인하기 때문이다. 이제
좀 더 실질적으로 우리의 관심사인 웹 표준화라는 관점에서의 문제점을 짚어보자.
웹 프로젝트의 투입인력을 대략의 역할(role)에 따라 크게 구분해보면 기획/디자인/코딩/
개발로 나뉘게 된다. 사실 대개의 경우 코딩을 따로 두는 경우도 많지 않다. 대부분 디자
이너가 겸하고 있다. 체계적인 개발 방법론이 확립되지 않은 많은 현장에서 코딩이란, "디
자이너가 Photoshop으로 그려낸 이미지를 적당히 잘라 Dreamweaver등의 도구를 이용
해 적당히 배치한 후 HTML형식으로 저장하는 것"으로 정의되어 있는 셈이다. 실제 현장
에서 지연된 일정을 만회하기 위해 택하는 가장 손쉬운 방법 중의 하나는 "코더를 추가투
입하여 디자이너의 작업 중 단순반복적인 작업을 덜어주는 것"으로 알려져 있다.
그러나 웹 표준화라는 관점에서 보자면, HTML 코드의 생산은 가장 중요한 부분이라 할
수 있다.
주지하다시피 웹 표준화는 크게 웹 접근성의 확보 및 의미론적 웹이라는 두마리 토끼를
잡으려는 셈이다. CSS를 이용한 디자인, 크로스 브라우징 기술, 재활용가능한 웹, Web 2.0
등등 현재 이슈가 되고 있는 주제들도 결국은 웹 표준화의 수단과 목적이라고 할 수 있다.
이를 위해 가장 기초적으로 요구되는 것은, well-formed(structured) document라 할 수
있다. CSS를 이용한 디자인의 필요조건은 (X)HTML 문서가 제대로 구조화되어 있어야
한다는 점이며, 크로스 브라우징을 위해서도 표준규약에 맞는 (X)HTML 문서를 필수로
한다. 의미에 맞는 태그를 적절히 사용해야만 symantic web을 구현할 수 있다.
따라서, HTML코드의 생산은 전문적으로 훈련된 인력에 의해 주의깊게 작성되어야 하며,
디자인과는 독립된 하나의 작업공정으로 인정되어야 한다.
역할을 중심으로 한 개발 공정
이상에서 살펴본 바와 같이, 기존의 웹 개발 공정은 웹 표준화를 준수하는데 있어, 구조적
으로 어려운 실정임을 알 수 있다. 물론, 개인과 조직의 역량에 따라 기존 방법론으로 완
벽히 불가능한 작업이라고는 할 수 없으나, 더 나은 개발 방법론에 대한 연구가 필요한 시
점이다.
이제, 일반적인 웹 개발 프로젝트 구성원의 역할에 따라 4가지 모델을 새롭게 제시한다.
각각의 모델은 장단점이 있으며, 또한 이 모델들이 최선의 선택이라고 할 수는 없다. 여기
에 제시되는 모델들은 예시이며, 개인의 능력과 조직의 구성, 기술숙달정도, 조직문화, 프
로젝트의 성격 등에 따라, 각 개별 프로젝트 단위마다 최적화된 다른 방법들이 존재할 것
이다. 여기에 제시된 모델들을 참고로 자신에게 최적화된 방법론을 연구해보는 일이 필요
하다.
전통적으로, 웹 개발 공정에는 다음 4가지 역할을 담당할 구성원들을 필요로 한다.
기획 : 한마디로 '기획'이라고 표현하긴 하지만, 각각 다른 여러 가지 분야를 포함하고
있다. 예컨데, 비즈니스 목표를 달성하기 위한 계획을 세우는 '마케팅 기획'이나 '경영
실전 웹 표준 가이드
- 188 -
기획'등이 있고, 필요한 기반 기술들을 결정짓고 감독하는 '기술 기획'도 있으며,
실질적으로 웹 페이지의 컨텐트를 채우는 '컨텐트 기획'등, 기획에 포함되는 분야는
다양하다. 여기에서는 실질적으로 웹 페이지 개발시 중요한 '웹 컨텐트 기획'을 중심으로
논의한다.
디자인 : 웹 페이지는 1 차적으로는 시각적 매체이기에 시각디자인은 매우 중요한
요소이다. 그러나 '디자인(design)'에는 '설계'의 의미도 들어있으며, 실제로 웹 페이지
개발에 있어서 디자인이란, '아름답게 보이는 것'을 넘어서 사용자의 이용 편의성, 정보의
효율적인 전달, 웹 페이지/사이트의 목적에 부합하는 미적 표현 등이 포함된 개념이다.
개발 : 프로그래머 역시 그 역할에 따라 다양한 직능으로 분화가 가능하다. 웹 사이트
개발과 운영에 필요한 환경을 관리하는 시스템 엔지니어에서부터 최종 사용자에게 rich
interface 를 제공하는 플래쉬 스크립터까지 여러 역할이 존재한다. 여기에서는, 실제로
웹 사이트 자체 제작에 필요한 서버사이드/클라이언트사이드 프로그래밍 역할을
중점적으로 살펴본다.
코딩/퍼블리싱 : 종래의 코딩이라는 작업은, “디자이너가 그린 그림을 HTML 로
옮김”이라는 개념이 강하였으며, 일반적으로 단순노동으로 저평가되었던 작업이었다.
실제로 특정프로그램을 이용한 HTML 코드 생산이라는 작업과정만 놓고 보면 그러한
저평가가 틀린 것만은 아니었다. 그러나 애초 HTML 의 목표자체가 인터넷 상에서
의미있는 정보를 교환하기 위함이라는 점을 감안한다면, 웹 상에 정보를
출판(publish)하기 위해 필요한 기술을 갖추고 이를 목적에 맞게 활용할 수 있는
전문가로서의 퍼블리셔(publisher)의 존재가 중요하다.
위와 같이 웹 개발 공정에 필요한 역할들을 나누었을 때, 웹 표준화를 적용시키기 위한 주
도적인 역할을 누가 맡느냐에 따라 세세한 작업 절차가 달라지게 된다. 여기에서는 각 역
할별로 4가지 모델을 제안한다. 각 모델은 이해를 돕기 위한 수단으로서의 제안이며, 실제
현장에서 적용시에는 반드시 프로젝트의 종류와 개개인의 역량에 따라 현실에 맞게 개별
적으로 맞춤해야 할 것이다.
여기에서는 기획 -> 프로그래밍/디버깅 까지의 과정만 논의하며, 제안, 수주 등의 프리프
로덕션 과정 및 검수, 인도 등의 포스트프로덕션 과정은 생략한다.
실전 웹 표준 가이드
- 189 -
디자이너 중심
그림 46 디자이너 중심 개발 공정표
디자이너를 중심으로 한 개발 공정 모델의 경우, 디자이너가 웹 표준화의 중심 작업 (구조
화, HTML 코딩)을 맡아하는 경우를 말한다. 기존 방식의 공정 모델과 비교하여, 변경되
는 부분이 작으므로 가장 쉽게 적용할 수 있는 방법이라 할 수 있겠다.
디자이너 중심의 모델을 적용하기 위해서는 디자이너가 웹 표준화에 관한 필요기술을 추
가적으로 습득해야 할 필요가 있다. 기존의 방법에서 대개의 경우 디자이너가 코딩까지 겸
하는 경우가 많으므로, 작업의 일관성을 유지하기 쉽다는 장점이 있다. 또한, 디자인보다
코딩이 먼저 끝나게 되므로, 프로그래머의 작업 시작이 빨라지게 된다.
그러나, 웹 표준화를 위해서 추가로 익혀야 할 기술에는 ECMA 스크립트 표준 등의 기술
중심적인 내용들이 많이 있기 때문에, 제대로 훈련받지 않은 디자이너에게는 상당히 어려
운 과정이 될 수 있으며, 감성적인 부분을 중시하는 디자이너 특성상 논리적, 구조적인 능
력을 필요로 하는 웹 표준화를 적용하는 것이 무리한 요구일 수도 있다. 예를 들어 정보의
구조와 가치에 따라 구조적 HTML을 생성해야함에도, 디자인적 감성으로 시각적인 요소
실전 웹 표준 가이드
- 190 -
에 집중하여 논리적 구조화보다는 시각적 구조화에 그치는 등의 문제점이 발생할 수 있다.
또한, 기존의 모델에서 크게 변경된 부분이 없으므로, 여전히 순차적 진행에 따른 작업 지
연 등의 문제점은 개선되지 못한다.
프로그래머 중심
그림 47 개발자 중심 개발 공정표
논리와 구조, 표준을 중요하게 여기는 프로그래밍의 특성상, 프로그래머들은 다른 어떤 역
할을 맡은 사람보다 웹 표준화에 대한 이해가 빠르며, 관련 기술에 대한 습득이 용이하다.
따라서 프로그래머 중심의 개발 공정 모델은 디자이너 중심의 개발 공정 모델보다 성공할
가능성이 높다. 또한 자신이 생산한 코드를 바로 프로그래밍에 사용할 수 있으므로 빠른
개발 속도를 확보할 수 있는 장점이 있다.
그러나 프로그래머가 웹 표준화에 대해 충분히 이해하고 있지 않다면, 단지 프로그램 적용
을 위한 HTML코드만을 의도적으로 생산할 가능성이 있으며, 이는 제대로 구조화되지 않
은 웹 페이지를 생산해내는 결과를 가져올 수 있다. 웹 페이지의 구조화는 개발의 용이성
실전 웹 표준 가이드
- 191 -
등의 문제와는 별개로 문서 자체의 가치와 내용에 따라 결정되어야 하기 때문이다.
이에 더하여, 프로그래머에게 너무 많은 작업이 배정되므로 충분한 인력과 시간을 확보하
지 못한다면 프로그래머에게 큰 부담이 되는 모델이다. 특히, 디자인과 프로그래밍이 동시
진행되게 되므로, 1인 개발 등의 소규모 프로젝트에서는 CSS 관련 작업에 대한 시간 배분
이 힘들어지는 단점이 있다.
기획자 중심
그림 48 기획자 중심 개발 공정표
기획자 중심 개발 공정 모델의 장점은 다른 모델들 보다 기획자의 기획의도에 맞게 웹 페
이지의 논리적 구조화가 가능하다는 점이다. 디자인이나 개발에 의해 구조화자체가 왜곡되
는 현상을 최소화시킬 수 있다는 점은 웹 표준화 개발에 있어 다른 모델들에 비해 큰 장
점이라 할 수 있다.
그러나 역시 디자이너 중심 모델과 마찬가지로, 기획자가 기술지향적인 관련기술을 습득해
실전 웹 표준 가이드
- 192 -
야 하는 부담이 있고, 과도한 스토리보드 작업에 더해 기획자의 작업부담이 늘어난다는 문
제점이 존재한다.
이상에서 제안한 세가지 기존 역할 중심 모델은 기존 개발 공정 모델에 비해 접근하기 쉬
우나, 중심 역할을 맡은 인력에게 추가 작업 부담이 더해지기 때문에 오히려 전체 공정 기
간이 늘어나고 업무 편중이 과도해지는 단점이 있다. 또한, 앞 장에서 말한 기존 모델의
문제점을 개선하는 데 구조적인 한계를 지니게 된다. 이를 해결하기 위해서는 기존의 역할
에서 벗어나 웹 표준화 작업을 담당할 새로운 역할이 필요하며, 이에 따라 새로운 개발 공
정 모델을 제시해보도록 한다.
개선된 모델(퍼블리셔 중심)
우선, 기존의 개발 공정 모델 및 기존 역할을 중심 모델들의 개선해야 할 부분들을 찾아보
자.
과도한 스토리보드
앞에서 언급한 바와 같이, 지나친 스토리보드 중심의 기획문서 생산과정은 기획자의 업무
를 과중하게 하고, 다른 역할들의 능동적, 적극적 참여를 제한하며, 작업 일정 지연 및 대
기기간 증가 등의 단점을 불러오게 된다.
이를 해결하기 위해서는 스토리보드를 경량화하고, 필요에 따라 각기 다른 종류의 문서로
분할하여, 전체적인 작업 일정을 단축시킬 수 있도록 해야 한다. 또한 과감히 다른 역할을
맡은 인력들이 프로젝트에 적극적이고 능동적인 참여가 가능하도록 하여 기획자의 부담을
줄이고 창의적이고도 효율적인 작업 결과를 산출해낼 수 있도록 해야 한다. 디자인 지시서
로서의 스토리보드의 성격을 폐기함으로써, 디자인은 온전히 디자이너 고유의 영역으로 남
겨주어야 한다.
개선된 기술의 도입
대표적인 웹 프로그래밍 언어 중 하나인 PHP를 예로 들자면, 간단히 HTML에 스크립트
를 추가하는 것만으로 프로그램 개발이 가능하며 문법도 쉽다는 장점이 있으나, 오히려 그
장점이 구조적이고 관리하기 용이한 프로그램을 작성하는 데 걸림돌이 되는 형편이다. 국
내의 많은 PHP 프로그래머들이 아직도 HTML코드와 PHP코드를 섞어 뷰(view)와 모델
(model)을 구분할 수 없고, 유지보수가 힘든 코드를 양산해내는 현실상, 웹 표준이 적용
된 결과물을 얻어내기에는 많은 노력과 시간이 소요된다.
디자인과 컨텐트를 분리하는 CSS의 개념처럼 PHP에서도 템플릿 등을 이용하여 뷰와 모
델을 분리하는 MVC 기법 등을 적용하면, HTML 코드와 독립된 개발이 가능할 수 있다.
이는 PHP만이 아닌 다른 모든 웹 개발 언어에도 마찬가지로 적용된다.
작업 과정의 재분배
기획/디자인/개발의 기존 역할 외에, 최종 사용자에게 보여질 내용의 코디네이팅을 전적
으로 담당할 퍼블리셔(publisher)를 두고 작업 과정을 재분배하도록 한다.
퍼블리셔란 기존의 단순 HTML 코드생산을 담당하던 코딩작업을 벗어나, 웹상에 컨텐트
실전 웹 표준 가이드
- 193 -
를 게제하는 방식을 책임지는 전문가를 말한다. 즉, 이전과는 달리, “디자인과 프로그램의
조합으로 웹상에 컨텐트를 보여준다”는 개념을 벗어난, 편집 겸 코디네이터로서의 역할
이 추가된 개념이다.
그림 49 개선된 개발 공정 도표
퍼블리셔는, 기획자가 만들어낸 컨텐트를 기획의도에 따라 디자인을 적용시켜 프로그램의
도움을 받아 웹 상에 게제하며, 이를 위해 퍼블리셔는 최종사용자가 대면하는 모든 부분을
책임져야 하므로, 웹 개발의 경우, 최소한 (x)HTML/CSS/JavaScript 부분을 전적으로
담당해야한다. 필요하다면, 프로그래밍에 이용된 템플릿 사용도 가능해야할 것이다.퍼블리
셔를 추가함으로써, 기존 역할을 맡은 인력의 업무를 경감시켜주고, 작업 강도와 기간이
단축되는 효과를 기대할 수 있다.
그림은 이상과 같은 개선점이 반영된 개선된 개발 공정 모델로써, 앞에서 소개된 모델들과
는 차이를 보이고 있음을 알 수 있다.
실전 웹 표준 가이드
- 194 -
우선, 스토리보드 생산 작업을 프로세스 흐름도와 컨텐트 명세서 작업으로 나누어 프로그
래머나 디자이너, 퍼블리셔 들의 작업 착수 기간을 앞당길 수 있게 하였다. 또한 스토리보
드의 폐기 혹은 경량화를 가능케 하여 전체적인 업무 부담을 줄일 수 있다.
또한 디자인 지시서로서의 스토리보드의 역할을 축소시킴으로써, 디자인을 디자이너의 고
유영역으로 보장해준다. 이를 위해서는 기존의 형식적이었던 시안/스타일가이드 작업을
실질적으로 디자인 및 CSS에 사용할 수 있도록 만들어야 한다. 프로그래머의 경우, MVC
기법을 도입하여 스토리보드나 HTML코드의 생산을 기다리지 않고도 전체적인 프로그램
설계 및 개발을 가능하도록 하였다.
다음 장에서는 개선된 모델에 따른 새로운 개발 프로세스의 각 업무에 대한 상세한 설명
이 이어진다.
실전 웹 표준 가이드
- 195 -
새로운 개발 프로세스
기획/분석/회의
기획이란 기획자의 “혼자만의 상상”을 문서화해내는 것을 말하지는 않는다. 비록 우리나
라의 대부분의 사업장에서 알게 모르게 그러한 관행이 이어지고 있지만, 본래 기획이란 의
미는 Plan(계획)과 Design(설계)과정을 뜻한다. 이를 위해서는 프로젝트 참여자 모두의
협력이 필요하며, 기획/분석/회의는 그것을 위한 수단이다.
기존 방식의 회의시간은 주로 일방적인 발표와 오류찾기 시간이나 마찬가지였다. 기획자는
며칠간 머리를 싸매고 기획안을 들고 나오고, 다른 참가자들은 그제서야 기획문서를 놓고
예상되는 문제점을 지적한다. 그럴 바에야 애초부터 같이 협력하여 기획을 잡아나가는 것
이 효율적이지 않을까?
바람직한 개발 과정은 다음 다섯가지 요소로 정리된다.
.. 해결하고자 하는 문제를 프로젝트팀이 명확하게 이해할 수 있도록 한다.
.. 한 팀은 여러 가지 역할의 여러 멤버로 이루어짐을 고려한다.
.. 각각의 역할을 맡은 멤버간의 의사소통이 원활하도록 한다.
.. 프로젝트 진행중에 각 단계간의 피드백을 수용하고 고려한다.
.. 클라이언트에게 보여줄 수 있는 작업결과물을 만들어내되, 불필요한 문서화는 하지
않는다.
이를 위한 방법론은 여러가지가 있지만, 여기에서 소개할 것은 그 중 한가지인 RAD3 :
GRAPPLE(Guidelines for Rapid APPlication Engineering) 방법론의 변형이다.
RAD3 : GRAPPLE에 관한 상세한 내용에 관한 설명은 본 문서의 취지와는 부합하지 않
으므로, 애플리케이션 공학과 관련된 별도의 자료로 학습하는 것이 필요할 것이다. 여기에
서는 RAD3 : GRAPPLE 등의 객체지향 개발방법론을 알지 못하는 국내의 일반적인 상황
에서도 통용될 수 있는 방식으로 응용하여 설명하도록 한다.
기획/분석/회의 단계에서 이루어져야 하는 내용들은 다음과 같다,
요구사항 수집 (Requirement Gathering) : 프로젝트의 목적과 의미를 파악하고, 필요한
기능들에 대한 정의와 목록을 만들어낸다. 프로젝트 결과물의 형태와 용도를 명확히
하여 프로젝트 참가자들 모두가 요구사항 및 결과에 대해 동일한 수준의 이해가
이루어져야 한다. 이 과정을 통해 추상적 수준의 로직 분석과 설계구성요소들을 정리할
수 있다. (만약 객체 지향 개발 방법론을 사용중이라면, 활동/클래스/컴포넌트/배포
다이어그램 등이 스케치될 것이다.)
분석 (Analysis) :: 분석은 요구사항 수집 단계에서 부분적으로 시작된다. 수집된
요구사항을 각자의 역할에 맞추어 프로젝트 진행과정에 필요한 요소들을 찾아낸다.
디자이너라면, 어떠한 컨셉의 디자인을 만들어낼 것인가, 프로그래머라면, 필요한 시스템
환경, 데이터 모델 등에 대한 요점을 잡아낼 수 있어야 한다. (객체지향 개발방법론에
따른다면 산출물은 유스케이스/상태/시퀀스/협력 다이어그램등이 될 것이다.)
설계 (Design) : 관점에 따라서는 분석 단계와 설계 단계를 별도로 분리하지 않을 수도
있다. 실질적인 문서화 작업은 여기에서부터 시작되며, 개선된 개발 공정에 따른다면
프로세스 플로우/스타일가이드/개발설계 단계의 초입에 해당한다.
실전 웹 표준 가이드
- 196 -
이러한 작업이 가능하도록 기획/분석/회의의 실제 진행은 프로젝트 인원 전체(JAD:Joint
Application Development)가 참여하도록 하며, 인터뷰, 브레인 스토밍, 페이퍼 시뮬레이
션, 아이디어 스케치 등의 기법을 사용하도록 한다.
기획자 공정
UML
UML(Unified Modeling Language)은 객체지향 설계 분석 전문가인 그래디 부치(Grady
Booch), 제임스 럼비(James Rumbaugh), 이바 야콥슨(Ivar Jacobson)에 의해 제안되었으
며, 시스템 개발 세계에서 표준으로 인정받은 표기 시스템이다. UML은 기획자에게 클라
이언트, 프로그래머, 그리고 개발 과정에 참여한 모든 사람들이 각자의 시점에서 이해할
수 있는 다방면의 설계도를 그릴 수 있는 표준을 제공하며, 제안하는 그래픽 요소를 조합
하여 다이어그램을 그릴 수 있도록 되어있다.
흔히, UML은 Java나 C++같은 객체지향 개발도구를 사용할 때 프로그래머들만 사용하는
설계분석도구로 잘못 알려져 있으나, 실제로는 기획자나 시스템 분석가들이 불필요한 문서
화 작업 대신, 실제 개발에 바로 사용될 수 있는 지시서를 만드는 데 아주 좋은 도구이다.
예를 들어, 잘 그려진 UML 다이어그램은 그 자체를 바로 OOP(Object-Oriented
Programming) 코드로 변환할 수 있다.(그러한 과정을 도와주는 애플리케이션 도구들이
있다.) 복잡하고 지루한 문서화 과정을 거치고, 프로그래머가 다시 이 문서를 해독, 이해한
후 나름대로 분석,설계,개발하는 과정보다 훨씬 빠르고 정확하게 기획의도를 프로그램으로
산출해낼 수 있다는 뜻이다.
현재 UML은 DEC, Hewlett-Packard, Intellicorp, Microsoft, Oracle, Texas
Instruments, Rational 등이 주축이 된 UML 컨소시엄에서 발전되고 있으며
OMG(Object Manage Group)의 표준 모델링 언어로 인정받고 있다. 97년 표준 모델링
언어로 채택된 UML 1.1에서 계속 발전하여 현재에는 UML 2.0이 승인된 상태이다. (참
고:http://www.omg.uml/)
그렇다면, 과연 웹 기획자가 UML을 반드시 배워야만 하는가?
UML을 사용하기 위해서는 프로젝트 참여자 모두가 UML을 알고 있어야 한다는 전제가
붙는다. 우리나라의 웹 개발 환경의 여건상 완벽한 UML을 웹 개발 분야에 적용하는 것
은 현재까지는 무리일. 수도 있다
그러나 UML의 기본 개념을 차용하면 기획자의 기획단계에서의 업무 부담을 경감시킬 수
있으며, 기획 의도를 더 명확하고 확실하게 다른 팀원들에게 이해시킬 수 있기 때문에, 프
로그래머의 개발효율을 높여주고, 디자이너나 퍼블리셔의 작업에 영향을 주지 않고도 스토
리보드를 경량화시킬 수 있다. 따라서 UML을 직접적으로 프로젝트에 적용시키지 않더라
도 기획자들은 UML의 기본 개념에 대한 이해를 갖추어야할 필요가 있다.
스토리보드
현실적으로, 스토리보드가 없으면 웹 개발 자체가 거의 불가능하다는 인식이 국내 웹 개발
실전 웹 표준 가이드
- 197 -
분야에 널리 퍼져있는 상황이다. 그러나 앞서 말했듯이 스토리보드는 그 복잡함과 상세함
에 비해 실제 개발에서의 효용성은 그다지 높다고 말할 수 없다. 오히려, 스토리보드라도
있기 때문에 겨우 개발이 가능하다는 표현이 더 어울릴 것이다. 다음은 복잡한 스토리보드
대신 UML 기법을 차용한 프로세스 플로우로 대체할 경우이다.
그림 50 스토리 보드 예제
이 프로세스 플로우는 어떤 사이트에서 로그인 과정을 UML의 활동 다이어그램을 이용하
여 정리하였다. 기존의 여러페이지로 구성된 스토리보드보다, 이러한 한장의 프로세스 플
로우가 개발단계에서의 프로그래머에게는 더 필요한 문서라 할 수 있다.
이러한 프로세스 플로우가 먼저 산출된다면, 프로젝트 참여 인원들은 전체적인 프로젝트의
흐름을 한눈에 알아보기 쉬우며, 자신이 어떤 작업들을 수행해야 하는지 쉽게 확인할 수
실전 웹 표준 가이드
- 198 -
있다. 프로그래머라면 비즈니스 로직을 설계하는데 큰 도움이 될 것이고, 디자이너라면 어
떠한 페이지들에 어떠한 디자인이 필요할지 미리 알 수 있게 된다.
프로세스 플로우는 반드시 UML 규칙을 따라야 하는 것은 아니며, 의도와 내용을 충분히
확인할 수 있고 팀원간의 의사소통에 문제가 없다면 나름대로의 고유한 방법을 사용해도
충분하다. 여기에서는 예시를 위해 표준규격인 UML을 이용하였다.
이렇게 프로세스 플로우가 먼저 완성이 된다면 기획자에게 필요한 남은 작업은 각 페이지
에 들어갈 내용을 정리하는 컨텐트 명세서의 작성이다.
컨텐트 명세서는, 위의 프로세스 플로우에서 미리 선언된 뷰 페이지마다,“이 페이지에는
이러저러한 메뉴가 있고, 이러저러한 내용들이 보여야 하며, 이러저러한 기능들이 있어야
한다.” 라는 것을 정리해놓는 문서를 말한다. 역시 마찬가지로 지정된 형식이 존재하는
것은 아니며, 각 개인, 조직, 기업, 프로젝트에 따라 목적에 부합하는 형식이면 충분하다.
페이지 이름 : 영화 정보 서비스 공통 구성요소
설명 :
영화 정보 서비스의 모든 페이지에 대해 다음 요소들을 공통으로 포함한다.
사이트 메뉴 (메일/카페/플래닛/블로그/쇼핑/뉴스/검색/전체보기/로그인)
서비스 로고
서비스 메뉴 (영화홈/상영정보/예매/매거진/재밌는DB/커뮤니티/시사이벤트/마이무비)
검색 (영화검색, 인물검색, 통합검색), 인기검색어 4-5건, 재밌는DB 신규 등록내용 1-2건을 같이 보여준
다.
영화 클릭 순위 : daily(default)/weekly 변경가능, 5건 정도 제목과 링크 제공. 상위 1건에 대해 이미지
썸네일 제공
영화기사목록 : 요즘뜨는이영화/Photo & Talk/뉴스매거진 각 5개씩 최근 등록 순서로, 상위 1건에 이미
지가 있을 경우 이미지 썸네일 포함.
Poll
서비스 크레딧
카피라이트
프로모션 배너 1
프로모션 배너 2
프로모션 배너 3
프로모션 배너 4
페이지 이름 : 개별 영화 정보 보기
URL : ./movieinfo?mkey=영화id
설명 :
이 페이지는 개별 영화 정보 보기 페이지로 검색결과 및 개별 영화 정보의 기본 링크가 된다.
전체 화면배치는 영화사이트 기본 레이아웃을 따른다. (공통 구성요소 및 UI 스타일 가이드 참고)
컨텐트 :
각 영화 정보 보기 페이지 및 그 서브 페이지에 공통으로
실전 웹 표준 가이드
- 199 -
전체보기/동영상,포토/영화지식/매거진/네티즌평
의 서브메뉴를 제공한다.
영화 타이틀, 원제, 제작년도, 제작국가의 정보 제공
영화 정보 제공
포스터 / 감독 / 출연 / 관람점수 / 장르 / 개봉일 / 상영시간 / 관람등급 / 관련정보 / 사이트 등
동영상 프리뷰 및 스틸컷 썸네일 4~5장 제공 -> 갤러리 페이지로 링크
평점
관람포인트 : 200자 내외의 텍스트 설명
줄거리 : 400자 내외의 텍스트로 된 줄거리
영화지식 : 해당 지식검색으로 연결되는 링크 모음
매거진 : 해당 뉴스 기사로 연결되는 링크 모음(종류, 기사제목, 출처, 날짜 등 부가 정보 필요)
네티즌리뷰 : 해당 네티즌 리뷰로 연결되는 링크 모음(제목, 작성자, 날짜등 부가 정보 필요)
400자평 보기 : 생략…
위의 내용은 컨텐트 명세서의 일례이다. 좀 더 자세하고 명확하게 서술해야 하나, 여기에
서는 예시를 위해 간략히 표기하였다. 실제 현장에서 사용하기 위해서는 형식이나 내용의
추가가 필요할 것이다. . 각 회사의 사정에 따라 내부 문서 규격도 있을 터이고. 디자이너
의 창의성과 퍼블리셔의 구조화를 저해하지 않는다면 기존의 스토리보드 형태의 파워포인
트 문서래도 상관없다.
이렇게 프로세스 플로우와 컨텐트 명세서를 작성하게 되면 굳이 기존의 스토리보드를 유
지할 필요가 없어진다. 프로그래머와 퍼블리셔, 디자이너는 이렇게 만들어진 프로세스 플
로우와 컨텐트 명세서만 가지고도 실제 개발작업에 들어갈 수 있으며, 기획자로서는 업무
의 양과 시간이 크게 줄어들 수 있는 좋은 방법이라 할 수 있겠다.
물론, 클라이언트에게 보여주기 위한 페이퍼 시뮬레이션으로써 스토리보드가 필요하다면
별도로 작성하는 과정이 필요할 수도 있다. 그러나 예전처럼 스토리보드 하나에 모든 것을
채워넣기 위한 문서화 작업에 큰 수고를 들이지 않아도 될 것이다..
퍼블리셔 공정
구조화
웹 표준화에 맞는 (x)HTML 코드 생성을 위한 컨텐트 구조화 작업을 기획자가 맡을 것인
가 퍼블리셔가 맡을 것인가에 대한 질문은 우문이라 할 수 있다. 애초에 명세서 작업시 구
조화를 염두에 두고 작성한다면 별도의 구조화 작업은 필요하지 않을 수도 있다.
앞에서 만든 컨텐트 명세서를 바탕으로 실제 (x)HTML 구조화방법을 예시를 통해 익혀보
도록 한다.
구조화의 요점은, “덩어리로 분할해서 나누어 공략한다.” Divide & Conquer라는 오래된
. 그러나 확실한 전략을 따른다. 효율적인 작업을 위해서 공통 레이아웃 등은 별도로 작
업하는 것이 좋겠지만, 여기에서는 이해를 돕기 위해 한번에 같이 다룬다.
실전 웹 표준 가이드
- 200 -
명세서를 받은 퍼블리셔는 해당 페이지의 목적과 컨셉과 스타일에 맞게 내용을 묶어 분할
하기 시작한다. 우선, 디자이너가 처음 잡은 스타일 가이드에 전형적인 2단 레이아웃 구조
를 이용하기로 결정했다고 가정하면 크게 보아 이 문서는 다음과 같이 러프하게 구조화할
수 있을 것이다. (2단 레이아웃이 아니더라도 사실 대부분 1단계 분할은 다음 형태처럼 되
기 마련이다.)
* Header 영역
* Content 영역
* Footer 영역
2단 레이아웃을 지시했으므로, Content영역은 좀 더 나눌 필요가 있을 것이다.
* Header
* Content
* MainContent
* SideContent
* Footer
퍼블리셔가 파악하기에, 위의 명세서에 들어간 내용들 중 Header에 속하는 것은 다음과
같다.
* Header
* SiteMenu
* ServiceLogo
* ServiceMenu
* Search
* Promotion_1
* MovieRank
같은 방식으로 나머지를 구조화한다.
* Header
* SiteMenu
* ServiceLogo
* ServiceMenu
* Search
* Promotion_1
* MovieRank
* Content
* MainContent
* SideContent
* Promotion_2
* ArticleBox
* Poll
* Promotion_3
실전 웹 표준 가이드
- 201 -
* Footer
* Credit
* Copyright
이제 대략적인 공통 페이지 구조는 다 잡은 셈이다. MainContent에 들어갈 내용만 페이
지 별로 상세화하면 된다.
이 페이지의 주된 컨텐트는 크게 “제목”, “메뉴”와 “내용”으로 나뉘어진다. 그러므로 그에
맞게 구조화하자.
* MainContent
* ContentTitle
* ContentMenu
* ContentBody
ContentBody에 들어갈 내용은 다음과 같다.
* ContentBody
* MovieInfo
* Poster
* Director
* Casting
* MovieField_1
* MovieField_2
* MovieField_3

* Score
* Point
* Synopsis
* Knowhow

이 구조가 정답이라는 소리는 아니다. 이런 식으로 계층적으로 내용을 분할해 들어갈 수
있다면 다른 방식의 구조화도 가능하다.
어쨌거나, 보이는 바와 같이, 결국 명세서에 써있는 내용을 잘 정리한 것 뿐이다. 애초에,
명세서에 내용을 이런 식으로 정리해놓았다면 별도의 구조화도 거의 필요없다. 그러나 기
획자가 처음부터 구조화를 염두에 두지 않고 기획을 진행했다면, 퍼블리셔는 그러한 기획
안을 가지고도 위와 같은 구조화 결과를 만들어 낼 수 있어야 한다.
코딩
이제 (x)HTML코딩을 해보자.

<body>
실전 웹 표준 가이드
- 202 -
<div id=”header”>
<div id=”sitemenu”></div>
<div id=”servicelogo”></div>
<div id=”servicemenu”></div>
<div id=”search”></div>
<div id=”promotion_1”></div>
<div id=”movierank”></div>
</div>
<div id=”content”>
<div id=”maincontent”>
<div id=”contenttitle”></div>
<div id=”contentmenu”></div>
<div id=”contentbody>
<div id=”movieinfo”>
<div id=”poster”></div>
<div id=”director”></div>
<div id=”casting”></div>
<div id=”moviefield_1”></div>

</div>
<div id=”score”></div>
<div id=”point”></div>
<div id=”synopsis”></div>
<div id=”knowhow”></div>
</div>
</div>
<div id=”sidecontent”>
<div id=”promotion_2”></div>
<div id=”articlebox”></div>
<div id=”poll”></div>
<div id=”promotion_3”></div>
</div>
</div>
<div id=”footer”>
<div id=”credit”></div>
<div id=”copyright”></div>
</div>
</body>
</html>
이 정도 결과가 나오면 절반 이상 도달한 셈이다. 보면 알겠지만, 위에 “구조화”의 결과를
그대로 HTML코드만 써서 붙인 셈이다.
이제 남은 것은 아직도 비어있는 각 블록의 안쪽을 세세하게 컨텐트에 맞춰 채워넣는 것
이다. 원리는 지금까지와 동일하다.
실전 웹 표준 가이드
- 203 -
예를 들어 sitemenu를 채워보자.
이 사이트 및 패밀리 사이트들이 공유하는 최상위 메뉴는 다음과 같다.
메일, 카페, 플래닛, 블로그, 쇼핑, 뉴스, 검색, 전체보기, 로그인
메일~뉴스까지는 패밀리사이트 링크들의 모음이므로 하나의 목록으로 묶을 수 있을 것이
다. 검색은 form이 들어가므로 별도.
전체보기는 사이트맵으로 가는 링크이니 앞의 메일~뉴스 링크들과는 성격이 다르고, 로그
인 역시 사용자 계정과 관련있는 링크이므로 별도로 분리하는 것이 낫다.
이와 같은 내용을 (x)HTML로 표현하면 다음 같은 구조가 되는 것이다.
<div id=”sitemenu”>
<ul id=”familysite>
<li><a href=””>메일</a></li>
<li><a href=””>카페</a></li>
<li><a href=””>플래닛</a></li>
<li><a href=””>블로그</a></li>
<li><a href=””>쇼핑</a></li>
<li><a href=””>뉴스</a></li>
</ul>
<form id=”form_search” action=”” method=””>
<input type=”text” id=”txt_search” name=”txt_search”
value=”” />
<input type=”image” src=”” alt=”검색”
id=”btn_search” name=”btn_search” />
</form>
<div id=”link_sitemap”>
<a href=””>전체보기</a>
</div>
<div id=”link_login”>
<a href=””><img src=”” alt=”로그인” /></a>
</div>
</div>
믿기지 않겠지만, sitemenu 부분의 코딩은 이걸로 끝났다. 나머지 부분들도 이런 식으로
상세화해나가면 된다.
만약 프로그래머들이 템플릿을 사용하고 있다면, 해당 템플릿 시스템의 템플릿 태그를 익
혀 (x)HTML 코드 생성시 퍼블리셔가 직접 템플릿을 생성해주는 과정도 필요하다. 현재
의 개발 추세는 점점 템플릿을 이용한 프레임워크 형태로 발전하고 있으며, 최종 사용자에
게 보이는 결과물을 책임져야 하는 퍼블리셔의 특성상, 이러한 템플릿 사용법은 웹 퍼블리
셔로서 갖추어야될 기본 기술이 될 것이다.
다음은 SixApart사에서 제작한 MovableType이란 blogtool 형태의 CMS 프레임워크에
사용되는 템플릿의 한 예이다. HTML코드에 미리 프로그래머에 의해 만들어진 템플릿 태
실전 웹 표준 가이드
- 204 -
그를 같이 사용하여 프로그래밍에 대해 모르더라도 퍼블리셔가 웹 페이지를 구체화하는
방식을 보이고 있다.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" id="sixapart-standard">
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=<$MTPublishCharset$>" />
<meta name="generator" content="Movable Type <$MTVersion$>" />
<link rel="stylesheet" href="<$MTBlogURL$>styles-site.css"
type="text/css" />
<link rel="alternate" type="application/atom+xml" title="Atom"
href="<$MTBlogURL$>atom.xml" />
<link rel="alternate" type="application/rss+xml" title="RSS 2.0"
href="<$MTBlogURL$>index.xml" />
<title><$MTBlogName encode_html="1"$>: <$MTEntryTitle
remove_html="1"$></title>
<link rel="start" href="<$MTBlogURL$>" title="Home" />
<MTEntryPrevious><link rel="prev" href="<$MTEntryPermalink$>"
title="<$MTEntryTitle encode_html="1"$>" /></MTEntryPrevious>
<MTEntryNext><link rel="next" href="<$MTEntryPermalink$>"
title="<$MTEntryTitle encode_html="1"$>" /></MTEntryNext>
<$MTEntryTrackbackData$>
<MTBlogIfCCLicense>
<$MTCCLicenseRDF$>
</MTBlogIfCCLicense>
<script type="text/javascript" src="<$MTBlogURL$>mtsite.
js"></script>
</head>
<body class="layout-one-column"
onload="individualArchivesOnLoad(commenter_name)">
<div id="container">
<div id="container-inner" class="pkg">
<div id="banner">
<div id="banner-inner" class="pkg">
<h1 id="banner-header"><a href="<$MTBlogURL$>"
accesskey="1"><$MTBlogName encode_html="1"$></a></h1>
<h2 id="banner-description"><$MTBlogDescription$></h2>
… (이하 생략)
실전 웹 표준 가이드
- 205 -
CSS 스타일 가이드
그림 51 CSS 스타일 가이드 예제
위의 그림들은 현장에서 사용되는 스타일 가이드의 일례이다. 물론 스타일 가이드의 형식
역시 각 개인, 조직, 기업, 프로젝트 별로 다양하므로 일률적으로 이렇다라고 단정짓기는
어려우나, 스타일 가이드의 목적 자체가 웹 페이지의 사용자 인터페이스 및 컨텐트 표현
방식에 대한 규칙이기 때문에 이를 CSS로 변환하는 작업이 필요하다.
잘 만들어진 스타일 가이드는 그 자체만으로 전체 CSS 작업의 절반 이상을 줄여 줄 수
실전 웹 표준 가이드
- 206 -
있다.
이를 위해서는 CSS의 기본 문법과 규칙을 이해하며, 특히 각 엘리먼트(element)와 셀렉
터(selector), 그리고 이용되는 프로퍼티(property)에 대해 충분히 숙지하고 있어야 한다.
여기에서는 간단하게 다음과 같은 스타일 가이드를 CSS로 적용하는 방법을 예시한다.

박스기사 본문은 다른 영역과 최소 3px 이상 간격을 두고 배치되어야 하며, 1px
크기의 #EEEEEE 색상의 경계선으로 구획지어진다. 경계선과 본문 내용과의 여백은
10px 이상이어야 한다. 배경색은 따로 지정하지 않고 상위 영역의 배경색 및
배경이미지를 그대로 사용한다.
기본 글꼴은 “sans-serif”로 한다. 글꼴 크기는 11.5pt 이며, 들여쓰기 하지 않는다.
본문 중의 링크는 사이트 전체의 일반 링크 표시 규칙을 따르되 밑줄(underline)을
표시한다.

위처럼 기술된 스타일 가이드를 CSS로 표현하면 다음과 같다.

.box_article .content{
margin:3px;
border:1px solid #EEEEEE;
padding:10px;
font-family:sans-serif;
font-size:11.5pt;
}
.box_article .content a{
text-decoration:underline;
}

레이아웃이나 링크 규칙, 이미지 규칙등도 이런 방식에 준하여 CSS로 변환해두면, 나중에
개별 (x)HTML 코드에 적용될 CSS 코드를 작성할 때 작업량이 크게 줄어든다. 반대로
스타일 가이드 작성시, 처음부터 CSS를 염두에 두고 작성하는 것도 좋은 방법이다.
JavaScript
JavaScript의 올바른 사용법은 본 문서의 3장 . 실전 DOM/SCRIPT 가이드를 참고하도
록 한다.
Validation
완성된 코드가 웹 표준에 부합하는지 여부를 체크하는 방법은 여러가지가 있다. 그 중 대
표적인 것을 소개하자면 다음과 같다.
실전 웹 표준 가이드
- 207 -
(x)HTML Validator
완성된 코드가 (x)HTML 표준을 따르는지는 웹 표준이 준수되었음을 증명하는 최소한의
조건이다. 많은 (x)HTML Validator가 존재하지만 여기에서는 W3C HTML Validator만
소개하도록 한다.
W3C HTML Validator : http://validator.w3.org/
간단히 이용하는 방법은, Mozilla(Firefox)의 확장기능 중 WebDeveloper Extension을
설치(http://chrispederick.com/work/webdeveloper/) 하거나, MS InternetExplorer
용 인 InternetExplorer Developer Toolbar를 설치’
http://www.microsoft.com/downloads/details.aspx?FamilyID=e59c3964-672d-
4511-bb3e-2d5e1db91038&DisplayLang=en )하거나, 또는 Opera 브라우저에 기본 기능
으로 내장되어있는 HTML Validator 기능을 이용하면 된다.
그림 52 Opera에 내장된 디버거
주의할 점은, 웹상에서 링크를 입력하여 사용하는 (x)HTML Validator의 경우, 방화벽을
사용중이거나 동적으로 생성된 페이지에서는 제대로 검사되지 않으므로, 방금 소개한 브라
우저 연동 검사기나 별도의 검사 애플리케이션을 이용하는 것이 좋다.
실전 웹 표준 가이드
- 208 -
CSS Validator
CSS의 경우에도 (x)HTML과 마찬가지로, W3C의 Validator가 유용하다.
W3C CSS Validator : http://jigsaw.w3.org/css-validator/
그림 53 Firefox Web Developer Extensions을 이용한 디버깅
역시 마찬가지로, , Mozilla(Firefox)의 확장기능 중 WebDeveloper Extension을 설치
(http://chrispederick.com/work/webdeveloper/ )하거나,
MS InternetExplorer용 인 InternetExplorer Developer Toolbar를 설치’
http://www.microsoft.com/downloads/details.aspx?FamilyID=e59c3964-672d-
4511-bb3e-2d5e1db91038&DisplayLang=en )하거나, 또는 Opera 브라우저에 기본 기능
을 이용하는 것이 손쉽다.
접근성(Accessibilty) Validator
웹 표준화가 준수된 후, 실제로 다종다양한 환경에서의 웹 접근성을 확보할 수 있는지 여
부를 판단한다.
웹 접근성을 고려하기 위해서는 다음 문서를 참고하도록 한다.
.. 웹접근성을 고려한 콘텐츠 제작기법 (http://www.mozilla.or.kr/docs/webdeveloper/
content_authoring_for_accessibility.pdf)
.. W3C Web Content Accessibility Guideline
(http://www.w3.org/WAI/intro/wcag.php)
웹 접근성을 검사하는 도구 역시 다양한데, 그 중 국내에서 개발된 KADO-WAH
(http://www.iabf.or.kr/web/kadowah.asp)를 사용할 수 있다.
이외에도 Webxact Accessibility Validator (http://webxact.watchfire.com) 등 강력한
실전 웹 표준 가이드
- 209 -
도구들이 있으며 좀 더 많은 목록을 원한다면,
http://www.w3.org/WAI/ER/existingtools.html 을 참조하도록 한다. 대개의 경우
(x)HTML Validator와 CSS Validator를 함께 제공하는 경우들도 많다.
디자이너 공정
UI 스타일 가이드
국내의 디자이너들 중 많은 수가 스타일 가이드를 작성하지 않고 바로 디자인 작업에 들
어가는 경우가 있다. 또한 기업이나 프로젝트 팀 단위에서도 스타일 가이드를 요구하지 않
는 경우도 있다.
그림 54 다음커뮤니케이션에서 사용하는 UI 가이드라인
그러나 스타일 가이드를 작성하지 않는다면, 사이트 전체의 디자인 일관성을 유지하기가
어려우며, 여러 명의 디자이너가 공동 작업시에도 통일감있는 디자인을 생산해내는 것이
어려워진다. 일반적으로 스타일 가이드에는 다음과 같은 내용들이 포함되어야 한다.
.. 디자인 목표, 컨셉
.. Color Scheme (사용되는 색상 일람)
.. Font, Typography (글꼴, 크기, 색상, 자간, 장평, 행간, 문단형태, 정렬방식 등)
.. Layout (문서 구조, 크기, 위치, 형태, 성격 등)
.. Graphic Element (아이콘, 이미지, 뷸릿, 버튼 등의 크기, 형태, 색상, 용도 등)
.. 기타 (표, Flash, 멀티미디어 등에 대한 상세한 규칙)
실전 웹 표준 가이드
- 210 -
스타일 가이드 작성시 주의해야할 점은, 스타일 가이드가 단지 외부에 전시용으로 구색맞
추듯 작성해서는 안되고, 실제 작업에 사용할 수 있도록 세부 사항을 꼼꼼히 기록해야 한
다는 것이다. 또 CSS 적용이 가능하도록 CSS를 염두에 둔 스타일 가이드 작성이 되어야
한다. 실제로, 잘 작성된 스타일 가이드는 CSS와 내용이 동일하며, CSS로 기록될 내용을
누구나 보기 쉽게 풀어 설명했다는 개념으로 이해하면 충분할 것이다.
프로그래머 공정
비즈니스 로직 분석
그림 55 비지니스 로직 분석도
실전 웹 표준 가이드
- 211 -
앞서 기획자 공정의 프로세스 플로우를 다시 살펴보자. 세세한 데이터 형식과 기능 구현은
컨텐트 명세서 및 (x)HTML 코드를 함께 살펴보아야겠지만, 전체적인 비즈니스 로직의
설계는 프로세스 플로우만으로도 가능하다.
예를 들어 위 그림의 경우에는,
.. 각 페이지 출력
.. 로그인에 필요한 데이터 모델
.. 사용자 입력값 전달
.. 로그인 판정
.. 개인쪽지에 필요한 데이터 모델
.. 페이지 전환
.. 팝업 기능
.. 에러 처리 등
등의 분석이 가능하다. 이를 바탕으로 DataBase 설계나, 프레임워크의 구현, 결과 페이지
의 시뮬레이션, 유스케이스 시나리오 생성 등의 작업을 진행시킬 수 있다. 스토리보드가
완성되어야만 분석이 가능했던 기존 방식에 비해 일정 초기부터 프로그램 작업에 들어갈
수 있으므로 상당한 시간적 여유를 확보할 수 있다.
MVC 모델
그림 56 MVC 모델 설명도
MVC 모델이란 Model-View-Controller의 세 가지 구성요소로 시스템을 구축하는 방법
실전 웹 표준 가이드
- 212 -
을 말한다.
웹 개발 과정에 대응하여 해석하자면,
.. View : 최종 사용자에게 보여지는 HTML 결과물
.. Model : 인터페이스와는 상관없이 정해진 기능들을 수행하고 그 결과를 갱신하는
프로그램
.. Controller : 사용자의 Action 을 받아 해당하는 Model 을 수행시키기 위한 관리
프로그램
이라 해석할 수 있다.
애플리케이션 개발에서는 이미 널리 알려진 방법론이며, 웹 개발에 있어서도 Java
나 .NET 진영 등을 중심으로 이를 이용한 프레임워크나 기법이 많이 개발되어 왔다. 그
러나 PHP, ASP, PERL등에서 상용화된 MVC 프레임워크가 없다 하여도, 이 개념을 이용
하면 훨씬 구조적이고 용이한 개발이 가능하다.
MVC모델을 도입하기 위해 가장 기본이 되는 개념은 Model과 View를 분리해야한다는
점이다. 웹 개발의 경우라면, 사용자에게 보여줄 HTML 코드를 출력하는 부분과 데이터
를 처리하는 부분은 분리되어야 한다고 표현할 수 있다.
PHP나 ASP, 심지어 JSP 프로그래머 중에도, HTML코드 안에 각종 스크립트 처리문을
그대로 코딩하는 프로그래머들이 많이 있는데, 이는 프로세스의 흐름을 몀확히 파악하는데
어려움을 주며, 프로그램과 HTML코드가 분리되지 않아 유지/보수가 용이하지 못하고,
코드의 가독성을 떨어뜨리는 데 일조를 한다. 이러한 개발 방식은 HTML코드에 의존하기
때문에, 애써 퍼블리셔를 두더라도, 퍼블리셔의 HTML코드 산출을 기다리느라 프로그래
밍 단계에서 작업이 지연되는 결과를 가져온다.
예를 들자면 로그인 프로세스의 경우
로그인 form 페이지 출력 -> 입력받은 ID/Password 를 확인하여 결과 처리
보다는
로그인 form 페이지 출력 -> 입력받은 ID/Password 확인 -> 로그인 결과 페이지 출력
(볼드체가 view / 이탤릭체가 model 에 해당)
방식이 MVC모델을 도입하여 좀 더 효율적인 개발이 가능해질 수 있다. 템플릿을 활용하
는 것도 이러한 MVC모델 개념을 이용한 개발 방법 중 하나이다.
실전 웹 표준 가이드
- 213 -
맺음말
우리나라에서 어느 정부기관이 조사한 바에 따르면, 각 운영체제별 웹 브라우저에 따른 정
부 및 공공기관, 금융기관의 정보접속성 현황은 대부분의 웹 사이트가 윈도우즈 환경 하에
익스플로러에 최적화 되어 리눅스 및 맥 OS 사용자는 정보접근에 제약이 따르는 것으로
나타났다. 특히 인터넷뱅킹과 관련한 문제는 윈도우즈 기반의 공인인증서만을 현재 대부분
금융기관에서 사용하고 있어, 다른 운영체제를 사용하는 사용자들은 인터넷뱅킹을 위해서
윈도우즈 운영체제로 다시 접속해야 하는 번거로움이 있다.
이것은 표준 기술에 대한 이해 없이 시장 기술에 따라 인터넷 산업이 이끌려 옴에 따라
생긴 부작용이라고 할 수 있다. 웹 개발자들이 자신도 모르는 사이에 표준에 어긋나는 개
발을 하게 되는데, 이것은 표준안에 대한 재교육과 학습과정이 결여되어 있었던 이유이기
도 하다. 이 가이드는 표준안에 대한 완벽한 설명을 담고 있지는 않지만 적어도 각 웹브라
우저의 차이로 인해 야기되는 문제를 거의 대부분 다루고 있으며 이를 해결할 수 있는 방
법을 제시하고 있기 때문에 이런 점들을 꼭 숙지한다면 보다 접근성이 향상된 웹사이트가
제작될 수 있을 것이다.
웹개발자가 표준 환경에 맞는 웹사이트를 구축할 수 있으려면 기본적인 마인드의 전환이
필요하다. 먼저 내용(Content: html/xhtml/xml)과 그 표현 방법(Presentation Method :
CSS/XSL), 행동 양식(Behavior: DOM Scripting)을 엄격하게 분리하여아 한다. 이것이
명확해야만 웹 사이트의 유지, 관리, 보수가 용이하고, 장치 독립성, 플랫폼 독립성, 접속
방법 독립성, 장애 정도와 무관한 내용에 대한 접근 가능성이 보장된다.
Tim Berners-Lee가 제창한 웹의 기본 정신은 내용에 대한 '보편적 접근 가능성'(상호 운
용성, 플랫폼/장치 독립성 등을 포함해서)이다. 보편적 접근 가능성(Universal
Accessibility)는 결코 글자 모양, 페이지 폭, 색깔 등이 언제 어디서나 다 똑같이 보여야
한다는 것을 의미하는 것이 아니다. XML/RDF 등을 이용한 Symantic Web의 구현에도
보편적 접근 가능성은 중요하게 적용 되고 있다.
웹은 계속해서 발전하고 있다. 그러나, 한국의 웹은 상업성과 화려함에 가려져 웹이 처음
만들어 졌던 기본 정신을 외면하고, 세계적인 표준 동향을 바로 찾아가지 못한 채 한국 내
부의 웹으로 전략하고 있다. 이 가이드가 국내 웹 환경의 접근성과 브라우저 호환성을 좀
더 높이는 계기가 되기를 희망한다.
실전 웹 표준 가이드
- 214 -
부록. 웹 표준 브라우저 호환표
실전 웹 표준 가이드
- 215 -
웹 브라우저 현황
국내의 대부분 웹사이트들은 IE를 기준으로 만들어졌다는 비난 아닌 비난을 받고 있다.
대부분의 사용자들이 IE를 쓰는 만큼 3~4% 내외인 비 IE 사용자를 위해 웹페이지나 서
비스를 바꾼다는 것은 쉽지 않다는 것은 사실이다. 그러나, 최근 모질라 파이어폭스가 해
외에서 IE의 시장 점유율을 90% 이하로 끌어 내리며 15~20%의 시장점유율을 획득하기
시작했다. 또한, 맥킨토시에서도 MS가 IE5.2Mac 버전을 더 이상 지원하지 않기로 결정함
으로서 사파리 브라우저에 대한 사용도가 늘어 나고 있다.
그림 57 브라우저 시장 점유율 (2005.10현재)
게다가 파이어폭스의 성공에 힘입어 오페라 브라우저도 무료 배포로 전환함으로서 웹 브
라우저들 간의 새로운 신선한 경쟁의 바람이 불고 있다. 이 경쟁은 과거와 달리 보다 나은
웹 표준 기술을 선보여 사용자의 관심을 불러 일으키는 것이다. 이 장에서는 대표적인 웹
브라우저들을 소개하고자 한다.
인터넷 익스플로러7
마이크로소프트는 파이어폭스의 시장 점유
율이 높아지자 위기감과 아울러 새 OS인
비지티에 탑재할 새로운 IE 개발에 착수하
고 최근에 윈도우 비스타 베타1과 함께 인
터넷 익스플로러(IE) 7을 함께 선보였다 IE7의 가장 눈에 띄는 특징은 보다 깔끔해진 툴
바라 할 수 있다. 이전, 다음 페이지를 오가기 위해 “Back”, “Forward”와 같은 버튼
으로 구분된 목록을 갖는 대신에, 리스트를 통해서 최근에 본 페이지들을 하나로 결합해서
실전 웹 표준 가이드
- 216 -
보여준다. 이와 같은 방식은 페이지간의 이동을 보다 논리적으로 만들뿐만 아니라 도구바
를 깔끔하게 만든다.
IE7에서는 웹 브라우저에서 가장 많이 찾는 기능인 탭 브라우징을 갖추게 되었다. 파이어
폭스, 오페라, 사파리 등 경쟁 브라우저가 이미 탑재한 기능인 탭 브라우징을 사용하면 하
나의 창에서 여러 웹 페이지를 볼 수 있으며, 링크에서 오른쪽 클릭해서 “새 탭 링크 열
기”를 선택해서 새로운 탭에서 링크를 볼 수 있다
또한, IE7의 유용한 기능은 RSS(Really Simple Syndication)를 지원하는 것이다. IE7의
다음 베타 버전(베타2)에서는 RSS 0.9x, 1.0, 2.0, Atom 0.3/1.0을 지원하게 될 것이다. 현
재 베타 버전에서는 Atom을 지원하지 않는다. IE7에서는 인기있는 검색 엔진을 사용하는
검색 기능을 내장했다.(그림12) 원하는 검색 엔진을 선택할 수 있다. 직접 다른 검색엔진
을 선택하지 않는한 기본 검색 엔진이 항상 사용될 것이다. 원하는 검색 엔진을 기본값으
로 설정하기 위해 Search Settings를 선택할 수 있다.
IE7 베타1에는 피싱(Phishing) 필터를 포함하고 있다. 주소를 로드할 때마다, IE7은 피싱
사이트로 알려진 블랙리스트 URL 데이터베이스와 입력된 주소를 비교한다. 피싱사이트로
결정되면 차단할 것인지, 보고할 것인지를 선택할 수 있다. 피싱 필터는 윈도 XP버전의
IE7 베타1에서만 이용할 수 있다. 윈도우 비스타의 IE7에서 이 기능을 지원하는 시기는
베타2가 될 것이다. IE7 작업이 끝난 것은 아니지만, 베타1을 통해 향상된 브라우저와 새
로운 기능들을 미리 살펴볼 수 있다. IE7 출시 임박은 브라우저 메이커들에게 자신들의 브
라우저를 개선하게 하는 자극이 될 것이다.
모질라(Mozilla) 계열 웹브라우저 : 파이어폭스
비 IE계열의 대표적인 웹브라우저가 Netscape이다. Netscape
는 4.58버전일 끝으로 Navigaor라고 불리는 브라우저 시대를
끝내고, 소스를 공개함으로서 공개 소프트웨어로 전환하였다.
이 공개 소프트웨어 프로젝트를 모질라(Mozilla)라고 명명하고,
Gegko라는 브라우저 엔진을 통해 웹브라우저를 발전시켜 왔다.
Netscape6/7 버전은 Mozilla의 1.0.2, 1.4를 기반으로 한 것이
며 모질라 기반 브라우저라고 할 수 있다. Mozilla, Netscape,
Mozilla Firebird, Kameleon 등은 모두 모질라 기반 브라우저
로서 모질라에 대한 정보만 제공하여도 비 IE 사용자의 상당수
를 지원할 수 있다.
모질라에서 브라우저 설정을 어떻게 하며 어떤 폴더에 저장되는지 궁금해 하는 경우가 있
다. 과거에 Netscape Communicator를 설치 해본 사람이라면, 프로필이라고 하는 개념
은 친숙할지도 모른다. 모질라 기반 브라우저에서 프로필은 북마크 주소장, 캐시 메일 사
용자 정의 설정등의 개인적인 데이터를 정리해 보존해 두는 폴더이다. Mozilla 는 복수의
프로필을 사용할 수 있게 되어 있어 프로필의 변환에 프로필 관리자라고 하는 전용의 컴
퍼넌트를 사용한다. 프로필 관리자는 Mozilla 프로그램의 실행전 혹은 종료후가 아니면
실행할 수 없다.
실전 웹 표준 가이드
- 217 -
파이어폭스
모질라 파이어폭스 (Mozilla Firefox)는 모질라 프로젝트에서 떨어져나온, 게코 엔진 기반
의 작고 가벼운 자유 소프트웨어 웹 브라우저이다. 모질라가 웹 브라우저 및 전자 우편 관
리 기능 등을 포함하면서 확장해나가, 덩치가 매우 커졌다. 그래서 많은 사람들이 보다 가
벼운 웹 브라우저를 원함에 따라 웹 브라우저만 따로 떼어내어 피닉스(phoenix)를 만들었
다.
나중에는 하위 프로젝트인 피닉스에서 기술을 개발하여 나중에 모질라에 적용시키며 앞서
나갔다. 상표권 문제로 Firebird, Firebird™, Mozilla Firebird로 바꾸다가 결국은
Mozilla Firefox로 이름을 바꿨다. 2004년 현재 모질라는 개발을 중단하고 웹 브라우저인
모질라 파이어폭스와 전자 우편 관리 프로그램인 썬더버드, 두 하위 프로젝트를 계속 진행
중이다.
파이어폭스는 2005년 11월 출시 이후 1년 만에 1억 다운로드를 기록하였고 전 세계 시장
점유율 10~15%를 기록하고 있는 인기 있는 브라우저이다.
주요 특징
.. 탭 브라우징, 팝업 광고 차단
.. 700여개의 사용자 확장 프로그램 및 다양한 동적인 테마의 전환
.. 개인 정보 보호 및 보안 및 폼의 자동 완성 기능
.. 빠르고 편리한 사이드바, 툴바의 검색창, 라이브 북마크 기능
.. Canvas 기능을 통해 2D/3D 그래픽 기능 브라우저에 내장
.. SVG(Scalable Vector Graphic) 표준 브라우저 내장 기능으로 탑재
.. CSS2, CSS3, Javascript 1.6의 새로운 웹 표준 기능 지원
오페라 브라우저
오페라(Opera)는 1990년 초, 노르웨이 통신회사, 텔레너의 연구소
에서 근무하던 3명의 로부터 시작하여 1995년에 오페라소프트웨어
가 설립되었다. 그리고 1996년에 윈도우 오페라 2.1의 오페라 최초
버전이 발표되었다. 1998년에, 오페라는 윈도우를 넘어 다른 플랫폼
으로 오페라 브라우저를 확대하여 2000년과 2001년에 Linux,
Macintosh, BeOS, Symbian OS (EPOC) 및 QNX와 같은 대중적인
플랫폼에 대해 출시되었다. 2000년 12월에 윈도우 오페라 5 버전이
광고가 지원되는 무료 버전으로 출시되었다. 첫달에 무료 오페라 5
버전은 2백만개가 다운로드되어 설치되었다. 오페라는 개발 초기부터 W3C의 표준 사양을
준수하고, 브라우징 속도를 가장 빠르게 한 특징을 가지고 사용자 층을 이끌어 나왔다.
오페라 한글판이 출시되기 앞서 이 한글 언어팩을 이용하여 한글로 오페라를 사용할 수
있다. 한글 언어팩을 클릭하여 다운로드 받은 후 오페라가 설치된 Opera 디렉토리에 압
축을 풀면 된다. 다음에 오페라를 실행하여 "파일(File)/환경설정(Preferences)/언어
(Language)"에서 사용자 인터페이스 언어 설정에서 옆에 버튼을 누르고 Opera 디렉토리
안에 owxxx_xxxxko.lng 파일을 찾아 선택하고 확인 후 설정한다. 그리고 오페라를 다시
실전 웹 표준 가이드
- 218 -
시작하면 한글로 오페라를 사용할 수 있다.
오페라 사용시 웹페이지 내에서 한글을 제대로 표현하려면 다음과 같이 한다. 메뉴바 파일
(File) -> 환경설정(Preferences) -> 글꼴 및 색( Fonts and colors)를 선택하면 오른쪽 화
면 나의 글꼴 및 색(my fonts and color)에서 먼저 일반글자(normal) 선택하고 변경을 누
르면 대화창이 나타나는데 거기서 글꼴은 TT굴림 또는 TT돋음을 선택하고 유형에서는 보
통, 크기는 10 또는 11(최적) 로 선택하고 확인을 선택한다. 그리고 다시 환경설정 창에서
아래 적용을 눌러 설정한다. 다른(css font-family 를 제외한) 항목들도 같은 방법으로 설
정한다. 다음에 [환경설정-언어]에서 인코딩유지 항목에서 html 을 euc-kr 로 선택하고
설정하여 사용한다. 메뉴바, 도구모음 글꼴도 변경할 수 있다. 환경설정> 브라우저 모양에
서 "글꼴 및 색" 항목에서 '시스템 기본설정 사용' 에 체크 지우고, "일반 텍스트", "비 활성
텍스트", "북마크창 글꼴"를 각각 누르고 차례로 글꼴을 바꾸면 된다. 크기는 동일하게 "9"
로 하면 되며, 글꼴 색상도 변경 가능하다.
.. 오페라 브라우저를 사용할 때, 어떤 페이지는 다른 브라우저와 다르게 표시되는 것을 볼
수 있다. 대부분의 경우에서 그 차이는 그 표시되는 페이지에서 표준을 지원하지 않는 오
류에 의해 나타난다. 어느정도까지 오페라는 넷스케이프 및 인터넷 익스플로러로 표시되는
오류를 그대로 복제하도록 시도하지만, 오페라는 우선적으로 표준 체계를 그대로 적용한다.
오페라와 넷스케이프/ 인터넷익스플로러 사이에 표시되는 차이에 대해서는 아래와 같다.
.. 오페라에서 <HR>의 색은 배경 특징 이다, 그래서 오페라는 생성하는 내용 뿐만 아니라
모든 배경스타일을 승인한다. NN4 및 IE에서 그것은 전경 특징이다 (색). NN6은 역시 바
르게 한다 (전에 내용을 생성하고 사용된 후라면 오페라와 NN6 사이에는 차이가 있다).
.. 링크 밑줄은 오페라 및 NN6 이전 버전에서와는 다르다 (하나의 색으로 밑줄이 사용되고,
텍스트는 다른 색으로 사용된다). 이것은 텍스트에 대한 CSS2의 결과이다.
.. IE5/Windows는 오페라 ( 및 NN6)에서 상자를 보다 크게 보이게 하는 높이와 폭에서
오류가 있다. 이것은 표준 양식으로 IE6에서 수정되었다.
.. IE5는 또한 위치에 대해 문제를 갖고 있다. 위치한 요소는 포함하는 요소가 아닌 가장 가
까이 위치한 요소에 위치되어야 한다. 배경 이미지의 위치는 창이 아닌 요소 상자와 관계
한다. 이것은 오페라에서 body 와 함께 위치한 이미지 (background-position: center)는
창의 중앙에서가 아닌 페이지의 중앙에서 보기 좋지 않게 나타난다는 것을 의미한다.
.. 보통 padding은 그 body 요소에 적용된다. 그리고 여백을 두지 않는다 (body 및
head/html 요소 사이의 여백).
오페라에 대한 소개 및 한글 지원 페이지는 http://opera114.pe.kr 를 참고하면 된다.
사파리
사파리(Safari)는 애플 컴퓨터가 자사의 맥 오에스 텐(Mac OS X) 운
영체제를 위해 개발한 웹 브라우저이다. 사파리는 맥 오에스 텐
v10.3(팬서)의 기본 브라우저로 포함되었고, 맥 오에스 텐 v10.4(타이
거)에서는 기본 탑재되어 있는 유일한 브라우저이다.
사파리는 아이튠즈 음악 감상 소프트웨어와 유사한 북마크 관리 체계
를 가지고 있고, 애플의 퀵타임 멀티미디어 기술과 통합되어 있으며,
모질라와 유사한 탭 브라우징 인터페이스를 사용한다. 구글 검색 상자
는 사파리 인터페이스의 기본 요소이며, 웹 주소 자동완성과 웹 페이지 텍스트 영역의 맞
실전 웹 표준 가이드
- 219 -
춤법 검사를 지원한다.
1997년까지 애플 매킨토시 컴퓨터는 넷스케이프 네비게이터를 기본으로 제공해왔다. 이후
마이크로소프트의 맥용 인터넷 익스플로러가 기본 브라우저로 포함되었다. 그러나 2003년
6월에 사파리 출시에 따른 마이크로소프트의 대응은 맥용 인터넷 익스프로러의 개발중단
선언이었다. 넉달 뒤에 맥 오에스 텐 v10.3에 맥용 인터넷 익스플로러가 들어 있긴 했지
만 기본 브라우저에 대한 대체 브라우저로써 포함된 것이었다. 맥 오에스 텐 v10.4의 도
래와 함께, 사파리는 이 운영체제에 포함된 유일한 웹 브라우저이다.
사파리는 웹페이지 렌더링 및 자바 스크립트 실행에 애플의 웹키트를 사용한다. 웹키트는
웹코어(컹커러의 KHTML 엔진에 기반한 것)와 자바스크립트코어(KDE의 kjs 자바스크립
트 엔진에 기반한 것)로 구성되어 있다. KHTML과 kjs와 마찬가지로 웹코어와 자바스립
트코어는 자유 소프트웨어이며, LGPL(약소 일반 공중 사용 허가서) 라이선스로 배포된다.
KHTML 코드로부터 애플이 개선한 일부 코드는 컹커러 프로젝트에 합쳐진다. 애플은 또
한 2절로 된 BSD 라이선스와 유사한 오픈 소스로 추가 코드를 공개한다.
2005년 4월 29일에 나온 사파리 2.0판은 RSS와 Atom 읽기 기능을 내장하고 있다. 다른
기능으로는 보안 브라우징, 웹페이지의 저장 및 이메일 전송, 북마크 검색 기능을 들 수
있고, 1.2.4판에 비해 1.8배의 속도 증진이 있었다는 보고가 있다.
사파리의 현재 개발자 버전은 Acid2 테스트, 즉 CSS2의 일부 기능(특히 에러 핸들링 부
분에서)을 점검하는 테스트에 통과한 최초의 브라우저이다. 그렇지만 이와 같은 개선점은
웹키트 소스를 다운로드해서 컴파일해야 얻을 수 있기 때문에 아직은 실사용자들과는 거
리가 멀다.
실전 웹 표준 가이드
- 220 -
장애인 웹 접근성 체크 리스트
웹 표준 범주에는 레이아웃 및 기술적 공통성을 추구하는 면이 있는 가 하면, 일반적이지
않는 웹사용자에 대한 지원이라는 포괄적인 의미도 함축하고 있다. 예를 들어, 청각 장애
자나 시각 장애자가 웹페이지를 보기 위해 필요한 것들이나 어린이 노약자를 위한 배려
같은 것들이 그것이다.
이러한 기능 옵션에 대한 중요한 사항은 웹 사이트를 기획 운영하는 웹마스터와 웹디자이
너 및 개발자들이 http://www.w3.org/TR/WAI-WEBCONTENT/에 제시되어 있는
'W3C web accessibility initiatives'의 규정한 지침에 유의해야 한다.
1) 텍스트
.. 핵심 정보는 반드시 텍스트/HTML 포맷으로 제공되어야 한다. 특히 Flash 같은 것으로
전체화면을 구성하거나 메뉴를 구성하는 것은 피해야 한다. 만약 꼭 사용해야 한다면 비
Flash 버전을 만들어야 한다.
.. 텍스트는 반드시 사용된 배경색에 대해 뚜렷이 대비되는 색으로 표시되어야 한다. (다양한
환경의 256 COLOR 지원 그래픽 카드에서 식별 가능여부가 테스트 되어야 한다)
.. 텍스트 색상은 텍스트를 표시하는 곳에서 사용자가 원하는 색상을 선택할 수 있으므로, 색
상별로 별도의 의미를 함축하지는 않는다.
2) 폰트 설정(Font)
.. 글자에 대한 형식은 <font> Tag를 사용하기 보다는 CSS을 통해 지정해서 사용한다.
HTML4.0에서는 FONT를 사용하는 것을 추천하고 있지 않다.
.. CSS에는 일반적으로 사용 가능한 글자꼴을 Face 속성에서 지정해야 한다. 예를 들면, 굴
림, 굴림체, 돋움, 돋움체 등 Arial, Helvetica, Times New Roman등이 있다. 또한, 가변
폭과 고정폭의 글꼴 선택에 있어 글자의 크기를 사용자가 임의로 조정할 수 있도록 가변
폭 글꼴을 우선한다.
.. 영문의 경우 모두 대문자로 표기하거나 이탤릭체를 과도하게 사용하는 것은 피해야 한다.
밑줄 친 글자는 하이퍼링크와 혼동될 우려가 있으므로 사용을 피한다.
.. 색상 속성은 인쇄 시 나타나지 않으므로 흰색이나 지나치게 밝은색으로 설정하지 않으며,
쉽게 읽을 수 있도록 배경색과 대비가 되어야 한다. 특히, 'Color'가 특정 의미 부여의 유
일한 방법이어서는 안 된다.
.. 어떤 정보가 특정 글꼴로 표현되어야 한다면, 해당 정보는 이미지로 표현되어야 하고 텍스
트 형식의 ALT 값을 제공해야 한다. 정보를 표현하는데 이미지를 사용하는 것은 최소화
해야 한다.
3) 테이블 (TABLE)
.. 브라우저에 따라, 특정 사용자의 경우에는, 복잡한 테이블을 생성하는 것이 어렵거나 레이
아웃이 틀려 보이는 경우가 매우 많다. 따라서, <TABLE> 태그 방식의 레이아웃 보다는
<DIV>와 CSS과 접목된 레이아웃 방식으로 변경하도록 노력한다.
.. 웹페이지 내에 테이블을 아예 사용하지 않는다는 정책을 고집하는 것은 현실적으로 불가
능하므로, 최소한 디자이너는 복잡한 테이블 사용 시 일어날 수 있는 문제에 대해 인식하
고 있어야 한다.
실전 웹 표준 가이드
- 221 -
.. 컬럼 수는 최소로 효과적으로 유지해야 하고, 중첩 테이블은 가능한 한 피하고, 다른 대안
이 없는 경우 사용한다
.. 테이블 내의 정보는 가능하면 수평으로 읽혀져야 하며, 서로 다른 웹 브라우저에 따라 가
능한 동일하게 표현되어야 하고 호환성이 확인되어야 한다.
.. Ending 태그는 절대 생략해서는 안 되며, 셀 내의 배경 이미지는 구버전의 브라우저에서
는 지원되지 않으므로 피해야 한다.
4) 대안 TAG의 정의
.. <img>, <applet>, <input> ,<object>, <applet> 태그 등에는 이미지를 보지 않거나 볼
수 없는 사용자나 검색 엔진 위치설정에 매우 유용한 ALT나 LONGDESC, TITLE 같은
텍스트 정의를 반드시 삽입한다.
.. 웹사이트는 그래픽을 연결시키지 않은 상태로도 사용이 가능해야 하며, 이미지를 볼 수 없
는 사람들의 비용과 이익간의 균형을 반드시 고려해야 한다.
.. 대안 태그는 항상 포함되어야 하며, 이미지의 외관뿐만 아니라 기능을 설명해야 한다. 내
용은 100 문자를 초과하지 않아야 한다.
.. 중요한 로고가 처음으로 사용되는 곳에는(예를 들면 웹사이트 상에), 완전한 공식적인 설
명("X 정보컨텐츠 팀 로고 : ....을 나타내는 로고" 등)을 제공하는 것이 권장된다. 이후 로
고가 반복될 때는 ALT 텍스트 내에 "X 정보컨텐츠 팀 로고"로 명명할 수 있다.
.. 때때로 중요 정보(예를 들면, 차트, 테이블 또는 다이어그램)를 나타내는 어떤 이미지의 내
용에 대해 자세한 설명이 제공될 필요가 있다. 이 설명은 주요 웹 페이지 내에 텍스트로
포함되거나, IMG 요소의 LONGDESC 속성에 의해 링크된 웹 페이지에 위치시킬 수도
있다.
.. IMG와 A에서 사용 실례
<img src="access.gif" alt="[Description]"
longdesc="imgdesc_a.html"><a href="w.htm" title="Description of
Accessbility">[D]</a>
.. OBJECT에서의 사용 실례
<object data="accessbrdlogo.gif" type="image/gif"> The Access
Board's <a href="projected.html">projected budget</a> for Fiscal
2005 is ... </object>
.. IMAGE MAP에서의 사용 실례
<OBJECT data="navigation.gif" type="image/gif" usemap="#mapnav">
<MAP name="map1"><P>Navigate the Access Board site.
[<A href="guidelines.html" shape="rect" coords="0,0,118,28">Access
Guide</A>]
[<A href="news.html" shape="rect" coords="118,0,184,28">Go</A>]
[<A href="search.html" shape="circle"
coords="184.200,60">Search</A>]
</MAP>
</OBJECT>
.. TABLE에서 사용 실례
<TABLE border="1" summary="This table charts the number of web pages
analyzed by each agency head, what kind of media the pages contain,
and whether or not the page is part of the Executive Branch.">
<CAPTION>Web pages Analyzed by Agency Heads</CAPTION>
<TR>
<TH id="header1">Agency Head</TH>
. . .
실전 웹 표준 가이드
- 222 -
</TR>
</TABLE>
5) 접근성 시험
웹사이트 접근성은 Website garage (http://www.websitegarage.com) 혹은 Bobby
(http://www.cast.org/bobby) 등에서 테스트해 볼 수 있다. 좋은 방법은 텍스트 브라우
저인 Lynx를 활용하여 웹사이트를 시범적으로 조사해 보는 방법도 있다.
실전 웹 표준 가이드
- 223 -
HTML 브라우저 호환표
끊임없이 새로운 브라우저가 출현함에 따라 표준과 호환성에 대한 중요도가 점점 증대되
고 있다. 그러나 많은 웹브라우저들은 여전히, HTML, CSS, 자바스크립트 등의 표준안을
충분히 지원하지 못하고 있다. 그러나 표준을 지키려는 노력들이 진행되고 있기 때문에 보
다 빠른 속도록 브라우저간 웹 호환성이 이루어 지고 있다.
모든 웹브라우저가 같은 형태의 페이지를 출력할 것으로 예상하지만 표에서 보이는 것 처
럼 1999년 이전에 나온 오래된 웹브라우저들은 자바스크립트, CSS, HTML4의 기능들을
구현하지 못하고 있다. 따라서 Cross Browsing의 목표는 완벽한 호환성에 두는 것이 아
니라 이종 웹브라우저에서 사용되는 비호환 및 비표준 구현 방식과 기법들을 가능한 표준
안에서 수용할 수 있는 방법을 찾는 것이다.
윈도우에서 주요 웹브라우저 별 HTML 지원 내역
프레임 테이블 플러그인 font
크기
Font
색상
자바스크
립트 자바 CSS gif89 DHTML IFRAME 테이블색 VML
IE6.0 V V V V V V V V V V V V
IE5.5 V V V V V V V V V V V V V
IE5.0 V V V V V V V V V V V V
IE4.0 V V V V V V V V V V V V
IE3.0 V V V V V V V V V V V
IE2.0 V V V
IE1.0 V V V
NS7.0 V V V V V V V V V V V V V
NS6.1 V V V V V V V V V V V V V
NS6.0 V V V V V V V V V V V V V
NN4.7 V V V V V V V V V V V
NN4.5 V V V V V V V V V V V
NN3.0 V V V V V V V V V
NN2.0 V V V V V V V
NN1.1 V V
MZ1.3 V V V V V V V V V V V V V
MZ1.0 V V V V V V V V V V V V V
OP7.V V V V V V V V V V V V V V
OP6.0 V V V V V V V V V V V V V
실전 웹 표준 가이드
- 224 -
OP5 V V V V V V V V V V V V V
OP4 V V V V V V V V V V V
OP3.6 V V V V V V V V
OP3.5 V V V V V V V
브라우저별 HTML3/4 지원 일람표
Element NN4 NS6 IE4 IE5 HTML3 HTML4 비고 세부 속성 내역
A Y Y Y Y Y Y
ABBR Y Y
ACRONYM Y Y Y Y
ADDRESS Y Y Y Y Y Y
APPLET Y Y Y Y Y Y HTML4.0에서
거부됨.
ALIGN, ARCHIVE,
CODE, CODEBASE,
HEIGHT, NAME,
OBJECT, WIDTH
AREA Y Y Y Y Y Y
B Y Y Y Y Y Y
BASE Y Y Y Y Y Y
BASEFONT Y Y Y Y Y HTML4.0에서
거부됨.
COLOR, FACE,
SIZE
BDO Y Y NS6에서 지원
안됨
BGSOUND Y Y
BIG Y Y Y Y Y Y
BLINK Y
BLOCKQUOTE Y Y Y Y Y Y
BODY Y Y Y Y Y Y ALINK,
BACKGROUND,
BGCOLOR, LINK,
TEXT, VLINK
BR Y Y Y Y Y Y CLEAR
BUTTON Y Y Y Y
CAPTION Y Y Y Y Y Y ALIGN
CENTER Y Y Y Y Y Y
CITE Y Y Y Y Y Y
CODE Y Y Y Y Y Y
COL Y Y Y Y
COLGROUP Y Y Y Y
COMMENT Y Y
DD Y Y Y Y Y Y
DEL Y Y Y Y
DFN Y Y Y Y Y
DIR Y Y Y Y Y Y HTML4.0에서
거부됨.
COMPACT
DIV Y Y Y Y Y Y
DL Y Y Y Y Y Y COMPACT
DT Y Y Y Y Y Y
실전 웹 표준 가이드
- 225 -
EM Y Y Y Y Y Y
EMBED Y Y Y Y
FIELDSET Y Y Y Y
FONT Y Y Y Y Y Y COLOR, FACE,
SIZE
FORM Y Y Y Y Y Y
FRAME Y Y Y Y Y
FRAMESET Y Y Y Y Y
H1 Y Y Y Y Y Y ALIGN
H2 Y Y Y Y Y Y ALIGN
H3 Y Y Y Y Y Y ALIGN
H4 Y Y Y Y Y Y ALIGN
H5 Y Y Y Y Y Y ALIGN
H6 Y Y Y Y Y Y ALIGN
HEAD Y Y Y Y Y Y
HR Y Y Y Y Y Y ALIGN, NOSHADE,
SIZE, WIDTH
HTML Y Y Y Y Y Y VERSION
I Y Y Y Y Y Y
IFRAME Y Y Y Y ALIGN
ILAYER Y DIV로 대체됨
IMG Y Y Y Y Y Y ALIGN, BORDER,
HSPACE, VSPACE
INPUT Y Y Y Y Y Y ALIGN
INS Y Y Y Y
ISINDEX Y Y Y Y Y Y HTML4.0에서
거부됨.
PROMPT
KBD Y Y Y Y Y Y
KEYGEN Y
LABEL Y Y Y Y
LAYER Y DIV로 대체됨
LEGEND Y Y Y Y ALIGN
LI Y Y Y Y Y Y TYPE, VALUE
LINK Y Y Y Y Y Y
LISTING Y Y Y Y HTML4.0에서
제외됨
MAP Y Y Y Y Y Y
MARQUEE Y Y
MENU Y Y Y Y Y Y HTML4.0에서
거부됨.
COMPACT
META Y Y Y Y Y Y
MULTICOL Y
NOBR Y Y Y Y Y Y
NOEMBED Y
NOFRAMES Y Y Y Y Y
NOLAYER Y 제거됨
NOSCRIPT Y Y Y Y Y
OBJECT Y Y Y Y Y ALIGN, BORDER,
HSPACE,
VSPACE
실전 웹 표준 가이드
- 226 -
OL Y Y Y Y Y Y COMPACT,
START, TYPE
OPTIONGROUP Y Y
OPTION Y Y Y Y Y Y
P Y Y Y Y Y Y ALIGN
PARAM Y Y Y Y Y Y
PLAINTEXT Y Y Y Y HTML4.0에서
제외됨.
PRE Y Y Y Y Y Y
Q Y Y Y Y
RT Y
RUBY Y
S Y Y Y Y Y Y HTML4.0에서
거부됨.
SAMP Y Y Y Y Y Y
SCRIPT Y Y Y Y Y
SELECT Y Y Y Y Y Y
SERVER Y
SMALL Y Y Y Y Y Y
SPACER Y
SPAN Y Y Y Y Y
STRIKE Y Y Y Y Y Y HTML4.0에서
거부됨.
STRONG Y Y Y Y Y Y
STYLE Y Y Y Y Y
SUB Y Y Y Y Y Y
SUP Y Y Y Y Y Y
TABLE Y Y Y Y Y Y ALIGN,
BGCOLOR
TBODY Y Y Y Y Y
TD Y Y Y Y Y Y BGCOLOR,
HEIGHT,
NOWRAP, WIDTH
TEXTAREA Y Y Y Y Y Y
TFOOT Y Y Y Y
TH Y Y Y Y Y Y BGCOLOR,
HEIGHT,
NOWRAP, WIDTH
THEAD Y Y Y Y
실전 웹 표준 가이드
- 227 -
TITLE Y Y Y Y Y Y
TR Y Y Y Y Y Y BGCOLOR
TT Y Y Y Y Y Y
U Y Y Y Y Y Y HTML4.0에서
거부됨.
UL Y Y Y Y Y Y COMPACT, TYPE
VAR Y Y Y Y Y Y
WBR Y Y Y Y
XML Y
XMP Y Y Y Y Y HTML4.0에서
제거됨.
실전 웹 표준 가이드
- 228 -
표준 HTML4.01/XHTML 브라우저 호환 차트
HTML 4.01
기능 목록 IE 5 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
a
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
accesskey Y Y Y Y I
charset Y Y Y Y Y
coords N N N N Y
href Y Y Y Y Y
hreflang Y Y Y Y Y
name Y Y Y Y Y
onblur Y Y Y Y Y
onfocus Y Y Y Y Y
rel Y Y Y Y Y
rev Y Y Y Y Y
shape N N N N Y
tabindex I I Y Y I
type Y Y Y Y Y
abbr
(일반) N N Y Y Y
Core attributes N N Y Y Y
Event attributes N N Y Y Y
I18n attributes N N Y Y N
acronym
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y N
address
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
area
(일반) Y Y Y Y I
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
accesskey Y Y Y Y Y
실전 웹 표준 가이드
- 229 -
alt I I Y Y Y
coords Y Y Y Y Y
href Y Y Y Y Y
nohref Y Y Y Y Y
onblur Y Y Y Y Y
onfocus Y Y Y Y Y
shape I I Y Y Y
tabindex Y Y Y Y I
b
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
base
(일반) Y Y Y Y Y
href Y Y Y Y Y
bdo
(일반) Y Y Y Y Y
Core attributes I I I I Y
dir Y Y Y Y Y
lang Y Y Y Y Y
big
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
blockquote
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
cite Y Y Y Y Y
body
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
onload Y Y Y Y Y
onunload Y Y Y Y Y
br
(일반) Y Y Y Y Y
Core attributes I I I I Y
button
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
실전 웹 표준 가이드
- 230 -
I18n attributes Y Y Y Y Y
accesskey Y Y Y Y I
disabled Y Y Y Y Y
name Y Y Y Y Y
onblur Y Y Y Y Y
onfocus Y Y Y Y Y
tabindex I I Y Y Y
type I I Y Y Y
value N N Y Y Y
caption
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
cite
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
code
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
col
(일반) Y Y Y Y Y
Core attributes I I I I I
Event attributes N N N N N
I18n attributes Y Y N N N
Cell alignment attributes I I N N I
span Y Y Y Y Y
width I I Y Y I
colgroup
(일반) Y Y Y Y Y
Core attributes I I I I I
Event attributes N N N N N
I18n attributes Y Y N N N
Cell alignment attributes I I N N I
span Y Y Y Y Y
width I I Y Y I
dd
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
del
실전 웹 표준 가이드
- 231 -
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
cite Y Y Y Y Y
datetime Y Y Y Y Y
dfn
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
div
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
dl
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
dt
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
em
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
fieldset
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
form
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
accept Y Y Y Y Y
accept-charset I I Y Y Y
action Y Y Y Y Y
enctype Y Y Y Y Y
method Y Y Y Y Y
실전 웹 표준 가이드
- 232 -
name Y Y Y Y Y
onreset Y Y Y Y Y
onsubmit Y Y Y Y Y
frame
(일반) Y Y Y Y Y
Core attributes I I N N N
frameborder I I I I I
longdesc Y Y Y Y Y
marginheight Y Y Y Y Y
marginwidth Y Y Y Y Y
name Y Y Y Y Y
noresize Y Y Y Y Y
scrolling I I I Y Y
src Y Y Y Y Y
frameset
(일반) Y Y Y Y Y
Core attributes I I I I N
cols Y Y Y Y Y
onload Y Y Y Y Y
onunload Y Y Y Y Y
rows Y Y Y Y Y
h1
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
h2
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
h3
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
h4
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
h5
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
실전 웹 표준 가이드
- 233 -
h6
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
head
(일반) Y Y Y Y Y
I18n attributes N N N N N
profile Y Y Y Y Y
hr
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
html
(일반) Y Y Y Y Y
I18n attributes Y Y Y Y Y
i
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
iframe
(일반) Y Y Y Y Y
Core attributes I I I I Y
align Y Y I I I
frameborder Y Y Y Y Y
height I I Y Y Y
longdesc Y Y Y Y Y
marginheight Y Y Y Y Y
marginwidth Y Y Y Y Y
name Y Y Y Y Y
scrolling I I I Y Y
src Y Y Y Y Y
width Y Y Y Y Y
img
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes N N Y Y N
alt Y Y Y Y Y
height Y Y Y Y Y
ismap Y Y Y Y Y
longdesc Y Y Y Y Y
name Y Y Y Y Y
src Y Y Y Y Y
실전 웹 표준 가이드
- 234 -
usemap Y Y Y Y Y
width Y Y Y Y Y
input
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y I
I18n attributes Y Y Y Y N
accept Y Y Y Y Y
accesskey Y Y Y Y Y
alt Y Y Y Y Y
checked Y Y Y Y Y
disabled Y Y Y Y Y
ismap Y Y Y Y Y
maxlength Y Y Y Y I
name Y Y Y Y Y
onblur Y Y Y Y I
onchange Y Y Y Y I
onfocus Y Y I I I
onselect Y Y Y Y I
readonly I I I I I
size I I I I I
src Y Y Y Y Y
tabindex I I Y Y Y
type Y Y Y Y Y
usemap N N Y Y Y
value Y Y Y Y Y
ins
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
cite Y Y Y Y Y
datetime Y Y Y Y Y
kbd
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
label
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
accesskey Y Y Y Y Y
for Y Y Y Y Y
onblur N N N N Y
실전 웹 표준 가이드
- 235 -
onfocus N N N N Y
legend
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
accesskey Y Y N Y N
li
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
link
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
charset Y Y Y Y Y
href Y Y Y Y Y
hreflang Y Y Y Y Y
media Y Y Y Y Y
rel Y Y Y Y Y
rev Y Y Y Y Y
type Y Y Y Y Y
map
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y I
I18n attributes Y Y Y Y Y
name Y Y Y Y Y
meta
(일반) Y Y Y Y Y
I18n attributes Y Y Y Y Y
content Y Y Y Y Y
http-equiv Y Y Y Y Y
name Y Y Y Y Y
scheme Y Y Y Y Y
noframes
(일반) N N Y Y Y
Core attributes N N I I I
Event attributes N N Y Y Y
I18n attributes N N Y Y Y
noscript
(일반) I I Y Y Y
Core attributes I I I I N
Event attributes N N Y Y Y
실전 웹 표준 가이드
- 236 -
I18n attributes Y Y Y Y N
object
(일반) I I I Y Y
Core attributes I I I I Y
Event attributes I I Y Y Y
I18n attributes N N Y Y N
archive N N N N N
classid Y Y Y Y Y
codebase N N N N Y
codetype Y Y Y Y Y
data I I I I Y
declare N N N N Y
height Y Y Y Y Y
name Y Y Y Y Y
standby N N N N N
tabindex N N Y Y N
type Y Y Y Y Y
usemap Y Y Y Y Y
width Y Y Y Y Y
ol
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
optgroup
(일반) Y Y Y Y Y
Core attributes I I I I N
Event attributes N N I I I
I18n attributes N N Y Y N
disabled N N Y Y Y
label Y Y Y Y Y
option
(일반) Y Y Y Y Y
Core attributes I I I I N
Event attributes N N I I I
I18n attributes N N I I N
disabled N N Y Y Y
label N N N N N
selected Y Y Y Y Y
value Y Y Y Y Y
p
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
param
실전 웹 표준 가이드
- 237 -
(일반) Y Y Y Y Y
id Y Y Y Y Y
name Y Y Y Y Y
type Y Y Y Y Y
value Y Y Y Y Y
valuetype Y Y Y Y Y
pre
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
q
(일반) I I Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
cite Y Y Y Y Y
samp
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
script
(일반) Y Y Y Y Y
charset Y Y Y Y Y
defer Y Y N N N
src Y Y Y Y Y
type Y Y Y Y Y
select
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y I
I18n attributes Y Y Y Y N
disabled Y Y Y Y Y
multiple Y Y Y Y Y
name Y Y Y Y Y
onblur Y Y Y Y Y
onchange Y Y Y Y I
onfocus Y Y Y Y Y
size Y Y Y Y Y
tabindex I I Y Y Y
small
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
실전 웹 표준 가이드
- 238 -
span
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
strong
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
style
(일반) Y Y Y Y Y
I18n attributes Y Y Y Y Y
media Y Y Y Y Y
title Y Y Y Y Y
type Y Y Y Y Y
sub
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
sup
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
table
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
border Y Y Y Y Y
cellpadding Y Y Y Y Y
cellspacing Y Y I I Y
frame I I I I I
rules I I Y Y Y
summary Y Y Y Y Y
width Y Y Y Y Y
tbody
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
Cell alignment attributes I I I I I
td
(일반) Y Y Y Y Y
실전 웹 표준 가이드
- 239 -
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
Cell alignment attributes I I I I I
abbr Y Y Y Y Y
axis Y Y Y Y Y
colspan I I Y Y I
headers Y Y Y Y Y
rowspan I I Y Y Y
scope Y Y Y Y Y
textarea
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y N
accesskey Y Y Y Y Y
cols Y Y Y Y Y
disabled Y Y Y Y Y
name Y Y Y Y Y
onblur Y Y Y Y Y
onchange Y Y Y Y Y
onfocus Y Y Y Y Y
onselect Y Y Y Y Y
readonly Y Y Y Y Y
rows Y Y Y Y Y
tabindex I I Y Y Y
tfoot
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
Cell alignment attributes I I I I I
th
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
Cell alignment attributes I I I I I
abbr Y Y Y Y Y
axis Y Y Y Y Y
colspan I I Y Y I
headers Y Y Y Y Y
rowspan I I Y Y Y
scope Y Y Y Y Y
thead
(일반) Y Y Y Y Y
실전 웹 표준 가이드
- 240 -
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
Cell alignment attributes I I I I I
title
(일반) Y Y Y Y Y
I18n attributes N N N N N
tr
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
Cell alignment attributes I I I I I
tt
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
ul
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
var
(일반) Y Y Y Y Y
Core attributes I I I I Y
Event attributes Y Y Y Y Y
I18n attributes Y Y Y Y Y
Core attributes
class Y Y Y Y Y
id I I Y Y Y
style Y Y Y Y Y
title I I I I Y
Event attributes
onclick Y Y Y Y Y
ondblclick Y Y Y Y Y
onkeydown Y Y Y Y Y
onkeypress Y Y Y Y Y
onkeyup Y Y Y Y Y
onmousedown Y Y Y Y Y
onmousemove Y Y Y Y Y
onmouseout Y Y Y Y Y
onmouseover Y Y Y Y Y
onmouseup Y Y Y Y Y
국제화 속성
dir Y Y Y Y Y
실전 웹 표준 가이드
- 241 -
lang Y Y Y Y Y
Cell alignment attributes
align I I I I I
char N N N N N
charoff N N N N N
valign I I I I I
XHTML 1.0
기능 목록 IE 5 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
HTML in XML
(일반) N N Y Y Y
Documents must be well-formed
(일반) Y Y Y Y Y
Media types
application/xhtml+xml N N Y Y Y
application/xml I I Y Y Y
text/xml I I Y Y Y
name fragment identifiers are now id
a Y Y Y Y Y
applet Y Y Y Y Y
form Y Y Y Y Y
frame Y Y Y Y Y
iframe Y Y Y Y Y
img Y Y Y Y Y
map Y Y Y Y Y
XHTML 1.1
기능 목록 IE 5 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
rb
(일반) Y Y N N N
Core attributes N N I I I
rbc
(일반) N N N N N
Core attributes N N I I I
rp
(일반) I I N N N
Core attributes N N I I I
rt
(일반) Y Y N N N
Core attributes I I I I I
rbspan Y Y N N N
rtc
실전 웹 표준 가이드
- 242 -
(일반) N N N N N
Core attributes N N I I I
ruby
(일반) Y Y N N N
Core attributes I I I I I
실전 웹 표준 가이드
- 243 -
표준 CSS 브라우저 호환 차트
CSS 2.1 Unit
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
Angle
(일반) N N N N N
deg N N N N N
grad N N N N N
rad N N N N N
Color
(일반) Y Y Y Y Y
#rrggbb Y Y Y Y Y
#rgb Y Y Y Y Y
rgb(<red>, <green>, <blue>) Y Y Y Y Y
aqua Y Y Y Y Y
black Y Y Y Y Y
blue Y Y Y Y Y
fuchsia Y Y Y Y Y
gray Y Y Y Y Y
green Y Y Y Y Y
lime Y Y Y Y Y
maroon Y Y Y Y Y
navy Y Y Y Y Y
olive Y Y Y Y Y
orange Y Y Y Y Y
purple Y Y Y Y Y
red Y Y Y Y Y
silver Y Y Y Y Y
teal Y Y Y Y Y
white Y Y Y Y Y
yellow Y Y Y Y Y
ActiveBorder Y Y Y Y Y
ActiveCaption Y Y Y Y Y
AppWorkspace Y Y Y Y Y
Background Y Y Y Y Y
ButtonFace Y Y Y Y Y
ButtonHighlight Y Y Y Y Y
ButtonShadow Y Y Y Y Y
ButtonText Y Y Y Y Y
CaptionText Y Y Y Y Y
GrayText Y Y Y Y Y
Highlight Y Y Y Y Y
HighlightText Y Y Y Y Y
실전 웹 표준 가이드
- 244 -
InactiveBorder Y Y Y Y Y
InactiveCaption Y Y Y Y Y
InactiveCaptionText Y Y Y Y Y
InfoBackground Y Y Y Y Y
InfoText Y Y Y Y Y
Menu Y Y Y Y Y
MenuText Y Y Y Y Y
Scrollbar Y Y Y Y Y
ThreeDDarkShadow Y Y Y Y Y
ThreeDFace Y Y Y Y Y
ThreeDHighlight Y Y Y Y Y
ThreeDLightShadow Y Y Y Y Y
ThreeDShadow Y Y Y Y Y
Window Y Y Y Y Y
WindowFrame Y Y Y Y Y
WindowText Y Y Y Y Y
Counter
(일반) N N N Y I
Frequency
(일반) N N N N N
Hz N N N N N
kHz N N N N N
Integer
(일반) Y Y Y Y Y
Length
(일반) Y Y Y Y Y
em Y Y Y Y Y
ex Y Y Y Y Y
px Y Y Y Y Y
in Y Y Y Y Y
cm Y Y Y Y Y
mm Y Y Y Y Y
pt Y Y Y Y Y
pc Y Y Y Y Y
Number
(일반) Y Y Y Y Y
Percentage
(일반) Y Y Y Y Y
String
(일반) N N I I Y
Time
(일반) N N N N Y
ms N N N N Y
s N N N N Y
URI
(일반) Y Y Y Y Y
실전 웹 표준 가이드
- 245 -
CSS 2.1 Importance
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
!important
(일반) I I Y Y Y
CSS 2.1 At-rules
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
@charset
(일반) Y Y Y Y Y
@import
(일반) I I Y Y Y
@media
(일반) Y Y Y Y Y
@page
(일반) N N N N Y
:left N N N N Y
:right N N N N Y
:first N N N N Y
CSS 2.1 Selectors
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
*
(일반) I I Y Y Y
E
(일반) I I Y Y Y
E F
(일반) Y Y Y Y Y
E > F
(일반) N N Y Y Y
E + F
(일반) N N Y Y Y
[attr]
(일반) N N Y Y Y
[attr="value"]
(일반) N N Y Y Y
[attr~="value"]
(일반) N N Y Y Y
[attr|="value"]
(일반) N N Y Y Y
실전 웹 표준 가이드
- 246 -
.class
(일반) I I Y Y Y
#id
(일반) I I Y Y Y
CSS 2.1 Pseudo-classes
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
:active
(일반) I I Y Y I
:first-child
(일반) N N Y Y Y
:focus
(일반) N N Y Y Y
:hover
(일반) I I Y Y I
:lang(C)
(일반) N N Y Y Y
:link
(일반) I I Y Y Y
:visited
(일반) I I Y Y Y
CSS 2.1 Pseudo-elements
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
:after
(일반) N N Y Y Y
:before
(일반) N N Y Y Y
:first-letter
(일반) I I Y Y Y
:first-line
(일반) I I Y Y Y
CSS 2.1 Basic properties
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
background
(일반) Y Y Y Y Y
(background-color) Y Y Y Y Y
(background-image) Y Y Y Y Y
(background-repeat) Y Y Y Y Y
실전 웹 표준 가이드
- 247 -
(background-attachment) I I Y Y Y
(background-position) Y Y Y Y Y
inherit N N Y Y Y
background-attachment
(일반) I I Y Y Y
scroll Y Y Y Y Y
fixed Y Y Y Y Y
inherit N N Y Y Y
background-color
(일반) Y Y Y Y Y
(Color) Y Y Y Y Y
transparent Y Y Y Y Y
inherit N N Y Y Y
background-image
(일반) Y Y Y Y Y
(URI) Y Y Y Y Y
none Y Y Y Y Y
inherit N N Y Y Y
background-position
(일반) Y Y Y Y Y
(Percentage) Y Y Y Y Y
(Length) Y Y Y Y Y
left Y Y Y Y Y
center (horizontal) Y Y Y Y Y
right Y Y Y Y Y
top Y Y Y Y Y
center (vertical) Y Y Y Y Y
bottom Y Y Y Y Y
inherit N N Y Y Y
background-repeat
(일반) Y Y Y Y Y
repeat Y Y Y Y Y
repeat-x Y Y Y Y Y
repeat-y Y Y Y Y Y
no-repeat Y Y Y Y Y
inherit N N Y Y Y
border
(일반) I I Y Y Y
(border-width) Y Y Y Y Y
(border-style) I I Y Y Y
(border-top-color) I I Y Y Y
inherit N N Y Y Y
border-bottom
(일반) I I Y Y Y
(border-width) Y Y Y Y Y
(border-style) I I Y Y Y
실전 웹 표준 가이드
- 248 -
(border-top-color) I I Y Y Y
inherit N N Y Y Y
border-bottom-color
(일반) I I Y Y Y
(Color) Y Y Y Y Y
transparent I I Y Y Y
inherit N N Y Y Y
border-bottom-style
(일반) I I Y Y Y
none Y Y Y Y Y
hidden N N Y Y Y
dotted I I Y Y Y
dashed Y Y Y Y Y
solid Y Y Y Y Y
double Y Y Y Y Y
groove Y Y Y Y Y
ridge Y Y Y Y Y
inset Y Y Y Y Y
outset Y Y Y Y Y
inherit N N Y Y Y
border-bottom-width
(일반) I I Y Y Y
thin Y Y Y Y Y
medium Y Y Y Y Y
thick Y Y Y Y Y
(Length) Y Y Y Y Y
inherit N N Y Y Y
border-collapse
(일반) I I Y Y Y
collapse Y Y Y Y Y
separate Y Y Y Y Y
inherit N N Y Y Y
border-color
(일반) I I Y Y Y
(Color) Y Y Y Y Y
transparent I I Y Y Y
inherit N N Y Y Y
border-left
(일반) I I Y Y Y
(border-width) Y Y Y Y Y
(border-style) I I Y Y Y
(border-top-color) I I Y Y Y
inherit N N Y Y Y
border-left-color
(일반) I I Y Y Y
(Color) Y Y Y Y Y
실전 웹 표준 가이드
- 249 -
transparent I I Y Y Y
inherit N N Y Y Y
border-left-style
(일반) I I Y Y Y
none Y Y Y Y Y
hidden N N Y Y Y
dotted I I Y Y Y
dashed Y Y Y Y Y
solid Y Y Y Y Y
double Y Y Y Y Y
groove Y Y Y Y Y
ridge Y Y Y Y Y
inset Y Y Y Y Y
outset Y Y Y Y Y
inherit N N Y Y Y
border-left-width
(일반) I I Y Y Y
thin Y Y Y Y Y
medium Y Y Y Y Y
thick Y Y Y Y Y
(Length) Y Y Y Y Y
inherit N N Y Y Y
border-right
(일반) I I Y Y Y
(border-width) Y Y Y Y Y
(border-style) I I Y Y Y
(border-top-color) I I Y Y Y
inherit N N Y Y Y
border-right-color
(일반) I I Y Y Y
(Color) Y Y Y Y Y
transparent I I Y Y Y
inherit N N Y Y Y
border-right-style
(일반) I I Y Y Y
none Y Y Y Y Y
hidden N N Y Y Y
dotted I I Y Y Y
dashed Y Y Y Y Y
solid Y Y Y Y Y
double Y Y Y Y Y
groove Y Y Y Y Y
ridge Y Y Y Y Y
inset Y Y Y Y Y
outset Y Y Y Y Y
inherit N N Y Y Y
실전 웹 표준 가이드
- 250 -
border-right-width
(일반) I I Y Y Y
thin Y Y Y Y Y
medium Y Y Y Y Y
thick Y Y Y Y Y
(Length) Y Y Y Y Y
inherit N N Y Y Y
border-spacing
(일반) N N Y Y Y
(Length) N N Y Y Y
inherit N N Y Y Y
border-style
(일반) I I Y Y Y
none Y Y Y Y Y
hidden N N Y Y Y
dotted I I Y Y Y
dashed Y Y Y Y Y
solid Y Y Y Y Y
double Y Y Y Y Y
groove Y Y Y Y Y
ridge Y Y Y Y Y
inset Y Y Y Y Y
outset Y Y Y Y Y
inherit N N Y Y Y
border-top
(일반) I I Y Y Y
(border-width) Y Y Y Y Y
(border-style) I I Y Y Y
(border-top-color) I I Y Y Y
inherit N N Y Y Y
border-top-color
(일반) I I Y Y Y
(Color) Y Y Y Y Y
transparent I I Y Y Y
inherit N N Y Y Y
border-top-style
(일반) I I Y Y Y
none Y Y Y Y Y
hidden N N Y Y Y
dotted I I Y Y Y
dashed Y Y Y Y Y
solid Y Y Y Y Y
double Y Y Y Y Y
groove Y Y Y Y Y
ridge Y Y Y Y Y
inset Y Y Y Y Y
실전 웹 표준 가이드
- 251 -
outset Y Y Y Y Y
inherit N N Y Y Y
border-top-width
(일반) I I Y Y Y
thin Y Y Y Y Y
medium Y Y Y Y Y
thick Y Y Y Y Y
(Length) Y Y Y Y Y
inherit N N Y Y Y
border-width
(일반) I I Y Y Y
thin Y Y Y Y Y
medium Y Y Y Y Y
thick Y Y Y Y Y
(Length) Y Y Y Y Y
inherit N N Y Y Y
bottom
(일반) I I Y Y Y
(Length) Y Y Y Y Y
(Percentage) Y Y Y Y Y
auto Y Y Y Y Y
inherit N N Y Y Y
caption-side
(일반) N N Y Y Y
top N N Y Y Y
bottom N N Y Y Y
inherit N N Y Y Y
clear
(일반) Y Y Y Y Y
none Y Y Y Y Y
left Y Y Y Y Y
right Y Y Y Y Y
both Y Y Y Y Y
inherit N N Y Y Y
clip
(일반) N N Y Y Y
rect(<top>, <right>, <bottom>,
<left>) N N Y Y Y
auto N N Y Y Y
inherit N N Y Y Y
color
(일반) Y Y Y Y Y
(Color) Y Y Y Y Y
inherit N N Y Y Y
content
(일반) N N Y Y Y
실전 웹 표준 가이드
- 252 -
none N N N N N
normal N N N Y Y
(String) N N I I Y
(URI) N N Y Y Y
counter(<counter>) N N N Y I
counter(<counter>, <list-styletype>)
N N N Y I
counters(<counter>, <string>) N N N Y I
counters(<counter>, <string>,
<list-style-type>) N N N Y I
attr(<attr>) N N Y Y Y
open-quote N N Y Y Y
close-quote N N Y Y Y
no-open-quote N N Y Y Y
no-close-quote N N Y Y Y
inherit N N Y Y Y
counter-increment
(일반) N N N Y I
(Counter) N N N Y Y
(Integer) N N N Y Y
none N N N Y Y
inherit N N N Y Y
counter-reset
(일반) N N N Y I
(Counter) N N N Y Y
(Integer) N N N Y Y
none N N N Y Y
inherit N N N Y Y
cursor
(일반) Y Y Y Y I
(URI) Y Y N Y N
auto Y Y Y Y Y
crosshair Y Y Y Y Y
default Y Y Y Y Y
pointer Y Y Y Y Y
move Y Y Y Y Y
e-resize Y Y Y Y Y
ne-resize Y Y Y Y Y
nw-resize Y Y Y Y Y
n-resize Y Y Y Y Y
se-resize Y Y Y Y Y
sw-resize Y Y Y Y Y
s-resize Y Y Y Y Y
w-resize Y Y Y Y Y
text Y Y Y Y Y
wait Y Y Y Y Y
help Y Y Y Y Y
실전 웹 표준 가이드
- 253 -
progress Y Y Y Y N
inherit N N Y Y Y
direction
(일반) Y Y Y Y Y
ltr Y Y Y Y Y
rtl Y Y Y Y Y
inherit N N Y Y Y
display
(일반) Y Y Y Y Y
inline Y Y Y Y Y
block Y Y Y Y Y
list-item Y Y I I Y
run-in N N N N Y
inline-block I I N N Y
table N N Y Y Y
inline-table N N Y Y Y
table-row-group N N Y Y Y
table-header-group N N Y Y Y
table-footer-group N N Y Y Y
table-row N N Y Y Y
table-column-group N N Y Y N
table-column N N Y Y N
table-cell N N Y Y Y
table-caption N N Y Y Y
none Y Y Y Y Y
inherit N N Y Y Y
empty-cells
(일반) N N Y Y Y
show N N Y Y Y
hide N N I I I
inherit N N Y Y Y
float
(일반) I I Y Y Y
left Y Y Y Y Y
right Y Y Y Y Y
none Y Y Y Y Y
inherit N N Y Y Y
font
(일반) Y Y Y Y Y
(font-style) Y Y Y Y Y
(font-variant) Y Y Y Y Y
(font-weight) Y Y Y Y Y
(font-size) Y Y Y Y Y
(line-height) Y Y Y Y Y
(font-family) Y Y Y Y Y
caption Y Y Y Y Y
실전 웹 표준 가이드
- 254 -
icon Y Y Y Y Y
menu Y Y Y Y Y
message-box Y Y Y Y Y
small-caption Y Y Y Y Y
status-bar Y Y Y Y Y
inherit N N Y Y Y
font-family
(일반) Y Y Y Y Y
(Family name) Y Y Y Y Y
serif Y Y Y Y Y
sans-serif Y Y Y Y Y
cursive Y Y Y Y Y
fantasy Y Y Y Y Y
monospace Y Y Y Y Y
inherit N N Y Y Y
font-size
(일반) Y Y Y Y Y
(Length) Y Y Y Y Y
(Percentage) Y Y Y Y Y
xx-small Y Y Y Y Y
x-small Y Y Y Y Y
small Y Y Y Y Y
medium Y Y Y Y Y
large Y Y Y Y Y
x-large Y Y Y Y Y
xx-large Y Y Y Y Y
larger Y Y Y Y Y
smaller Y Y Y Y Y
inherit N N Y Y Y
font-style
(일반) Y Y Y Y Y
normal Y Y Y Y Y
italic Y Y Y Y Y
oblique Y Y Y Y Y
inherit N N Y Y Y
font-variant
(일반) Y Y Y Y Y
normal Y Y Y Y Y
small-caps Y Y Y Y Y
inherit N N Y Y Y
font-weight
(일반) Y Y Y Y Y
normal Y Y Y Y Y
bold Y Y Y Y Y
bolder Y Y Y Y Y
lighter Y Y Y Y Y
실전 웹 표준 가이드
- 255 -
100 Y Y Y Y Y
200 Y Y Y Y Y
300 Y Y Y Y Y
400 Y Y Y Y Y
500 Y Y Y Y Y
600 Y Y Y Y Y
700 Y Y Y Y Y
800 Y Y Y Y Y
900 Y Y Y Y Y
inherit N N Y Y Y
height
(일반) I I Y Y Y
(Length) Y Y Y Y Y
(Percentage) Y Y Y Y Y
auto Y Y Y Y Y
inherit N N Y Y Y
left
(일반) Y Y Y Y Y
(Length) Y Y Y Y Y
(Percentage) Y Y Y Y Y
auto I I Y Y Y
inherit N N Y Y Y
letter-spacing
(일반) Y Y Y Y Y
normal Y Y Y Y Y
(Length) Y Y Y Y Y
inherit N N Y Y Y
line-height
(일반) Y Y Y Y Y
normal Y Y Y Y Y
(Number) Y Y Y Y Y
(Length) Y Y Y Y Y
(Percentage) Y Y Y Y Y
inherit N N Y Y Y
list-style
(일반) Y Y Y Y Y
(list-style-type) Y Y Y Y Y
(list-style-position) Y Y Y Y Y
(list-style-image) Y Y Y Y Y
inherit N N Y Y Y
list-style-image
(일반) Y Y Y Y Y
(URI) Y Y Y Y Y
none Y Y Y Y Y
inherit N N Y Y Y
list-style-position
실전 웹 표준 가이드
- 256 -
(일반) Y Y Y Y Y
inside Y Y Y Y Y
outside Y Y Y Y Y
inherit N N Y Y Y
list-style-type
(일반) Y Y Y Y Y
disc Y Y Y Y Y
circle Y Y Y Y Y
square Y Y Y Y Y
decimal Y Y Y Y Y
decimal-leading-zero N N Y Y Y
lower-roman Y Y Y Y Y
upper-roman Y Y Y Y Y
lower-greek N N Y Y Y
lower-latin N N Y Y Y
upper-latin N N Y Y Y
armenian N N Y Y Y
georgian N N Y Y Y
lower-alpha Y Y Y Y Y
upper-alpha Y Y Y Y Y
none Y Y Y Y Y
inherit N N Y Y Y
margin
(일반) I I Y Y Y
(Length) Y Y Y Y Y
(Percentage) I I Y Y Y
auto Y Y Y Y Y
inherit N N Y Y Y
margin-bottom
(일반) I I Y Y Y
(Length) Y Y Y Y Y
(Percentage) I I Y Y Y
auto Y Y Y Y Y
inherit N N Y Y Y
margin-left
(일반) I I Y Y Y
(Length) Y Y Y Y Y
(Percentage) Y Y Y Y Y
auto Y Y Y Y Y
inherit N N Y Y Y
margin-right
(일반) I I Y Y Y
(Length) Y Y Y Y Y
(Percentage) Y Y Y Y Y
auto Y Y Y Y Y
inherit N N Y Y Y
실전 웹 표준 가이드
- 257 -
margin-top
(일반) I I Y Y Y
(Length) Y Y Y Y Y
(Percentage) I I Y Y Y
auto Y Y Y Y Y
inherit N N Y Y Y
max-height
(일반) N N Y Y Y
(Length) N N Y Y Y
(Percentage) N N Y Y Y
none N N Y Y Y
inherit N N Y Y Y
max-width
(일반) N N Y Y Y
(Length) N N Y Y Y
(Percentage) N N Y Y Y
none N N Y Y Y
inherit N N Y Y Y
min-height
(일반) N N Y Y Y
(Length) N N Y Y Y
(Percentage) N N Y Y Y
inherit N N Y Y Y
min-width
(일반) N N Y Y Y
(Length) N N Y Y Y
(Percentage) N N Y Y Y
inherit N N Y Y Y
outline
(일반) N N N Y Y
(outline-color) N N N Y Y
(outline-style) N N N Y Y
(outline-width) N N N Y Y
inherit N N N Y Y
outline-color
(일반) N N N Y Y
(Color) N N N Y Y
invert N N N Y Y
inherit N N N Y Y
outline-style
(일반) N N N Y Y
(border-style) N N N Y Y
inherit N N N Y Y
outline-width
(일반) N N N Y Y
(border-width) N N N Y Y
실전 웹 표준 가이드
- 258 -
inherit N N N Y Y
overflow
(일반) Y Y Y Y Y
visible I I Y Y Y
hidden Y Y Y Y Y
scroll Y Y Y Y Y
auto Y Y Y Y Y
inherit N N Y Y Y
padding
(일반) Y Y Y Y Y
(Length) Y Y Y Y Y
(Percentage) I I Y Y Y
inherit N N Y Y Y
padding-bottom
(일반) Y Y Y Y Y
(Length) Y Y Y Y Y
(Percentage) I I Y Y Y
inherit N N Y Y Y
padding-left
(일반) Y Y Y Y Y
(Length) Y Y Y Y Y
(Percentage) Y Y Y Y Y
inherit N N Y Y Y
padding-right
(일반) Y Y Y Y Y
(Length) Y Y Y Y Y
(Percentage) Y Y Y Y Y
inherit N N Y Y Y
padding-top
(일반) Y Y Y Y Y
(Length) Y Y Y Y Y
(Percentage) I I Y Y Y
inherit N N Y Y Y
position
(일반) Y Y Y Y Y
static Y Y Y Y Y
relative Y Y Y Y Y
absolute Y Y Y Y Y
fixed N N Y Y Y
inherit N N Y Y Y
quotes
(일반) N N I Y I
(String) N N I I Y
none N N N Y N
inherit N N Y Y Y
right
실전 웹 표준 가이드
- 259 -
(일반) I I Y Y Y
(Length) Y Y Y Y Y
(Percentage) Y Y Y Y Y
auto Y Y Y Y Y
inherit N N Y Y Y
table-layout
(일반) Y Y Y Y Y
auto Y Y Y Y Y
fixed Y Y Y Y Y
inherit N N Y Y Y
text-align
(일반) Y Y Y Y Y
left Y Y Y Y Y
right Y Y Y Y Y
center Y Y Y Y Y
justify Y Y Y Y Y
inherit N N Y Y Y
text-decoration
(일반) Y Y Y Y Y
none Y Y Y Y Y
underline Y Y Y Y Y
overline Y Y Y Y Y
line-through Y Y Y Y Y
blink N N Y Y Y
inherit N N Y Y Y
text-indent
(일반) Y Y Y Y Y
(Length) Y Y Y Y Y
(Percentage) Y Y Y Y Y
inherit N N Y Y Y
text-transform
(일반) Y Y Y Y Y
capitalize Y Y Y Y Y
uppercase Y Y Y Y Y
lowercase Y Y Y Y Y
none Y Y Y Y Y
inherit N N Y Y Y
top
(일반) Y Y Y Y Y
(Length) Y Y Y Y Y
(Percentage) Y Y Y Y Y
auto Y Y Y Y Y
inherit N N Y Y Y
unicode-bidi
(일반) Y Y Y Y Y
normal Y Y Y Y Y
실전 웹 표준 가이드
- 260 -
embed Y Y Y Y Y
bidi-override Y Y Y Y Y
inherit N N Y Y Y
vertical-align
(일반) Y Y Y Y Y
baseline I I Y Y Y
sub Y Y Y Y Y
super Y Y Y Y Y
top I I Y Y Y
text-top I I Y Y Y
middle I I Y Y Y
bottom I I Y Y Y
text-bottom I I Y Y Y
(Percentage) Y Y Y Y Y
(Length) Y Y Y Y Y
inherit N N Y Y Y
visibility
(일반) Y Y Y Y Y
visible Y Y Y Y Y
hidden Y Y Y Y Y
collapse N N I Y I
inherit N N Y Y Y
white-space
(일반) Y Y Y Y Y
normal Y Y Y Y Y
pre Y Y Y Y Y
nowrap Y Y Y Y Y
pre-wrap N N N N Y
pre-line N N N N N
inherit N N Y Y Y
width
(일반) I I Y Y Y
(Length) Y Y Y Y Y
(Percentage) Y Y Y Y Y
auto Y Y Y Y Y
inherit N N Y Y Y
word-spacing
(일반) Y Y Y Y Y
normal Y Y Y Y Y
(Length) Y Y Y Y Y
inherit N N Y Y Y
z-index
(일반) Y Y Y Y I
auto Y Y Y Y Y
(Integer) Y Y Y Y Y
inherit N N Y Y Y
실전 웹 표준 가이드
- 261 -
CSS 2.1 Print properties
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
orphans
(일반) N N N N I
(Integer) N N N N Y
inherit N N N N Y
page-break-after
(일반) Y Y Y Y Y
auto Y Y Y Y Y
always Y Y Y Y Y
avoid Y Y Y Y Y
left I I N N I
right I I N N I
inherit N N Y Y Y
page-break-before
(일반) Y Y Y Y Y
auto Y Y Y Y Y
always Y Y Y Y Y
avoid Y Y Y Y Y
left I I N N I
right I I N N I
inherit N N Y Y Y
page-break-inside
(일반) N N N N Y
avoid N N N N Y
auto N N N N Y
inherit N N N N Y
widows
(일반) N N N N I
(Integer) N N N N Y
inherit N N N N Y
CSS 2.1 Voice properties
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
azimuth
(일반) N N N N N
(Angle) N N N N N
left-side N N N N N
far-left N N N N N
left N N N N N
center-left N N N N N
실전 웹 표준 가이드
- 262 -
center N N N N N
center-right N N N N N
right N N N N N
far-right N N N N N
right-side N N N N N
behind N N N N N
leftwards N N N N N
rightwards N N N N N
inherit N N N N N
cue
(일반) N N N N Y
(cue-before) N N N N Y
(cue-after) N N N N Y
cue-after
(일반) N N N N Y
(URI) N N N N Y
none N N N N Y
inherit N N N N Y
cue-before
(일반) N N N N Y
(URI) N N N N Y
none N N N N Y
inherit N N N N Y
elevation
(일반) N N N N N
(Angle) N N N N N
below N N N N N
level N N N N N
above N N N N N
higher N N N N N
lower N N N N N
inherit N N N N N
pause
(일반) N N N N Y
(Time) N N N N Y
(Percentage) N N N N Y
inherit N N N N Y
pause-after
(일반) N N N N Y
(Time) N N N N Y
(Percentage) N N N N Y
inherit N N N N Y
pause-before
(일반) N N N N Y
(Time) N N N N Y
(Percentage) N N N N Y
실전 웹 표준 가이드
- 263 -
inherit N N N N Y
pitch
(일반) N N N N N
(Frequency) N N N N N
x-low N N N N N
low N N N N N
medium N N N N N
high N N N N N
x-high N N N N N
inherit N N N N N
pitch-range
(일반) N N N N N
(Number) N N N N N
inherit N N N N N
play-during
(일반) N N N N N
(URI) N N N N N
mix N N N N N
repeat N N N N N
auto N N N N N
none N N N N N
inherit N N N N N
richness
(일반) N N N N N
(Number) N N N N N
inherit N N N N N
speak
(일반) N N N N Y
normal N N N N Y
none N N N N Y
spell-out N N N N Y
inherit N N N N Y
speak-header
(일반) N N N N N
once N N N N N
always N N N N N
inherit N N N N N
speak-numeral
(일반) N N N N N
digits N N N N N
continuous N N N N N
inherit N N N N N
speak-punctuation
(일반) N N N N N
code N N N N N
none N N N N N
실전 웹 표준 가이드
- 264 -
inherit N N N N N
speech-rate
(일반) N N N N N
(Number) N N N N N
x-slow N N N N N
slow N N N N N
medium N N N N N
fast N N N N N
x-fast N N N N N
faster N N N N N
slower N N N N N
inherit N N N N N
stress
(일반) N N N N N
(Number) N N N N N
inherit N N N N N
voice-family
(일반) N N N N Y
(Specific voice) N N N N Y
male N N N N Y
female N N N N Y
child N N N N Y
inherit N N N N Y
volume
(일반) N N N N N
(Number) N N N N N
(Percentage) N N N N N
silent N N N N N
x-soft N N N N N
soft N N N N N
medium N N N N N
loud N N N N N
x-loud N N N N N
inherit N N N N N
CSS 2.1 Conformance
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
Conformance
Support a media type Y Y Y Y Y
Attempt to retrieve all style
sheets Y Y Y Y Y
Follow all specified grammar N N N Y Y
Assign elements all applicable
properties N N Y Y Y
Support alternate style sheets N N Y Y Y
실전 웹 표준 가이드
- 265 -
Allow disabling author style
sheet N N Y Y Y
Support user style sheets Y Y Y Y Y
CSS 3 Units
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
Appearance
(일반) I I I I I
icon I I I I I
window N N N N N
desktop N N N N N
workspace N N N N N
document N N N N N
tooltip N N N N N
dialog N N N N N
button N N N N N
push-button N N N N N
hyperlink N N N N N
radio-button N N N N N
checkbox N N N N N
menu-item N N N N N
tab N N N N N
menu I I I I I
menubar N N N N N
pull-down-menu N N N N N
pop-up-menu N N N N N
list-menu N N N N N
radio-group N N N N N
checkbox-group N N N N N
outline-tree N N N N N
range N N N N N
field N N N N N
combo-box N N N N N
signature N N N N N
password N N N N N
Color
rgba(<red>, <green>, <blue>,
<alpha>) N N N N N
transparent I I I I I
hsl(<hue>, <saturation>,
<lightness>) N N Y Y N
hsla(<hue>, <saturation>,
<lightness>, <alpha>) N N N N N
currentColor N N N Y N
flavor N N N N N
실전 웹 표준 가이드
- 266 -
aliceblue Y Y Y Y Y
antiquewhite Y Y Y Y Y
aquamarine Y Y Y Y Y
azure Y Y Y Y Y
beige Y Y Y Y Y
bisque Y Y Y Y Y
blanchdalmond Y Y Y Y Y
blueviolet Y Y Y Y Y
brown Y Y Y Y Y
burlywood Y Y Y Y Y
cadetblue Y Y Y Y Y
chartreuse Y Y Y Y Y
chocolate Y Y Y Y Y
cornflowerblue Y Y Y Y Y
cornsilk Y Y Y Y Y
crimson Y Y Y Y Y
cyan Y Y Y Y Y
darkblue Y Y Y Y Y
darkcyan Y Y Y Y Y
darkgoldenrod Y Y Y Y Y
darkgray Y Y Y Y Y
darkgreen Y Y Y Y Y
darkgrey N N Y Y Y
darkkhaki Y Y Y Y Y
darkmagenta Y Y Y Y Y
darkolivegreen Y Y Y Y Y
darkorange Y Y Y Y Y
darkorchid Y Y Y Y Y
darkred Y Y Y Y Y
darksalmon Y Y Y Y Y
darkseagreen Y Y Y Y Y
darkslateblue Y Y Y Y Y
darkslategray Y Y Y Y Y
darkslategrey N N Y Y Y
darkturquoise Y Y Y Y Y
darkviolet Y Y Y Y Y
deeppink Y Y Y Y Y
deepskyblue Y Y Y Y Y
dimgray Y Y Y Y Y
dimgrey N N Y Y Y
dodgerblue Y Y Y Y Y
firebrick Y Y Y Y Y
floralwhite Y Y Y Y Y
forestgreen Y Y Y Y Y
gainsboro Y Y Y Y Y
ghostwhite Y Y Y Y Y
gold Y Y Y Y Y
실전 웹 표준 가이드
- 267 -
goldenrod Y Y Y Y Y
greenyellow Y Y Y Y Y
grey N N Y Y Y
honeydew Y Y Y Y Y
hotpink Y Y Y Y Y
indianred Y Y Y Y Y
indigo Y Y Y Y Y
ivory Y Y Y Y Y
khaki Y Y Y Y Y
lavender Y Y Y Y Y
lavenderblush Y Y Y Y Y
lawngreen Y Y Y Y Y
lemonchiffon Y Y Y Y Y
lightblue Y Y Y Y Y
lightcoral Y Y Y Y Y
lightcyan Y Y Y Y Y
lightgoldenrodyellow Y Y Y Y Y
lightgray Y Y Y Y Y
lightgreen Y Y Y Y Y
lightgrey N N Y Y Y
lightpink Y Y Y Y Y
lightsalmon Y Y Y Y Y
lightseagreen Y Y Y Y Y
lightskyblue Y Y Y Y Y
lightslategray Y Y Y Y Y
lightslategrey N N Y Y Y
lightsteelblue Y Y Y Y Y
lightyellow Y Y Y Y Y
limegreen Y Y Y Y Y
linen Y Y Y Y Y
magenta Y Y Y Y Y
mediumaquamarine Y Y Y Y Y
mediumblue Y Y Y Y Y
mediumorchid Y Y Y Y Y
mediumpurple Y Y Y Y Y
mediumseagreen Y Y Y Y Y
mediumslateblue Y Y Y Y Y
mediumspringgreen Y Y Y Y Y
mediumturquoise Y Y Y Y Y
mediumvioletred Y Y Y Y Y
midnightblue Y Y Y Y Y
mintcream Y Y Y Y Y
mistyrose Y Y Y Y Y
moccasin Y Y Y Y Y
navajowhite Y Y Y Y Y
oldlace Y Y Y Y Y
olivedrab Y Y Y Y Y
실전 웹 표준 가이드
- 268 -
orangered Y Y Y Y Y
orchid Y Y Y Y Y
palegoldenrod Y Y Y Y Y
palegreen Y Y Y Y Y
paleturquoise Y Y Y Y Y
palevioletred Y Y Y Y Y
papayawhip Y Y Y Y Y
peachpuff Y Y Y Y Y
peru Y Y Y Y Y
pink Y Y Y Y Y
plum Y Y Y Y Y
powderblue Y Y Y Y Y
rosybrown Y Y Y Y Y
royalblue Y Y Y Y Y
saddlebrown Y Y Y Y Y
salmon Y Y Y Y Y
sandybrown Y Y Y Y Y
seagreen Y Y Y Y Y
seashell Y Y Y Y Y
sienna Y Y Y Y Y
skyblue Y Y Y Y Y
slateblue Y Y Y Y Y
slategray Y Y Y Y Y
slategrey N N Y Y Y
snow Y Y Y Y Y
springgreen Y Y Y Y Y
steelblue Y Y Y Y Y
tan Y Y Y Y Y
thistle Y Y Y Y Y
tomato Y Y Y Y Y
turquoise Y Y Y Y Y
violet Y Y Y Y Y
wheat Y Y Y Y Y
whitesmoke Y Y Y Y Y
yellowgreen Y Y Y Y Y
Counter
pages N N N N N
ID
(일반) N N N N N
Target name
(일반) N N N N N
CSS 3 At-rules
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
@color-profile
실전 웹 표준 가이드
- 269 -
(일반) N N N N N
name N N N N N
src N N N N N
rendering-intent N N N N N
@media
width N N N N I
min-width N N N N I
max-width N N N N I
height N N N N I
min-height N N N N I
max-height N N N N I
device-width N N N N I
min-device-width N N N N I
max-device-width N N N N I
device-height N N N N I
min-device-height N N N N I
max-device-height N N N N I
device-aspect-ratio N N N N Y
min-device-aspect-ratio N N N N Y
max-device-aspect-ratio N N N N Y
color N N N N N
min-color N N N N N
max-color N N N N N
color-index N N N N N
min-color-index N N N N N
max-color-index N N N N N
monochrome N N N N N
min-monochrome N N N N N
max-monochrome N N N N N
resolution N N N N N
min-resolution N N N N N
max-resolution N N N N N
scan N N N N N
grid N N N N N
@page
@top N N N N N
@top-left-corner N N N N N
@top-left N N N N N
@top-center N N N N N
@top-right N N N N N
@top-right-corner N N N N N
@bottom N N N N N
@bottom-left-corner N N N N N
@bottom-left N N N N N
@bottom-center N N N N N
@bottom-right N N N N N
@bottom-right-corner N N N N N
실전 웹 표준 가이드
- 270 -
@left-top N N N N N
@left-middle N N N N N
@left-bottom N N N N N
@right-top N N N N N
@right-middle N N N N N
@right-bottom N N N N N
@float-area N N N N N
(Page name) N N N N N
CSS 3 Selectors
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
E ~ F
(일반) N N Y Y N
[attr^="value"]
(일반) N N Y Y N
[attr$="value"]
(일반) N N Y Y N
[attr*="value"]
(일반) N N Y Y N
CSS 3 Pseudo-classes
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
:root
(일반) N N Y Y N
:nth-child(N)
(일반) N N N N N
b N N N N N
an N N N N N
an+b N N N N N
odd N N N N N
even N N N N N
:nth-last-child(N)
(일반) N N N N N
b N N N N N
an N N N N N
an+b N N N N N
odd N N N N N
even N N N N N
:nth-of-type(N)
(일반) N N N N N
b N N N N N
an N N N N N
실전 웹 표준 가이드
- 271 -
an+b N N N N N
odd N N N N N
even N N N N N
:nth-last-of-type(N)
(일반) N N N N N
b N N N N N
an N N N N N
an+b N N N N N
odd N N N N N
even N N N N N
:last-child
(일반) N N Y Y N
:first-of-type
(일반) N N N N N
:last-of-type
(일반) N N N N N
:only-child
(일반) N N N Y N
:only-of-type
(일반) N N N N N
:empty
(일반) N N Y Y N
:target
(일반) N N Y Y N
:enabled
(일반) N N N Y N
:disabled
(일반) N N N Y N
:checked
(일반) N N Y Y N
:indeterminate
(일반) N N N N N
:contains(C)
(일반) N N N N N
:not(S)
(일반) N N Y Y N
:default
(일반) N N N N N
:valid
(일반) N N N Y N
:invalid
(일반) N N N Y N
:in-range
(일반) N N N Y N
:out-of-range
(일반) N N N Y N
실전 웹 표준 가이드
- 272 -
:required
(일반) N N N N N
:optional
(일반) N N N N N
:read-only
(일반) N N N N N
:read-write
(일반) N N N N N
CSS 3 Pseudo-elements
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
::selection
(일반) N N N N N
::value
(일반) N N N N N
::choices
(일반) N N N N N
::repeat-item
(일반) N N N N N
::repeat-index
(일반) N N N N N
CSS 3 Basic properties
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
appearance
(일반) N N N N N
(Appearance) N N N N N
normal N N N N N
inherit N N N N N
box-sizing
(일반) N N N N Y
content-box N N N N Y
border-box N N N N Y
inherit N N N N Y
color
attr(<attr>, color) N N N N N
color-profile
(일반) N N N N N
(Profile name) N N N N N
(URI) N N N N N
auto N N N N N
sRGB N N N N N
실전 웹 표준 가이드
- 273 -
inherit N N N N N
content
(Appearance) N N N N N
icon N N N N N
cursor
(일반) Y Y I Y I
(Number) N N N Y N
none N N N N N
context-menu N N N Y N
cell N N N Y N
vertical-text Y Y N Y N
alias N N N Y N
copy N N N Y N
no-drop Y Y N Y N
not-allowed Y Y N Y N
ew-resize N N N Y N
ns-resize N N N Y N
nesw-resize N N N Y N
nwse-resize N N N Y N
col-resize Y Y N Y N
row-resize Y Y N Y N
all-scroll Y Y N Y N
display
ruby N N N N N
ruby-base N N N N N
ruby-base-container N N N N N
ruby-text N N N N N
ruby-text-container N N N N N
font
(Appearance) I I I I I
icon
(일반) N N N N N
(URI) N N N N N
auto N N N N N
inherit N N N N N
nav-down
(일반) N N N N N
(ID) N N N N N
current N N N N N
root N N N N N
(Target name) N N N N N
inherit N N N N N
nav-index
(일반) N N N N N
(Number) N N N N N
auto N N N N N
실전 웹 표준 가이드
- 274 -
inherit N N N N N
nav-left
(일반) N N N N N
(ID) N N N N N
current N N N N N
root N N N N N
(Target name) N N N N N
inherit N N N N N
nav-right
(일반) N N N N N
(ID) N N N N N
current N N N N N
root N N N N N
(Target name) N N N N N
inherit N N N N N
nav-up
(일반) N N N N N
(ID) N N N N N
current N N N N N
root N N N N N
(Target name) N N N N N
inherit N N N N N
opacity
(일반) N N Y Y N
(Number) N N Y Y N
outline-offset
(일반) N N N Y N
(Length) N N N Y N
inherit N N N Y N
rendering-intent
(일반) N N N N N
auto N N N N N
perceptual N N N N N
relative-colorimetric N N N N N
saturation N N N N N
absolute-colorimetric N N N N N
inherit N N N N N
resize
(일반) N N N N N
none N N N N N
horizontal N N N N N
vertical N N N N N
inherit N N N N N
ruby-align
(일반) N N N N N
auto N N N N N
실전 웹 표준 가이드
- 275 -
start N N N N N
left N N N N N
center N N N N N
end N N N N N
right N N N N N
distribute-letter N N N N N
distribute-space N N N N N
line-edge N N N N N
ruby-overhang
(일반) N N N N N
auto N N N N N
start N N N N N
end N N N N N
none N N N N N
ruby-position
(일반) N N N N N
before N N N N N
after N N N N N
right N N N N N
ruby-span
(일반) N N N N N
attr(<attr>) N N N N N
none N N N N N
CSS 3 Print properties
기능 목록 IE 5.0 IE 6.0 Fx 1.0 Fx 1.5 Op 8.5
image-orientation
(일반) N N N N N
(Angle) N N N N N
auto N N N N N
page
(일반) N N N N N
(Page name) N N N N N
auto N N N N N
page-policy
(일반) N N N N N
start N N N N N
first N N N N N
last N N N N N
size (@page)
(일반) N N N N N
(Length) N N N N N
auto N N N N N
landscape N N N N N
실전 웹 표준 가이드
- 276 -
portrait N N N N N
A5 N N N N N
A4 N N N N N
A3 N N N N N
B5 N N N N N
B4 N N N N N
letter N N N N N
legal N N N N N
ledger N N N N N
실전 웹 표준 가이드
- 277 -
표준 DOM 2/3 브라우저 호환 차트
DOM Level 3 Core
기능 목록 IE5 IE6 Fx 1.0 Op 8.5
Interface DOMStringList
(일반) N N N Y
length N N N Y
contains() N N N Y
item() N N N Y
Interface NameList
(일반) N N N N
length N N N N
contains() N N N N
containsNS() N N N N
getName() N N N N
getNamespaceURI() N N N N
Interface DOMImplementationList
(일반) N N N N
length N N N N
item() N N N N
Interface DOMImplementationSource
(일반) N N N N
getDOMImplementation() N N N N
getDOMImplementationList() N N N N
Interface DOMImplementation
(일반) Y Y Y Y
createDocument() N N Y
createDocumentType() N N Y Y
get 기능 목록() N N N N
has 기능 목록() Y Y Y Y
Interface DocumentFragment
(일반) Y Y Y Y
Interface Document
(일반) Y Y Y Y
doctype N N Y Y
documentElement Y Y Y Y
documentURI N N Y N
domConfig N N N N
implementation Y Y Y Y
inputEncoding N N N N
strictErrorChecking N N Y N
xmlEncoding N N N
실전 웹 표준 가이드
- 278 -
xmlStandalone N N N
xmlVersion N N N
adoptNode() N N Y N
createAttribute() Y Y Y Y
createAttributeNS() N N Y Y
createCDATASection() N N Y Y
createComment() Y Y Y Y
createDocumentFragment() Y Y Y Y
createElement() Y Y Y Y
createElementNS() N N Y Y
createEntityReference() N N N N
createProcessingInstruction() N N N N
createTextNode() Y Y Y Y
getElementById() I I Y Y
getElementsByTagName() Y Y Y Y
getElementsByTagNameNS() N N Y I
importNode() N N Y Y
normalizeDocument() N N Y N
renameNode() N N Y N
Interface Node
(일반) Y Y Y Y
attributes Y Y Y Y
baseURI N N Y N
childNodes Y Y Y Y
firstChild Y Y Y Y
lastChild Y Y Y Y
localName N N Y Y
namespaceURI N N Y
nextSibling Y Y Y Y
nodeName Y Y Y Y
nodeType Y Y Y Y
nodeValue Y Y Y Y
ownerDocument Y Y Y Y
parentNode Y Y Y Y
prefix N N Y Y
previousSibling Y Y Y Y
textContent N N Y N
appendChild() Y Y Y Y
cloneNode() Y Y Y Y
compareDocumentPosition() N N Y N
get 기능 목록() N N Y Y
getUserData() N N N N
hasAttributes() N N Y Y
hasChildNodes() Y Y Y Y
insertBefore() Y Y Y Y
isDefaultNamespace() N N Y N
isEqualNode() N N N N
실전 웹 표준 가이드
- 279 -
isSameNode() N N Y N
isSupported() N N Y Y
lookupNamespaceURI() N N Y N
lookupPrefix() N N Y N
normalize() Y Y
removeChild() Y Y Y Y
replaceChild() Y Y Y Y
setUserData() N N N N
Interface NodeList
(일반) Y Y Y Y
length Y Y Y Y
item() Y Y Y Y
Interface NamedNodeMap
(일반) Y Y Y Y
length Y Y
getNamedItem() Y Y Y Y
getNamedItemNS() N N Y Y
item() Y Y Y Y
removeNamedItem() Y Y Y Y
removeNamedItemNS() N N Y Y
setNamedItem() Y Y Y Y
setNamedItemNS() N N Y Y
Interface CharacterData
data Y Y Y Y
length Y Y Y Y
appendData() Y Y Y Y
deleteData() Y Y Y Y
insertData() Y Y Y Y
replaceData() Y Y Y Y
substringData() Y Y Y Y
Interface Attr
(일반) Y Y Y Y
isId N N N N
name Y Y Y Y
ownerElement N N Y Y
schemaTypeInfo N N N N
specified
value Y Y Y Y
Interface Element
(일반) Y Y Y Y
schemaTypeInfo N N N N
tagName Y Y Y Y
getAttribute() Y Y
getAttributeNS() N N I Y
getAttributeNode() Y Y Y Y
getAttributeNodeNS() N N I Y
실전 웹 표준 가이드
- 280 -
getElementsByTagName() Y Y Y Y
getElementsByTagNameNS() N N Y I
hasAttribute() N N Y Y
hasAttributeNS() N N Y Y
removeAttribute() Y Y
removeAttributeNS() N N Y Y
removeAttributeNode() Y Y
setAttribute() Y Y
setAttributeNS() N N Y Y
setAttributeNode() Y Y Y Y
setAttributeNodeNS() N N Y Y
setIdAttribute() N N N N
setIdAttributeNS() N N N N
setIdAttributeNode() N N N N
Interface Text
(일반) Y Y Y Y
isElementContentWhitespace N N N N
wholeText N N N N
replaceWholeText() N N N N
splitText() Y Y Y Y
Interface Comment
(일반) Y Y Y Y
Interface TypeInfo
(일반) N N N N
typeName N N N N
typeNamespace N N N N
isDerivedFrom() N N N N
Interface UserDataHandler
(일반) N N N N
handle() N N N N
Interface DOMError
(일반) N N N N
location N N N N
message N N N N
relatedData N N N N
relatedException N N N N
severity N N N N
type N N N N
Interface DOMErrorHandler
(일반) N N N N
handleError() N N N N
Interface DOMLocator
(일반) N N N N
byteOffset N N N N
columnNumber N N N N
lineNumber N N N N
실전 웹 표준 가이드
- 281 -
relatedNode N N N N
uri N N N N
utf16Offset N N N N
Interface DOMConfiguration
(일반) N N N Y
parameterNames N N N Y
canSetParameter() N N N I
getParameter() N N N Y
setParameter() N N N N
Interface CDATASection
(일반) N N Y Y
Interface DocumentType
(일반) N N Y Y
entities N N Y
internalSubset N N Y N
name N N Y Y
notations N N I Y
publicId N N Y Y
systemId N N Y Y
Interface Notation
(일반) N N N N
publicId N N N N
systemId N N N N
Interface Entity
(일반) N N N N
inputEncoding N N N N
notationName N N N N
publicId N N N N
systemId N N N N
xmlEncoding N N N N
xmlVersion N N N N
Interface EntityReference
(일반) N N N N
Interface ProcessingInstruction
(일반) N N N N
data N N N N
target N N N N
DOM Level 2 Events
기능 목록 IE5 IE 6.0 Fx 1.0 Op 8.5
Interface EventTarget
(일반) N N Y Y
addEventListener() N N Y Y
dispatchEvent() N N Y
실전 웹 표준 가이드
- 282 -
removeEventListener() N N Y Y
Interface EventListener
(일반) Y Y Y Y
handleEvent() N N N N
Interface Event
(일반) Y Y Y Y
bubbles N N Y Y
cancelable N N Y Y
currentTarget N N Y Y
eventPhase N N Y Y
target N N Y Y
timeStamp N N Y Y
type Y Y Y Y
initEvent() N N Y Y
preventDefault() N N Y Y
stopPropagation() N N Y Y
Interface DocumentEvent
(일반) N N Y Y
createEvent N N Y Y
Interface UIEvent
(일반) N N Y Y
detail N N
view N N Y Y
initUIEvent() N N Y Y
Interface MouseEvent
(일반) Y Y Y Y
altKey Y Y Y Y
button Y Y
clientX Y Y Y Y
clientY Y Y Y Y
ctrlKey Y Y Y Y
metaKey N N Y Y
relatedTarget N N Y Y
screenX Y Y Y Y
screenY Y Y Y Y
shiftKey Y Y Y Y
initMouseEvent() N N Y Y
Type click Y Y Y Y
Type mousedown Y Y Y Y
Type mouseup Y Y Y Y
Type mouseover Y Y Y Y
Type mousemove Y Y Y Y
Type mouseout Y Y Y Y
Interface MutationEvent
(일반) N N Y Y
실전 웹 표준 가이드
- 283 -
attrChange N N Y Y
attrName N N Y Y
newValue N N Y Y
prevValue N N Y Y
relatedNode N N Y Y
initMutationEvent() N N Y Y
HTML event types
Type load Y Y Y Y
Type unload Y Y Y
Type abort N N Y Y
Type error N N Y N
Type select Y Y Y Y
Type change Y Y Y Y
Type submit Y Y Y Y
Type reset Y Y Y Y
Type focus Y Y Y Y
Type blur Y Y Y Y
Type resize Y Y Y Y
Type scroll Y Y Y Y
DOM Level 2 HTML
기능 목록 IE5 IE 6.0 Fx 1.0 Op 8.5
Interface HTMLCollection
(일반) Y Y Y Y
length Y Y Y Y
item() Y Y Y Y
namedItem() Y Y Y Y
Interface HTMLOptionsCollection
(일반) Y Y Y Y
length Y Y Y Y
item() Y Y Y N
namedItem() N N Y N
Interface HTMLDocument
(일반) Y Y Y Y
URL Y Y Y Y
anchors Y Y Y Y
applets Y Y Y Y
body Y Y Y Y
cookie Y Y Y Y
domain Y Y Y Y
forms Y Y Y Y
images Y Y Y Y
links Y Y Y Y
referrer Y Y Y Y
실전 웹 표준 가이드
- 284 -
title Y Y Y Y
close() Y Y
getElementsByName() Y
open() Y Y
write() Y Y
writeln() Y Y
Interface HTMLElement
(일반) Y Y Y Y
className Y Y Y Y
dir Y Y Y Y
id Y Y Y Y
lang Y Y Y Y
title Y Y Y Y
Interface HTMLHtmlElement
(일반) Y Y Y Y
version Y Y Y Y
Interface HTMLHeadElement
(일반) Y Y Y Y
profile I I Y Y
Interface HTMLLinkElement
(일반) Y Y Y Y
charset Y Y Y Y
disabled I I Y Y
href I I Y Y
hreflang Y Y Y Y
media Y Y Y Y
rel Y Y Y Y
rev Y Y Y Y
target Y Y Y Y
type Y Y Y Y
Interface HTMLTitleElement
(일반) Y Y Y Y
text Y Y Y Y
Interface HTMLMetaElement
(일반) Y Y Y Y
content Y Y Y Y
httpEquiv Y Y Y Y
name Y Y Y Y
scheme Y Y Y Y
Interface HTMLBaseElement
(일반) Y Y Y Y
href I I Y Y
target Y Y Y Y
Interface HTMLIsIndexElement
(일반) N N Y Y
form N N Y Y
실전 웹 표준 가이드
- 285 -
prompt N N Y Y
Interface HTMLStyleElement
(일반) Y Y Y Y
disabled Y Y Y
media Y Y Y
type Y Y Y Y
Interface HTMLBodyElement
(일반) Y Y Y Y
aLink Y Y Y Y
background I I Y Y
bgColor Y Y Y Y
link Y Y Y Y
text Y Y Y Y
vLink Y Y Y Y
Interface HTMLFormElement
(일반) Y Y Y Y
acceptCharset Y Y Y Y
action I I I Y
elements Y Y Y Y
enctype Y Y Y Y
length Y Y Y Y
method Y Y Y Y
name Y Y Y Y
target Y Y Y Y
reset() Y Y Y Y
submit() Y Y Y Y
Interface HTMLSelectElement
(일반) Y Y Y Y
disabled Y Y Y Y
form Y Y Y Y
length Y Y Y Y
multiple Y Y Y Y
name Y Y Y Y
options Y Y Y Y
selectedIndex Y Y Y Y
size Y Y Y Y
tabIndex Y Y Y Y
type Y Y Y Y
value Y Y Y Y
add() Y Y
blur() Y Y Y Y
focus() Y Y Y Y
remove() Y Y Y Y
Interface HTMLOptGroupElement
(일반) Y Y Y Y
disabled Y Y Y Y
실전 웹 표준 가이드
- 286 -
label Y Y Y Y
Interface HTMLOptionElement
(일반) Y Y Y Y
defaultSelected Y Y Y Y
disabled Y Y Y Y
form Y Y Y Y
index Y Y Y Y
label Y Y Y Y
selected Y Y Y Y
text Y Y Y Y
value Y Y Y Y
Interface HTMLInputElement
(일반) Y Y Y Y
accept Y Y Y Y
accessKey Y Y Y Y
align Y Y
alt Y Y Y Y
checked Y Y Y Y
defaultChecked Y Y Y Y
defaultValue Y Y Y Y
disabled Y Y Y Y
form Y Y Y Y
maxLength Y Y Y Y
name Y Y Y Y
readOnly Y Y Y Y
size Y Y Y Y
src Y Y I Y
tabIndex Y Y Y Y
type Y Y Y Y
useMap I I I Y
value Y Y Y Y
blur() Y Y Y Y
click() I I Y Y
focus() Y Y Y Y
select() Y Y Y Y
Interface HTMLTextAreaElement
(일반) Y Y Y Y
accessKey Y Y Y Y
cols Y Y Y Y
defaultValue Y Y Y Y
disabled Y Y Y Y
form Y Y Y Y
name Y Y Y Y
readOnly Y Y Y Y
rows Y Y Y Y
tabIndex Y Y Y Y
실전 웹 표준 가이드
- 287 -
type Y Y Y Y
value Y Y Y Y
blur() Y Y Y Y
focus() Y Y Y Y
select() Y Y Y Y
Interface HTMLButtonElement
(일반) I I Y Y
accessKey Y Y Y Y
disabled Y Y Y Y
form Y Y Y Y
name Y Y Y Y
tabIndex Y Y Y Y
type Y Y Y Y
value Y Y Y Y
Interface HTMLLabelElement
(일반) Y Y Y Y
accessKey Y Y Y Y
form Y Y Y Y
htmlFor Y Y Y Y
Interface HTMLFieldSetElement
(일반) Y Y Y Y
form Y Y Y Y
Interface HTMLLegendElement
(일반) Y Y Y Y
accessKey Y Y Y Y
align Y Y Y Y
form N N Y Y
Interface HTMLUListElement
(일반) Y Y Y Y
compact Y Y Y Y
type Y Y Y
Interface HTMLOListElement
(일반) Y Y Y Y
compact Y Y Y Y
start Y Y Y Y
type Y Y Y Y
Interface HTMLDListElement
(일반) Y Y Y Y
compact Y Y Y Y
Interface HTMLDirectoryElement
(일반) Y Y Y Y
compact Y Y Y Y
Interface HTMLMenuElement
(일반) Y Y Y Y
compact Y Y Y Y
Interface HTMLLIElement
실전 웹 표준 가이드
- 288 -
(일반) Y Y Y Y
type Y Y Y Y
value Y Y Y Y
Interface HTMLDivElement
(일반) Y Y Y Y
align Y Y Y Y
Interface HTMLParagraphElement
(일반) Y Y Y Y
align Y Y Y Y
Interface HTMLHeadingElement
(일반) Y Y Y Y
align Y Y Y Y
Interface HTMLQuoteElement
(일반) Y Y Y Y
cite I I Y Y
Interface HTMLPreElement
(일반) Y Y Y Y
width Y Y Y Y
Interface HTMLBRElement
(일반) Y Y Y Y
clear Y Y Y Y
Interface HTMLBaseFontElement
(일반) Y Y Y Y
color Y Y Y Y
face Y Y Y Y
size Y Y Y Y
Interface HTMLFontElement
(일반) Y Y Y Y
color Y Y Y Y
face Y Y Y Y
size Y Y Y Y
Interface HTMLHRElement
(일반) Y Y Y Y
align Y Y Y Y
noShade Y Y Y Y
size Y Y Y Y
width Y Y Y Y
Interface HTMLModElement
(일반) Y Y Y Y
cite I I I Y
dateTime Y Y Y Y
Interface HTMLAnchorElement
(일반) Y Y Y Y
accessKey Y Y Y Y
charset Y Y Y Y
coords Y Y Y Y
실전 웹 표준 가이드
- 289 -
href Y Y Y Y
hreflang Y Y Y Y
name Y Y Y Y
rel Y Y Y Y
rev Y Y Y Y
shape I I I Y
tabIndex Y Y Y Y
target Y Y Y Y
type Y Y Y Y
blur() Y Y Y Y
focus() Y Y Y Y
Interface HTMLImageElement
(일반) Y Y Y Y
align Y Y Y Y
alt Y Y Y Y
border Y Y Y Y
height Y Y Y Y
hspace Y Y Y Y
isMap Y Y Y Y
longDesc I I Y Y
name Y Y Y Y
src Y Y Y Y
useMap I I I Y
vspace Y Y Y Y
width Y Y Y Y
Interface HTMLObjectElement
(일반) Y Y Y Y
align Y Y Y Y
archive Y Y Y Y
border Y Y Y Y
code Y Y Y Y
codeBase I I Y Y
codeType Y Y Y Y
contentDocument N N Y Y
data I I Y I
declare Y Y Y Y
form Y Y Y Y
height Y Y Y Y
hspace Y Y Y Y
name Y Y Y Y
standby Y Y Y Y
tabIndex Y Y Y Y
type Y Y Y Y
useMap I I I Y
vspace Y Y Y Y
width Y Y Y Y
Interface HTMLParamElement
실전 웹 표준 가이드
- 290 -
(일반) Y Y Y Y
name Y Y Y Y
type Y Y Y Y
value Y Y Y Y
valueType N N Y Y
Interface HTMLAppletElement
(일반) Y Y Y Y
align Y Y Y Y
alt Y Y Y Y
archive Y Y Y Y
code Y Y Y Y
codeBase I I Y Y
height Y Y Y Y
hspace Y Y Y Y
name Y Y Y Y
object I I Y Y
vspace Y Y Y Y
width Y Y Y Y
Interface HTMLMapElement
(일반) Y Y Y Y
areas Y Y Y Y
name Y Y Y Y
Interface HTMLAreaElement
(일반) Y Y Y Y
accessKey Y Y Y Y
alt Y Y Y Y
coords Y Y Y Y
href Y Y Y Y
noHref I I Y Y
shape Y Y Y Y
tabIndex Y Y Y Y
target Y Y Y Y
Interface HTMLScriptElement
(일반) Y Y Y Y
charset Y Y Y Y
defer Y Y Y Y
event Y Y Y Y
htmlFor Y Y Y Y
src I I Y Y
text Y Y Y I
type Y Y Y Y
Interface HTMLTableElement
(일반) Y Y Y Y
align Y Y Y Y
bgColor Y Y Y Y
border Y Y Y Y
실전 웹 표준 가이드
- 291 -
caption Y Y Y Y
cellPadding Y Y Y Y
cellSpacing Y Y Y Y
frame Y Y Y Y
rows Y Y Y Y
rules Y Y Y Y
summary Y Y Y Y
tBodies Y Y Y Y
tFoot Y Y Y Y
tHead Y Y Y Y
width Y Y Y Y
createCaption() Y Y Y Y
createTFoot() Y Y Y Y
createTHead() Y Y Y Y
deleteCaption() Y Y Y Y
deleteRow() Y Y Y Y
deleteTFoot() Y Y Y Y
deleteTHead() Y Y Y Y
insertRow() Y Y Y Y
Interface HTMLTableCaptionElement
(일반) Y Y Y Y
align Y Y Y Y
Interface HTMLTableColElement
(일반) Y Y Y Y
align Y Y Y Y
ch I I Y Y
chOff I I Y Y
span Y Y Y Y
vAlign Y Y Y Y
width Y Y Y Y
Interface HTMLTableSectionElement
(일반) Y Y Y Y
align Y Y Y Y
ch I I Y Y
chOff I I Y Y
rows Y Y Y Y
vAlign Y Y Y Y
deleteRow() Y Y Y Y
insertRow() Y Y Y Y
Interface HTMLTableRowElement
(일반) Y Y Y Y
align Y Y Y Y
bgColor Y Y Y Y
cells Y Y Y Y
ch I I Y Y
chOff I I Y Y
실전 웹 표준 가이드
- 292 -
rowIndex Y Y Y Y
sectionRowIndex Y Y Y Y
vAlign Y Y Y Y
deleteCell() Y Y Y Y
insertCell() Y Y Y Y
Interface HTMLTableCellElement
(일반) Y Y Y Y
abbr Y Y Y Y
align Y Y Y Y
axis Y Y Y Y
bgColor Y Y Y Y
cellIndex Y Y Y Y
ch I I Y Y
chOff I I Y Y
colSpan Y Y Y Y
headers Y Y Y Y
height Y Y Y Y
noWrap Y Y Y Y
rowSpan Y Y
scope Y Y Y Y
vAlign Y Y Y Y
width Y Y Y Y
Interface HTMLFrameSetElement
(일반) Y Y Y Y
cols Y Y Y Y
rows Y Y Y Y
Interface HTMLFrameElement
(일반) Y Y Y Y
contentDocument N N Y Y
frameBorder Y Y Y Y
longDesc I I Y Y
marginHeight Y Y Y Y
marginWidth Y Y Y Y
name Y Y Y Y
noResize Y Y Y Y
scrolling Y Y Y Y
src I I Y Y
Interface HTMLIFrameElement
(일반) Y Y Y Y
align Y Y Y Y
contentDocument N N I I
frameBorder Y Y Y Y
height Y Y Y Y
longDesc I I Y Y
marginHeight Y Y Y Y
marginWidth Y Y Y Y
실전 웹 표준 가이드
- 293 -
name Y Y Y Y
scrolling Y Y Y Y
src I I Y Y
width Y Y Y Y
DOM Level 3 Load and Save
기능 목록 IE5 IE 6.0 Fx 1.0 Op 8.5
Interface DOMImplementationLS
(일반) N N N Y
createLSInput() N N N Y
createLSOutput() N N N Y
createLSParser() N N N Y
createLSSerializer() N N N Y
Interface LSParser
(일반) N N N Y
async N N N Y
busy N N N Y
domConfig N N N I
filter N N N Y
abort() N N N Y
parse() N N N Y
parseURI() N N N Y
parseWithContext() N N N Y
Interface LSInput
(일반) N N N Y
baseURI N N N Y
byteStream N N N Y
certifiedText N N N Y
characterStream N N N Y
encoding N N N Y
publicId N N N Y
stringData N N N Y
systemId N N N Y
Interface LSResourceResolver
(일반) N N N N
resolveResource() N N N N
Interface LSParserFilter
(일반) N N N Y
whatToShow N N N N
acceptNode() N N N N
startElement() N N N N
Interface LSProgressEvent
(일반) N N N N
input N N N N
실전 웹 표준 가이드
- 294 -
position N N N N
totalsize N N N N
Interface LSLoadEvent
(일반) N N N N
input N N N N
newDocument N N N N
Interface LSSerializer
(일반) N N N Y
domConfig N N N I
filter N N N Y
newLine N N N Y
write() N N N Y
writeToString() N N N Y
writeToURI() N N N Y
Interface LSOutput
(일반) N N N Y
byteStream N N N Y
characterStream N N N Y
systemId N N N Y
Interface LSSerializerFilter
(일반) N N N Y
whatToShow N N N N
DOM Level 2 Style
기능 목록 IE5 IE 6.0 Fx 1.0 Op 8.5
Interface StyleSheet
(일반) Y Y Y N
disabled Y Y Y N
href I I Y N
media I I Y N
ownerNode N N Y N
parentStyleSheet Y Y Y N
title Y Y Y N
type Y Y Y N
Interface StyleSheetList
(일반) Y Y Y N
length Y Y Y N
item() Y Y Y N
Interface MediaList
(일반) N N Y N
length N N Y N
mediaText N N Y N
appendMedium() N N Y N
deleteMedium() N N Y N
실전 웹 표준 가이드
- 295 -
item() N N Y N
Interface LinkStyle
(일반) N N Y N
sheet N N Y N
Interface DocumentStyle
(일반) Y Y Y N
styleSheets Y Y Y N
Interface CSSStyleSheet
(일반) N N Y N
cssRules N N I N
ownerRule N N Y N
deleteRule() N N Y N
insertRule() N N Y N
Interface CSSRuleList
(일반) N N Y N
length N N Y N
item() N N Y N
Interface CSSRule
(일반) N N Y N
cssText N N Y N
parentRule N N Y N
parentStyleSheet N N Y N
type N N Y N
Interface CSSStyleRule
(일반) N N Y N
selectorText N N Y N
style N N Y N
Interface CSSMediaRule
(일반) N N Y N
cssRules N N Y N
media N N Y N
deleteRule() N N Y N
insertRule() N N Y N
Interface CSSFontFaceRule
(일반) N N N N
style N N N N
Interface CSSPageRule
(일반) N N N N
selectorText N N N N
style N N N N
Interface CSSImportRule
(일반) N N Y N
href N N I N
media N N Y N
styleSheet N N Y N
Interface CSSCharsetRule
실전 웹 표준 가이드
- 296 -
(일반) N N Y N
encoding N N Y N
Interface CSSUnknownRule
(일반) N N N N
Interface CSSStyleDeclaration
(일반) Y Y Y Y
cssText Y Y Y N
length N N Y Y
parentRule N N Y N
getPropertyCSSValue() N N I N
getPropertyPriority() N N Y N
getPropertyValue() N N Y Y
item() N N Y Y
removeProperty() N N Y Y
setProperty() N N Y Y
Interface CSSValue
(일반) N N N N
cssText N N N N
cssValueType N N N N
Interface CSSPrimitiveValue
(일반) N N N N
primitiveType N N N N
getCounterValue() N N N N
getFloatValue() N N N N
getRGBColorValue() N N N N
getRectValue() N N N N
getStringValue() N N N N
setFloatValue() N N N N
setStringValue() N N N N
Interface CSSValueList
(일반) N N N N
length N N N N
item() N N N N
Interface RGBColor
(일반) N N N N
blue N N N N
green N N N N
red N N N N
Interface Rect
(일반) N N N N
bottom N N N N
left N N N N
right N N N N
top N N N N
Interface Counter
(일반) N N N N
실전 웹 표준 가이드
- 297 -
identifier N N N N
listStyle N N N N
separator N N N N
Interface ViewCSS
(일반) N N Y Y
getComputedStyle() N N
Interface DocumentCSS
(일반) N N N N
getOverrideStyle() N N N N
Interface DOMImplementationCSS
(일반) N N N N
createCSSStyleSheet() N N N N
Interface ElementCSSInlineStyle
(일반) Y Y Y Y
style Y Y Y Y
Interface CSS2Properties
(일반) Y Y Y Y
azimuth N N Y N
background Y Y Y Y
backgroundAttachment Y Y Y Y
backgroundColor Y Y Y Y
backgroundImage Y Y Y Y
backgroundPosition Y Y Y Y
backgroundRepeat Y Y Y Y
border Y Y Y Y
borderBottom Y Y Y Y
borderBottomColor Y Y Y Y
borderBottomStyle Y Y Y Y
borderBottomWidth Y Y Y Y
borderCollapse Y Y Y Y
borderColor Y Y Y Y
borderLeft Y Y Y Y
borderLeftColor Y Y Y Y
borderLeftStyle Y Y Y Y
borderLeftWidth Y Y Y Y
borderRight Y Y Y Y
borderRightColor Y Y Y Y
borderRightStyle Y Y Y Y
borderRightWidth Y Y Y Y
borderSpacing N N Y Y
borderStyle Y Y Y Y
borderTop Y Y Y Y
borderTopColor Y Y Y Y
borderTopStyle Y Y Y Y
borderTopWidth Y Y Y Y
borderWidth Y Y Y Y
실전 웹 표준 가이드
- 298 -
bottom Y Y Y Y
captionSide N N Y Y
clear Y Y Y Y
clip Y Y Y Y
color Y Y Y Y
content N N Y Y
counterIncrement N N Y Y
counterReset N N Y Y
cssFloat N N Y Y
cue N N Y N
cueAfter N N Y N
cueBefore N N Y N
cursor Y Y Y Y
direction Y Y Y Y
display Y Y Y Y
elevation N N Y N
emptyCells N N Y Y
font Y Y Y Y
fontFamily Y Y Y Y
fontSize Y Y Y Y
fontSizeAdjust N N Y Y
fontStretch N N Y Y
fontStyle Y Y Y Y
fontVariant Y Y Y Y
fontWeight Y Y Y Y
height Y Y Y Y
left Y Y Y Y
letterSpacing Y Y Y Y
lineHeight Y Y Y Y
listStyle Y Y Y Y
listStyleImage Y Y Y Y
listStylePosition Y Y Y Y
listStyleType Y Y Y Y
margin Y Y Y Y
marginBottom Y Y Y Y
marginLeft Y Y Y Y
marginRight Y Y Y Y
marginTop Y Y Y Y
markerOffset N N Y Y
marks N N Y Y
maxHeight N N Y Y
maxWidth N N Y Y
minHeight Y Y Y Y
minWidth N N Y Y
orphans N N Y Y
outline N N Y Y
outlineColor N N Y Y
실전 웹 표준 가이드
- 299 -
outlineStyle N N Y Y
outlineWidth N N Y Y
overflow Y Y Y Y
padding Y Y Y Y
paddingBottom Y Y Y Y
paddingLeft Y Y Y Y
paddingRight Y Y Y Y
paddingTop Y Y Y Y
page N N Y Y
pageBreakAfter Y Y Y Y
pageBreakBefore Y Y Y Y
pageBreakInside N N Y Y
pause N N Y Y
pauseAfter N N Y Y
pauseBefore N N Y Y
pitch N N Y N
pitchRange N N Y Y
playDuring N N Y N
position Y Y Y Y
quotes N N Y Y
richness N N Y N
right Y Y Y Y
size N N Y Y
speakHeader N N Y N
speakNumeral N N Y N
speakPunctuation N N Y N
speechRate N N Y Y
stress N N Y N
tableLayout Y Y Y Y
textAlign Y Y Y Y
textDecoration Y Y Y Y
textIndent Y Y Y Y
textShadow N N Y Y
textTransform Y Y Y Y
top Y Y Y Y
unicodeBidi Y Y Y Y
verticalAlign Y Y Y Y
visibility Y Y Y Y
voiceFamily N N Y Y
volume N N Y Y
whiteSpace Y Y Y Y
widows N N Y Y
width Y Y Y Y
wordSpacing Y Y Y Y
zIndex Y Y Y Y
실전 웹 표준 가이드
- 300 -
DOM Level 2 Traversal and Range
기능 목록 IE5 IE 6.0 Fx 1.0 Op 8.5
Interface NodeIterator
(일반) N N N Y
expandEntityReferences N N N Y
filter N N N Y
root N N N Y
whatToShow N N N Y
detach() N N N Y
nextNode() N N N
previousNode() N N N
Interface NodeFilter
(일반) N N Y Y
acceptNode() N N Y Y
Interface TreeWalker
(일반) N N Y Y
currentNode N N Y Y
expandEntityReference N N Y Y
filter N N I Y
root N N Y Y
whatToShow N N Y Y
firstChild() N N I Y
lastChild() N N I Y
nextNode() N N I Y
nextSibling() N N I Y
parentNode() N N I Y
previousNode() N N I Y
previousSibling() N N I Y
Interface DocumentTraversal
(일반) N N Y Y
createNodeIterator() N N N Y
createTreeWalker() N N Y Y
Interface Range
(일반) N N Y Y
collapsed N N Y Y
commonAncestorContainer N N Y Y
endContainer N N Y Y
endOffset N N Y Y
startContainer N N Y Y
startOffset N N Y Y
cloneContents() N N Y Y
cloneRange() N N Y Y
collapse() N N Y Y
compareBoundaryPoints() N N Y Y
deleteContents() N N Y Y
실전 웹 표준 가이드
- 301 -
detach() N N Y Y
extractContents() N N Y Y
insertNode() N N Y Y
selectNode() N N Y Y
selectNodeContents() N N Y Y
setEnd() N N Y Y
setEndAfter() N N Y Y
setEndBefore() N N Y Y
setStart() N N Y Y
setStartAfter() N N Y Y
startStartBefore() N N Y Y
surroundContents() N N Y Y
toString() N N Y Y
Interface DocumentRange
(일반) N N Y Y
createRange() N N Y Y
DOM Level 3 Validation
기능 목록 IE5 IE 6.0 Fx 1.0 Op 8.5
Interface DocumentEditVAL
(일반) N N N N
continuousValidityChecking N N N N
domConfig N N N N
getDefinedElements() N N N N
validateDocument() N N N N
Interface NodeEditVAL
(일반) N N N N
defaultValue N N N N
enumeratedValues N N N N
canAppendChild() N N N N
canInsertBefore() N N N N
canRemoveChild() N N N N
canReplaceChild() N N N N
nodeValidity() N N N N
Interface ElementEditVAL
(일반) N N N N
allowedAttributes N N N N
allowedChildren N N N N
allowedFirstChildren N N N N
allowedNextSiblings N N N N
allowedParents N N N N
allowedPreviousSiblings N N N N
contentType N N N N
requiredAttributes N N N N
실전 웹 표준 가이드
- 302 -
canRemoveAttribute() N N N N
canRemoveAttributeNS() N N N N
canRemoveAttributeNode() N N N N
canSetAttribute() N N N N
canSetAttributeNS() N N N N
canSetAttributeNode() N N N N
canSetTextContent() N N N N
isElementDefined() N N N N
isElementDefinedNS() N N N N
Interface CharacterDataEditVAL
(일반) N N N N
canAppendData() N N N N
canDeleteData() N N N N
canInsertData() N N N N
canReplaceData() N N N N
canSetData() N N N N
isWhitespaceOnly() N N N N
DOM Level 2 Views
기능 목록 IE5 IE 6.0 Fx 1.0 Op 8.5
Interface AbstractView
(일반) Y Y Y Y
document Y Y Y Y
Interface DocumentView
(일반) N N Y Y
defaultView N N Y Y
실전 웹 표준 가이드
- 303 -
참고 사이트
각 웹 표준 브라우저별 호환 여부
HTML 호환 차트
- http://nanobox.chipx86.com/browser_support_html.php
CSS 호환 차트
- http://nanobox.chipx86.com/browser_support_css.php
- http://www.quirksmode.org/css/contents.html
DOM 호환 차트
- http://nanobox.chipx86.com/browser_support_dom.php
- http://www.quirksmode.org/dom/contents.html
ECMAScript 호환 차트
- http://nanobox.chipx86.com/browser_support_ecmascript.php
- http://www.quirksmode.org/js/contents.html
국내 웹 표준 커뮤니티
웹 표준화 프로젝트
http://webstandard.or.kr
모질라 웹 표준 게시판
http://forums.mozilla.or.kr/viewforum.php?f=9
CSS 디자인 코리아
http://css.macple.com
실전 웹 표준 가이드
- 304 -
실전 웹 표준 가이드
한국소프트웨어진흥원
(138-711) 서울특별시 송파구 가락본동 79-2 KIPA 빌딩
발행일: 2005. 12
발행처: 한국소프트웨어진흥원 공개SW지원센터
전 화: 02-2141-5000 FAX: 02-2141-5199
E-mail: webmaster@oss.or.kr URL: http://www.oss.or.kr 
Posted by 1010
98..Etc/JavaFX2008. 10. 17. 14:56
반응형

Build rich internet applications (RIAs) with the JavaFX family of products. It includes the tools and platform SDK for developers, web scripters, and designers to create dynamic applications for the next generation of web delivered content. Learn more about JavaFX technology and how you can build applications for desktop, mobile devices, and TV screens here.


 



image of swirling squares
Launch


 









Launch
 
The JavaFX Preview SDK was used to build these applications. Try them out!
(Check the system requirements on the Download page if you encounter problems.)
 
 
Get the JavaFX Preview SDK now and try it out for yourself!
 
Posted by 1010
98..Etc/JavaFX2008. 10. 17. 14:54
반응형
Robert Eckstein 및 JavaFX Programming Language Reference 필진 작성, 2007년 7월

JavaFX Script 프로그래밍 언어(JavaFX)는 Sun Microsystems, Inc.에서 제공하는 선언적, 정적 형식의 스크립팅 언어이다. Open JavaFX (OpenJFX) 웹 사이트에서 언급한 대로, JavaFX 기술은 Java 기술 API에 직접 호출하는 것을 비롯한 다양한 기능으로 구성되어 있다. JavaFX 스크립트는 정적 형식인 만큼 동일한 코드 구조, 재사용 및 캡슐화 기능을 갖추고 있어(예: 패키지, 클래스, 상속, 별도의 컴파일 및 배포 단위) Java 기술을 사용해 매우 큰 규모의 프로그램을 만들고 유지 관리할 수 있다.

시리즈로 구성된 이 세 기사는 JavaFX 프로그래밍 언어를 처음 사용하는 데 도움이 될 것이다. 이번 시리즈의 1부에서는 JavaFX 프로그래밍 언어를 소개하며, 이미 Java 기술과 스크립팅 언어의 기초를 알고 있는 독자를 대상으로 한다. 시리즈 2부와 3부에서는 JavaFX 기술과 RMI(Remote Method Invocation)JAX-WS(Java API for XML Web Services)와 같은 기술을 이용하여 원격 서버에 연결하는 방법을 소개한다.

JavaFX Pad 응용 프로그램

시스템에 JRE(Java Runtime Environment)가 있는 경우, JavaFX 기술을 가장 손쉽게 시작하는 방법은 Java Web Start 사용 가능 데모 프로그램인 JavaFX Pad를 시작하는 것이다. 응용 프로그램을 시작했으면 그림 1과 같은 화면이 나타나야 한다.

그림 1. Microsoft Windows Vista, JDK 6에서 실행 중인 JavaFX Pad 응용 프로그램
그림 1. Microsoft Windows Vista, JDK 6에서 실행 중인 JavaFX Pad 응용 프로그램

JavaFX Pad는 기본 응용 프로그램이 로드된 상태에서 시작하므로, 이 응용 프로그램이 즉시 실행된다. 그러나 이 기사의 JavaFX 소스 코드를 잘라내어 샘플에 붙여 넣어 수정 사항을 볼 수도 있다. 또한 JavaFX 소스 예제를 로컬 디스크에 저장하고 로드할 수 있다. JavaFX Pad 응용 프로그램은 런타임 시 수행하는 작업을 정확하게 파악하고 진행 과정에서 수정하며 즉시 그 결과를 볼 수 있는 효과적인 방법이다.

JavaFX 기술: 정적 형식 언어

JavaFX 프로그래밍 언어는 정적(static) 형식의 스크립팅 언어이다. 이는 정확하게 어떤 의미인가? 다음을 살펴 본다.

var myVariable = "Hello";

JavaScript 기술에서 볼 수 있는 것과 비슷한 이 선언에서는 myVariable이라는 변수를 만들고 여기에 string 값 Hello를 지정한다. 그러나 변수를 선언한 다음에 string이 아닌 다른 것을 지정해 보겠다.

myVariable = 12345;

이 코드에서는 12345를 따옴표로 묶지 않았기 때문에 이 변수에는 string이 아니라 integer가 지정된다. JavaScript 기술에서는 변수 형식을 동적으로 재지정할 수 있다. 그러나 JavaFX와 같은 정적 형식의 언어는 이를 허용하지 않는다. myVariable은 원래 String 형식으로 선언되었지만, 나중에 코드에서 이 변수를 integer로 재지정하려고 하기 때문이다. JavaFX를 사용할 경우, String으로 선언된 변수는 String으로 유지되어야 한다.

실제로 JavaFX Pad 데모에서 이 두 줄의 코드를 만나면 그림 2와 같이 창 맨 아래에 즉시 오류가 표시된다.

그림 2. JavaFX 기술에서는 정적 형식의 변수에서 형식을 변경할 수 없다.
그림 2. JavaFX 기술에서는 정적 형식의 변수에서 형식을 변경할 수 없다.



JavaFX 기술: 선언적 스크립팅 언어

JavaFX 기술은 선언적 스크립팅 언어이기도 하다. 그러나 선언적이란 정확하게 무엇을 의미하는가? 이 질문에 답하기 위해 OpenJFX 웹 사이트의 이 Hello World 프로그램을 살펴 보겠다.

class HelloWorldModel {
    attribute saying: String;
}

var model = HelloWorldModel {
    saying: "Hello World"
};

var win = Frame {
    title: bind "{model.saying} JavaFX"
    width: 200
    content: TextField {
        value: bind model.saying
    }
    visible: true
};

Java 프로그래밍 언어를 비롯하여 대부분의 컴파일된 언어는 imperative 프로그래밍 언어로 간주된다. 무엇보다도 이는 Java 기술의 main() 메소드와 같은 시작점에 의존한다는 뜻이다. 이 시작점으로부터 다른 클래스나 필드를 인스턴스화거나 변수 또는 프로그램 상태에 따라 자원을 처리한다. 이 예제를 다소 확장하자면, imperative 프로그래밍 언어에서는 런타임 시 "공식을 통해(formulaically)" 실행 경로를 결정한다고 할 수 있다. 이 공식이 각 실행에서 동일한 경로를 만들 수도 있으나, 이 언어에서는 그 실행 경로를 런타임에 결정한다.

그러나 앞서 소개한 Hello World와 같은 JavaFX 프로그램에는 main() 메소드가 없다. 그 대신, 스크립팅 엔진에서는 실행 직전에 전체 프로그램을 읽으므로, 인터프리터가 프로그램을 올바르게 실행하는 데 필요한 모든 단계를 적용할 수 있다. 더 정확하게 말하자면, 스크립팅 엔진에 필요한 것은 실행 시작 전에 선언되며 모든 선언이 주어진 가운데 엔진은 명시된 목표 달성에 필요한 작업을 결정한다.

JavaFX Pad에서 System.out.println() 사용

곧 살펴 보겠지만, JavaFX는 기존의 Java 라이브러리를 호출할 수 있다. 그러나 JavaFX Pad 응용 프로그램에서 System.out.println()를 사용하려면 콘솔 지원을 활성화해야 한다. 그 방법은 다음과 같다.

  • Microsoft Windows XP 또는 Vista를 사용 중이라면 제어판에서 Java 아이콘을 클릭하고 고급 탭을 선택한 다음 Java 콘솔 항목에서 콘솔 표시를 선택한다.

  • Solaris 사용자라면 Preferences 탭에서 Java 아이콘을 클릭하고 Advanced 탭을 선택한 다음 Java Console 항목에서 Show Console을 선택한다. Preferences 탭에 Java 아이콘이 없으면 Java 배포판의 bin 디렉토리에서 ControlPanel 응용 프로그램(또는 jcontrol)을 실행한다.

  • Linux 사용자라면 해당 Java 배포판의 bin 디렉토리에서 ControlPanel(또는 jcontrol)이라는 응용 프로그램을 찾는다. 이를 실행한 다음 Preferences 탭에서 Java 아이콘을 클릭하고 Advanced 탭을 선택한 다음 Java Console 항목에서 Show Console을 선택한다.

  • Mac OS X 사용자라면 /Applications/Utilities/Java/[Java version]/ 아래에서 Java Preferences 응용 프로그램을 연다. 그런 다음 Advanced 탭을 선택하고 Java Console 항목에서 Show Console을 선택한다. 참고: Intel Mac에서 Java Preferences를 변경한 후 Java Web Start가 제대로 시작하지 않을 경우, 홈 디렉토리에서 Library/Caches/Java/deployment.properties 파일을 열고 모든 osarch 변수를 i386에서 ppc로 다시 변경해 본다.

JavaFX Pad에서 Run 메뉴의 Run Automatically 설정을 비활성화하고, JavaFX 응용 프로그램을 수동으로 실행하기 직전에 Java Console을 지운다. 응용 프로그램을 수동으로 실행하려면 JavaFX Pad 응용 프로그램의 Run 메뉴에서 Run 메뉴 항목을 사용한다.

그림 3에서는 Intel 기반 Macintosh에서 콘솔이 열린 상태로 실행 중인 JavaFX Pad를 보여 준다. 그림 4는 OpenSolaris에서 실행 중인 JavaFX Pad이다.

그림 3. Mac OS X, JDK 1.5.0_07의 Java Console에서 실행 중인 JavaFX Pad

그림 3. Mac OS X, JDK 1.5.0_07의 Java Console에서 실행 중인 JavaFX Pad


그림 4. OpenSolaris, JDK 6의 Java Console에서 실행 중인 JavaFX Pad 

그림 4. OpenSolaris, JDK 6의 Java Console에서 실행 중인 JavaFX Pad

마지막으로, JavaFX에서 string 내부에 변수를 포함시킨 경우(주로 Java 프로그래밍 언어에서 System.out.println()을 사용), 알맞은 JavaFX 구문은 다음과 같다.

    import java.lang.System;

    System.out.println("Text {variable} and more text");

이는 Java 언어 구문과 다르다.

    import java.lang.System;

    System.out.println("Text " + variable + " and more text");

JavaFX 기술 알아보기

이 섹션에서는 JavaFX 기술의 기본 사항을 살펴 본다. 이 정보의 대부분은 정식 JavaFX Programming Language Reference에서 직접 발췌한 것이며, 단 이 기사의 작성자들이 Java 프로그래머를 위해 그 내용을 수정했다.

Primitive

JavaFX 프로그래밍 언어는 String, Boolean, NumberInteger의 4개 primitive 형식만 제공한다. Java 프로그래밍 언어와 달리 primitive는 대문자로 시작한다. 표 1에서는 JavaFX 인터프리터 내부의 형식 그리고 이 형식이 매핑되는 Java 객체를 보여 준다.

JavaFX의 Primitive 매핑 JavaFX 기술의 Primitive 대표적인 Java 기술 Primitive 또는 클래스
String     java.lang.String
Boolean Number          java.lang.Number
Integer byte, short, int, long,          java.math.BigInteger

참고: 복잡성을 피하기 위해, Integer는 작은 수와 큰 수를 모두 나타내는데, Java 프로그래머는 short 또는 long과 같이 서로 다른 primitive 형식을 사용하기도 한다. Java 기술의 부동 소수점 숫자(예: float, double)는 Number 형식으로 표현한다.

Java 객체가 이 primitive를 나타내므로 이 형식 각각에서 기존의 Java 메소드를 호출할 수 있다.

var s:String = "Hello";
s.toUpperCase();      // String method that yields "HELLO";
s.substring(1);       // String method that yields "ello";

var n:Number = 1.5;
n.intValue();         // Number method that yields integer 1
(1.5).intValue();     // Number method that yields integer 1

var b:Boolean = true;
b instanceof Boolean; // Boolean method that yields true

그 결과를 보고 싶다면 System.out.println() 문에서 각 표현식을 줄바꿈하고 반드시 맨 위에 java.lang.System을 가져온다. 또한 호환되지 않는 형식이라는 오류가 발생할 경우, 우선 스크립트 끝에 null return을 추가하면 된다. 예제 코드는 다음과 같다.

import java.lang.System;

var s:String = "Hello";
System.out.println(s.toUpperCase());      // String method that yields "HELLO";
System.out.println(s.substring(1));       // String method that yields "ello";

var n:Number = 1.5;
System.out.println(n.intValue());         // Number method that yields integer 1
System.out.println((1.5).intValue());     // Number method that yields integer 1

var b:Boolean = true;
System.out.println(b instanceof Boolean); // Boolean method that yields true

return null;                              // Final node returned for JavaFX Pad display

역시 var 키워드 사용에 주목한다. Java 기술에서 사용되지는 않지만 var는 JavaFX 및 그 밖의 스크립팅 언어에서 새 변수를 선언할 때 쓰인다. JavaFX는 정적 형식 언어이므로, 선언에서 변수의 형식을 지정할 수 있으며 그렇지 않으면 JavaFX 인터프리터는 변수의 쓰임새로부터 변수의 형식을 유추하려고 한다. 예를 들어, 다음 세 가지 모두 JavaFX에서 유효하다.

var s:String;
var s:String = "A New String";
var s = "A New String";

첫 번째와 두 번째 선언에서는 공식적으로 String 형식을 변수에 지정하지만, 세 번째에서는 등호 (=) 부호의 오른쪽에 있는 초기값으로부터 이를 String으로 유추한다. 이를 더 공식적으로 나타낸다면 JavaFX 변수 선언을 이렇게 표현할 수 있다.

var variableName [: typeName] [? | + | *] [= initializer];

물음표, 더하기 부호 및 별표는 카디널리티 연산자라고 부른다. 표현식 언어를 사용한 적이 있으면 이 용어가 익숙할 것이다. 이 세 연산자 중 하나를 사용하여 변수의 카디널리티(구성원 수)를 나타낼 수 있다. 표 2를 참조한다.

표. JavaFX 카디널리티 연산자
연산자
의미
?
선택 사항(예를 들어 null이 될 수 있음)
+
하나 이상
*
0 이상

다음은 그 예제이다.

var nums:Number* = [5, 9, 13];

이 예제에서 선언하는 새 변수, nums의 값은 Number 형식의 인스턴스 0개 이상으로 구성되도록 정의되며, 초기 값은 3개의 숫자, 5, 9 그리고 13이다.

선언에서 typeName, 카디널리티 연산자와 초기값은 선택 사항이므로, 다음은 위의 예제와 동일하다.

var nums = [5, 9, 13];

리터럴

JavaFX 기술에서 리터럴 문자 스트링은 작은 따옴표 또는 큰 따옴표로 지정된다.

var s = 'Hello';
var s = "Hello";

필자가 앞서 언급한 대로, 변수와 심지어 JavaFX 표현식 전체를 중괄호({})로 묶을 수 있다.

var name = 'Joe';
var s = "Hello {name}"; // s = 'Hello Joe'
 

포함된 표현식 자체가 따옴표가 붙은 스트링을 포함할 수 있으며, 이 스트링이 다시 표현식을 포함하기도 한다.

var answer = true;
var s = "The answer is {if answer then "Yes" else "No"}";
    // s = 'The answer is Yes'
 

마지막으로, Java 기술과 달리 큰 따옴표로 묶인 String 리터럴은 새 행을 포함할 수 있다.

var s = "This
         contains
         new lines";
 

어레이 및 리스트 이해

앞서 카디널리티 연산자가 어레이를 생성하는 것을 보았을 것이다. JavaFX에서 어레이는 대괄호와 쉼표로 표시한다. Java와 마찬가지로 JavaFX 어레이의 요소는 모두 형식이 동일해야 한다.

var weekdays = ["Mon","Tue","Wed","Thur","Fri"];
var days = [weekdays, ["Sat","Sun"]];
 

어레이는 객체의 시퀀스를 나타낸다. JavaFX에서는 어레이 자체가 객체는 아니다. 또한 중첩된 어레이를 만드는 표현식(예: 앞의 코드 예제에서 두 번째 변수 days의 초기화)은 자동으로 평면화된다.

days == ["Mon","Tue","Wed","Thur","Fri","Sat","Sun"];
     // returns true
 

System.out.println(days)을 실행하면 어레이의 첫 번째 요소만 표시된다. 나머지 요소를 얻으려면 어레이 색인을 사용한다. 또한 존재하지 않는 색인을 지정할 경우, Java와 같이 ArrayIndexOutOfBoundsException이 발생하지 않고 0을 얻을 뿐이다.

sizeof 연산자를 사용하여 현재 어레이 크기를 구할 수 있다.

var n = sizeof days;     // n = 7
 

또한 간략하게 마침표 2개(..)를 사용하여 요소가 산술적 시리즈를 형성하는 어레이를 나타낼 수 있다. 예를 들어, 다음은 100개 요소의 어레이를 생성한다.

var oneToAHundred = [1..100];
var arraySize = sizeof oneToAHundred;   // size == 100
 

JavaFX 기술은 어레이 사용 시 insertdelete 문도 지원한다. 다음은 값을 어레이에 삽입하는 예제이다.

var x = [1,2,3];
insert 12 into x;                 // yields [1,2,3,12]
insert 10 as first into x;        // yields [10,1,2,3,12]
insert [99,100] as last into x;   // yields [10,1,2,3,12,99,100]
 

into 외에도 다음과 같이 beforeafter 키워드를 사용할 수 있다.

var x = [1,2,3];
insert 10 after x[. == 3];        // yields [1,2,3,10]
insert 12 before x[1];            // yields [1,12,2,3,10]
insert 13 after x[. == 2];        // yields [1, 12, 2, 13, 3, 10];
 

대괄호로 묶인 표현식 중 일부가 이상하게 보이더라도 신경 쓸 필요 없다. 실제로 Xquery-Update(XPath와 유사) 술어이다. 여기서 괄호 안의 마침표는 색인을 나타내지 않지만, 대신 색인의 을 의미한다. JavaFX 기술은 표현식이 true가 될 때까지 어레이의 요소 각각을 테스트한 다음 insert를 적용한다. 예를 들어, 마지막 문은 어레이의 각 값을 거치면서 반복되다가 (어레이의 세 번째 요소인)2와 동일한 어레이 값을 찾아내면 숫자 13을 삽입한다. 여기서 중지한다.

delete 문도 거의 동일하게 실행된다. 대괄호 안의 표현식이 생략될 경우, 어레이 전체가 지워진다.

var x = [1,2,3];
insert 10 into x;          // yields [1,2,3,10]
insert 12 before x[1];     // yields [1,12,2,3,10]
delete x[. == 12];         // yields [1,2,3,10]
delete x[. >= 3];          // yields [1,2]
insert 5 after x[. == 1];  // yields [1,5,2];
insert 13 as first into x; // yields [13, 1, 5, 2];
delete x;                  // clears the array and yields []
 

마지막으로, selectfor each 연산자를 사용하여 어레이에 대해 더 복잡한 쿼리를 수행할 수 있다. 이를 list comprehension이라고 한다. 다음은 select를 사용하는 간단한 예제이다.

var a:Integer* = select n*n from n in [1..10];
    //  yields [1,4,9,16,25,36,49,64,81,100]
 

이는 "[1..10] 어레이의 각 숫자를 루프하면서 로컬 변수 n에 지정한 다음 각 n에 대해 새 요소 n squared를 생성하고 이를 Integers a의 어레이에 추가한다"는 뜻이다.

또한 다음을 사용하여 필터를 추가할 수 있다.

var a:Integer* = select n*n from n in [1..10] where (n%2 == 0);
    //  yields [4,16,36,64,100]
 

이는 정의를 다음으로 변경한다. "[1..10] 어레이의 각 숫자를 루프하면서 그 숫자를 2로 나눈 나머지가 0인 경우에만, 즉 짝수인 경우에만 로컬 변수 n에 지정한다. 그런 다음 결과 값인 n 각각에 대해 새 요소 n squared를 생성하고 이를 Integers a의 어레이에 추가한다."

마지막으로, 여러 개의 리스트를 선택에 추가할 수도 있다.

var a:Integer* = select n*m from n in [1..4], m in [100,200] where (n%2 == 0);
    //  yields [200, 400, 400, 800]
 

실제로 이는 루프 안에 루프가 존재하면서 공식적으로는 Cartesian Product.를 생성한다. 먼저 첫 번째 유효한 n(즉 2)을 얻고 여기에 첫 번째 유효한 m인 100을 곱한다. 그런 다음 다시 2를 다음 번 유효한 m인 200과 곱한다. 그리고 나서 다음 번 유효한 n인 4를 사용하여 유효한 m의 리스트(100과 200)를 반복해 400과 800을 얻는다. 여기서 선택이 종료하며, 최종 어레이(어레이 a)가 얻어진다.

동일한 내용을 foreach 연산자를 사용하여 표현할 수 있다.

var a:Integer* =
    foreach(n in [1..4], m in [100,200] where (n%2 == 0) )
            n*m;      // also yields [200, 400, 400, 800]
 
형식 지정

format as 연산자는 표 3에서 보여주는 것처럼 몇 가지 형식 지정 지시문을 지원한다.

JavaFX 형식 지정 지시문 지시문사용된 형식의 클래스%로 시작하는 형식 지정 지시문java.util.Formatter표현식이 Numberjava.text.DecimalFormat표현식이 java.util.Date java.text.SimpleDateFormat

다음은 몇 가지 예제이다.

import java.util.Date;

100.896 format as <<%f>>; // yields '100.896000'
31.intValue() format as <<%02X>>;
    // yields '1F'
var d = new Date();
d format as <<yyyy-MM-dd'T'HH:mm:ss.SSSZ>>;
    // yields '2005-10-31T08:04:31.323-0800'
0.00123 format as <<00.###E0>>;
    // yields '12.3E-4'

이 예제에서는 프랑스어 따옴표, 즉 guillemets(<< >>)가 사용되었다. JavaFX 기술에서는 공백을 비롯하여 프랑스어 따옴표로 묶인 문자 시퀀스를 모두 식별자로 취급한다. 따라서 JavaFX 키워드 또는 평소에는 적합하지 않은 식별자를 클래스, 변수, 함수 또는 속성 이름으로 사용할 수 있다. 다음은 그 예제이다.

var <<while>> = 100;

이 기능에서는 이 예제와 같이 JavaFX 키워드와 이름이 같은 Java 메소드를 호출할 수 있다.

import javax.swing.JTextArea;

var textArea = new JTextArea();
textArea.<<insert>>("Hello", 0);
클래스 선언

클래스를 지정하는 JavaFX 구문은 class 키워드 다음에 클래스 이름, extends 키워드(옵션) 그리고 쉼표로 구분된 기본 클래스 이름의 목록이다. Java와 달리 JavaFX 기술에서는 둘 이상의 클래스를 확장할 수 있다. 그 다음에 여는 중괄호, 속성, 함수 및 연산의 목록(각각 세미콜론(;)으로 끝남)과 닫는 중괄호가 이어진다. 다음은 그 예제이다.

class Person {

    attribute name: String;
    attribute parent: Person;
    attribute children: Person*;

    function getFamilyIncome(): Number;
    function getNumberOfChildren(): Number;

    operation marry(spouse: Person): Boolean;
}

속성, 함수 및 연산

세 가지 형식의 클래스 구성원 선언을 자세히 살펴 보도록 한다. 속성(Attribute)attribute 키워드 다음에 속성의 이름, 콜론(:), 속성의 형식, 카디널리티 사양(옵션) 및 역 절(inverse clause)(옵션)을 사용하여 선언한다. 카디널리티를 사용하는 경우, 종종 그 속성을 다중 값 속성(multivalued attribute)이라고 한다.

더 공식적으로 설명하자면, 속성이 다음 구문을 사용한다.

attribute AttributeName [: AttributeType] [? | + | *] [inverse ClassName.InverseAttributeName];
>

맨 끝에 오는 inverse 절 옵션은 다른 속성과의 양방향 관계를 지정한다. inverse 절이 존재하는 경우, JavaFX 기술은 inverse 절에 지정된 속성이 수정될 때마다 그 속성을 자동으로 업데이트한다(속성의 업데이트 및 카디널리티 종류에 따라 insert, delete 또는 replace 사용).

함수(Function)는 JavaFX 프로그래밍 언어의 순수 기능 하위 집합을 나타낸다. 즉 함수의 본문은 일련의 변수 선언과 return 문만 포함할 수 있다. 그 정도면 속성 접근자(getter) 및 간단한 수학적 절차 구현에 충분하다. 몇 가지 함수의 예제를 소개한다.

function z(a,b) {
    var x = a + b;
    var y = a - b;
    return sq(x) / sq (y);
}

function sq(n) {return n * n; }

JavaFX에서 연산(Operation)operation 키워드를 사용하여 선언한다. 함수와 달리 연산은 조건문, 루핑문, trycatch 문을 비롯하여 개수 제한 없이 문을 포함할 수 있다. 따라서 Java 기술의 클래스 메소드와 더 비슷하다. 본문을 선언할 때 연산의 이름이 주어지고 괄호로 묶인 입력 변수, 콜론 그리고 반환 변수 형식이 이어진다. 다음은 그 예제이다.

operation substring(s:String, n:Number): String {
    try {
        return s.substring(n);
    } catch (e:StringIndexOutOfBoundsException) {
        throw "sorry, index out of bounds";
    }
}

선언된 속성 초기화

함수 및 프로시저와 마찬가지로, 속성의 초기 값은 클래스 정의의 외부에서 선언한다. 이 초기값은 새로 생성된 객체의 컨텍스트에 따라 클래스 선언에서 속성이 지정된 순서대로 평가된다.

import java.lang.System;

class X {
    attribute a: Number;
    attribute b: Number;
}

attribute X.a = 10;
attribute X.b = -1;

var x = new X();
System.out.println(x.a); // prints 10
System.out.println(x.b); // prints -1
>

JavaFX 객체는 선언적 구문을 사용하여 초기화할 수도 있다. 이 구문은 클래스 이름, 중괄호로 구분된 속성 초기값 목록의 순서로 구성된다. 각 초기값은 속성 이름, 콜론 그리고 그 값을 정의하는 표현식의 순서로 구성된다. new 키워드는 생략된다. 다음은 동일한 예제이다.

var myXClass = X {
    a: 10
    b: -1
};

선언적 구문은 JavaFX 기술에서 자주 사용된다. 그러나 Java 객체 할당 구문도 지원된다. Java 클래스의 경우, Java 기술에서처럼 클래스의 구성자에 인수를 전달하거나 선언적 구문을 사용할 수 있다.

import java.util.Date;
import java.lang.System;

var date1 = new Date(95, 4, 23);    // call a Java constructor
var date2 = Date {  // create the same date as an object literal
    month: 4
    date: 23
    year: 95
};

System.out.println(date1 == date2);   // prints true

함수 및 연산 정의

Java 메소드와 달리 모든 구성원 함수 및 연산의 본문은 클래스 선언의 외부에서 정의된다. 이 구문이 맨 처음에는 Java 프로그래머에게 약간 이상하게 보일 수 있으나 비교적 간단하게 이해할 수 있다. JavaFX 기술을 사용하면 연산 이름의 함수 앞에 그 함수가 속한 클래스 및 마침표가 온다. 반환 값은 함수 또는 연산 이름 뒤에 나열할 수 있으며, 앞에 콜론이 온다. 매개 변수는 서명 괄호에 포함시킬 수 있다. 이들은 쉼표로 구분되며, 앞서 연산에 대해 설명했던 name:type 구문을 따른다. 다음은 그 예제이다.

operation Person.marry(spouse: Person): Boolean {
    //  Body of operation
}

클래스 선언 내부의 연산 및 함수 선언에서는 괄호와 반환 값이 반드시 필요하다. 그러나 외부 정의에서는 생략 가능하다. 따라서 다음과 같이 쉽게 표현할 수 있다.

operation Person.marry() {
    //  Body of operation
}

트리거

Java 기술과 달리, JavaFX 클래스는 구성자가 없으며 JavaFX 속성은 일반적으로 "setter" 메소드를 갖지 않는다. 그 대신 JavaFX 기술에서는 데이터 수정 이벤트를 처리할 수 있도록 SQL과 비슷한 트리거를 제공한다. 이 트리거에서는 trigger 키워드를 사용한다.

객체 생성 트리거

생성 트리거를 지정하는 방법으로 새로 생성된 객체의 컨텍스트에서 작업을 트리거할 수 있다.

import java.lang.System;

class X {
     attribute nums: Number*;
}

trigger on new X {
     insert [3,4] into this.nums;
}

var x = new X();
System.out.println(x.nums == [3,4]); // prints true

이 예제에서는 X 클래스의 새 인스턴스가 만들어질 때마다 실행될 트리거를 정의한다. 여기서는 두 개의 숫자를 nums 속성에 삽입한다. 트리거의 컨텍스트에서 현재 객체를 가리킬 때 this 키워드를 사용한다.

Insert 트리거

또한 다중 값 속성에 요소가 삽입될 때마다 어떤 작업을 트리거할 수 있다.

import java.lang.System;

class X {
     attribute nums: Number*;
}

trigger on insert num into X.nums {
     System.out.println("just inserted {num} into X.nums at position {indexof num}");
}

var x = new X();
insert 12 into x.nums;
    // prints just inserted 12 into X.nums at position 0
insert 13 into x.nums;
    // prints just inserted 13 into X.nums at position 1

Delete 트리거

동일한 방법으로 다중 값 속성에서 요소가 삭제될 때마다 어떤 작업을 트리거할 수 있다.

import java.lang.System;

class X {
     attribute nums: Number*;
}

trigger on delete num from X.nums {
     System.out.println("just deleted {num} from X.nums at position {indexof num}");
}

var x = X {
     nums: [12, 13]
};

delete x.nums[1];
    // prints just deleted 13 from X.nums at position 1
delete x.nums[0];
    // prints just deleted 12 from X.nums at position 0

Replace 트리거

마지막으로, 속성의 값이 대체될 때마다 작업을 수행할 수 있다. 다음 예제에서 oldValuenewValue는 대체되는 요소의 이전 값과 현재 값을 참조하는 임의의 변수 이름이다. 다른 변수 이름을 자유롭게 선택할 수 있다.

import java.lang.System;

class X {
     attribute nums: Number*;
     attribute num: Number?;
}

trigger on X.nums[oldValue] = newValue {
     System.out.println("X.nums: replaced {oldValue} with {newValue} at position {indexof newValue}");
}

trigger on X.num[oldValue] = newValue {
     System.out.println("X.num: replaced {oldValue} with {newValue}");
}

var x = X {
     nums: [12, 13]
     num: 100
};

x.nums[1] = 5;
    // prints replaced 13 with 5 at position 1 in X.nums
x.num = 3;
    // prints X.num: replaced 100 with 3
x.num = null;
    // prints X.num: replaced 3 with null

JavaFX 기술에서는 Java 기술의 해당 문과 비슷하지만 똑같지 않은 몇몇 문을 지원한다. 이 섹션에서는 그 차이점을 간략하게 소개한다.

If

JavaFX if 문은 중괄호가 필요하다는 점을 제외하고 Java 기술의 문과 같다.

if (condition1) {
    System.out.println("Condition 1");
} else if (condition2) {
    System.out.println("Condition2");
} else {
    System.out.println("not Condition 1 or Condition 2");
}

While

JavaFX while 문 역시 본문을 중괄호로 묶어야 한다.

var i = 0;
while (i < 10) {
    if (i > 5) {
       break;
    }
    System.out.println("i = {i}");
    i += 1;
}

Try, CatchThrow

JavaFX trycatch 문은 JavaFX 변수 선언 구문을 제외하고 Java 기술의 문과 같다. JavaFX 기술에서는 java.lang.Throwable을 확장하는 객체 외에 어떤 객체도 throw 및 catch할 수 있다.

try {
   throw "Hello";
} catch (s:String) {
   System.out.println("caught a String: {s}");
} catch (any) {
   System.out.println("caught something not a String: {any}");
} finally {
   System.out.println("finally...");
}

For

JavaFX for 문의 헤더에서는 앞서 설명한 foreach list-comprehension 연산자와 동일한 구문을 사용한다. 문의 본문은 list comprehension에서 생성한 각 요소에 대해 실행된다. 다음은 그 예제이다.

for (i in [0..10]) {
     System.out.println("i = {i}");
}

// print only the even numbers using a filter
for (i in [0..10] where (i%2 == 0) ) {
     System.out.println("i = {i}");
}

// print only the odd numbers using a range expression
for (i in [1,3..10]) {
     System.out.println("i = {i}");
}

// print the cartesian product
for (i in [0..10], j in [0..10]) {
     System.out.println(i);
     System.out.println(j);
}

Return

JavaFX return 문은 Java 기술의 문과 동일하다.

operation add(x, y) {
    return x + y;
}

BreakContinue

JavaFX breakcontinue 문은 레이블이 지원되지 않는다는 점을 제외하고 Java 기술의 문과 같다. Java 프로그래밍에서처럼 breakcontinuewhile 또는 for 문의 본문에 나타나야 한다.

operation foo() {
   for (i in [0..10]) {
       if (i > 5) {
           break;
       }
       if (i % 2 == 0) {
           continue;
       }
       System.out.println(i);
   }
}

operation bar() {
    var i = 0;
    while (i < 10) {
        if (i > 5) {
            break;
        }
        if (i % 2 == 0) {
            continue;
        }
        System.out.println(i);
        i += 1;
    }
}

DoDo Later

JavaFX do 문에서는 JavaFX 코드의 블록을 실행할 수 있다. 그러나 do 본문은 항상 백그라운드 스레드에서 실행된다. 일반적으로 JavaFX 코드는 AWT EDT(Event Dispatch Thread)에서 실행된다. do 문의 본문에 포함된 코드만 다른 스레드에서 실행 가능하다. 다음 예제를 살펴 본다.

import java.net.URL;
import java.lang.StringBuffer;
import java.lang.System;
import java.io.InputStreamReader;
import java.io.BufferedReader;

// in the AWT Event Dispatch Thread (EDT)
var result = new StringBuffer();

do {
    // now in a background thread
     var url = new URL("http://www.foo.com/abc.xml");
     var is = url.openStream();
     var reader = new BufferedReader(new InputStreamReader(is));
     var line;
     while (true) {
          line = reader.readLine();
          if (line == null) {
               break;
          }
          result.append(line);
          result.append("\n");
     }
}

// now back in the EDT
System.out.println("result = {result}");

do 문의 본문이 실행되는 중에 EDT 블록에서 실행되는 코드이다. 그러나 백그라운드 스레드가 완료될 때까지 기다리는 동안 스택에서 새로운 이벤트 디스패치 루프가 생성된다. 그 결과, do 문이 실행되는 동안 GUI(graphical user interface) 이벤트는 계속 처리된다.

do 문은 do later라는 두 번째 형식을 갖는데, 이 형식은 java.awt.EventQueue.invokeLater()의 기능과 비슷하게, 백그라운드 스레드에서 동시 실행이 아니라 EDT에서 본문이 비동기식으로 실행될 수 있게 한다. 다음은 그 예제이다.

import java.lang.System;
var saying1 = "Hello World!";
var saying2 = "Goodbye Cruel World!";
do later {
     System.out.println(saying1);
}
System.out.println(saying2);

이 코드를 실행하면 다음과 같은 출력이 생성된다.

Goodbye Cruel World!
Hello World!

증분 평가

증분 평가(incremental evaluation)는 JavaFX 기술에서 가장 강력한 기능 중 하나이다. 프로그래머가 복잡한 동적 GUI를 선언적으로 정의할 수 있다. JavaFX 기술에서는 bind 연산자를 사용하면 속성 초기값을 증분식으로 평가할 수 있다. 바인딩된 이 속성은 스프레드시트의 셀처럼 작동하면서 리터럴 값 대신 공식을 포함한다. 초기값 표현식의 오른쪽에서 참조하는 객체가 변경될 때마다 속성의 값인 왼쪽이 자동으로 업데이트된다.

다음은 간단한 예제이다.

import java.lang.System;

class X {
    attribute a: Number;
    attribute b: Number;
}

var x1 = X {
    a: 1
    b: 2
};

var x2 = X {
    a: x1.a           // nonincremental
    b: bind x1.b      // incremental
};

System.out.println(x2.a); // prints 1
System.out.println(x2.b); // prints 2

x1.a = 5;
x1.b = 5;

System.out.println(x2.a); // prints 1
System.out.println(x2.b); // prints 5

이 예제에서 x2b 속성은 x1b 속성에 바인딩된다. 즉 x1b 속성이 업데이트될 때마다 x2b 속성도 업데이트된다.

함수의 본문은 bind 연산자가 없더라도 항상 증분식으로 평가되지만, 연산의 본문은 그렇지 않다. 함수와 달리, 연산 내부의 로컬 변수가 변경되더라도 증분 평가가 트리거되지 않는다. 표현식 앞에 명시적으로 bind라는 접두어가 붙지 않는 한 연산의 본문 내부에서는 증분 평가가 수행되지 않는다.

느린 증분 평가(lazy incremental evaluation)도 사용하도록 예제를 수정할 수 있다. 여기서는 attribute 값이 맨 처음 액세스될 때까지 바인딩이 적용되지 않는다.

import java.lang.System;

class X {
    attribute a: Number;
}

var x1 = X {
    a: 1
};

var x2 = X {
    a: bind lazy x1.a
    // no value is assigned yet
};

System.out.println(x2.a);
// Now the value is accessed, so x2.a is set to 1

느린 증분 평가 기능은 재귀적 데이터 구조(예: 트리, 그래프)를 처리할 때 자주 쓰인다.

결론

이 기사에서는 JavaFX 플랫폼을 간단하게 소개했다. 2부와 3부에서는 JavaFX 기술 기반의 GUI를 사용하여 클라이언트 서버 통신을 처리하는 방법을 다룬다.

자세한 정보

"Java FX" 카테고리의 다른 글

Posted by 1010
98..Etc/Etc...2008. 10. 17. 13:59
반응형

Apache 2.x + Tomcat 4.x
+ Load Balancing (or Private JVMs)

January 24, 2002 by Pascal Forget
Revised September 25, 2002 by Matt Raible
Original Article at http://www.ubeans.com/tomcat/.

This article contains step by step instructions for configuring an Apache 2.x web server which handles static content and delegates JSP (Java Server Pages) and Servlet requests to two Tomcat 4.x servers using AJP 13 connectors and a load balancing worker.

Introduction

Apache 2.0 is a standards compliant, fast and mature web server which excels at delivering static content such as static HTML pages and images. The Tomcat web server is great for serving Java Server Pages and servlets, but it is not as fast as Apache for delivering static content.

In order to build a fast, scalable web application, the requirements call for an Apache server that delegates servicing of JSP and servlet requests to multiple tomcat servers by using an Apache module, mod_jk, that performs load balancing with session affinity, also known as "sticky" sessions.

Session affinity explained. When a client browser requests a JSP page for the first time, the load balancer redirects the request received by Apache to one of the two tomcat servers; further requests originating from the same client session will be automatically forwarded to the same tomcat server, so that the user's session data is retrieved.

This document describes how I configured Apache 2.x to dispatch JSP and servlet requests to two Tomcat 4.x instances listening on different ports. This setup was done on a Linux system. Your mileage may vary.

1. Download the required software

2. Compile, Install and Configure Apache

2.1 Install Apache.

Linux: gunzip the *.gz you downloaded, untar and run install-bindist.sh

For *nux, to install Apache 2.0.42 with mod_sll installed, you will need to compile from source:

I used http://httpd.apache.org/docs-2.0/install.html as a reference.

$ lynx http://www.apache.org/dist/httpd/httpd-2.0.42.tar.gz
$ gzip -d httpd-2.0.42.tar.gz
$ tar xvf httpd-2.0.42.tar
$ ./configure --enable-mods-shared=most --enable-ssl=shared
$ make
$ make install

Then download mod_jk-2.0.42.so and put it into your modules directory and rename it mod_jk.so.


Windows: Execute the downloaded executable and install.

2.2 Configure the JK Module in httpd.conf

Edit the Apache server's configuration file httpd.conf which is located in the /usr/local/apache2/conf directory.

2.2.1 Below "# LoadModule foo_module modules/mod_foo.so", insert the following lines:

#
# Load mod_jk
#
LoadModule jk_module modules/mod_jk.so

#
# Configure mod_jk
#
JkWorkersFile conf/workers.properties
JkLogFile logs/mod_jk.log
JkLogLevel info

NOTE: You will need to change mod_jk.so to mod_jk.dll for Windows.

2.2.2 Below the "DocumentRoot" line, insert the following two lines:

JkMount /*.jsp loadbalancer
JkMount /servlet/* loadbalancer

2.3 Create the workers.properties file

Now we will create a file called worker.properties, and we will place it under /usr/local/apache2/conf. The worker.properties file tells Apache about the various Tomcat servers that are running, and on which port they are listening.

In my setup, I installed the two Tomcat servers in different directories, on the same machine as Apache. Feel free to put your Tomcat servers on different machines.

I made the first Tomcat server's AJP13 connector listen on port 11009 instead of the default port which is 8009, and the second one listens on port 12009.

I have decided to name my tomcat servers tomcat1 and tomcat2. This is purely my choice.

Create the file exactly like this:
#
# workers.properties 
#

# In Unix, we use forward slashes:
ps=/

# list the workers by name

worker.list=tomcat1, tomcat2, loadbalancer

# ------------------------
# First tomcat server
# ------------------------
worker.tomcat1.port=11009
worker.tomcat1.host=localhost
worker.tomcat1.type=ajp13

# Specify the size of the open connection cache.
#worker.tomcat1.cachesize

#
# Specifies the load balance factor when used with
# a load balancing worker.
# Note:
#  ----> lbfactor must be > 0
#  ----> Low lbfactor means less work done by the worker.
worker.tomcat1.lbfactor=100


# ------------------------
# Second tomcat server
# ------------------------
worker.tomcat2.port=12009
worker.tomcat2.host=localhost
worker.tomcat2.type=ajp13

# Specify the size of the open connection cache.
#worker.tomcat2.cachesize

#
# Specifies the load balance factor when used with
# a load balancing worker.
# Note:
#  ----> lbfactor must be > 0
#  ----> Low lbfactor means less work done by the worker.
worker.tomcat2.lbfactor=100


# ------------------------
# Load Balancer worker
# ------------------------

#
# The loadbalancer (type lb) worker performs weighted round-robin
# load balancing with sticky sessions.
# Note:
#  ----> If a worker dies, the load balancer will check its state
#        once in a while. Until then all work is redirected to peer
#        worker.
worker.loadbalancer.type=lb
worker.loadbalancer.balanced_workers=tomcat1, tomcat2

#
# END workers.properties
#

That's it, we're done with Apache.

3. Install and Configure the Tomcat Servers

Now let's suppose that Java 1.4.x is installed under /usr/local/jdk1.4.x/. Create two Tomcat 4.x servers and install them under /usr/local/:

   tar fvxz jakarta-tomcat-4.x.tar.gz
   mv jakarta-tomcat-4.x /usr/local/tomcat1 
   cp -R /usr/local/tomcat1 /usr/local/tomcat2

In both /usr/local/tomcat1 and /usr/local/tomcat2, the same files will be modified. I here by present the modifications made to the files contained in the /usr/local/tomcat1 directory tree structure. You should also apply the same changes to the corresponding files located under the /usr/local/tomcat2 directory tree structure.

3.1 Modify catalina.sh

In my many years of consulting, I have learned not to rely on environment variables which can be unset by ignorant or malicious people. This is why I explicitely set the JAVA_HOME and CATALINA_HOME variables directly in the catalina.sh file.

At line 32, before the "# ----- Verify and Set Required Environment Variables " line, insert the following two lines:

    JAVA_HOME=/usr/local/jdk1.4 ; export JAVA_HOME
    CATALINA_HOME=/usr/local/tomcat1 ; export CATALINA_HOME

(Set CATALINA_HOME to /usr/local/tomcat2 in /usr/local/tomcat2/conf/catalina.sh)

3.2 Modify conf/server.xml

3.2.1 Add a unique jvmRoute to the Catalina engine

Near line 100, replace:

    <Engine name="Standalone" defaultHost="localhost" debug="0">

with:

    <Engine jvmRoute="tomcat1" name="Standalone" defaultHost="localhost" debug="0">

For tomcat2, put jvmRoute="tomcat2".

3.2.2 Change the control port

At line 13, replace:

    <Server port="8005"

with:

    <Server port="11005"

For the tomcat2 server, replace port 8005 with 12005. This will prevent the two servers from conflicting.

3.2.3 Change the AJP13 port

At line 75, in the AJP 13 connector definition, replace:

    port="8009"

with:

    port="11009"

For the tomcat2 server, replace port 8009 with 12009.

3.2.4 Disable the standalone HTTP port

We don't want or need our tomcat servers to directly respond to HTTP requests. So we comment out the HttpConnector section between lines and 58 in the server.xml file.

Example:

<!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
<!--
    <Connector className="org.apache.catalina.connector.http.HttpConnector"
               port="8080" minProcessors="5" maxProcessors="75"
               enableLookups="true" redirectPort="8443"
               acceptCount="10" debug="0" connectionTimeout="60000"/>
-->    

NOTE: If you don't comment this out, you will need to change the port numbers so they don't conflict between tomcat instances.

3.2.5 Disable the WARP connector

At line 314, comment out the <Connector...WarpConnector...> tag.

Example:

<Service name="Tomcat-Apache">
<!--
    <Connector className="org.apache.catalina.connector.warp.WarpConnector"
     port="8008" minProcessors="5" maxProcessors="75"
     enableLookups="true" appBase="webapps"
     acceptCount="10" debug="0"/>
-->

Do not forget to do the same thing to tomcat2's server.xml file.

NOTE: You might want to comment out the entire <Service name="Tomcat-Apache"> element. If so, make sure and remove the comments within it - XML doesn't like comments within comments.

3.3 Create test JSP pages (index.jsp)

3.3.1 Create a file named index.jsp and put it in the /usr/local/tomcat1/webapps/ROOT directory:

<html>
<body bgcolor="red">
<center>
<%= request.getSession().getId() %>
<h1>Tomcat 1</h1>
</body>
</html>

3.3.2 Create a file named index.jsp and put it in the /usr/local/tomcat2/webapps/ROOT directory:

<html>
<body bgcolor="blue">
<center>
<%= request.getSession().getId() %>
<h1>Tomcat 2</h1>
</body>
</html>

4. Start Tomcat1, Tomcat2 and Apache

    /usr/local/tomcat1/bin/startup.sh
    /usr/local/tomcat2/bin/startup.sh
    /usr/local/apache2/bin/apachectl start

5. Test your Installation

Now is the time to test your setup. First, verify that Apache serves static content.

Click on: http://localhost/. You should see the default Apache index.html page.

Now test that tomcat (either Tomcat 1 or Tomcat 2) is serving Java Server Pages.

Click on: http://localhost/index.jsp

If you get a red page, the page was served by the tomcat1 server, and if you get a blue page, it was served by the tomcat2 server.

Now test that session affinity - also known as sticky sessions - works within the load balancer. Hit the reload button of your web browser several times and verify that the index.jsp page you get is always received from the same tomcat server.

6. Configuring Private JVMs

If you don't need load-balancing, but you are interested in configuring Apache/Tomcat for private Tomcat instances, you can add one of the following near the end of httpd.conf:

6.1 Name-based (1 IP address or NIC).

NameVirtualHost *

<VirtualHost *>
ServerName localhost1
JkMount /*.jsp tomcat1
JkMount /servlet/* tomcat1
</VirtualHost>

<VirtualHost *>
ServerName localhost2
JkMount /*.jsp tomcat2
JkMount /servlet/* tomcat2
</VirtualHost>

6.2 IP-based (different IP for each site).

# First Virtual Host.
#
<VirtualHost 192.168.0.1:80>
ServerName localhost
JkMount /*.jsp tomcat1
JkMount /servlet/* tomcat1
</VirtualHost>

# Second Virtual Host.
#
<VirtualHost 192.168.0.2:80>
ServerName localhost2
JkMount /*.jsp tomcat2
JkMount /servlet/* tomcat2
</VirtualHost>

Where the serverNames are fully-qualified host names in a DNS Server. More information can be found at http://httpd.apache.org/docs-2.0/vhosts/.

NOTE: When using SSL with multiple Virtual Hosts, you must use an ip-based configuration. This is because SSL requires you to configure a specific port (443), whereas name-based specifies all ports (*). You might the following error if you try to mix name-based virtual hosts with SSL.

[error] VirtualHost _default_:443 -- mixing * ports and non-* ports with a NameVirtualHost address is not supported, proceeding with undefined results

Starting Apache and Tomcat on Startup

To start Apache and Tomcat on startup in a *nix environment, see http://www.raibledesigns.com/tomcat/boot-howto.html.

On Windows, you can install Tomcat as a service.

Supplemental Information

Question 1:
Why did you choose to use the AJP13 connector rather than the WARP connector that is recommended?

Answer:
The warp connector is used in conjunction with mod_webapp, and mod_webapp does not currently support load balancing.

Also, I found the documentation for the warp connector on the Jakarta web site to be quite lacking. See: http://jakarta.apache.org/tomcat/tomcat-4.0-doc/config/warp.html

I know that the future lies in the warp connector, but in the meantime, I needed something. The documentation did not explain to me exactly what benefits I would get from using the Warp connector as opposed to AJP13.

Question 2:
You might specify that creating two instances of the tomcat installation is not needed as you can share the main binaries and libs by specifying 2 distinct CATALINA_BASE variables.

True, but in real life the two tomcat servers are usually located on two different machines. My setup might be overkill for a single machine setup, but it's easy to tar up the "tomcat2" server and put it on a second machine; you just have to change "localhost" to the appropriate machine name in /usr/local/apache2/conf/workers.properties and you're done.

Question 3:
What does not work and what does work in load balancing?

Answer:
Load balancing works great.

1. Session affinity works
Which means that when a client browser is directed to a Tomcat server by the load balancer, then future queries from that same browser session will always be directed to the same tomcat server. This is important because sessions that are created in a specific tomcat server, say "tomcat1", do not exist in the other server "tomcat2", and thus if the client was directed to another tomcat server than the one where his session is stored, then all his session data would be lost.

Some people are working on sessions that will be replicated across all tomcat servers in the cluster, so I'll just wait for it to become available rather than make a homebrewed distributed session mechanism.

The downside of not having sessions replicated across all the tomcat servers in the cluster is that if one tomcat server dies, all the sessions that it contained are lost, which usually makes a lot of unhappy users.

2. Failover works
If one tomcat server dies, the load balancer then "rebalances" the queries to the remaining tomcat servers.

3. Failback works
When a tomcat server comes back from the dead, the load balancer automatically starts to send queries to it. So you can actually add capacity to your cluster on the fly.

4. Weighted load balancing works
In /usr/local/apache2/conf/workers.properties, I assigned a load balancing factor of 100 to both "tomcat1" and "tomcat2" servers. Then I changed the lbfactor of "tomcat1" to 101, and I saw that effectively the "tomcat1" server received more load than the "tomcat2" server, which is something you want when for example your "tomcat1" server is a faster/newer machine while your "tomcat2" server is a slower machine which cannnot take as much load as the other one.

References

For more information, you should read An Apache Load Balancing Cluster. It talks about mod_jserv, which is now mod_jk, and it uses JServ instead of Tomcat, but the concepts are still valid.

Conclusion

The list of steps that are required to obtain a scalable web application solution based on Apache 2.x and a group of distibuted Tomcat servers are well-defined and if you follow the receipe exactly, you should be able to achieve success.

I hope that this article will be helpful to you. Good Luck.

Posted by 1010
01.JAVA/Java2008. 10. 10. 16:58
반응형

JAVA/Advance 2008/09/23 16:08

1 . 다운로드주소 http://james.apache.org/download.cgi
     다운로드파일 : http://apache.mirror.cdnetworks.com/james/server/binaries/james-binary-2.3.1.zip


2. james-binary-2.3.1.zip  파일을 압축 풀고 Path에 추가
  Path = %Path%;C:\kjy\james-2.3.1\bin;

3. C:\kjy\james-2.3.1\bin\run.bat 실행

사용자 삽입 이미지


4. 텔넷 접속 : 새로운 콘솔 창 띄워서 실행
   telnet localhost 4555
사용자 삽입 이미지

5. 로그인
   아이디/패스워드 : root/root

6. 사용자 추가
   adduser [사용자 이름] [패스워드]
    예) adduser test 1234

7. 사용자 추가 확인
    listusers
사용자 삽입 이미지

8. 아웃룩 설정 추가

     새로운 계정을 만들고,
사용자 삽입 이미지

     메일주소는 [사용자이름]@localhost,
사용자 삽입 이미지

     POP3는 localhost ,
     SMTP도 localhost
사용자 삽입 이미지

9. 메일 송수신 확인
사용자 삽입 이미지

추가 : C:\kjy\james-2.3.1\apps\james\SAR-INF\config.xml 설정파일 수정으로 localhost 가 아니 IP로 송수신 가능 함
Posted by 1010
01.JAVA/Java2008. 10. 10. 16:56
반응형

[펌] JavaMail

JAVA/Basic 2008/09/23 14:56

JavaMail 1.4
http://java.sun.com/products/javamail/index.jsp
http://java.sun.com/products/javamail/downloads/index.html

압축풀어서 mail.jar 파일을 %JAVA_HOME%\lib 아래 복사


JavaBeans Activation Framework (JAF)
http://java.sun.com/products/javabeans/jaf/index.jsp
http://java.sun.com/products/javabeans/jaf/downloads/index.html

압축풀어서 activation.jar 파일을 %JAVA_HOME%\lib 아래 복사


classpath 에 mail.jar 와 activation.jar 파일 추가



import java.util.*;
import java.io.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;


public class MailTest {

        public static void main(String[] args)
        throws Exception
        {
                String host =  "SMTP서버";
                String senderemail = "보내는 사람 메일 주소";
                String email = "받는 사람 메일 주소";
                String subject = "제목";
                String mailtext = "<html><body><h1>내용</h1></body></html>";
                String[] attached = {"D:/projects/encyclopedia/java/mail/석양.jpg", "D:/projects/encyclopedia/java/mail/겨울.jpg"};

                sendEmail(host, senderemail, email, subject, mailtext, attached);
        }


        /**
         * send Email.
         *
         * @param       host    메일서버주소
         * @param       from    보내는 사람
         * @param       to              받는사람 - ","로 구분된 메일 주소
         * @param       subject 제목
         * @param       mailtext        내용
         * @param       attached        첨부파일
         * @result      boolean
         * @exception   javax.mail.internet.AddressException
         *                              javax.mail.MessagingException
         */
        public static void sendEmail(String host, String senderemail, String email,
         String subject,String mailtext, String[] attached)
        throws javax.mail.internet.AddressException, javax.mail.MessagingException,
        java.io.UnsupportedEncodingException
        {
                Properties props = new Properties();


                props.put("mail.smtp.host", host);


                Session session = Session.getDefaultInstance(props, null);
                Multipart mp = new MimeMultipart();


                // create a message
                MimeMessage msg = new MimeMessage(session);
                msg.setFrom(new InternetAddress(senderemail));


                // 받는사람
                InternetAddress[] toAddress = InternetAddress.parse(email);
                msg.setRecipients(Message.RecipientType.TO, toAddress);


                // 제목
                msg.setSubject(subject, "euc-kr");


                // 내용
                MimeBodyPart mbp1 = new MimeBodyPart();

                mbp1.setContent(mailtext, "text/html; charset=euc-kr");

                mp.addBodyPart(mbp1);


                System.out.println("host="+host);
                System.out.println("sender="+senderemail);
                System.out.println("receive="+email);
                System.out.println("mbp1="+mbp1);


                // 파일첨부
                if (attached != null) {
                        for (int i = 0; i < attached.length; i++) {

                                MimeBodyPart mbp2 = new MimeBodyPart();

                                FileDataSource fds = new FileDataSource(attached[i]);
                                mbp2.setDataHandler(new DataHandler(fds));

                                mbp2.setFileName(iso8859(fds.getName()));

                                mp.addBodyPart(mbp2);
                        }
                }


                // 메시지 add
                msg.setContent(mp);


                // header 에 날짜 삽입
                msg.setSentDate(new Date());


                // send the message
                Transport.send(msg);
        }


        public static String iso8859(String strStr)
        throws java.io.UnsupportedEncodingException
        {
                if (strStr == null)
                {
                        return  null;
                }
                else
                {
                        return new String(strStr.getBytes("KSC5601"), "8859_1");
                }
        }
}

Posted by 1010
06.Ajax2008. 10. 9. 15:59
반응형
Posted by 1010
61.Linux2008. 10. 6. 17:31
반응형

fdisk /dev/sda

The number of cylinders for this disk is set to 4462.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
   (e.g., DOS FDISK, OS/2 FDISK)

Command (m for help): p

Disk /dev/sda: 36.7 GB, 36703934464 bytes
255 heads, 63 sectors/track, 4462 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1          16      128488+  83  Linux
/dev/sda2              17         147     1052257+  82  Linux swap
/dev/sda3             148        4462    34660237+  83  Linux

Command (m for help): q

위에서 진한글씨가 명령어구요

주홍색 글씨가 용량이죠^^;

참고로 파티션 정보를 확인해 보세요~~

Posted by 1010
99.유용한정보/잡식2008. 10. 2. 14:33
반응형

출처 : http://sazabis.egloos.com/628144


집에서 만든 CPU로 서버 운영?


[세계일보 2005-09-19 13:57]





직접 만든 중앙처리장치(CPU)로 텔넷 서버를 운영하는 한 마니아가 해외 네티즌들 사이에서 화제다.

화제의 주인공은 ''매직-1 홈브루 CPU(Magic-1 homebrew CPU, www.homebrewcpu.com)''를 개발한 빌 버즈비(Bill Buzbee·미국 캘리포니아)씨. 버즈비씨가 개발한 이 것은 74시리즈 TTL 집적회로 200여개를 전선으로 엮어 만든 ''중앙처리장치''다.


그가 만든 CPU는 크기나 외형만으로 볼 때는 ''컴퓨터''를 닮았다. 그러나 완전한 하드웨어 어드레스 및 메모리 I/O, 그리고 DMA 구조를 가지고 있으며 3Mhz로 동작하는 CPU다. 16비트 어드레스에서 8비트 와이드 데이터버스로 동작하고, 각 프로세스마다 128Kb 어드레싱이 가능하다. CPU 전체는 74LS와 74F 시리즈 TTL 집적회로 200여개, S램, 그리고 구형 바이폴라 프로그래밍 롬(bipolar PROM) 등으로 구성됐다. 개인용 컴퓨터에 탑재되고 있는 인텔 펜티엄이나 AMD 애슬론 마이크로프로세서 역시 집적도와 설계의 차이가 극명하긴 하지만 근본적으로 이 같은 논리 구조의 집적체다.


컴파일러 전문가인 버즈비씨는 지난 2001년 말부터 컴퓨터 구상을 시작해 지난 5월에 전체 설계를 끝내고 최근 이를 탑재한 텔넷 서버를 본격 가동하기 시작했다. 그는 이를 위해 인스트럭션 세트, 집적회로 배선, 어셈블러. 컴파일러, 링커, 텍스트 에디터, 운영체제까지 모두 직접 만들었다.


사실 그는 설계 당시에 CPU의 구조에 대해서 잘 알지 못했다고 한다. 대학 시절에도 전자 회로 관련 과목에는 관심이 없었다. 그가 결정적으로 CPU를 만들겠다고 마음먹은 것은 한 친구가 건네 준 오래된 잡지 한 권 때문이다. 이 잡지에는 CPU와 관련된 흥미로운 글이 실려 있었다.


2001년 12월부터 프로세서 개발 일지를 쓰기 시작한 버즈비씨는 여러 차례의 시행 착오 끝에 2003년 5월 지금의 ''매직-1'' 골격이 된 시뮬레이터를 구상했다. 이어 C언어를 통한 피보나치(Fibonacci) 수열 알고리즘 구현에 성공했다. 결국 2004년 10월 매직-1은 시스템 성능 테스트인 드라이스톤(Dhrystone) 점수가 384(0.25MIPS)점에 이르게 된다. 이어 지난 5월 13일 매직-1의 하드웨어 설계가 마무리됐다.


버즈비씨는 차기버전 ''매직-2''는 개발하지 않겠다고 선언했다 그러나 그는 "FPGA, 16비트 파이프라인 RISC, 리얼타임 OS(MicroC-OSII) 등을 특징으로 한 ''매직-16''을 구상하고 있다"고 밝혔다.


현재 20Mb, 30Mb짜리 1.3인치 마이크로드라이브 2대가 장착된 ''매직-1'' 시스템은 네티즌들에게 무료로 간단한 텔넷 서비스(telnet://magic-1.org)를 제공한다. 텔넷 방명록에는 해외 각국에서 소문을 듣고 찾아온 마니아들의 글 수십 여개가 그를 응원하고 있다. 네티즌들은 대부분 "멋진 작업이다" "확실히 신선한 프로젝트다" "정말 충격적이다. 정말 대단하다"며 엽기 시스템에 대한 찬사를 보냈다.


세계일보 인터넷뉴스팀 서명덕기자 mdseo@segye.com

보도자료 및 제보 bodo@segye.com


------------------------------------------------------------------


대단합니다..

빌 버즈비 씨, 당신의 노력과 탐구심.


멋집니다. +_+b


Carpe Diem!
Posted by 1010
반응형

그냥 메일로만 써오던 Gmail의 엄청난 용량을 웹하드처럼 쓸수있는 프로그램이 있습니다.


지금 2008년 9월 21일 기준으로 용량이 7.1GB네요... ㅎㅎ
써도써도 용량이 10%를 안넘어가요

그럼 그 프로그램이 어떤 놈이냐

프로그램 이름은 GmailFS입니다.

하단에 첨부된 파일을 받으셔서 설치를 하시면 아래와 같은 창이 뜨면서

Gmail Driver 라는걸 깔게 됩니다.


그리고는 별 반응이 없어요.. 뭥미..?? 끝?

네 끝 맞습니다.

이제 윈도우 탐색기를 엽니다

그럼 아래와 같이 드라이버중에 Gmail Driver 가 생겼을겁니다

이 드라이브를 선택하면



여기에서 지금까지 써오던 Gmail ID와 PW를 입력하고 OK를 누릅니다

MORE버튼은 누르실 필요없어요 프록시 서버와 관련된거라..


로그인을 하시면 위와 같은 접속 중 창이 뜨다가 오른쪽 화면(폴더내용)에는 아무것도 없게 나오죠

당연한겁니다 이건 메일을 읽는 프로그램이 아니고 웹하드입니다

이제 파일을 올리려면 그냥 파일을 끌어다가 올리기만 하면 됩니다

근데 Gmail이 국내 메일보다 좀 느린점때문에 이것도 느리네요


나훈아님의 땡벌을 올려보겠습니다..

그리고 확인은 Gmail 읽은 편지함에서 확인합니다.

주의하실건 Gmail을 인터넷에서 열기전에 윈도우 탐색기를 닫아주셔야 합니다

동시에 열면 이중 로그인이 되기 때문입니다.



받은편지함을 보시면 첨부파일로 메일이 와있고 보낸사람은 "나"로 되어있습니다.

그리고 더 재미(?)있는건 윈도우 탐색기에서 방금 지웠던 땡벌 을 지우면

받은 편지에서도 같이 지워진다는거.. ㅎㅎ

일반 웹하드와 틀린점을 전혀~찾을수가 없군요 ㅋ

마지막으로 파일 올려드립죠~

Posted by 1010
61.Linux2008. 10. 2. 11:43
반응형

서버점검사항
1. SUID 점검하기.(root 소유의 SetUID및 SetGID 파일들 점검

     find / -user root -perm -4000 -print (SetUID)
     find / -user root -perm -2000 -print (SetGID)
     find / -user root -perm -4000 -print -xdev

2. 파티션별 디스크사용량 점검
     df -h

3. 파일무결성 점검.

    
http://weblog.websea.co.kr/tripwire/tripwire

4. 백도어 설치여부 점검.(/dev 체크 및 rootkit 점검)

     find /dev -type f -exec ls -l {} ;
     ./chkrootkit
    
5. 현재 열려진 포트 및 응답가능한 포트 점검.

     netstat -atp | grep LISTEN (사용 프로토콜 : TCP인가? 또는 UDP인가?
   사용중인 포트번호
   서버와 연결된 IP 및 도메인명
   생성 PID
   서비스중인 프로세스명
   현재 응답가능상태인가?
     lsof | grep LISTEN(현재 서비스 중인 프로세스명(데몬명)
       현재 생성중인 PID번호.
   현재 서비스중인 프로세스의 소유자
   프로토콜 버전 : Ipv4 또는 Ipv6
   TCP 또는 UDP의 여부
   응답가능 상태인가?

6. 실생중인 프로세스 및 데몬점검.(프로세스의 생성관계)

     pstree

7. 시스템 운용상황 점검.

    top -d2

8. 백업점검.

    /home2/backup/nexfor/
    /home2/backup/websea/

9. 스팸메일 점검.(메일큐 디렉토리 점검)

   /var/spool/mqueue    (동일한 날짜, 동일한 사이즈를 가진 다수 파일구분)

10. Core 점검.

  서버내에 긴급한 이상이 발생하였을 경우나 시스템의 정확한 분석을 위해
  서버의 메모리 상태를 순간적으로 dump 받는 경우의 파일
   find / -name core -exec ls -l {} ;
  
11. 파일용량 점검

  repquota -av -ag
  df -h

12. 최근 서버 접속자 점검.

   vi /var/log/secure
   last -n 10  최근 10번째까지의 접속기록을 확인.

13. 계정별 최후접속기록 점검.

   lastlog는 현재 /etc/passwd에 존재하는 모든 계정을 대상으로 하
여 언제 마지막으로
   서버에 접속을 했는가를 확인.
   Mail, adm, bin 등의 계정들은 모두 "** Never logged in **" 이라
고 되어 있는것이 정상.

   lastlog

14. 현재 서버접속자 보기

    w (telnet)
    ftpwho(ftp)

15. root명령어 사용기록 점검.

   vi /root/.bash_history  (.set nu)
   cat /root/..bash_history | wc -l    (1000라인 이상 되어야 정상)

16. 계정별 사용명령어파일 점검.

   find / -name .bash_history -exec ls -l {} ;    (각 계정
별 .bash_history 파일의 존재여부)
   find / -name .bash_history -exec cat {} ;     (파일의 내용까
지 모두 확인해 볼 수 있음)

17. root소유자 점검(UID와 GID가 0인 사용자 점검)

   cat /etc/passwd | grep 0:0

18. 서버내에 중요한 디렉토리 점검

   /etc/xinetd.d/    (xinetd로 서비스되는 인터넷서비스 파일들이 존재하는 디렉토리)
   /etc/rc.d/           (부팅에 관계된 파일) (파일들을 복사 후 파일용량등을 비교하기) (커널패닉의원인)
   /etc/rc.d/init.d/ (부팅시에 특정 서비스나 데몬들을 시작시키는 스키립트 파일)

19. .rhosts 파일 점검

   원격에서 패스워드등의 확인과정없이 바로 접속하기 위해서 사용되는 파일
  
   find / -name .rhosts -exec ls -l {} ;
   find / -name .rhosts -exec cat {} ;

20. 메모리사용량 점검.

   free -m
   cat /proc/meminfo   (free 와 top 는 이 파일을 참조하여 보여준다.)
   top -d2

21. 중요 관리자용명령어 점검.

   아래의 명령어들을 퍼미션을 100으로 설정한다. 변경 후 퍼미션 변경여부를 확인.
  
   chmod 100 /usr/bin/top
   chmod 100 /usr/bin/pstree
   chmod 100 /usr/bin/w
   chmod 100 /bin/ps
   chmod 100 /usr/bin/who
   chmod 100 /usr/bin/find
   chmod 100 /bin/df
   chmod 100 /bin/netstat
   chmod 100 /sbin/ifconfig
   chmod 100 /usr/sbin/lsof
   chmod 100 /usr/bin/make
   chmod 100 /usr/bin/gcc
   chmod 100 /usr/bin/g++
   chmod 100 /usr/bin/c++

22. su 명령어를 이용한 root권한 사용자 점검.

   su 명령어의 사용내역을 확인할 수 있음.

   cat /var/log/messages | grep root

23. 최근 n 일전 변경된 파일 점검. (단위는 일)

   find / -ctime -1 -print | more

24.
http://weblog.websea.co.kr/

25. find 를 이용한 특정파일 점검하기.

   .exec 파일찾기
   find / -name '.exec' -exec cat {} ; -print

   .forward 파일체크
   find / -name '.forward' -exec cat {} ; -print

   write 퍼미션이 있는 파일(디렉토리)찾기
   find / -type f  ( -perm -2 -o -perm -20 ) -exec ls -lg {} ;
   find / -type d ( -perm -2 -o -perm -20 ) -exec ls -ldg {} ;

   SteUID SetGID 체크하기
   find / -type f ( -perm -004000 -o -perm -002000 ) -exec ls -lg {} ;

   /dev 체크
   find /dev -type f -exec ls -l {} ;

   소유자없는 파일 및 디렉토리 찾기
   find / -nouser -o -nogroup -print

   원격리모트 접속허용 파일(.rhosts)찾기
   find / -name .rhosts -print

   최근 변경된 파일들 찾기.(파일or디렉토리) 단위는 일
   find / -ctime -20 -type f or d

   현재 서버에서 열려진 포트 및 접근저보 점검

   netstat -an | grep LISTEN   (포트들과 열결되어 있는 실행데몬들을 확인)
   lsof | grep LISTEN   (좀 더 자세히 확인)

26. 관리자용 명령어 퍼미션 수정하기.

   chmod 100 /usr/bin/top
   chmod 100 /usrbin/pstree
   chmod 100 /usr/bin/w
   chmod 100 /bin/ps
   chmod 100 /usr/bin/who
   chmod 100 /usr/bin/find
   chmod 100 /bin/df
   chmod 100 /bin/netstat
   chmod 100 /sbin/ifconfig
   chmod 100 /usr/sbin/lsof
   chmod 100 /usr/bin/make
   chmod 100 /usr/bin/gcc
   chmod 100 /usr/bin/g++
   chmod 100 /usr/bin/c++

27. 중요한 파일퍼미션과 소유권 제한 및 점검.

   chmod 644 /etc/service
   chmod 600 /etc/xinetd
   chmod 644 /etc/mail/aliases
   chmod 600 /etc/httpd/conf/httpd.conf
   chmod 644 /var/log/wtmp
   chmod 644 /var/run/utmp
   chmod 644 /etc/motd
   chmod 644 /etc/mtab
   chmod 600 /etc/syslog.conf
  
   /etc, /usr/etc, /bin, /usr/bin, /sbin, /usr/sbin

   chmod 1777 /tmp
   chmod 1777 /var/tmp
  
28. umask 값 확인하기.

   root의 umask 값 확인하기.
   umask
   022 -->파일은 644 디렉토리는 755로 생성됨.
   027 -->파일은 640 디렉토리는 750로 생성됨.

29. /dev 에 device 파일 이외의 것이 존재하고 있는지 확인.

   find /dev -type f -exec ls -l {} ;

30. 일반사용자의 명령어 패스

   /usr/local/bin:usr/local/mysql/bin:/home/hosting/bin/
   일반사용자가 사용가능한 명령어를 모두 이것에 둠.

31. 관리자의 명령어 패스

   :/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/bin

   /X11:/usr/X11R6/bin:/usr/kerberos/bin:/root/bin

32. 특정 그룹만의 su 사용권한 허용하기

   vi /etc/group  (wheel구릅에 su 사용권한을 가질 유저 추가하기)
   wheel:x:10:root,cream

   vi /etc/pam.d/su (두줄 추가하기)

   auth   sufficient   /lib/security/pam_rootok.so
   auth   required      /lib/security/pam_wheel.so allow group=wheel

   vi /var/log/message 에서 확인

33. chmod 400 /etc/shadow

34. 시스템 기본로그파일.

   /var/log/messages
   /var/log/secure
   /var/log/wtmp
   /var/run/utmp
   /var/log/lastlog

35. utmp, wtmp, lastlog 파일

   utmp파일 : 현재시스템에 접속해 있는 사용자의 정보를 가지고 있음.
  
   strings utmp | more
  
   정보 이용 명령어
   login(1), who(1), init(8), last(8), lastcomm(8)

   wtmp파일 : 처음부터 접속했던 모든 사용자의 로그인정보와 로그아웃정보를 가지고 있음.

   strings wtmp | more

   정보 이용 명령어
   login(1), who(1), init(8), last(8), lastcomm(8)

   lastlog 파일

   가장 최근에 로그인한 정보를 저장함.

   last 라는 명령어로 확인할 수 있음.

36.  패스워드 유출대처방안(웹)

   perl을 이용한 방법.


    AllowOverride FileInfo AuthConfig Limit
    Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
    Options Indexes SymLinksIfOwnerMatch IncludesNoExec ExecCGI
    Options Indexes SymLinksIfOwnerMatch IncludesNoExec
   
        Order allow,deny
        Allow from all
   
   
        Order deny,allow
        Deny from all
   


   SSI의 exec 명령어를 이용하는 방법

#    AddType text/html .shtml
#    AddHandler server-parsed .shtml

27. PortSentry를 이용한 실시간 해킹방어 구현.(잘못 사용할시 서버접속 안됨)

   tar -xvzf portsentry-1.1.tar.gz
   make linux
   make install

   /usr/local/psionic/portsentry/portsentry -tcp
   /usr/local/psionic/portsentry/portsentry -udp
   /usr/local/psionic/portsentry/portsentry -stcp
   /usr/local/psionic/portsentry/portsentry -atcp
   /usr/local/psionic/portsentry/portsentry -stdp

   vi /etc/hosts.deny 점검.

28. Chkrootkit 로 백도어 점검.

   tar -xvzf chkrootkit.tar.gz
   make sense
   ./chkrootkit     (점검명령어)

29 ping 을 이용한 DOS 공격 막는 방법.

   vi  /etc/sysctl.conf
   net.ipv4.icmp_echo_ignore_broadcasts = 1

   sysctl -w
   /etc/rc.d/init.d/network restart
   sysctl -a | grep ignore_broadcasts

30. Nmap를 이용 포트스켄 하여 해킹가능성 체크.

   nmap -sS -p80 211.42.48.110 -O -v www.armian.net
   nmap -sS -O -v 211.42.48.114

출처 :
http://blog.empas.com/jjh7266/2886273 망구블로그
Posted by 1010
56. Eclipse Etc.../Eclipse2008. 9. 29. 09:47
반응형

지난 6월말 이클립스의 3.4 버전 가니메데가 릴리스되었다. 가니메데는 이전 배포판인 칼리스토, 유로파와 마찬가지로 목성의 위성 이름이다. 가니메데는 이전 버전인 유로파보다 많은 23개의 프로젝트로 구성되어 있다. 많은 기능이 추가되고 개선되었지만 자바 개발자에게 필요한 기능 위주로 가니메데의 기능을 알아본다.

 

시작하기 전에

새로운 기능을 알아보기 전에 윈도 운영체제 사용자들이 겪을 치명적인 문제를 포함한 몇 가지 문제점과 가능한 해결책을 간략히 알아본다.

  1. 이클립스가 실행 되지 않는 문제

    다운받은 가니메데 배포판의 종류에 따라서 ECLIPSE_HOME/eclipse.ini 파일에 기록된 메모리 크기 관련 설정값이 다르다. 보통은 윈도 버전의 이 클립스에서 메모리 부족 때문에 나타나는 현상으로 Java EE 버전이나 플러그인 개발 버전을 다운 받았다면, eclipse.ini 파일의 -Xmx512m를 – Xmx256으로 수정한다.

  2. 한글 깨짐 현상

    일부 영문 전용 폰트에서 한글 깨짐 현상이 발생한다. 대표적으로 많은 개발자의 사랑을 받고 있는 ‘Bitstream Vera Sans Mono’을 이용하면 문제를 확인할 수 있다. 임시방편으로 영문 전용 폰트에 한글 폰트를 추가해 새로운 폰트를 만들어 사용하는 방법이 있다.

 

자바 개발환경 개선사항

새로운 리팩터링

자바 리팩터링에 ‘Extract Class(클래스 추출)’가 추가됐다. Extract Class는 한 클래스가 너무 많은 책임을 수행할 때, 책임을 다른 클래스로 분리하는 리팩터링이다.

리팩터링 책의 예제를 활용해보자. <리스트 1>은 리팩터링 전의 Person 클래스로 간단하지만 개인 정보와 연락처 정보 관리라는 두 가지 책임을 가진다. Extract Class로 연락처 관리의 책임을 추출해보자.

 

<리스트 1>Extract Class 리팩터링을 적용하기 전 Person 클래스

  1. package refactoring;  
  2.   
  3. public class Person {  
  4.   private String name;  
  5.   private String officeAreaCode;  
  6.   private String officeNumber;  
  7.   
  8.   public String getName() {  
  9.    return name;  
  10.   }  
  11.   
  12.   public void setName(String name) {  
  13.    this.name = name;  
  14.   }  
  15.   
  16.   public String getOfficeAreaCode() {  
  17.    return officeAreaCode;  
  18.   }  
  19.   
  20.   public void setOfficeAreaCode(String officeAreaCode) {  
  21.    this.officeAreaCode = officeAreaCode;  
  22.   }  
  23.   
  24.   public String getTelephoneNumberNumber() {  
  25.    return "( " + officeAreaCode + ") "+ officeNumber;  
  26.   }  
  27.   
  28.   public String getOfficeNumber() {  
  29.    return officeNumber;  
  30.   }  
  31.   
  32.   public void setOfficeNumber(String officeNumber) {  
  33.    this.officeNumber = officeNumber;  
  34.   }  
  35. }  

 

먼저 Extract Class 메뉴를 선택한다. 최상단 메뉴나 <화면 1>과 같이 편집기 의 오른쪽 마우스 컨텍스트 메뉴에서 Refactor -> Extract Class를 선택한다.

 

<화면 1>Extract Class 메뉴 선택

 

Extract Class 메뉴를 선택하면 <화면 2>와 같이 설정 다이얼로그가 나온다. 설정 다이얼로그에서는 추출 대상 필드를 선택하고, 추출할 클래스 이름과 추출한 클래스의 객체를 참조할 필드 이름을 지정한다. 여기서는 연락처 정보와 관련된 officeAreaCode와 officeNumber 필드를 Telephone 클래스로 추출한다. Person 클래스가 참조하는 Telephone 클래스 인스턴스의 이름은 telephone으로 설정한다.

 

<화면 2>Extract Class 설정 다이얼로그

 

<리스트 2>와 <리스트 3>의 코드 로 리팩터링되었다. 위에서 선택한 두 필드를 가지고 있는 Telephone 클래스가 생성되었고, Person 클래스는 Telephone 클래스의 인스턴스를 필드로 가지고 이를 참조하도록 변경되었다. 이클립스가 자동으로 처리해주는 리팩터링 기능에서 특히 클래스간의 관계를 다루는 리팩터링에 대한 처리가 미흡한 편인데 편리한 리팩터링이 하나 더 추가되었다.

 

<리스트 2>Extract Class 리팩터링 적용 후 Person 클래스

  1. package refactoring;  
  2.   
  3. public class Person {  
  4.     private String name;  
  5.     private Telephone telephone = new Telephone();  
  6.   
  7.     public String getName() {  
  8.         return name;  
  9.     }  
  10.      
  11.     public void setName(String name) {  
  12.         this.name = name;  
  13.     }  
  14.      
  15.     public String getOfficeAreaCode() {  
  16.         return telephone.getOfficeAreaCode();  
  17.     }  
  18.      
  19.     public void setOfficeAreaCode(String officeAreaCode) {  
  20.         this.telephone.setOfficeAreaCode(officeAreaCode);  
  21.     }  
  22.      
  23.     public String getTelephoneNumberNumber() {  
  24.         return "( " + telephone.getOfficeAreaCode() + ") "+ telephone.getOfficeNumber();  
  25.     }  
  26.      
  27.     public String getOfficeNumber() {  
  28.         return telephone.getOfficeNumber();  
  29.     }  
  30.      
  31.     public void setOfficeNumber(String officeNumber) {  
  32.         this.telephone.setOfficeNumber(officeNumber);  
  33.     }  
  34. }  

 

<리스트 3>Extract Class 리팩터링 적용 후 Telephone 클래스

  1. package refactoring;  
  2.   
  3. public class Telephone {  
  4.     private String officeAreaCode;  
  5.     private String officeNumber;  
  6.   
  7.     public Telephone() {  
  8.     }  
  9.   
  10.     public String getOfficeAreaCode() {  
  11.         return officeAreaCode;  
  12.     }  
  13.   
  14.     public void setOfficeAreaCode(String officeAreaCode) {  
  15.         this.officeAreaCode = officeAreaCode;  
  16.     }  
  17.   
  18.     public String getOfficeNumber() {  
  19.         return officeNumber;  
  20.     }  
  21.   
  22.     public void setOfficeNumber(String officeNumber) {  
  23.         this.officeNumber = officeNumber;  
  24.     }  
  25. }  

 

Breadcrumb

자바 편집기 영역에 추가된 기능 중 단연 돋보이는 기능은 ‘Breadcrumb’다. 노트북 등 화면이 크지 않은 환경에서 개발할 때는 편집기 영역을 최대화(커맨드 + M)해서 작업하는 경우가 많은데, Breadcrumb를 통해 현재 위치를 한눈에 볼 수 있고, 편집기의 최대화를 해제하고 ‘Package Explorer (패키지 탐색기)’등을 이용해서 다른 파일을 열어야 하는 불편함을 해소한다.

사용법은 정말 간단한데 화면 상단 툴바의 ‘Toggle Breadcrumb’를 선택하거나, <화면 3>과 같이 편집기의 컨텍스트 메뉴 중 ‘Show in Breadcrumb’를 선택하면 된다. 컨텍스트 메뉴에서 Breadcrumb를 비활성화 시킬 수 있는 방법은 없으니 참고하자. Breadcrumb를 비활성화 시키려면 상단 툴바의 토글 버튼을 이용하자.

 

<화면 3> Breadcrumb 활성화

 

Breadcrumb가 활성화되면 <화면 4>와 같이 편집기 상단에 현재 위치를 표시해주는 표시영역이 생긴다. 이 영역을 통해 최대화 상태의 편집기에서도 현재 위치를 한눈에 볼 수 있고, 최대화 상태에서도 편리하게 다른 파일을 열 수 있다.

<화면 4>Breadcrumb의 활성화와 다른 클래스로 이동하기

 

향상된 Call Hierarchy

이클립스를 사용하는 자바 개발자에게 인기 좋은 기능 중 하나가 ‘Call Hierarchy (호출 계층)’를 살펴보는 기능으로 호출 관계가 복잡한 함수의 호출 관계를 트리 구조로 보여준다. 이클립스 3.3까지는 호출자(caller)를 찾을 때, 특정 함수나 생성자를 사용하고 있는 함수를 찾는 기능만을 제공했다.

이 정도로도 편리한 기능이지만 코드에 존재하지 않는 기본 생성자를 호출해서 객체를 생성하는 위치를 찾으려면, 기본 생성자를 코드에 추가해서 찾아야 하는 단점이 있었다. 또, 상수나 필드를 사용하는 위치를 찾는 기능은 없기 때문에 검색 기능을 이용해서 찾아야 하는 불편함이 있었다.

이클립스 3.4에서는 클래스를 선택하고 ‘Call Hierarchy’를 찾아보면(CTRL + ALT + H) 모든 생성자를 호출하는 위치를 찾아준다. 기본 생성자가 코드 상에 존재하지 않아도 찾아주니 편리하다. 또, 상수나 필드를 사용하는 위치도 ‘Call Hierarchy’를 통해 보여주니 더 이상 불편하게 검색하지 않아도 된다. <화면 5>과 같이 모든 생성자와 상수에 대한 호출 계층을 확인할 수 있다.

 

hierarchy1.jpg

hierarchy2.jpg

 <화면 5>향상된 Call Hierarchy. 모든 생성자의 호출 위치(상단)과 필드나 상수의 사용 위치(하단)를 확인할 수 있다.

실행 가능한 JAR 파일 내보내기

기존의 이클립스의 내보내기(Export) 기능에 실행 가능한 JAR(Runnable JAR) 파일을 내보낼 수 있는 기능이 추가되었다. 이를 통해 자바 실행 환경(Java Runtime Environment, JRE)이 설치 되었다면 JAR 파일을 더블클릭하는 것만으로 애플리케이션을 실행할 수 있다.

<리스트 4>는 “Hello Ganymede!”라는 메시지를 화면에 출력하는 단순한 자바 스윙 애플리케이션이다. 이 예제를 실행 가능한 형태의 JAR 파일로 배포해보자.

 

<리스트 4> main() 함수를 가지는 단순한 스윙 예제

  1. package runnable;  
  2.   
  3. import javax.swing.JFrame;  
  4. import javax.swing.JLabel;  
  5.   
  6. public class HelloSwing extends JFrame {  
  7.   
  8.   public HelloSwing() {  
  9.    setTitle("Eclipse 3.4 Ganymede");  
  10.    getContentPane(). add(new JLabel("Hello Ganymede!"));  
  11.    setSize(250, 100);  
  12.   }  
  13.   
  14.   public static void main(String[] args) {  
  15.   new HelloSwing().setVisible(true);  
  16.   }  
  17. }  

 

<화면 6> 실행 가능한 JAR 파일 내보내기

‘File -> Export -> Java -> Runnable JAR file’옵션을 통해 실행 가능한 JAR 파일을 생성할 수 있다. 먼저, Launch Configuration 중에서 JAR 파일을 생성할 대상을 선택한다. 선택한 대상이 MANIFEST.MF 파일에서 Main-Class로 이용된다. 대상 경로와 파일이름을 선택하면 실행 가능한 파일을 생성한다. 생성된 JAR 파일을 더블클릭하면 <화면 7>과 같이 애플리케이션이 실행된다.

 

<화면 7>JAR로 실행한 애플리케이션

 

<리스트 5>와 같이 자동 생성된 MANIFEST.MF 파일 은 이전에도 사용자가 직접 작성할 수 있었다. 하지만 이클립스는 단지 MANIFEST.MF 파일을 자동 생성해주는 기능 이상을 제공한다.

 

<리스트 5>자동 생성된 MANIFEST.MF 파일

  1. Manifest-Version: 1.0  
  2. Class-Path: .  
  3. Main-Class: runnable.HelloSwing  

 

예제는 외부 라이브러리를 사용하지 않으니 그리 복잡하지 않지만, 만약 애플리케이션을 구동하는 데 수많은 이클립스 프로젝트에 대한 참조와 라이브러리 파일이 필요하다면 사용자가 직접 작업하기에는 꽤나 복잡해진다. 그래서 이클립스의 실행 가능한 JAR파일 생성 기능은, 참조하는 프로젝트의 모든 클래스 파일과 포함된 모든 라이브러리의 압축을 해제한 클래스 파일을 함께 묶어주는 기능을 제공한다. 사용자는 압축을 해제한 형태로 라이브러리를 재배포하는 것이 라이센스를 위반 하는지만 주위를 기울이면 된다.

 

Outline 화면에서 코드 재배열하기

개요(Outline) 화면에서 코드의 구성 요소의 위치를 재배열 할 수 있는 기능이 이클립스 3.4에 조용히 추가되었다. 작업 중 추가한 한 뭉치의 코드에서 구성 요소간의 순서가 마음에 들지 않으면 하나씩 잘라내서 원하는 위치에 붙여넣는 작업을 반복하게 된다. 이제 개요 화면 에서 한눈에 전체 구조를 보면서 드래그 앤 드롭 기능을 이용해서 코드를 재배열 할 수 있다. <화면 8>에서 자바 메서드의 드래그 앤 드롭을 통한 위치 이동을 보여준다.

 outline1.jpg

outline2.jpg

<화면 8> Outline에서 구성 요소의 드래그 앤 드롭

 

이때, Outline의 자동 정렬 기능 을 이용 중이라면 드래그 앤 드롭은 동작하지 않는다. 특정 요소의 위치를 옮길 때 요소와 요소 사이의 빈 줄 삽입 여부가 의도한 대로 처리되지 않을 수 있으니 처리가 필요하다면 주의하자. Outline에서의 재배치 기능은 자바 에디터뿐 아니라 XML 에디터에서도 지원한다. 앞으로 다양한 에디터 환경에서 지원할 것으로 기대된다.

 

리치 호버

특정 요소 위에 마우스를 가져다 두면 나타나는 JavaDoc 설명을 보여주는 것과 같은 호버 기능이 향상되었다. JavaDoc 호버는 <화면 9>의 상단 화면과 같이 JavaDoc 화면에서 보기, 외부 브라우저에서 보여주기 등 더 풍부한 기능을 제공한다. 리치 호버 기능이 정말 유용하게 사용되는 때는 디버그 상황에서다. <화면 9>의 하단 화면에서 볼 수 있듯이 복잡한 자료구조에 대한 값도 한 눈에 볼 수 있는 기능을 제공한다. 예전처럼 Variables 화면을 뒤지거나, Expressions 화면에 표현식을 입력해 봐야 하는 불편함이 해소되었다.

 hover1.jpg

hover2.jpg

<화면 9> 향상된 호버 기능. JavaDoc 호버(상단)와 디버거 호버(하단)

 

저장 기본 동작 정의

아무리 팀에서 코드 형식을 정해놓고, 이클립스 자동 포맷에 맞춰서 만들어 두어도 자신만의 스타일에 익숙하다면 종종 잊어버리곤 한다. 또, 개발과정 중에 사용하다 남은 불필요한 Import 잔재를 한번에 없애고 싶지만 자동으로 처리해 주지 않으면(Organized Import 기능이 자동으로 처리해 주지만, 직접 명령을 수행해야 한다.) 역시 잊어버리기 쉽다.

이런 요구를 충족해 주는 기능으로 Save Actions 기능이 추가됐다. ‘Windows (윈도) /Eclipse (맥) -> Preferences -> Java -> Editor -> Save Actions’를 보면 저장 시 자동으로 문서 포맷 맞추기, 불필요한 Import 구문 정리하기 등의 기능을 제공한다. <화면 9>와 같이 저장 시 실행할 행동을 정의할 수 있으며, 문서 정렬은 전체 문서에 저장할 것인지 수정된 영역에만 적용할 것인지를 지정할 수 있다.

save.jpg

<화면 10 >저장 시 함께 처리할 행동 정의

 

Launch Configuration 내보내기/들여오기

Import(가져 오기)/Export(내보내기) 메뉴에 추가된 기능으로 그 동안의 실행 설정(Launch Configuration)을 XML 파일로 저장하고, 저장된 XML 파일을 가지고 오는 기능이 추가됐다.

이 설정은 JDK 버전을 여러 버전으로 맞춰놓고 작업하는 것(컴파일 레벨의 변경이 아니라 실제 JRE를 대체하면 전부 재빌드를 수행하므로 하나의 작업공간에서 모두 처리하기에는 번거롭다)과 같은 이유 등으로 이클립스를 여러 개 설치해 놓고 작업 하거나 작업 공간을 다시 구축해야 하는 경우 매번 복잡한 실행 설정을 하지 않아도 되기에 유용하다.

 

그 외 자바 개발 환경 개선사항

개발 중인 애플리케이션의 모든 메시지를 별도의 리소스 파일로 따로 뽑아서 관리한다면, 문자열 하나를 찾기 위해 키 값을 찾고, 리소스 파일을 열어서 다시 해당 키값으로 찾아가는 과정이 번거롭게 느껴진다. 가니메데에 새로 추가된 기능으로 리소스 파일로 바로 찾아가는 기능이 추가됐다.

이제 자바 빌드에서 멀티 코어 CPU를 지원한다. 기존의 프로젝트를 이클립스 3.4와 이전 버전의 이클립스에서 모두 새로 빌드해서 체감속도 향상을 느껴보자.

JUnit 테스트를 실행하면 이제 테스트케이스 별로 실행시간을 각각 표시해 준다. 오래 걸리는 테스트케이스를 따로 관리할 때 유용하다.

또, Content Assist 기능, Quick Fix 기능 등 에디터 영역이 전반적으로 편리해졌다.

 

자바 개발 환경외 주요 변경사항

여기서 다루는 내용은 이클립스 3.4의 자바 개발환경에서의 변경과 개선사항이지만, 자바 개발 환경 이외의 주요한 몇 가지 사항은 알아둘 가치가 있다. 물론 자바 개발과 관련 없는 가장 큰 변경 사항은 화려해진 시작 화면(스플래시 이미지)이다.

새로운 설치 /업데이트 서비스 – p2

기존에 업데이트 매니저를 이용해 플러그인을 설치하던 사용자라면 바로 알아차렸을 텐데, 이클립스의 플러그인 설치/업데이트 기능이 단순히 UI만 변경된 것이 아니라 완전히 새로 변경되었다.

다운로드 자동 재시도, 적합한 미러 자동 선택하기 등의 개선 사항이 있지만 무엇보다도, 기존 사용자들이 가장 불만을 가지고 있던 부분인 버전 의존성 확인 부분이 크게 개선되었다.

이클립스 소스 코드 보고 베끼기 - 플러그인 스파이

이클립스 3.4의 플러그인 개발 환경(Plug-in Development Environment, PDE) 에서 가장 눈에 띄는 기능은 ‘플러그인 스파이 (Plug-in Spy)’다. 이클립스를 사용하다 보면 플러그인 개발 자가 아닐지라도 , 어떻게 구현됐는지 코드 를 보고 싶은 경우가 있다. 기존에는 플러그인 개발자에게도 특정 영역의 코드를 찾아가는 작업이 쉽지 않았다. 이제 플러그인 스파이 덕분에 코드를 보고 싶은 관심 대상 화면을 선택한 후 ‘SHIFT +ALT+F1’을클릭하면 해당 화면이 정의된 플러그인과 해당 화면의 클래스 등 각종 정보를 쉽게 얻을 수 있다.

플러그인 스파이 기능을 활용하려면 PDE 관련 플러그인을 설치하거나 플러그인 개발자용 이클립스를 다운받아야 한다. 이클립스의 소스 코드를 참조해서 자신만의 플러그인을 만드는 내용에 대해서는 다음에 기회가 되면 자세히 알아보겠다.

자바스크립트 개발 툴킷

웹 개발 환경에서 가장 눈에 띄는 변화는 WTP 3.0에 새로 추가된 자바스크립트 개발 툴킷(JavaScript Development Toolkit, JSDT)이다. js 파일의 포맷팅 기능, 콜 계층 보기 지원 등의 기능이 눈에 띈다. 게다가 추가적인 자바스크립트 라이브러리의 지원을 위한 확장점도 제공하고 있으니, 자신만의 라이브러리를 지원하는 것도 용이하다. WTP 3.0에 포함된 기능이므로 WTP 3.0을 별도로 설치하거나 Java EE 버전 이클립스를 다운받으면 된다.

서브버전(SVN) 클라이언트 전쟁의 승자 –Subversive

가니메데에 서브버전 클라이언트로 Subversive 프로젝트가 채택되었다. 이미 그 전부터 예견된 일이었지만, 이로써 Subclipse보다 한 발 앞서 나가게 되었다.아직 서브버전 클라이언트를 결정하지 못했다면 Subversive를 도입해 보자. 승자라고 표현했지만, 정식 프로젝트로 합류가 빨랐을 뿐이지 아직 Subclipse가 사장되는 것은 아니 라는 점을 염두에 두자.

 

마치며

지금까지 이클립스 3.4 가니메데의 새로운 기능을 자바 개발자의 시각에서 알아보았다. 이클립스 는 새로운 버전이 나올 때 마다 하위 프로젝트의 규모가 계속 커지고 있 기에 새로운 기능을 모두 다루는 것은 현실적으로 불가능하다. 개인적으로는 여기서 소개한 내용 외에도 ECF 2.0 에 추가된 협업시스템을 이용한 인스턴스 메신저 와 짝 프로그래밍 지원 , DLTK프로젝트의 동적 언어 지원, 그리고 DSDP 프로젝트의 터미널 환경 지원 등 에 관심이 간다. 이처럼 자바 개발 환경 외에 새로운 기능 중에서도 자신에게 맞는 보석 같은 기능 들이 많이 숨겨져 있으니 간단히 한 번 살펴보는 것을 권한다 .

아직도 이클립스를 무거운 텍스트 에디터의 용도로 사용하 는 경우가 많은데, 시간을 조금만 투자하면 정말 훌륭한 IDE 로 활용할 수 있다. 필요한 기능부터 하나씩 적용해 나가보자 .

 

참고문헌

  1. 한눈에 보는 이클립스 가니메데
    http://www.ibm.com/developerworks/kr/library/os-eclipse-ganymede/index.html?ca=drs-kr

  2. Eclipse 3.4 – New and Noteworthy
    http://ganymede-mirror2.eclipse.org/eclipse/downloads/drops/R-3.4-200806172000/whatsnew3.4/eclipse-news.html

  3. Eclipse Ganymede: An in-depth look at JDT (Java Development Tools)

    http://www.infoq.com/news/2008/06/eclipse-ganymede-jdt

Posted by 1010
56. Eclipse Etc.../Eclipse2008. 9. 29. 09:44
반응형
사용자 삽입 이미지


 2008년 6월 25일로 eclipse 3.4 버젼인 Ganymede 가 발표되었다. eclipse 는 정말 다양한 곳에서 쓰이고 있는데 생각보다 3.4 의 발표에 대한 관심이 적은 듯 하다. 아마 지금도 충분히 만족하면서 써서 그런듯 하다(?)

 정말 광범위하게 쓰이기는 하지만 아직 eclipse 는 Java 의 개발툴이라는 인식이 강한데 사실 CDT 플러그인의 덕택으로 C/C++ 에 대한 지원도  상당히 잘되는 편이다. Java 로 만들어져서 꽤 느린감도 있지만 이제 꽤 쓸만한 수준이다.

 다음 2개의 링크에서 eclipse 3.4/Ganymede 의 새로운 기능 중 쓸만한 것들을 뽑아서 번역해보았다.

 * [Eng] eclipse 3.4 의 새로운 기능
 * [Eng] CDT 5.0 의 새로운 기능
 

전체
 - Editor 탭을 마우스 가운데 버튼 클릭으로 현재 문서를 닫을 수 있음
 - 찾기/바꾸기에서 정규식을 쉽게 쓸 수 있게 되었음
 - debugging 시에 변수를 watch 창으로 Drag & Drop 가능

CDT 5.0
 - file template 기능을 통해 New Class 를 했을 때 기본 코드를 지정할 수 있음
 - include 를 할 때 Ctrl+Space(Content Assist) 를 하면 쉽게 include 파일명을 넣을 수 있음
 - for, while, if 문등의 block 도 folding 할 수 있음
 - 단축키 설정에서 Scheme 에 "Microsoft Visual Studio" 가 추가되어 쉽게 단축키 설정을 할 수 있음
 - Rename 밖에 없던 C++ Refactoring 기능에 다음과 같은 기능들이 추가되었다.
  - Getter/Setter 생성
  - 함수 숨기기(private 로 이동)
  - Implement Method(함수 선언부에서 선택시 함수 구현부 생성)
  - Extract Constant
  - Extract Function
 - Indexer 향상(여러 상황 지원, 속도 향상)
 - Ensure newline at end of file 옵션이 기본적으로 켜져 있어서, 파일의 마지막 줄에 빈 줄을 넣지 않아서 warning 이 뜨는 현상을 위해 옵션을 고치지 않아도 된다.

자바
 - 숫자를 따로 하이라이트해준다.
 - 변수를 읽기/쓰기 하는 부분을 따로 표시할 수 있게 해준다(디버깅할 때 편할듯)
 - 멀티CPU 를 통해 30% 까지 속도 향상이 있다.
 - Java String 을 StringBuffer 로 컨버트

SWT
 - 3개의 상태를 가지는 체크 버튼(on/off 외에 중간 상태가 추가)
 - 윈도우 비스타에서의 native progress bar 지원
 - 이미지와 url 에 대한 Drag & drop 지원
 - 전체 화면 지원
 - 투명도(Alpha, Transparent) 지원

기타
 - (Beta인 셈이지만)Subversion 을 위한 Provider 제공(Help -> Software Updates -> Available Software 에서 Ganymede Update Sites -> Collaboration Tools -> SVN Team Provider 에서 설치)



출처 : http://www.wimy.com/tt/140
Posted by 1010
56. Eclipse Etc.../Eclipse2008. 9. 29. 09:43
반응형

이클립스 3.4 가니메데(eclipse 3.4 Ganymede)에는 편리한 기능이 많이 추가되어서 꽤 만족하며 사용하고 있다. 하지만 언제나 그렇듯 몇가지 문제점이 눈에 뛴다.

  • 먼저, 환경 변수에서의 한글 처리 문제

    환경 변수에 들어간 한글 경로를 제대로 인식하지 못한다. 불편하지만 크게 문제되는 사항이 아니라서 딱히 찾아보지는 않았지만, Ganymede로 넘어오고서 발생하는 문제이다. 윈도우에서만 확인했다.

  • 특정 폰트에서의 한글 처리 문제

    가장 좋아하는 프로그램용 폰트가 Bitstream Vera Sans Mono인데, 여기서는 한글 폰트의 사이즈가 엄청나게 작게 보이는 문제가 있다. 주석 등을 볼 때 꽤나 불편하다. 아마 다른 몇몇 폰트에서도 문제가 있을 것으로 보인다. 오피스 류의 프로그램에서처럼 한글 폰트, 영문 폰트 따로 지정할 수 있으면 좋겠다. 일단 "Bitstream Vera Sans Mono + 맑은 고딕"으로 만들어진 폰트를 발견해서 문제는 해결했다.

  • 윈도우에서 발생하는 eclipse 실행 에러

    윈도우 환경에서 Ganymede가 정상 실행되지 않는 상황이 있다. 부팅하고 막 실행하면 정상 실행되지만, eclipse 3.3이라던지 이전 버전을 실행한 후 실행하려니 동작하지 않아서 자주 재부팅 하는 삽질을 했다. 다음 사이트를 참조해서 eclipse.ini 파일의 설정을 변경하면 해결할 수 있다.

  • Mac용은 Java EE 버전과 플러그인 개발 버전의 PDE 차이점 존재

    Java EE에서 동작할 플러그인을 만들고 있기에, Java EE용 Ganymede를 설치해서 PDE를 이용하는데 아무래도 무언가 이상하다 싶었다. 확장점을 확장할 때 제대로된 컨텍스트 메뉴도 제공되지 않고(Generic이라는 메뉴만 등장하는 문제), 클래스를 지정할 때도 Browse 버튼도 없고, class로 바로갈 수 있는 링크도 없다. 플러그인 개발 버전에서는 잘 동작한다. 몰랐으면 Ganymede의 사용을 포기할 뻔 했다.

  • 그리고 SWT 애플리케이션을 바로 런치할 수 있는 Run Configuration이 사라졌다.

    의도된 변경 같은데 자주 사용하지는 않는 기능이었지만 SWT Snippets를 동작해보고 하는데 유용했는데 허전하다.

  • Eclipse Fragment 프로젝트 생성한 다음, PDE Tools를 이용해서 문자열을 외부화하면 fragment.properties 파일을 생성해야 함에도 plugin.properties를 생성한다. Mac용 가니메데 배포판에서 확인했다. (2008. 7. 24 추가)
    마법사 첫 번째 페이지에서 번들 지역화 타입을 plugin에서 fragment로 수정하면 된다. plugin으로 그냥 두고서 fragment 정보를 추출하면 아무런 의미 없는 자료 추출이다. 무언가 직관적이지는 않은데 PDE UI 팀에서는 오류는 아니라고 판단하고 있다.

그나저나 eclipse는 커뮤니티가 활성화되어 있어서 내가 발견한 에러도 이미 많은 사람들이 발견한 문제인지라 버그 리포팅의 의지가 생기지 않는다. 조금더 은밀하게 숨어 있는 버그를 찾아야 하나 보다. 나쁜점만 얘기했지만 Ganymede는 좋은점이 더 많기에 3.3으로 돌아갈 생각은 전혀 없다.



출처 : http://www.eclipsegeek.com/pages/1467806

Posted by 1010
반응형

Network를 공부 中 패킷에 구조를 확인하기 위해 사용하는 프로그램이
책에 설명이 되어있었다.

인터넷을 찾아보니 대단히 유명한 프로그램!..
너무 유명해서 찾는게 미안 할 정도!! 그 프로그램이 바로 Ethereal이라는 프로그램이었는데.. 이거 원래 주소로 찾아 들어갔더니 보이질 않더라. 그래서 알아본결과 Ethereal이 개명하여 WireShark가 되었단다!!

자세한 내용은 다음사이트를 참고 하길 바란다.

사이트 주소 : http://www.wireshark.org/

일단 다운로드를 받아서 Next신공을 사용하여 설치를 하게 되면 2개의 프로그램이
설치가 되는데 WireShark와 WinPcap이다.

WireShark는 결과를 보여주기 위한 프로그램인거 같고.
WinPcap은 보시다 싶이. 패킷 윈도우 프로토콜 캡춰 모듈인거 같다.
Window Packet Capture 뭐 이정도 되지 않겠나 싶다.

그런데 설치해 보면알겠지만.. 개명한거 치곤 업그레이드가 빈약하다고 볼 수 있다.
회사가 뭔가 노림수가 있었나 보다. 하여간...

어쨋든 사용방법은 다음과 같다.

WireShark 실행화면

WireShark를 실행한 사진


WireShark Option

WireShark의 시작을 위해 설정창을 연다.


LANCARD설정 화면

캡춰할 인터페이스를 설정한다.여기서 말하는 인터페이스는 INC즉 PC의 LANCARD를 말한다. WireShark의 Interface에서 자신의 LANCARD(NIC)를 선택한다. 선택 후 하단의 Start를 클릭&#13;&#10;


Naver접속

패킷을 캡춰 하기 위해 임의의 사이트에 접속한다. 접속한 화면은 Naver이다.



WireShark의 패킷추출 화면

WireShark가 Never에 접속시에 사용한 패킷의 정보를 확인


위와 같이 패킷이 캡춰되서 나온다. 아직 무슨말인지 모르는게 당연하다..

사용하다 보면 차츰 차츰 알게 될것이고 이것을 이해 한다면
Network 프로그래밍과 Network에 대한 공부가 좀 더 수월해 지지 않을까 한다.
Posted by 1010
02.Oracle/DataBase2008. 9. 25. 14:38
반응형

접속

접속명령

conn 아이디/비밀번호 as 접속권한

conn 아이디 as 접속권한

conn / as 접속권한 (익명 접속도 가능)

 

접속 해제 명령

disconn

 

오라클 서버에 접속시 관리자 계정(system)으로 접속하려면 'as sysdba' 사용

 

접속포트 바꾸기

exec dbms_xdb.sethttpport(9090);

 

 

시스템 기본 테이블 스페이스 조회

msSQL과는 달리 DB의 개념이 없고 비슷하게 테이블 스페이스라는 것이 있다.

select tablespace_name, status

from dba_tablespaces

order by tablespace_name

 

 

오라클 사용자 계정 만들기

  1. 테이블 스페이스 생성
    [이름] => TS_lazy
    [경로] => D:\java\TS_lazy.dbf
    create tablespace TS_lazy
    datafile 'D:\java\TS_lazy.dbf' size 10M
    default storage
    (initial 128k next 64k pctincrease 10);
  2. 사용자 계정 생성에 테이블 스페이스 지정
    [아이디] => lazy
    [비밀번호] => 302
    create user [아이디] identified by [비밀번호]
    default tablespace TS_lazy
    temporary tablespace temp
    사용자 보기 : select username, user_id from dba_users;
  3. 사용자 권한 부여
    grant connect, resource to [아이디]

 

데이터베이스와 일반 데이터의 차이

  1. 데이터에 보안을 적용하기가 쉽다.
  2. 데이터의 중복을 막을 수 있고 자료의 일관성을 유지할 수 있다.

 

 

데이터베이스 종류

  1. 관계형(R) 데이터 베이스 : MySQL, MS-SQL, Oracle9i, 10g

 

 

테이블 구조

2차원 배열의 형태로 구성

테이블을 구성하는 최소 단위 - item

item이 어러개 모이면 - 필드

필드가 어러개 모이면 - 레코드

레코드가 여러개 모이면 - 테이블

 

 

SQL 명령문 종류

  1. DDL : 데이터 정의 ( create, drop, alter )
  2. DML : 데이터 조작 ( select, update, insert, delete )
  3. DCL : 데이터 제어 ( grant, revoke, rollback, commit )

 

 

 

ORACLE 자료형

-- char : 문자형 (고정길이) max : 2000 byte
-- nchar : 문자형 (고정길이), 유니코드 지원,  max : 2000 byte
-- varchar2 : 문자형 (가변길이) max : 2000 byte
-- nvarchar2 : 문자형 (가변길이) 유니코드 지원, max : 2000 byte
-- date : 날짜형, 형식 지정자로 변환가능, max : 7 byte
-- number : 숫자(정수, 실수)형, max : 37자리까지 정수, 실수 표현가능
-- number(n) : 최대 n byte 정수
-- number(n, m) : n - 소수점 제외자릿수, m - 소수점 이하 자릿수

-- 대용량 데이터 저장용 자료형
-- long : 문자/바이너리 저장용, max : 2 byte
-- 테이블에 단 한번만 사용 가능
-- clob : 문자 저장용, max : 4 Gbyte
-- blob : 바이너리 저장용,  max : 4 Gbyte
-- 데이터 저장 / 출력시 특수한 변환과정 필요 

 

 

저장 프로시저 ( store procedure )

  1. 기본문법
  2. create procedure [저장프로시져 이름] (
  3. -- create or replace procedure [저장프로시져 이름] : 저장과 수정을 동시에 함.
  4. < 매개변수 목록 >

  5. ) is
  6. begin
  7. <프로시져 본문>

  8. end [저장프로시져 이름]

< 매개변수 목록 > : 프로그램 실행시 필요한 데이터를 받을 경우 사용

변수명   in/out   <자료형>

 

< 프로시져 지역변수 > : 프로시져 안에서만 사용

변수명   <자료형>

 

< 프로시져 수식 >

문자연결 연산자 : ||

대입 연산자 :       :=

 

  1. CREATE OR REPLACE PROCEDURE savesungjuk2(
  2.      iname IN sungjuk.names%TYPE, -- 매개변수
  3.   ikor IN sungjuk.kor%TYPE,
  4.   ieng IN sungjuk.eng%TYPE,
  5.   imat IN sungjuk.mat%TYPE
  6. ) IS
  7.   itot sungjuk.tot%TYPE;   -- 지역변수
  8.   iavg sungjuk.avgs%TYPE;
  9.   igrd sungjuk.grd%TYPE;
  10. BEGIN
  11.   itot := ikor + ieng + imat;
  12.   iavg := itot/3;
  13.   IF(iavg > 89) THEN
  14.     igrd := 'A';
  15.   ELSIF(iavg > 79) THEN
  16.      igrd := 'B';
  17.    ELSIF(iavg > 69) THEN
  18.         igrd := 'C';
  19.    ELSIF(iavg > 59) THEN
  20.        igrd := 'D';
  21.    ELSE
  22.        igrd := 'F';
  23.   END IF;
  24.  

     

  25.   INSERT INTO sungjuk VALUES(sjseq.NEXTVAL, iname, ikor, ieng, imat, itot, iavg, igrd, SYSDATE);
  26. END savesungjuk2;
  27. EXECUTE savesungjuk2 ('lazy5', 50, 60, 99);
  28. SELECT * FROM SUNGJUK

 

  1. CREATE OR REPLACE PROCEDURE listBoard(
  2.            rs OUT       SYS_REFCURSOR      -- 결과값 저장 변수
  3. ) IS
  4. BEGIN
  5.          OPEN rs FOR
  6.                   SELECT bno, subject, id, rdate, reads FROM BOARD;
  7. END listBoard;

 

  1. CREATE OR REPLACE PROCEDURE viewBoard(
  2.            ibno         IN              board.bno%TYPE,
  3.            rs           OUT     sys_refcursor
  4. ) IS
  5. BEGIN
  6.          OPEN rs FOR
  7.          SELECT * FROM board WHERE bno = ibno;
  8. END;
Posted by 1010
반응형

  1. <script type="text/javascript" src="http://widget.wzd.com/scripts/myjit.js">  
  2. </script>  
  3. <script type="text/javascript">  
  4. var myjit = new WZD.Myjit({   
  5.     myjitid: 'f472492259e3736f'   
  6. });   
  7. myjit.setConfiguration({   
  8.     skin: 21,   
  9.     width: 640,   
  10.     height: 480,   
  11.     title: '지하철 노선도'   
  12. });   
  13. myjit.load();   
  14. </script>  




    <script type="text/javascript" src="http://widget.wzd.com/scripts/myjit.js"> 
    </script> 
    <script type="text/javascript"> 
    var myjit = new WZD.Myjit({  
        myjitid: 'f472492259e3736f'  
    });  
    myjit.setConfiguration({  
        skin: 21,  
        width: 640,  
        height: 480,  
        title: '지하철 노선도'  
    });  
    myjit.load();  
    </script> 
Posted by 1010