'98..Etc'에 해당되는 글 370건

  1. 2008.11.21 #.net 기본개념정리파일.
  2. 2008.11.19 JSP에서 원하는 Appender 선택하여 쓰기 (처음시작하기...필독)
  3. 2008.11.19 Log4j Summary
  4. 2008.11.17 Vmware를 이용한 Ubuntu 설치 방법
  5. 2008.11.12 학습 곡선 일지 4편: 웹 서비스 액세스
  6. 2008.11.12 학습 곡선 일지 3편: JavaFX 스크립트 함수
  7. 2008.11.12 학습 곡선 일지 2편: 선언적 사용자 인터페이스
  8. 2008.11.12 학습 곡선 일지 1편: JavaFX 스크립트 탐구
  9. 2008.11.12 TableNode: JavaFX에서 스크롤 가능한 사용자 지정 테이블 만들기
  10. 2008.11.12 자신만의 JavaFX "사용자 지정 노드" 만들기: 그래픽 메뉴의 예
  11. 2008.11.12 JNDI의 소개
  12. 2008.11.12 커스텀 태그 파일
  13. 2008.11.12 J2EE 커넥터 아키텍처 1.5
  14. 2008.11.12 GlassFish v2에서 SSL 사용하기
  15. 2008.11.12 GlassFish v2: Open for Business
  16. 2008.10.30 jeus 설정 및
  17. 2008.10.28 원도우 탐색기 오류시 대체방법
  18. 2008.10.27 톰캣에서 java.lang.IllegalStateException: Post too large 가 발생하는 경우
  19. 2008.10.23 엑셀 주민등록번호 남여 구분
  20. 2008.10.20 FTP 서버의 passive mode에 대해
  21. 2008.10.17 JavaFX DEMO Applets
  22. 2008.10.17 웹표준 가이드 (Asp기초에서 고급까지)
  23. 2008.10.17 JavaFX DEMO
  24. 2008.10.17 JavaFX Programming Language Reference
  25. 2008.10.17 Apache 2.x + Tomcat 4.x + Load Balancing (or Private JVMs)
  26. 2008.09.17 이지 웹에디터
  27. 2008.09.17 그누보드4 설치방법
  28. 2008.09.05 CVS 사용에 대한 FAQ 모음
  29. 2008.09.05 linux cvs 설치 및 프로젝트 적용
  30. 2008.09.05 CVSNT 서버 설치 매뉴얼
98..Etc/ASP.NET2.02008. 11. 21. 18:07
반응형
Posted by 1010
98..Etc/Log4J2008. 11. 19. 14:07
반응형

JSP에서 원하는 Appender 선택하여 쓰기


참고로 이글의 원저자는 제가 아니므로 퍼가셔서 사용하실때 신중해주시기 바랍니다



만약 log4j 가 처음이라면 이 카테고리의 다음 포스트를 먼저 필독하세요


- log4j 웹에서 사용하기

- log4j 고급스럽게 사용하기

 

 

 

I. 먼저 log4j 프로퍼티 파일입니다

log4j.properties

log4j.rootLogger=INFO, stdout1, stdout2


log4j.logger.jsp1=INFO,stdout1
log4j.additivity.jsp1=false


log4j.logger.jsp2=INFO,stdout2
log4j.additivity.jsp2=false


log4j.appender.stdout1=org.apache.log4j.ConsoleAppender
log4j.appender.stdout1.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout1.layout.ConversionPattern=jsp1 appender log %d %-5p [%t] %-17c{2} (%13F:%L) %3x - %m%n


log4j.appender.stdout2=org.apache.log4j.ConsoleAppender
log4j.appender.stdout2.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout2.layout.ConversionPattern=jsp2 appender log %d %-5p [%t] %-17c{2} (%13F:%L) %3x - %m%n


log4j.logger.jsp1=INFO, stdout1
log4j.logger.jsp2=INFO, stdout2
jsp1과 jsp2의 두개의 logger를 정의합니다

jsp1 logger는 appender로 stdout1을 사용하며, jsp2 logger는 appender로 stdout2로 사용한다는 의미입니다


log4j.additivity.jsp1=false

additivity 속성은 jsp1 logger를 상위 로거(root logger)의 속성을 삭송받지 않겠다는 의미입니다

만약 이 속성이 없으면 동일한 메세지가 여러번 로깅될 것입니다

이하 속성은

http://www.jakartaproject.com/article/jakarta/1110438405982 등의 사이트를 참고하세요


II. JSP 샘플 소스

test_jsp1_appender.jsp

<%@ page contentType="text/html;charset=MS949"
 import="org.apache.log4j.Logger" %>

<%!
 static Logger logger1 = Logger.getLogger("jsp1");
%>

<%
logger1.warn("warn");
%>

로깅 메세지

jsp1 appender log2005-11-07 13:05:23,687 WARN  [http-8080-Processor5] jsp1 (test_jsp1_appender_jsp.java:48)     - warn


test_jsp2_appender.jsp

<%@ page contentType="text/html;charset=MS949"
 import="org.apache.log4j.Logger" %>

<%!
 static Logger logger2 = Logger.getLogger("jsp2");
%>

<%
logger2.warn("warn");
%>

로깅 메세지

jsp2 appender log2005-11-07 13:05:58,031 WARN  [http-8080-Processor4] jsp2 (test_jsp2_appender_jsp.java:48)     - warn

Posted by 1010
98..Etc/Log4J2008. 11. 19. 14:04
반응형

아래 글은 SKT 소액 결재 개발팀 손정호 님이 작성하신 글임을 알려 드립니다.

참고로 preparedStatement에서 적용한 예 입니다.

====================================================================

Log4j Summary

이번 WebChannel 개발시에 적용된 Log4j 환경을 바탕으로 작성한 간단한 summary입니다.

1. 다운로드

다운로드http://logging.apache.org/log4j/docs/download.html
매뉴얼http://logging.apache.org/log4j/docs/documentation.html
API spechttp://logging.apache.org/log4j/docs/api/index.html

2. 구조
Log4j는 크게 3가지 요소로 구성되어 있습니다.
① Logger : logging 메시지를 Appender에 전달합니다.
② Appender : 전달받은 logging 메시지를 원하는 곳으로 보내는 매개체의 역할을 합니다.
   아래 표는 Appender의 종류입니다. API에서 보고 이해가 된 선에서 적었습니다.
ConsoleAppender        로그 메시지를 콘솔에 출력합니다.
DailyRollingFileAppender        로그 메시지를 파일로 저장합니다.
DatePattern 옵션에 따라 원하는 기간마다 로그파일을 갱신합니다.
ExternallyRolledFileAppender        
FileAppender        직접적으로 사용되지 않고 DailyRollingFileAppender와 RollingFileAppender의 superclass로 사용되는듯 합니다.
JDBCAppender        로그 메시지를 DB에 저장합니다. 현재는 완벽하지 않으니 왠만하면 차기 버전에서 사용하라고 하는 것 같습니다.
JMSAppender        로그 메시지를 JMS Topic으로 보냅니다.
NTEventLogAppender        NT 이벤트 로그를 위한 Appender. 윈도우에서만 사용가능합니다.
NullAppender        내부적으로만 사용되는 Appender입니다.
RollingFileAppender        로그 메시지를 파일로 저장합니다. 설정된 size를 초과하면 로그파일이 갱신됩니다.
SMTPAppender        로그 메시지를 지정된 이메일로 발송합니다.
SocketAppender        로그 메시지를 socket을 이용해서 지정된 곳으로 보냅니다.
SocketHubAppender        위와 비슷하게 사용하는듯 합니다.
SyslogAppender        로그 메시지를 원격 syslog deamon으로 보냅니다.
TelnetAppender        로그 메시지를 telnet을 통해 보낸다는 것 같습니다. 원격 모니터링, 특히 servlet의 모니터링에 유용하다고 합니다.
WriterAppender        FileAppender처럼 주로 superclass로서 사용되는듯 합니다.
③ Layout : logging 메시지의 출력 형식을 지정합니다.
        - 아래에서 설명.

3. 로깅레벨
FATAL : 가장 크리티컬한 에러가 발생했을 때 사용합니다.
ERROR : 일반적인 에러가 발생했을 때 사용합니다.
WARN : 에러는 아니지만 주의가 필요할 때 사용합니다.
INFO : 일반적인 정보가 필요할 때 사용합니다.
DEBUG : 일반적인 정보를 상세히 나타낼 때 사용합니다.

로깅레벨의 우선순위는 FATAL이 가장 높고 DEBUG가 가장 낮습니다.
예를 들어 레벨을 WARN으로 설정하면 WARN이상되는 로그(FATAL, ERROR, WARN)만
출력합니다.

4. 환경설정
- Log4j의 환경설정은 직접 코드에서 메서드를 이용하는 방법과 properties 파일을 이용하는 방법, XML파일을 이용하는 방법이 있습니다.
① 코드에서 설정
String layout = "%d %-5p [%t] %-17c{2} (%13F:%L) %3x - %m%n";
String logfilename = "DailyLog.log";
String datePattern = ".yyyy-MM-dd ";

PatternLayout patternlayout = new PatternLayout(layout);
DailyRollingFileAppender appender = new DailyRollingFileAppender(patternlayout, logfilename, datePattern);
logger.addAppender(appender);
logger.setLevel(Level.INFO);
logger.fatal("fatal!!");

위 코드처럼 설정하시면 됩니다.


② properties 파일로 설정
#---------- file logging ----------
log4j.rootLogger=INFO, rolling
#---------- consol logging -----------
#log4j.rootLogger=INFO, stdout
#---------- file, console logging -----------
#log4j.rootLogger=INFO, stdout, rolling
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%d] %-5p  at %C{3}.%M(%13F:%L) %3x - %m%n
log4j.appender.rolling=org.apache.log4j.DailyRollingFileAppender
log4j.appender.rolling.File=/WEB_BACKUP1/pgw_log/webchannel.log
log4j.appender.rolling.Append=true
#---------- every day renew ------------
log4j.appender.rolling.DatePattern='.'yyyy-MM-dd
#---------- every month renew ------------
#log4j.appender.rolling.DatePattern='.'yyyy-MM
#---------- every week renew ------------
#log4j.appender.rolling.DatePattern='.'yyyy-MM-ww
#---------- every 12hours renew -------------
#log4j.appender.rolling.DatePattern='.'yyyy-MM-dd-a
#---------- every hour renew --------------
#log4j.appender.rolling.DatePattern='.'yyyy-MM-dd-HH
#---------- every min renew --------------
#log4j.appender.rolling.DatePattern='.'yyyy-MM-dd-HH-mm
log4j.appender.rolling.layout=org.apache.log4j.PatternLayout
log4j.appender.rolling.layout.ConversionPattern=[%d] %-5p  at %C{3}.%M(%13F:%L) %3x - %m%n


위 properties 파일은 실제 WebChannel에 적용한 파일입니다.
- log4j.rootLogger=INFO, rolling
        : 로깅레벨을 ‘INFO’로 하고 ‘rolling’이라는 이름의 Appender를 사용한다.
        위 properties파일에는 ConsoleAppender(stdout)와 DailyRollingFileAppender(rolling)가
정의되어 있습니다.
- log4j.rootLogger=INFO, stdout : console에만 출력
- log4j.rootLogger=INFO, stdout, rolling : console과 file 로 출력
위처럼 설정이 가능합니다.
- log4j.appender.stdout=org.apache.log4j.ConsoleAppender
        : ConsoleAppender의 이름은 ‘stdout’으로 한다.
- log4j.appender.rolling=org.apache.log4j.DailyRollingFileAppender
        : DailyRollingFileAppender의 이름은 ‘rollong’으로 한다.
- log4j.appender.rolling.File=/WEB_BACKUP1/pgw_log/webchannel.log
        : 로그파일의 위치와 파일명을 지정한다.
- log4j.appender.rolling.Append=true
        : 서버 restart시에도 파일이 reset되지 않는다.
- log4j.appender.rolling.DatePattern='.'yyyy-MM-dd
        : DatePattern 을 ‘매일갱신’으로 설정. 매일 자정이 지나면
파일명 뒤에 날짜가 붙는다.
        ex) webchannel.log.2005-11-21
- log4j.appender.rolling.layout=org.apache.log4j.PatternLayout
        : layout을 PatternLayout으로 설정.
- log4j.appender.rolling.layout.ConversionPattern=[%d] %-5p  at %C{3}.%M(%13F:%L) %3x - %m%n
        : 로그의 출력 형식을 설정. 아래 설명.

# log4j.appender.rolling.MaxFileSize=500KB
: 파일의 최대size 설정하는 부분인데 서버 기동시 최초에 이 부분의 property를 읽지 못했다는 경고가 자꾸 떠서 삭제 했습니다. 설정하지 않으면 Default로 10MB가 설정된다고 합니다.

#### properties 파일의 변경사항은 server restart시에 적용됩니다. ####
③ XML 파일로 설정
현재 잘 모르니 넘어가겠습니다.-_-


5. 설정 포맷
① DatePattern 설정 포맷
'.'yyyy-MM         매달 첫번째날에 로그파일을 변경합니다
'.'yyyy-ww         매주의 시작시 로그파일을 변경합니다.
'.'yyyy-MM-dd        매일 자정에 로그파일을 변경합니다.
'.'yyyy-MM-dd-a        자정과 정오에 로그파일을 변경합니다.
'.'yyyy-MM-dd-HH        매 시간의 시작마다 로그파일을 변경합니다.
'.'yyyy-MM-dd-HH-mm        매분마다 로그파일을 변경합니다.




② PatternLayout 설정 포맷
%p        debug, info, warn, error, fatal 등의 로깅레벨이 출력된다.
%m        로그내용(코드상에서 설정한 내용)이 출력됩니다.
ex) logger.info("log"); 라고 코딩했다면 ‘log’가 로그 내용임.
%d        로깅 이벤트가 발생한 시간을 기록합니다.
포맷은 %d{HH:mm:ss, SSS}, %d{yyyy MMM dd HH:mm:ss, SSS}
같은 형태로 사용하며 SimpleDateFormat에 따른 포맷팅을 하면 된다
%t        로그이벤트가 발생된 쓰레드의 이름을 출력합니다.
%%        % 표시를 출력하기 위해 사용한다.
%n        플랫폼 종속적인 개행문자가 출력된다. \r\n 또는 \n 일것이다.
%c        카테고리를 표시합니다.
ex) 카테고리가 a.b.c 처럼 되어있다면
%c{2}로 설정하면 b.c 가 출력됩니다.
%C        클래스명을 포시합니다.
ex) 클래스구조가 org.apache.xyz.SomeClass 처럼 되어있다면
%C{2}는 xyz.SomeClass 가 출력됩니다
%F        로깅이 발생한 프로그램 파일명을 나타냅니다.
%l        로깅이 발생한 caller의 정보를 나타냅니다
%L        로깅이 발생한 caller의 라인수를 나타냅니다
%M        로깅이 발생한 method 이름을 나타냅니다.
%r        어플리케이션 시작 이후 부터 로깅이 발생한 시점의 시간(milliseconds)
%x        로깅이 발생한 thread와 관련된 NDC(nested diagnostic context)를
출력합니다.
%X        로깅이 발생한 thread와 관련된 MDC(mapped diagnostic context)를
출력합니다.

ex) [%d] %-5p  at %C{3}.%M(%13F:%L) %3x - %m%n
 [2005-11-23 10:43:21,560] INFO   at
pgw.database.PGWBoardDAO.selectList(PGWBoardDAO.java:146) -
========== PGWBoardDAO#selectList ==========

포맷의 각 색깔별로 출력되는 실제 예입니다. 포맷 중간에 원하는 단어(at)나
기호(`.` , `-`)등을 넣으면 그대로 출력됩니다.



6. 실제 적용 예

다운받은 log4j.jar파일을 원하는 디렉토리에 복사하고 weblogic의
startWebLogic.cmd내의 classpath에 잡아줍니다. buildpath도 잡아주셔야 합니다.

① PGWBoardDAO.java
//import 해줍니다.
import org.apache.log4j.Logger;
.
//중략/

public class PGWBoardDAO extends PGWDAO {
    //parameter로 받은 이름의 instance를 생성합니다.
    static Logger logger = Logger.getLogger("PGWBoardDAO");
.
//중략/
.
public PGWBean selectList(HashMap hashMap) throws Exception {
.
/중략/
.
//            pstmt = conn.prepareStatement(sql.toString());
//LoggableStatement instance생성. LoggableStatement는 아래에서 설명.
            pstmt = new LoggableStatement(conn, sql.toString());

.
//중략/
.
pstmt.setInt(nIdx++, ((curPage-1)*listSize) + 9);
          pstmt.setInt(nIdx++, (curPage-1)*listSize);
        //주어진 로그내용을 ‘INFO’레벨로 출력합니다.
getQueryString()으로 ‘?’가 실제데이터로 치환된 query를 출력합니다.
            logger.info("\n======== PGWBoardDAO#selectList ========\n "
                        + ((LoggableStatement)pstmt).getQueryString() +
                       "\n========================================\n");


.
//중략/
.

        } catch (SQLException se) {
            System.out.println("PGWBoardDAO.selectList SQLException ====" + se);
           //Exception은 ‘ERROR’레벨로 출력합니다.
            logger.error("\n==== PGWBoardDAO#selectList Exception ====" , se );
            return null;
        } catch (Exception e) {
            System.out.println("PGWBoardDAO.selectList Exception ====" + e);
            logger.error("\n==== PGWBoardDAO#selectList Exception ====" , e );
            return null;
        } finally {
.
//중략/


- 위 코드에서 INFO 레벨의 로그는 주어진 로그를 출력하고,
ERROR 레벨의 로그는 발생한 Exception을 로그로 출력합니다.

로그의 출력메서드는 2가지 형식을 지원합니다.
logger.fatal(Object message)        logger.fatal(Object message, Throwable t)
logger.error(Object message)        logger.error(Object message, Throwable t)
logger.warn(Object message)          logger.warn(Object message, Throwable t)  
logger.info(Object message)          logger.info(Object message, Throwable t)  
logger.debug(Object message)         logger.debug(Object message, Throwable t)

- Throwble 타입의 변수를 parameter로 받는 메서드를 이용하면 원하는 위치에서
원하는 Exception을 발생시킬 수도 있습니다.

- 위 코드에서 INFO 레벨의 로그는 주어진 내용를 출력하고,
ERROR 레벨의 로그는 발생한 Exception을 로그로 출력합니다.


② LoggableStatement.java
- 이 클래스는 query를 로그로 출력할 때 부가적으로 필요한 클래스로 PreparedStatement의 ‘?’를 실제 데이터로 치환해서 출력하는 기능을 합니다.
이 클래스는 Interface인 PreparedStatement를 구현하는 클래스로 파일이름은 임의로 정하셔도 됩니다.
클래스내에는 PrepareddStatement의 메서드를 오버라이딩한 메서드와 넘어온 데이터를 ArrayList에 넣어주는 메서드, 그리고 query의 ‘?’를 치환해 리턴해주는 메서드를 구현합니다.

//PreparedStatement 와 ArrayList를 import 해줍니다.
//메서드 오버라이딩시에 필요한 클래스도 추가적으로 import 해줍니다.
import java.sql.PreparedStatement;
import java.util.ArrayList;

public class LoggableStatement implements PreparedStatement {

        private ArrayList parameterValues;
 
    private String sqlTemplate;

    private PreparedStatement wrappedStatement;

//connection.prepareStatement(String sql) 대신에 사용할 생성자 입니다.
//PreparedStatement Object를 생성, query를 String에 담고 ArrayList를 생성합니다.
    public LoggableStatement(Connection connection, String sql)
            throws SQLException {
            wrappedStatement = connection.prepareStatement(sql);
            sqlTemplate = sql;
            parameterValues = new ArrayList();
    }

.
//중략/
.



//실제로 필요한 메서드만 오버라이딩 하고, 나머지는 auto generate하시면 됩니다.
//여기서는 query문 실행관련 메서드와 setInt, setString, setDate, setCharacterStream 을 오버라이딩 했습니다.
        public boolean execute() throws java.sql.SQLException {
            return wrappedStatement.execute();
    }

        public boolean execute(String sql) throws java.sql.SQLException {
            return wrappedStatement.execute(sql);
    }

        public int[] executeBatch() throws java.sql.SQLException {
            return wrappedStatement.executeBatch();
    }

        public java.sql.ResultSet executeQuery() throws java.sql.SQLException {
            return wrappedStatement.executeQuery();
    }

        public java.sql.ResultSet executeQuery(String sql)
            throws java.sql.SQLException {
            return wrappedStatement.executeQuery(sql);
    }

        public int executeUpdate() throws java.sql.SQLException {
            return wrappedStatement.executeUpdate();
    }

        public int executeUpdate(String sql) throws java.sql.SQLException {
            return wrappedStatement.executeUpdate(sql);
    }

        public java.sql.Connection getConnection() throws java.sql.SQLException {
            return wrappedStatement.getConnection();
    }

       
public void setCharacterStream(
            int parameterIndex,
            java.io.Reader reader,
            int length)
            throws java.sql.SQLException {
            wrappedStatement.setCharacterStream(parameterIndex, reader, length);
            saveQueryParamValue(parameterIndex, reader);

    }

        public void setDate(int parameterIndex, java.sql.Date x)
            throws java.sql.SQLException {
            wrappedStatement.setDate(parameterIndex, x);
            saveQueryParamValue(parameterIndex, x);
    }

        public void setDate(
            int parameterIndex,
            java.sql.Date x,
            java.util.Calendar cal)
            throws java.sql.SQLException {
            wrappedStatement.setDate(parameterIndex, x, cal);
            saveQueryParamValue(parameterIndex, x);
    }

        public void setInt(int parameterIndex, int x)
                        throws java.sql.SQLException {
                        wrappedStatement.setInt(parameterIndex, x);
            saveQueryParamValue(parameterIndex, new Integer(x));
        }

        public void setString(int parameterIndex, String x)
                        throws java.sql.SQLException {        
                        wrappedStatement.setString(parameterIndex, x);
            saveQueryParamValue(parameterIndex, x);
        }
       
//넘어온 데이터를 ArrayList에 담아주는 메서드입니다.
        private void saveQueryParamValue(int position, Object obj) {
                String strValue;
                if (obj instanceof String || obj instanceof Date) {
                        strValue = "'" + obj + "'";
                } else {
                        if (obj == null) {
                              strValue = "null";
                        } else {
                                strValue = obj.toString();
                        }
                }
                while (position >= parameterValues.size()) {
                parameterValues.add(null);
                }
                parameterValues.set(position, strValue);
        }
       
        //instance생성시 String에 넣어둔 query의 ‘?’를 ArrayList에 담긴 실제 데이터로
//치환해서 리턴해 줍니다.
        public String getQueryString() {
                //여기서 query를 String에도 담아준 이유는 webLogic의 jdk가 1.3 버전으로
//StringBuffer의 indexOf(String str) 메서드를 사용할 수 없었기 때문입니다.
//다른 방법이 있으시면 알려주세요..
                String sql = sqlTemplate;
                StringBuffer query = new StringBuffer(sqlTemplate);
                int idx = 0;
               
                if(!parameterValues.isEmpty())
                {
                        for(int i=1;i < parameterValues.size();i++)
                        {
                                idx = sql.indexOf("?");
                                query.replace(idx, idx+1, (String)parameterValues.get(i));
                                sql = query.toString();
                        }
                        parameterValues = null;
                        return query.toString();
                }
                else
                {
                        parameterValues = null;
                        return query.toString();
                }
        }
}


- 다음은 실제 출력문입니다.

[2005-11-23 13:50:19,030] INFO at pgw.database.listDAO.modify(listDAO.java:543)   -
========== llistDAO#modify#if Customer ==========
UPDATE ACKLIST
   SET NM_USER = 'aaaaaaaaaa',
       NO_SSN = '2222222222222',
       NO_MINHEADER = '222',
       NO_MINNUMBER = '22222222',
       REASON = '22222222222222222444444444444444444444',
       ID_MODIFY = 'pbadmin',
       DT_MODIFY = SYSDATE
WHERE SEQ_NUM = '460'
   AND TYPE = '2'
Posted by 1010
98..Etc/Etc...2008. 11. 17. 21:23
반응형

Vmware를 이용한 Ubuntu 설치 방법


저는 Vmware 6.x 버전을 사용했습니다. Ubuntu Linux는 8.04 버전이며 여기서 다운로드 합니다. 저는 32bit 로 Daum 서버에서 다운로드 했습니다. 로케이션에 보시면 Daum서버가 있으니 그걸 이용하세요.

Windows에 Vmware와 Ubuntu의 이미지가 준비 되었다면 이제 본격적으로 Ubuntu를 설치해 보겠습니다.

Vmware에서 New Virtual Machine 을 누릅니다.
Menu -> File -> New -> Virtual Machine
or
Crtl + N


이런 화면이 나오게 됩니다.

다음 을 눌러 줍니다.


Guest의 OS를 선택하는 부분입니다.
리눅스를 선택하시고 우분투를 선택합니다.


버추얼 머신이 만들어 장소와 이름을 지정해 줍니다.


이제 네트워크를 선택할 차례입니다. 네트워크는 4가지 선택을 할 수가 있습니다.
첫번째 Use bridged networking은 많이들 사용하지만 가끔 문제가 생긴다고 보고되고 있습니다. 그 문제가 호스트(Windows)가 인터넷을 사용할 경우 게스트에서 인터넷이 안 될 경우도 있고 게스트가 인터넷을 사용할 경우 호스트가 인터넷이 안되는 경우가 있다고 하더군요.

두번째 NAT 방식은 쉽게 말하면 호스트가 라우터의 기능을 하게 됩니다. 그래서 게스트에게 IP를 나눠 주지요. 설명하기 편하게 호스트가 "공유기"가 되어 게스트에게 IP를 할당해 주게 됩니다. 여기서 NAT를 선택해 주시면 됩니다.

세번째 Use Host Only는 말 그대로 호스트만 인터넷이 되는 것입니다. 게스트는 인터넷이 안돼죠.

Virtual Machine의 하드디스크를 설정하는 부분입니다.
하드디스크의 용량과 어떤 방식을 사용할 것인지 선택합니다.
우분투 리눅스는 4GB USB에도 설치가 가능합니다. 6GB 면 충분하다고 생각해서 저는 6 GB를 선택했습니다. 기본은 8 GB입니다.


아래의 체크 버튼 Allocate all disk space now는 Ubuntu가 설치될 공간을 미리 만들어 놓는 것입니다. 가상 하드디스크는 파일로 만들어지게 되는데 이것을 선택하면 6GB 의 파일을 미리 만들어 놓고 시작하게 됩니다. 체크를 해제하게 되면 6GB 까지 사용 가능하지만 디스크 사용량에 따라서 파일의 크기가 점점 늘어나는 형식입니다. 물론 6GB 이상은 안돼겠지요.


자 이제 Virtual Machine이 다 만들어 졌습니다.
세부 설정으로 넘어갑니다.


Edit virtual machine setting을 선택합니다.


여기서 Memory의 크기나 CD의 마운트 등을 할 수 있습니다.
다른것은 모두 기본으로 놔두고 Floppy는 사용하지 않으니 Floppy는 삭제 해 줍니다.
그리고 CD-ROM을 선택합니다.


CD-ROM을 선택한 뒤 오른쪽에서 Use ISO image를 선택하시고 Browser 버튼을 눌러 앞서 다운로드한 Ubuntu의 이미지를 불러옵니다. 그리고 OK버튼을 누르시면 됩니다.

이제 새로 맞춘 새 컴퓨터의 전원을 넣어 볼 차례입니다.
아이콘의 재생 버튼을 누릅니다.


한국어를 선택해 줍니다.


맨위의 설치하지 않고 우분투 사용해 보기 를 누르시고 진행 합니다.


부팅 중 입니다.

부팅이 완료 되었습니다. 이제 Ubuntu를 사용해 볼 수도 있으며 설치도 할 수 있습니다. 우리는 설치를 하기 위한 것이므로 몇 가지 설정을 마친 뒤 바로 설치를 하도록 하겠습니다.


설정이란 네트워크 설정을 하는 것 입니다. 우분투는 가상 랜카드를 인식하게 되는데 이를 무선랜 카드로 인식합니다.
우분투의 오른쪽 위의 모니터가 두개 겹쳐있는 아이콘을 클릭합니다. 이 아이콘은 네트워크를 뜻하는 아이콘 입니다. 클릭하게 되면 메뉴가 펼쳐집니다.

+ 왜 인터넷을 연결하고 설치를 해야하죠?
인터넷을 연결하고 설치를 하는 이유는 간단합니다. 한국어 지원을 받기 위해서 입니다. CD에는 한글패키지 중 몇가지가 빠져있어서 CD로만 설치를 진행하면 나중에 한글팩 설치를 따로 해줘야 하는 불편함이 있습니다. 인터넷을 연결하고 설치를 진행하게 되면 자동으로 한글팩을 다운로드 받아 설치 해 주게 됩니다.


여기서 마지막 메뉴인 Maual configuration을 눌러 줍니다.


위와 같이 Wired connection을 선택하고 옆의 Properties 버튼을 누릅니다.


가운데 작은 창이 하나 뜨고 Enable roaming mode 가 체크되어 있는데 이를 체크해제해 주시고 Configuration 항목을 DHCP 방식으로 바꿔 주시고 OK버튼을 누르세요


설정이 되었습니다. 이제 Close를 누르시고 인터넷이 되는지 확인해 볼 차례입니다.


Firefox를 실행시킵니다. Firefox는 인터넷 익스플로러와 같은 인터넷 브라우져 입니다.


잘 되는군요. 저는 youtube 사이트로 한번 가보았습니다. 여러분들도 자주 가는 사이트로 한번 들어가 보세요.
그럼 설치를 진행 하도록 하겠습니다. Firefox를 끄시고 바탕화면의 설치아이콘을 더블 클릭 해주세요


자동으로 한국어가 선택 됩니다. 앞으로를 누르세요.


자동으로 서울의 시간대가 선택되어있습니다. 앞으로를 누르세요.


여기서 중요한 키보드 설정입니다. 대부분의 사람들이 기본 설정인 USA의 키보드를 선택하는데요. 그렇게 설치하시면 나중에 한/영키가 안먹어서 다시 설정을 해 주어야 하는 번거로움이 있습니다. 왼쪽으 스크롤 바를 올려 보시면 Korea, Republic of 가 있습니다 이를 선택하시고 오른쪽에서 101/104 키를 선택해 주시면 나중에 한/영키가 자동으로 반영 됩니다.

다음은 파티션의 설정부분인데 네이티브로 Ubuntu를 설치한다면 몰라도 가상머신에서 돌리는 것이므로 파티션 설정은 자동으로 해 놓고 넘어 갑니다. 계속 앞으로를 눌러주세요.
설치가 진행될때 까지요.

여기까지 Vmware를 이용한 Ubuntu 설치였습니다.

이제 설치가 모두 끝나고 재부팅이 끝났나요?

마지막으로 우분투를 설치하고 바로 설정해 줘야 할 것이 있습니다.


제 글만 잘 따라오시면 됩니다.

메뉴에서 "시스템" -> "관리" -> "소프트웨어 소스" 를 클릭합니다.


여기서 다운로드 위치 의 수정을 해야 합니다. 처음엔 대한민국 서버가 선택되어있는데
이것을 Daum서버로 바꾸어 주어야 합니다. 대한민국 서버로는 총 세개가 있는데, 카이스트서버와 Daum서버와 letsopen서버가 있습니다. 주로 카이스트 서버와 다음서버를 많이 사용하는데 카이스트서버는 메인서버와 동기화가 잘 되어있지않아 누락된 패키지가 몇개 있습니다. 그래서 동기화와 다운로드 속도가 안정적인 Daum 서버를 선택합니다.
Other를 누르면 Daum서버를 고를 수 있습니다.

 

서버선택
버튼을 누르고 닫기를 누르시면 다시읽기가 나옵니다 그것을 눌러주시면 됩니다.
이제 업데이트 목록이 뜰텐데요, 128개 정도 됩니다. 전부 업데이트 해 줍니다.

업데이트 후 재부팅을 합니다. 재부팅 후 마음대로 우분투를 사용하시면 됩니다.
우분투의 세팅과 설치가 끝났습니다.




추가 : 당신이 필요한 패키지

vi 를 사용하신다면
터미널에서
sudo apt-get install vim-full

c언어를 공부하신다면

터미널에서
sudo apt-get install build-essential

emacs 를 사용하신다면
터미널에서
sudo apt-get install emacs


수고하셨습니다.
Posted by 1010
98..Etc/JavaFX2008. 11. 12. 17:29
반응형

2007년 8월과 9월에 썬 개발자 네트워크의 John O'Conner는 JavaFX 스크립트 프로그래밍 언어(이 기사에서는 JavaFX 스크립트라고 줄여서 부름)를 시작하는 사용자에게 도움을 주고자 "학습 곡선 일지(Learning Curve Journal)"라는 제목의 시리즈를 기고했습니다.

 그 이후로 이 언어의 많은 중요한 부분이 개선되었습니다. 아마도 가장 중요한 변화는 JavaFX 스크립트의 초기 인터프리터 기반 버전을 대신하여 컴파일러 기반 버전을 사용할 수 있게 되었다는 점입니다. 학습 곡선 일지 시리즈의 1편, 2편 및 3편은 컴파일러 기반 버전의 언어 사용 방법을 보여주기 위해 업데이트 되었습니다. 최신 내용을 반영하여 다른 변경 사항도 적용되었습니다. 4편은 시리즈의 2편에서 시작된 JavaFX 이미지 검색 애플리케이션을 완결하는 새로운 부분입니다.

학습 곡선 일지의 앞 부분에서는 JavaFX 스크립트를 사용하여 Flickr에서 이미지를 검색하는 기존 이미지 검색 애플리케이션의 사용자 인터페이스(UI)를 재현했습니다. 결과 JavaFX 스크립트는 원래 UI와 완전히 똑같진 않지만 상당히 근접했습니다. 그림 1은 JavaFX 스크립트 구현으로 생성된 기본 UI를 보여줍니다.


그림 1. JavaFX 이미지 검색 애플리케이션 UI

 UI 구축에는 계층 구조적인 Swing 기반 접근 방법을 따랐습니다. 이 시리즈의 1편에서 언급한 것처럼 JavaFX 개발자는 앞으로 노드 기반 접근 방법을 사용할 것입니다.

이제 애플리케이션의 JavaFX 스크립트 버전을 완료하고 사용자가 Flickr 웹 사이트에서 이미지를 검색, 나열 및 표시할 수 있도록 하겠습니다. 완성된 JavaFX 스크립트 애플리케이션을 위해 NetBeans 프로젝트 다운로드를 받을 수 있습니다.


이미지 검색

구 현할 첫 번째 동작은 이미지 검색입니다. 사용자가 UI의 검색 필드에 검색어를 입력하면 애플리케이션은 Flickr 웹 사이트에서 이미지 검색을 시작합니다. 검색어와 매칭되는 이미지가 있으면 애플리케이션은 최대 100개의 매칭되는 축소판 이미지의 목록을 로드하여 UI의 Matched Images 영역에 선택 가능한 목록으로 표시합니다. 또한 진행 표시줄이 이미지 검색을 추적합니다.

기 존 이미지 검색 애플리케이션은 Matched Images 영역에 반환된 축소판 이미지의 목록을 제목과 함께 표시합니다. 우리는 JavaFX 스크립트 애플리케이션 목록에서 매칭되는 이미지의 반환된 제목만 보여주도록 단순화하겠습니다. JavaFX 스크립트의 ListItem 구성요소는 현재 icon 속성을 갖지 않습니다. 따라서 현재 ListListItem 구성요소가 생성하는 목록은 이미지를 포함할 수 없습니다.

이미지 검색을 위해 ImageSearcherPhoto의 두 가지 JavaFX 스크립트 클래스를 생성했습니다. 또한 진행 표시줄을 위한 별도의 클래스도 생성했습니다. JavaFX 스크립트 패키지에 ProgressBar 구성요소는 아직 없습니다. 임시 해결책으로 학습 곡선 일지 시리즈에서 구축한 이미지 검색 UI에 Swing JProgressBar 구성요소로부터 JavaFX 스크립트 진행 표시줄을 생성하는 createProgressBar 함수를 포함했습니다. 우리는 이 함수를 자체 파일의 자체 클래스로 이동하기로 결정했습니다. 이는 애플리케이션의 주요 부분을 깔끔하게 만드는 이점이 있습니다. 따라서 애플리케이션에는 이제 4개의 파일이 있습니다.

  • Main.fx: 애플리케이션의 주요 부분을 제공합니다. UI를 표시하고 이미지 검색 및 가져오기를 호출합니다.
  • ImageSearcher.fx: 이미지 검색을 수행합니다.
  • Photo.fx: Flickr 사진을 나타냅니다.
  • TempProgressBar.fx: 진행 표시줄을 생성합니다.

다음은 이미지 검색을 호출하는 Main.fx의 코드입니다.


  var searcher = ImageSearcher {
      callback: function(photos:Photo[]):Void {
          thumbnailList.items = for(photo in photos) {
              ListItem {
                  text: photo.title
                  value: photo
              }
          };

          matchedImagePB.indeterminate= false;
      }
  };

  var search = function():Void {
      System.out.println("searching... {searchTextField.text}");
      matchedImagePB.indeterminate = true;
      searcher.search(searchTextField.text);
  };

  searchTextField.action=search;

사용자가 UI의 검색 필드에 검색어를 입력하면 ImageSearcher 클래스 내의 search 함수를 호출하는 작업을 트리거하고 검색어를 search 함수로 전달합니다.

변수에 함수가 지정된 것에 유의하십시오.


  var search = function():Void {...}
 

 JavaFX 스크립트에서 함수는 변수에 지정되거나 매개 변수로써 다른 함수에 전달될 수 있는 1급 개체(first-class object)입니다.

또한 함수는 matchedImagePB의 indeterminate 등록 정보를 true로 설정합니다.


  var matchedImagePB = TempProgressBar { };

        matchedImagePB.indeterminate = true;
 


TempProgressBar 클래스는 matchedImagePB 변수에 지정됩니다. 따라서 matchedImagePB의 indeterminate 등록 정보를 설정하는 것은 실질적으로 TempProgressBar 개체의 indeterminate 등록 정보를 설정하는 것입니다. 그 영향을 이해하기 위해 TempProgressBar 클래스를 살펴보겠습니다.


TempProgressBar 클래스

다음은 TempProgressBar 클래스입니다.


 
package javafxscriptimgsearch2;

  import javafx.ext.swing.*;

  public class TempProgressBar extends Component {
      protected function createJComponent():javax.swing.JComponent {
          return new javax.swing.JProgressBar();
      }
      public attribute indeterminate:Boolean = false on replace {
          var prog = this.getJComponent() as javax.swing.JProgressBar;
          prog.setIndeterminate(indeterminate);
      }
}
 

클래스에는 createJComponent 함수와 indeterminate 속성이 있습니다.
replace
트리거가 indeterminate 속성에 연결되어 있습니다.


      public attribute indeterminate:Boolean = false on replace {
          var prog = this.getJComponent() as javax.swing.JProgressBar;
          prog.setIndeterminate(indeterminate);
      }
 

애플리케이션의 주요 부분이 속성을 true로 설정하는 것과 같이 속성 값이 변경되면 트리거는 진행 표시줄을 생성합니다. 특히 트리거는 getJComponent() 함수를 사용하여 JavaFX 스크립트 구성요소로 캡슐화된 Swing JProgressBar 구성요소를 생성합니다. 트리거는 또한 JProgressBar 구성요소의 indeterminate 등록 정보를 true로 설정하여 검색 진행 중에 진행 표시줄이 계속 움직이도록 합니다.

트 리거는 JavaFX 스크립트의 강력한 기능 중 하나입니다. 트리거는 특정 조건 충족 시 코드 블록을 실행하도록 합니다. 또한 기존 Swing 구성요소의 재사용이 얼마나 쉬운지에도 유의하십시오. Swing 구성요소를 사용하려면 JavaFX 스크립트로 간단한 래퍼(wrapper)를 작성하기만 하면 됩니다.


ImageSearcher 클래스

다음은 ImageSearcher 클래스입니다.


    package javafxscriptimgsearch2;

import javax.xml.parsers.*;
import org.xml.sax.helpers.DefaultHandler;
import java.lang.System;
import java.lang.Thread;
import java.lang.Runnable;
import javax.swing.SwingUtilities;

public class ImageSearcher {
public attribute callback: function(photos:Photo[]):Void;

public function search(search:String) {
var thread = new Thread(Runnable {
public function run():Void {
var photos:Photo[];

var handler = DefaultHandler {
public function startDocument() { }
public function startElement(uri:String, localName:String, qName:String , attributes:org.xml.sax.Attributes ) {
if(qName == "photo") {
var photo = Photo {
id: attributes.getValue("id")
server: attributes.getValue("server")
farm: attributes.getValue("farm")
title: attributes.getValue("title")
secret: attributes.getValue("secret")
};
insert photo into photos;
}
}
public function endElement(uri:String , localName:String , qName:String ) { }
public function endDocument() { }

};

var SEARCH_URL = "http://api.flickr.com/services/rest/?" +
"method=flickr.photos.search";
var key = "339db1433e5f6f11f3ad54135e6c07a9";
var MAX_IMAGES = 100;
var searchUrl = "{SEARCH_URL}&api_key={key}&per_page={MAX_IMAGES}&text={search}";
var url = new java.net.URL(searchUrl);
var is = url.openStream();
var factory = SAXParserFactory.newInstance();
var saxParser = factory.newSAXParser();
saxParser.parse(is, handler);

SwingUtilities.invokeLater(Runnable {
public function run():Void {

if(callback != null) {
callback(photos);
}
}
});
}
});
thread.start();
}
}
 

ImageSearcher 클래스는 애플리케이션에서 이미지 검색을 수행하는 search 함수의 래퍼(wrapper)입니다.

새 스레드를 시작하여 search 함수가 시작됩니다. 스레드 내에서 함수는 검색어와 매칭되는 이미지(Flickr에서는 사진)를 가져오기 위해 Flickr 사진 검색 웹 서비스를 호출합니다. 다음은 Flickr 서비스를 호출하는 코드입니다.


   var SEARCH_URL = "http://api.flickr.com/services/rest/?" +
          "method=flickr.photos.search";
  var key = "339db1433e5f6f11f3ad54135e6c07a9";
  var MAX_IMAGES = 100;
  var searchUrl = "{SEARCH_URL}&api_key={key}&per_page={MAX_IMAGES}&text={search}";
  var url = new java.net.URL(searchUrl);
  var is = url.openStream();
 


호출은 Flickr API의 REST(Representational State Transfer) 버전을 사용합니다(Flickr는 XML-RPC 및 SOAP 버전도 제공합니다). API에 전달되는 인수에는 API 키, 반환되는 이미지의 최대 갯수, 사용자가 지정한 검색어가 포함됩니다. 애플리케이션에서 최대 100개의 매칭되는 이미지 목록을 다운로드하고 싶으므로 이미지 최대 갯수를 100으로 설정했습니다.

사진 검색 서비스는 사진을 XML 문서로 반환하므로 문서를 분석하는 기법이 필요합니다. 이 애플리케이션에서는 분석 수행을 위해 SAX DefaultHandler를 사용했습니다.

   var handler = DefaultHandler {
public function startDocument() { }
public function startElement(uri:String, localName:String, qName:String , attributes:org.xml.sax.Attributes ) {
if(qName == "photo") {
var photo = Photo {
id: attributes.getValue("id")
server: attributes.getValue("server")
farm: attributes.getValue("farm")
title: attributes.getValue("title")
secret: attributes.getValue("secret")
};
insert photo into photos;
}
}
public function endElement(uri:String , localName:String , qName:String ) { }
public function endDocument() { }

};

 

각 Flickr 사진에 대해 DefaultHandler사진 개체를 인스턴스화하고 속성 값을 Flicker 사진의 해당 속성 값으로 설정합니다. DefaultHandler는 그 다음 각 Photo 개체를 photos라는 시퀀스에 추가합니다. 학습 곡선 일지 3편: JavaFX 스크립트 함수에서 시퀀스는 동일한 유형을 갖는 개체의 순서별 목록을 나타냈습니다.

search 함수는 그 다음 callback을 호출하는 다른 스레드를 시작합니다.


 
 SwingUtilities.invokeLater(Runnable {
          public function run():Void {

              if(callback != null) {
                  callback(photos);
              }
          }
  }
 

SwingUtilities.invokeLater 메소드는 스레드의 Runnable 작업을 이벤트 디스패치 스레드에 놓습니다.


Callback 함수

ImageSearcher 클래스는 속성 유형이 함수인 callback이라는 속성을 갖습니다. 함수는 photos 시퀀스를 매개 변수로 받고 아무 것도 반환하지 않습니다.


   
public attribute callback: function(photos:Photo[]):Void;
 
ImageSearcher 클래스가 인스턴스화되면(애플리케이션의 주요 부분에 발생) callback 함수는 UI의 Matched Images 영역에 표시하기 위해 제목의 목록을 구축합니다. 목록의 각 항목은 속성 값이 반환된 사진의 제목인 text 속성과 속성 값이 Photo 개체인 value 속성을 갖습니다. 다음 코드는 애플리케이션의 주요 부분 내에서 ImageSearcher 클래스를 인스턴스화하고 callback 함수를 제공합니다.


  var searcher = ImageSearcher {

       callback: function(photos:Photo[]):Void {
          thumbnailList.items = for(photo in photos) {
              ListItem {
                  text: photo.title
                  value: photo
              }
          };

          matchedImagePB.Indeterminate= false;
      }
  };
 


매칭되는 사진 목록을 구축한 후 callback 함수는 Matched Images 진행 표시줄의 indeterminate 등록 정보를 기본값인 false로 다시 설정합니다.


이미지 검색 수행

이미지 검색을 다루는 코드를 검토했으니 이제 작업을 살펴봅시다. 그림 2는 사용자가 검색어를 입력한 후 Search 필드와 Matched Images 진행 표시줄의 상태를 보여줍니다.



그림 2.
검색어 입력

애플리케이션이 매칭되는 이미지를 검색하는 동안 검색어를 기반으로 검색 중임을 나타내는 메시지가 나타납니다. 이 예제에서는 "searching... polar bear" 메시지가 나타납니다.

그림 3은 매칭되는 이미지의 반환된 제목 목록 일부를 보여줍니다.


그림 3. 이미지 검색 결과

검색 함수가 올바르게 작동합니다!


이미지 표시

구현할 다음 동작은 이미지 표시입니다. 사용자가 반환된 이미지 제목 목록에서 제목을 선택하면 애플리케이션은 해당 이미지를 Flickr 사이트에서 가져와 UI의 Selected Image 영역에 표시해야 합니다.

표시를 위해 이미지를 가져오도록 onChange 위임을 추가하는 List 클래스의 사용자 정의 하위 클래스인 PhotoList라는 클래스를 추가했습니다. 다음은 Main.fx 파일에서 PhotoList 가 인스턴스화되는 방법을 보여줍니다.


   class PhotoList extends List {
       
public attribute onChange:function(photo:Photo);
       
public attribute selectedPhoto:ListItem = bind selectedItem on replace {
           
var photo = selectedPhoto.value as Photo;
           
if(onChange != null) {
               onChange
(photo);
           
}
       
}
   
}
 
   
var thumbnailList = PhotoList {
       preferredSize
:[300, 230]
       hmax
: Layout.UNLIMITED_SIZE
       vmax
: Layout.UNLIMITED_SIZE
   
};


사용자가 목록에서 항목을 선택하면 애플리케이션은 PhotoList 개체의 selectedPhoto 속성을 선택된 항목으로 설정합니다. 이는 PhotoList 개체의 selectedPhoto 속성이 다음 표현식의 결과에 바인딩되었기 때문입니다.

   
      selectedItem on replace {
      var photo = selectedPhoto.value as Photo;
  }
 

바인딩은 표현식의 결과를 변수와 연관시키는 것을 의미합니다. 표현식이 변경되면(이 경우 selectedItem가 변경됨) 변수 값은 변경됩니다(이 경우 PhotoListselectedPhoto 속성이 자동으로 업데이트됨). 바인딩은 JavaFX 스크립트의 또 다른 강력한 기능입니다. 바인딩을 사용하여 애플리케이션의 부분을 직접적이고 우아하게 동기화할 수 있습니다.

또한 사용자가 목록에서 항목을 선택하면 애플리케이션은 PhotoList 개체의 onChange 속성과 연관된 이미지 로더 함수를 호출합니다. 이 함수는 선택된 진행 표시줄의 indeterminate 등록 정보를 true로 설정하여 이미지를 가져오는 동안 계속 진행되도록 합니다. 그 다음 선택된 Photo 개체에서 해당 이미지를 가져오기 위해 loadFullImage 함수를 호출합니다.


 class PhotoList extends List {
      public attribute onChange:function(photo:Photo);
      ...
          if(onChange != null) {
              onChange(photo);
       }

  // configure the image loader
  var imageLoader = function(photo:Photo):Void {
      if(photo != null) {
          selectedImagePB.indeterminate = true;
          photo.loadFullImage(function():Void{
              selectedImageDisplay.icon = Icon { image: photo.fullImage };
              selectedImagePB.indeterminate = false;
          });
      }
  };

thumbnailList.onChange = imageLoader;
 

이미지 로더는 Selected Image 영역에 표시하기 위해 이미지를 설정하고 이미지를 가져온 후 선택된 진행 표시줄의 indeterminate 등록 정보를 다시 false로 설정합니다.


  selectedImageDisplay.icon = Icon { image: photo.fullImage };
  selectedImagePB.indeterminate = false;
 


Photo 클래스

Photo 클래스를 살펴봅시다.

    package javafxscriptimgsearch2;

import javafx.scene.image.*;
import java.lang.*;
import javax.swing.SwingUtilities;
import javax.imageio.ImageIO;

public class Photo {
public attribute id:String;
public attribute server:String;
public attribute farm:String;
public attribute title:String;
public attribute secret:String;

private attribute image:Image = null;

public attribute fullImage:Image = null;

public attribute fullImageURL = bind "http://static.flickr.com/{server}/{id}_{secret}.jpg";

public function loadFullImage(
callback:function():Void
):Void {

if(image == null) {
var thread = new Thread(Runnable {
public function run():Void {
var strImageUrl = "http://static.flickr.com/{server}/{id}_{secret}.jpg";
System.out.println("loading: {strImageUrl}");
var buffImg = ImageIO.read(new java.net.URL(strImageUrl));

SwingUtilities.invokeLater(Runnable {
public function run():Void {
image = Image.fromBufferedImage(buffImg);
fullImage = image;
if(callback != null) {
callback();
}
}
});

}});
thread.start();
} else {
callback();
}

}
}
 

Photo 클래스는 Flickr에 저장된 사진과 연관시키는 XML 속성에 해당하는 몇 가지 속성을 갖습니다. 예를 들어 Photo 클래스의 id 속성은 Flickr에 저장된 사진의 id 속성에 해당합니다. 또한 클래스는 Flickr에서 사진을 가져오는 loadFullImage 함수도 제공합니다.

새 스레드를 시작하여 loadFullImage 함수가 시작됩니다. 스레드 내에서 함수는 특정 사진에 대해 사진 소스 URL을 구성한 다음 사진을 가져옵니다. 다음은 사진 소스 URL을 구성하고 사진을 가져오는 코드입니다


   var strImageUrl = "http://static.flickr.com/{server}/{id}_{secret}.jpg"

   var buffImg = ImageIO.read(new java.net.URL(strImageUrl));
 


loadFullImage 함수가 URL 구성을 위해 Photo 개체의 server, idsecret 속성을 사용하는 것에 유의합니다. 또한 이미지 로드를 위해 자바 imagio 패키지의 ImageIO.read 메소드를 사용했습니다.

함수는 JavaFX 스크립트 Image 클래스의 fromBufferedImage 메소드를 사용하여 가져온 사진을 Photo 개체의 image 속성에 지정합니다. 그런 다음 호출자(이 경우 애플리케이션의 주요 부분에 있는 이미지 로더)에게의 callback을 호출하는 다른 스레드를 시작합니다.


   SwingUtilities.invokeLater(Runnable {
       public function run():Void {
           image = Image.fromBufferedImage(buffImg);
           fullImage = image;
           if(callback != null) {
               callback();
           }
       }
   });
 

SwingUtilities.invokeLater 메소드는 스레드의 Runnable 작업을 이벤트 디스패치 스레드에 놓습니다.


목록에 이미지 표시

애플리케이션의 이미지 표시 부분을 테스트해봅시다. 그림 4는 Matched Images 영역에서 이미지를 선택한 후 Selected Image 진행 표시줄의 상태를 보여줍니다.


그림 4. 표시할 이미지 선택

애플리케이션이 이미지를 가져오면 이미지의 사진 소스 URL을 식별하는 메시지를 표시합니다. 이 예제에서는 "loading: http://static.flickr.com/3234/2595583764_a2e6661d3a.jpg" 메시지가 나타납니다. 이미지 가져오기가 끝나면 애플리케이션은 "loaded" 메시지를 표시합니다.

그림 5는 UI의 Selected Image에 선택한 이미지가 표시된 완전한 UI를 보여줍니다.


그림 5. 표시된 이미지

애플리케이션의 이미지 가져오기 부분이 작동합니다. 애플리케이션도 의도대로 작동합니다.

완성된 JavaFX 스크립트 애플리케이션을 위해 NetBeans 프로젝트 다운로드를 받을 수 있습니다.

요약

이 학습 곡선 일지 시리즈에서는 JavaFX 스크립트 프로그래밍 언어(이 시리즈에서는 JavaFX 스크립트라고 줄여서 부름)의 사용을 시작하는데 도움이 되는 몇 가지 기본 개념 및 기법을 소개했습니다.

시리즈의 1편에서는 간단한 JavaFX 애플리케이션을 만드는 방법을 소개했습니다.

2편에서는 풍부한 UI 생성을 위해 사용 가능한 JavaFX 라이브러리 내의 일부 클래스와 언어의 선택적 구문을 설명했습니다. UI 구축에는 계층 구조적인 Swing 기반 접근 방법을 따랐습니다. 이 시리즈의 1편에서 언급한 것처럼 앞으로 JavaFX 개발자는 노드 기반 접근 방법을 사용할 것입니다. 노드 기반 접근 방법에서는 UI 구축을 위해 다른 JavaFX 라이브러리를 사용할 것입니다.

3편에서는 뷰와 데이터 모델 등의 애플리케이션 부분을 동기화하기 위해 사용 가능한 JavaFX 스크립트의 바인딩 기능과 JavaFX 스크립트 함수를 다뤘습니다.

4편(본 기사)에서는 웹 서비스 액세스를 위한 JavaFX 스크립트 사용 방법을 보여주었습니다. 그 과정 중에 FX 스크립트에서 Swing 클래스와 같은 자바 기술 슬래스의 액세스가 얼마나 쉬운지도 보여주었습니다.

또한 이 시리즈를 통해 코드 완성과 같은 기능이 어떻게 NetBeans IDE 6.1에서 JavaFX 애플리케이션의 빌드 및 실행을 단순화하는지도 볼 수 있었습니다. JavaFX Preview SDK를 사용하여 명령줄에서 JavaFX 애플리케이션을 빌드 및 실행할 수도 있습니다.

JavaFX 포함 NetBeans IDE 6.1을 다운로드하여 설치하거나 JavaFX Preview SDK를 다운로드하여 JavaFX 스크립트를 시작하십시오.


자세한 정보
이 글의 영문 원본은
Learning Curve Journal, Part 4: Accessing a Web Service
에서 보실 수 있습니다.

"Java FX" 카테고리의 다른 글

Posted by 1010
98..Etc/JavaFX2008. 11. 12. 17:29
반응형

2007년 8월과 9월에 썬 개발자 네트워크의 John O'Conner는 JavaFX 스크립트 프로그래밍 언어(이 기사에서는 JavaFX 스크립트라고 줄여서 부름)를 시작하는 사용자에게 도움을 주고자 "학습 곡선 일지(Learning Curve Journal)"라는 제목의 시리즈를 기고했습니다.

그 이후로 이 언어의 많은 중요한 부분이 개선되었습니다. 아마도 가장 중요한 변화는 JavaFX 스크립트의 초기 인터프리터 기반 버전을 대신하여 컴파일러 기반 버전을 사용할 수 있게 되었다는 점입니다. 이전의 학습 곡선 일지에서는 인터프리터 기반 버전 사용에 대해 설명했습니다.

업데이트된 학습 곡선 일지에서는 컴파일러 기반 버전의 언어 사용법을 보여줍니다. 최신 내용을 반영하여 다른 변경 사항도 적용되었습니다.

지난 학습 곡선 기사에서는 간단한 사용자 인터페이스(UI)를 구현하고 UI 시험이 성공적이었음을 확인했습니다. 결과 JavaFX 스크립트는 Flickr에서 이미지를 검색하는 이미지 검색 애플리케이션 구축을 위한 원래 자바 프로그래밍 언어 UI와 비슷하게 보였습니다. 그림 1은 결과적인 기본 프레임을 보여줍니다.


그림 1. 원래 UI를 복제한 JavaFX 이미지 검색 애플리케이션

선언적 JavaFX 스크립트 구문을 사용한 결과 코드는 자바 언어 UI의 이식을 위한 괜찮은 시작이었습니다. 그러나 유휴 상태의 프레임, 응답하지 않는 검색 필드, 비활성 진행 표시줄, 빈 목록 상자 및 빈 이미지 레이블에 대한 추가 작업이 필요합니다. 여기에서는 아무 일도 발생하지 않습니다. 현재까지는 활성 데이터모델에 아무 UI 요소도 연결되지 않았으며 사용자 상호작용에도 응답하지 않습니다. 예를 들어 Search 텍스트 필드는 입력한 문자를 받아서 보여주지만 아직 아무 것도 하지 않습니다.

이 골격 뿐인 UI에는 추가 작업이 필요합니다. 이를 위해 비활성 애플리케이션에서 필요한 작업을 수행하도록 하는 함수가 필요합니다.


함수

JavaFX 스크립트 함수는 자바 프로그래밍 언어 메소드와 비슷합니다. 이들 메소드와 마찬가지로 함수는 매개 변수와 반환 값을 갖습니다. 또한 속성 및 변수와 if-then, while 루프, for 루프 및 기타 조건문도 가질 수 있습니다. 다음은 몇 가지 유효한 함수의 예입니다.


 
function z(a,b) {
      var x = a + b;
      var y = a - b;
      return sq(x) / sq (y);
  }

  function sq(n) {return n * n; }

  function main() {
      return z(5, 10);
  }

  function min(x1 : Number, x2 : Number ): Number {
      if (x1 < x2) {
        return x1;
      }
      else {
        return x2;
  }
 

반환 값 유형이나 매개 변수 유형을 선언할 필요가 없습니다. 그러나 자바 언어 프로그래머인 저에게는 min 함수에서와 같이 유형을 사용하는 것이 익숙하므로 가능한 경우에는 항상 사용하곤 합니다. 매개 변수 유형을 선언하는 것은 명확성에 도움이 됩니다. 따라서 z 함수를 다음과 같이 다시 작성하겠습니다.


function z(a: Number, b: Number): Number {
   var x: Number = a + b;
   var y: Number = a - b;
   return sq(x) / sq (y);
}
 


return 키워드는 선택 사항입니다.

   function sq(n) {n*n;}

위 함수는 다음과 같습니다.

   function sq(n) {return n*n;}

함수는 function 키워드로 시작합니다. 그 뒤에는 함수 이름과 매개 변수 목록이 나옵니다. JavaFX 스크립트에서는 유형이 변수나 함수 이름 다음에 나옵니다. 예를 들면 b: Number 매개변수는 b 라는 인수의 유형이 Number라는 의미입니다. 마지막으로 함수는 Number를 반환하므로 이를 매개 변수 목록 뒤에 선언할 수 있습니다. 함수의 본문 앞뒤에는 자바 언어에서 메소드 본문을 둘러싸는 것과 같이 괄호가 있습니다.

함수는 매개 변수나 기타 참조 변수가 변경될 때마다 반환 값을 재평가합니다. 이 기능은 개체를 자주 변경될 수 있는 특정 값에 바인드하려는 경우 유용합니다. 바인딩에 대해서는 나중에 자세히 설명하겠습니다.

클래스에 대해 함수가 정의될 수도 있습니다. 다음은 Friends 클래스에 대해 정의된 함수의 예입니다.


   import java.lang.System;
  import javafx.lang.Sequences;

  class Friends {
      attribute knownNames: String[];
      function sayHello(name: String): String {
          var index = Sequences.indexOf(knownNames,name);
          if (index >= 0) {
              return "Hello, {name}!";
              } else {
              return "Sorry, I can't talk to strangers.";
              }
      }
  }

  var buddies = Friends {
      knownNames: ["John", "Robyn", "Jack", "Nick", "Matthew",
      "Tressa", "Ruby"]
  };

  var greeting = buddies.sayHello("John");
  System.out.println(greeting);
 


이 작은 프로그램은 sayHello 메소드에 아는 이름을 입력하면 "Hello"라고 응답합니다. 그렇지 않은 경우엔 "can't talk to strangers"라고 합니다. Friends 클래스에는 한 가지 속성과 속성을 사용하여 메시지를 반환하는 함수가 포함되어 있습니다. Sequences 클래스를 사용하는 것에 유의합니다. 이 클래스는 시퀀스 조작을 위한 다양한 함수를 포함합니다. 시퀀스는 이 예제에서 아는 이름의 목록과 같이 개체의 순서별 목록을 나타냅니다. SequencesindexOf 함수는 지정된 시퀀스에서 같은 값을 갖는 개체를 검색합니다. 여기에서 indexOf는 아는 이름 시퀀스에서 지정된 이름(이 예제에서는 "John")과 매칭되는 개체를 검색합니다.


반응적 UI 요소

UI 요소(JavaFX 스크립트 라이브러리에서는 노드)는 키 입력이나 마우스 클릭과 같은 사용자 상호작용에 응답할 수 있습니다. 위젯은 action, onMouseClicked, onKeyTyped 및 기타 이벤트 기반 속성을 갖습니다. 이들 속성과 함수를 연관시킬 수 있습니다. 예를 들어 함수를 TextFieldaction 속성과 연관시키면 해당 함수는 필드 내에서 Enter를 누를 때 실행됩니다. Button 위젯의 동일한 action 속성은 사용자가 클릭할 때마다 활성화됩니다.

JavaFX 이미지 검색 애플리케이션과 관련된 함수가 필요하므로 UI 요소에 대한 이벤트 핸들러를 작성하기로 했습니다. 다음 애플리케이션은 두 개의 버튼과 하나의 레이블을 생성합니다. Bigger 버튼을 누르면 레이블의 글꼴 크기가 증가하고 텍스트가 변경됩니다. Smaller 버튼을 누르면 레이블의 글꼴 크기가 감소하고 텍스트가 변경됩니다.

이 애플리케이션에서는 계층 구조적인 Swing 기반 접근 방법을 따릅니다. 이 시리즈의 1편에서 언급한 것처럼 앞으로는 JavaFX 스크립트 개발자가 노드 기반 접근 방법을 사용하도록 할 것입니다.


   import javafx.ext.swing.SwingFrame;
  import javafx.ext.swing.BorderPanel;
  import javafx.ext.swing.FlowPanel;
  import javafx.ext.swing.Button;
  import javafx.scene.Font;
  import javafx.scene.HorizontalAlignment;
  import javafx.ext.swing.Label;

  var font = Font { size: 18 };

  class FontDataModel {
      attribute text: String;

      function increaseFontSize() {
         font = Font { size: font.size + 1 };
         text= "Font Test ({font.size})";
         }
      function decreaseFontSize() {
         font = Font { size: font.size - 1 };
         text= "Font Test ({font.size})";
      }
  }

  SwingFrame {
       var myFont = FontDataModel {
           text: "Font Test (18)"

       }

      content:
      BorderPanel {
          top: FlowPanel {
              alignment: HorizontalAlignment.LEADING
              content: [
                  Button { text:"Bigger"
                      action :
                      function() {
                           myFont.increaseFontSize();
                      }
              },

              Button { text:"Smaller"
                  action : function() {
                      myFont.decreaseFontSize();
                  }
              }

              ]
          }
          center:
              Label {
                  width: 200
                  font: bind font
                  text: bind myFont.text

          }

       }
       visible: true
  }
 

이 코드를 잘라내어 JavaFX 애플리케이션에 바로 붙여넣을 수 있습니다. Preview 버튼을 사용하면 그림 2의 결과가 보입니다.


그림 2. 미리보기 기능을 사용하여 JavaFX 스크립트 언어를 대화형으로 시험

이 Bigger-Smaller 글꼴 애플리케이션은 텍스트 문자열 속성을 갖는 FontDataModel을 생성합니다. 애플리케이션은 FontDataModel 인스턴스를 생성하고 text 속성을 초기화합니다. FontDataModel에도 increaseFontSizedecreaseFontSize라는 두 가지 함수가 있습니다. 이들 함수는 텍스트 속성을 변경하고 Font 클래스의 인스턴스를 생성하며 인스턴스의 글꼴 크기를 업데이트합니다.

왜 글꼴을 FontDataModel의 속성으로 지정하고 텍스트 속성과 같은 방법으로 함수에서 업데이트하지 않는지 궁금할 지도 모릅니다. 이러한 접근 방법은 Font가 변경할 수 없는 개체, 즉 원래 개체의 속성을 변경할 수 없기 때문에 사용할 수 없습니다. 개체의 인스턴스에서만 속성을 변경할 수 있습니다.

각 버튼은 연관된 함수를 포함하는 action 속성을 갖습니다. 예를 들어 Bigger 레이블이 있는 버튼은 myFont 변수의 increaseFontSize 함수를 호출합니다.


           
Button { text:"Bigger"

       action :
      function() {
           myFont.increaseFontSize();
      }
   
}
 

버튼을 누를 때마다 글꼴 크기와 텍스트가 변경되는 것을 볼 수 있습니다. 그림 3은 Bigger 버튼을 두 번 눌렀을 때의 결과를 보여줍니다.


그림 3. 버튼을 클릭하면 텍스트와 글꼴 크기 변경

분명히 increaseFontSize 메소드는 글꼴과 텍스트를 변경합니다. 이를 위해 바인딩이라는 JavaFX 스크립트 기능을 사용했습니다.


뷰와 모델 바인딩

JavaFX 스크립트에는 하나의 속성이 다른 속성의 변경을 추적하도록 하는 bind 연산자가 있습니다. 하나의 속성을 다른 속성에 바인딩한다는 것은 바인딩된 속성이 대상 속성의 변경 사항을 항상 인지한다는 것을 의미합니다. 이 Bigger-Smaller 글꼴 애플리케이션에서는 Label이 글꼴과 텍스트의 변경 사항을 추적하도록 하려고 합니다. 이를 위해 Labelfont 속성을 Font 변수에 바인드하도록 bind 연산자를 사용했습니다. 또한 Labeltext 속성을 FontDataModeltext 속성에 바인드하도록 bind 연산자를 사용했습니다.

다음은 Label 선언입니다.


 
Label {
      width: 200
      font: bind font
      text: bind myFont.text

  }
 

bind 연산자는 함수에도 사용할 수 있습니다. 함수는 인수나 참조 변수가 변경될 때마다 결과를 업데이트하므로 함수에의 바인딩은 단일 속성에의 바인딩과 마찬가지로 작용합니다. 사실 함수는 실제로 바인딩과 함께 사용하도록 설계되었습니다. 본문 내의 매개 변수 및 참조 변수를 모두 포함하는 모든 종속성을 자동으로 추적하는 재사용 가능한 하위 루틴으로의 바인딩을 리팩터링하기 위해 이들을 사용할 수 있습니다.

표 1에서 코드의 일부를 참조하십시오.

표1. 함수와 함께/함수 없이 바인드 사용
함수 없이 바인드
함수와 함께 바인드
   import java.lang.System;

class Data {
attribute foo: Number;
attribute baz: Number;
}

var data = Data {
foo: 4
baz: 7
};

var zoo = bind data.foo +
data.baz + 10;
System.out.println(zoo);
data.baz = 12;
System.out.println(zoo);
   import java.lang.System;

class Data {
attribute foo: Number;
attribute baz: Number;
function add(x, y, z): Number {
return x+y+z;
}
}

var data = Data {
foo: 4
baz: 7
};

var zoo = bind data.add(data.foo, data.baz, 10);
System.out.println(zoo);
data.baz = 12;
System.out.println(zoo);
출력:
21.0
26.0
출력:
21.0
26.0

요약

JavaFX 애플리케이션에 동작을 추가하기 위해 함수를 사용합니다. UI 구성요소의 속성은 함수에 매핑됩니다. action, onMouseClickedonKeyTyped와 같은 UI 이벤트 처리를 위해 이들 함수를 정의할 수 있습니다. 함수에는 함수 본문 내에서 매개 변수 및 참조 변수를 재평가하는 추가적인 등록 정보가 있습니다.

bind 연산자를 사용하여 하나의 속성을 다른 속성에 연결할 수 있습니다. 이는 UI 위젯이 모델 속성을 추적하도록 할 때 특히 유용합니다. 뷰 속성을 모델 속성에 바인딩한다는 것은 모델과 뷰가 동일한 데이터로 항상 동기화됨을 의미합니다.

JavaFX 이미지 검색 애플리케이션의 UI에 아직 기능을 추가하지 않았지만 함수가 필요하다는 것을 알게 되었습니다. 검색 텍스트를 가져오기 위해서는 거의 확실히 함수를 사용해야 합니다. 같은 함수가 이미지를 가져오기 위해 Flickr 사이트에도 액세스할 것입니다. 또한 뷰를 기본 모델에 연결하기 위해 bind 연산자도 사용해야 할 것입니다.

이제 UI를 일부 기본 작업 및 함수에 연결하는 방법을 알게 되었습니다. 또한 UI를 기본 모델에 연결하기 위해 bind 연산자도 사용할 수 있습니다.

자세한 정보
이 글의 영문 원본은
Learning Curve Journal, Part 3: JavaFX Script Functions
에서 보실 수 있습니다.

"Java FX" 카테고리의 다른 글

Posted by 1010
98..Etc/JavaFX2008. 11. 12. 17:28
반응형

2007 년 8월과 9월에 썬 개발자 네트워크의 John O'Conner는 JavaFX 스크립트 프로그래밍 언어(이 기사에서는 JavaFX 스크립트라고 줄여서 부름)를 시작하는 사용자에게 도움을 주고자 "학습 곡선 일지(Learning Curve Journal)"라는 제목의 시리즈를 기고했습니다.

그 이후로 이 언어의 많은 중요한 부분이 개선되었습니다. 아마도 가장 중요한 변화는 JavaFX 스크립트의 초기 인터프리터 기반 버전을 대신하여 컴파일러 기반 버전을 사용할 수 있게 되었다는 점입니다. 이전의 학습 곡선 일지에서는 인터프리터 기반 버전 사용에 대해 설명했습니다.

업데이트된 학습 곡선 일지에서는 컴파일러 기반 버전의 언어 사용법을 보여줍니다. 최신 내용을 반영하여 다른 변경 사항도 적용되었습니다.

사용자 인터페이스를 정의하기 위해 10년 가까이 자바 프로그래밍 언어를 사용해온 저는 JavaFX 스크립트를 처음 사용해보고 두 가지 환경 사이의 큰 차이점을 금방 느낄 수 있었습니다. 프로그래머는 자바 언어에서 사용자 인터페이스(UI) 정의를 위해 절차적 언어를 사용하지만 JavaFX Script에서는 UI 정의에 선언적 문을 사용할 수 있습니다. 이는 커다란 차이이며 여기에 적응하는 데는 약간의 시간과 노력이 필요할 수 있습니다.

UI 생성을 위한 새로운 선언적 스타일에 대해 알아보고자 기존 애플리케이션 UI를 자바 언어 구현에서 JavaFX 스크립트로 이식하기로 했습니다. 썬 개발자 네트워크자바 언어 허브에 있는 Swingworker 기사에서 만든 이미지 뷰어 애플리케이션을 선택했습니다. 원래 애플리케이션은 Java SE 6에서 SwingWorker 클래스의 사용 방법을 보여주기 위한 것이었지만 UI 자체는 JavaFX 스크립트로의 간편한 이전을 제공할 만큼 충분히 단순해 보입니다.


기존 사용자 인터페이스

기 존 애플리케이션에서는 사용자가 유명한 Flickr 웹 사이트에서 이미지를 검색, 나열 및 표시할 수 있도록 했습니다. 사용자는 검색어를 입력할 수 있으며 애플리케이션은 REST API를 사용하여 매칭되는 축소판 이미지 목록을 Flickr에 쿼리합니다. 사용자는 축소판 이미지를 하나 선택하여 크고 상세한 이미지를 가져올 수 있습니다. 그림 1은 검색 결과가 나온 기존 애플리케이션을 보여줍니다.

그림 1. 검색 결과가 나온 애플리케이션 UI

이 UI는 위에서부터 아래로 다음 구성요소로 이루어져 있습니다.

  • 기본 프레임 창 컨테이너
     
  • 검색 레이블 및 검색 텍스트 필드
     
  • 검색 매칭 레이블 및 진행 표시줄
     
  • 매칭되는 축소판 이미지 목록과 짧은 설명
     
  • 선택 레이블 및 진행 표시줄
     
  • 선택한 이미지를 보여주는 레이블
     

UI는 JFrame, JLabel, JProgressBar, JScrollPaneJList.와 같은 일반 Swing 구성요소로 이루어집니다. JList 구성요소는 축소판 이미지와 제공되는 짧은 설명을 표시하기 위한 사용자 정의 렌더러를 갖지만 여전히 상대적으로 간단한 UI로서 JavaFX 스크립트의 선언적 UI 측면을 조사하는 데 도움이 될 것입니다. 전체 애플리케이션의 구현을 시도해 보겠지만 현재로는 기존 UI와 적당히 비슷한 정도로도 충분합니다. 작동하는 데모처럼 극적이진 않겠지만 그림 2에 나온 비활성 UI는 JavaFX 스크립트의 선언적 UI에 대한 초기 목표를 보여줍니다.

그림 2. 애플리케이션 UI

원래 UI는 NetBeans IDE 6.1과 Matisse GUI 편집기를 사용하여 구현했습니다. Swingworker 기사에서 모든 원래 코드 및 생성된 UI 주변의 코드를 다운로드 받을 수 있습니다. 코드에서 이 UI를 생성하기 위해 NetBeans IDE가 GroupLayout를 어떻게 사용했는지 볼 수 있습니다.

    private void initComponents() {
lblSearch = new javax.swing.JLabel();
txtSearch = new javax.swing.JTextField();
lblImageList = new javax.swing.JLabel();
scrollImageList = new javax.swing.JScrollPane();
listImages = new JList(listModel);
lblSelectedImage = new javax.swing.JLabel();
lblImage = new javax.swing.JLabel();
progressMatchedImages = new javax.swing.JProgressBar();
progressSelectedImage = new javax.swing.JProgressBar();

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Image Search");
lblSearch.setText("Search");
lblImageList.setText("Matched Images");

// ...
// event listeners, models, and cell renderers removed for this example
//

lblSelectedImage.setText("Selected Image");

lblImage.setBorder(javax.swing.BorderFactory.createLineBorder(
new java.awt.Color(204, 204, 204)));
lblImage.setFocusable(false);
lblImage.setMaximumSize(new java.awt.Dimension(500, 500));
lblImage.setMinimumSize(new java.awt.Dimension(250, 250));
lblImage.setOpaque(true);
lblImage.setPreferredSize(new java.awt.Dimension(500, 250));

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lblImage, javax.swing.GroupLayout.Alignment.LEADING,
javax.swing.GroupLayout.DEFAULT_SIZE, 462, Short.MAX_VALUE)
.addComponent(scrollImageList, javax.swing.GroupLayout.DEFAULT_SIZE,
462, Short.MAX_VALUE)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblImageList)
.addComponent(lblSelectedImage))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(progressMatchedImages, javax.swing.GroupLayout.DEFAULT_SIZE,
350, Short.MAX_VALUE)
.addComponent(progressSelectedImage, javax.swing.GroupLayout.DEFAULT_SIZE,
350, Short.MAX_VALUE)))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addComponent(lblSearch)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txtSearch, javax.swing.GroupLayout.DEFAULT_SIZE,
411, Short.MAX_VALUE)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblSearch)
.addComponent(txtSearch, javax.swing.GroupLayout.PREFERRED_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblImageList)
.addComponent(progressMatchedImages, javax.swing.GroupLayout.PREFERRED_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(scrollImageList, javax.swing.GroupLayout.PREFERRED_SIZE, 235,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblSelectedImage)
.addComponent(progressSelectedImage, javax.swing.GroupLayout.PREFERRED_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblImage, javax.swing.GroupLayout.DEFAULT_SIZE, 305, Short.MAX_VALUE)
.addContainerGap())
);
pack();
}
 
NetBeans IDE를 사용한 UI 레이아웃은 쉽습니다. 드래그 앤 드롭이면 충분합니다. 이 예제에서 NetBeans IDE 6.1은 여러 가지 호스트 플랫폼에서 정확한 크기, 위치 및 구성요소의 간격을 제공하는 javax.swing.GroupLayout을 사용하여 UI 코드를 생성했습니다. 결과 코드는 그다지 읽기 쉽진 않지만 도구 지원이 뛰어나 레이아웃 코드를 직접 수동으로 작업할 필요가 없습니다.


선언적 JavaFX 스크립트 인터페이스

JavaFX 스크립트용의 설계 도구가 개발 중이지만 아직은 사용할 수 없습니다. 그러나 JavaFX 스크립트 플러그인이 포함된 NetBeans IDE 6.1의 미리보기 기능을 사용하면 수동으로 UI 코드를 입력하고 결과를 즉시 볼 수 있습니다.

이 인터페이스에 필요한 UI 구성요소는 javafx.ext.swing 패키지 및 javafx.scene으로 시작하는 다양한 패키지에 들어 있습니다. UI 구축은 계층 구조적인 Swing 기반 접근 방법을 따릅니다. 이 시리즈의 1편에서 언급한 것처럼 앞으로 JavaFX 개발자는 노드 기반 접근 방법을 사용할 것입니다. 노드 기반 접근 방법으로 UI를 구축하면 javafx.application 클래스의 일부 클래스가 필요할 것입니다.

JavaFX 스크립트는 패키지 구조 및 가져오기 문을 지원한다는 점에서 자바 언어와 유사합니다. 구성요소에 대해 공부하는 동안은 전체 패키지를 가져오는 대신 한 번에 하나씩 특정 구성요소를 가져오겠습니다. 이는 매우 지루하지만 하나씩 사용하게 함으로써 패키지에 어떤 구성요소가 있는지 보여줍니다.

JavaFX 스크립트 구성요소는 height, width, textcontent와 같은 속성을 갖습니다. content 속성은 자녀 구성요소를 갖습니다. 구성요소에 따라 content 속성은 array로 선언되는 여러 개의 구성요소를 포함할 수 있습니다. 이미지 검색 애플리케이션을 위해 사용자 인터페이스를 선언할 때는 JavaFX 스크립트 구성요소의 선택 및 사용 후 속성을 설정합니다.

예를 들어 다음의 짧은 스크립트는 빈 프레임을 정의합니다. 이 코드는 컨텐츠가 없는 프레임 컨테이너를 생성합니다.


  import javafx.ext.swing.SwingFrame;

  SwingFrame {
      title: "JFX Image Search"
      height: 500
      width: 500
      visible: true
  }
 

Swing의 JFrame에 해당하는 JavaFX 스크립트는 javafx.ext.swing.SwingFrame입니다. title 속성은 프레임에 나타나는 텍스트인 창 프레임 제목을 선언합니다. heightwidth 속성은 픽셀 단위로 크기 규격을 정의합니다. 마지막으로 visible 속성은 Swing의 JFrame 클래스 setVisible 메소드와 유사하게 프레임의 가시성 여부를 선언합니다.


Border Panel 및 Flow Panel

javafx.ext.swing 패키지에는 SwingFrame, Label, BorderPanel, FlowPanelList와 같은 구성요소가 포함됩니다. 이러한 이름은 일반적인 Swing 구성요소 같으므로 대상 UI 구현에 이들을 먼저 사용해보겠습니다. javafx.scene 패키지의 HorizontalAlignment 구성요소와 javafx.scene.paint 패키지의 Color 구성요소도 사용했습니다. 그러나 JavaFX 스크립트 패키지에 ProgressBar 구성요소는 아직 없습니다. 따라서 진행 표시줄을 생성하는 함수를 코딩했습니다. 이 시리즈의 3편에서는 JavaFX 스크립트 함수를 검토합니다. BorderPanelFlowPanel 등의 구성요소와 진행 표시줄의 함수를 사용하기로 결정하고 다음 JavaFXImageSearchUI1.fx 코드를 생성했습니다.


 
package com.sun.demo.jfx;

  import javafx.ext.swing.SwingFrame;
  import javafx.ext.swing.BorderPanel;
  import javafx.ext.swing.FlowPanel;
  import javafx.ext.swing.Label;
  import javafx.ext.swing.TextField;
  import javafx.ext.swing.List;
  import javafx.ext.swing.Component;
  import javafx.scene.paint.Color;
  import javafx.scene.HorizontalAlignment;
  import java.awt.Dimension;

  function createProgressBar(preferredSize:Integer[]) :Component {
      var jprogressbar = new javax.swing.JProgressBar();
      var comp = Component.fromJComponent(jprogressbar);
      comp.preferredSize = preferredSize;
      comp;
  }

  SwingFrame {
      title: "JFX Image Search"
      content: BorderPanel  {

          top: FlowPanel {
              alignment: HorizontalAlignment.LEFT
              content: [
              Label {
                  text: "Search"
                  },
              TextField {
                  columns: 50
              }
              ]
          }
          center: BorderPanel {
              top: FlowPanel {
                  alignment: HorizontalAlignment.LEFT
                  content: [
                  Label {
                      text: "Matched Images"

                      },
                  createProgressBar([360, 20])
                  ]
              }
              center: List {
                  preferredSize: [100, 200]
              }
              bottom: FlowPanel {
                  alignment: HorizontalAlignment.LEFT
                  content: [
                  Label {
                      text: "Selected Image"
                      },
                  createProgressBar([365, 20])
                  ]
              }
          }
          bottom: Label {
                  preferredSize: [400, 300]

          }

      }
      visible: true
  }
 

NetBeans IDE 6.1에 프로젝트를 생성한 후에 JFXImageSearchUI1.fx 파일에 위의 코드를 입력했습니다. 미리보기 버튼을 클릭하면 그림 3과 같은 결과가 나타납니다.

그림 3. JavaFX 이미지 검색 UI -- 첫 번째 시도


프레임의 컨텐츠는 BorderPanel 구성요소로, top 속성은 FlowPanel 구성요소에 지정되고 center 속성은 다른 BorderPanel 구성요소에 지정되며 bottom 속성은 Label 구성요소에 지정되었습니다. FlowPanel 구성요소는 content 등록 정보를 갖습니다. 이 등록 정보에 하나 이상의 구성요소를 넣을 수 있습니다. 여러 개의 구성요소를 삽입할 때는 array를 정의하는 괄호 속에 구성요소를 넣어야 합니다. 다음과 같이 쉼표를 사용하여 컨텐츠 array에서 개별 구성요소를 구분합니다.


  content: [
  Label {
     text: "Search"
     },
  TextField {
     columns: 50
  }
  ]
 

상단 FlowPanel에는 Label 구성요소와 TextField 구성요소가 중첩되어 있습니다. FlowPanel 의 방향 속성은 HorizontalAlignment.LEFT입니다. 이는 FlowPanel 내의 구성요소를 가로와 왼쪽으로 정렬합니다. 가운데의 BorderPanel은 이 영역의 상단에 가로로 정렬된 레이블과 진행 표시줄을, 중앙에 목록을, 하단에 다른 레이블과 진행 표시줄을 레이아웃합니다. 프레임의 하단에는 레이블이 들어갑니다.

FlowPanel 구성요소는 레이블-구성요소 쌍을 만들기에 좋습니다. 여기에서는 여러 개의 FlowPanel을 사용하여 레이블과 TextField 등의 구성요소를 묶었습니다.

createProgressBar 함수는 JavaFX 스크립트를 사용하여 Swing 구성요소로부터 javafx.gui 구성요소를 생성하는 방법을 보여줍니다. 여기에서는 Swing JProgressBar 구성요소로부터 JavaFX 스트립트 진행 표시줄을 생성했습니다.


 
 function createProgressBar(preferredSize:Integer[]) :Component {
          var jprogressbar = new javax.swing.JProgressBar();
          var comp = Component.fromJComponent(jprogressbar);
          comp.preferredSize = preferredSize;
          comp;
  }
 

첫 번째 시도에서 UI는 상당히 잘 작동하지만 원래 UI를 제대로 재현하지는 못합니다. 그래서 다른 접근 방법을 시도해 보겠습니다.


클러스터

원래 UI를 복제하려는 두 번째 시도에서는 JavaFX 스크립트 ClusterPanel 구성요소를 활용하겠습니다. 이 구성요소를 사용하여 프레임 내에서 구성요소를 클러스터할 수 있습니다. JavaFX 스크립트에는 ClusterPanel 내에서 구성요소를 순서대로나 병렬로 정리하기 위해 사용할 수 있는 SequentialClusterParallelCluster도 포함됩니다.

진행 표시줄, 검색 텍스트 필드, 축소판 이미지 목록 및 선택된 이미지 표시 영역의 최대 너비 및 높이를 설정하기 위해 JavaFX 스크립트 Layout 구성요소도 활용하기로 결정했습니다. Layout 구성요소는 UNLIMITED_SIZE 등의 레이아웃 관련 상수를 제공합니다.

UI의 두 번째 버전은 다음 JFXImageSearchUI.fx 파일에 코딩되었습니다.


   package com.sun.demo.jfx;

import javafx.ext.swing.Component;
import javafx.ext.swing.SwingFrame;
import javafx.ext.swing.Label;
import javafx.ext.swing.TextField;
import javafx.ext.swing.List;
import javafx.ext.swing.Cluster;
import javafx.ext.swing.Layout;
import javafx.ext.swing.ClusterPanel;
import javafx.ext.swing.SequentialCluster;
import javafx.ext.swing.ParallelCluster;
import javafx.scene.paint.Color;
import java.awt.Dimension;
import java.lang.System;

import javax.swing.border.LineBorder;

function createProgressBar() :Component {
var jprogressbar = new javax.swing.JProgressBar();
var comp = Component.fromJComponent(jprogressbar);
comp.hmax = Layout.UNLIMITED_SIZE;
comp;
}

var searchLabel = Label {
text: "Search:"

}
var searchTextField = TextField {
hmax: Layout.UNLIMITED_SIZE
columns: 50
}

var matchedImageLabel = Label {
text: "Matched Images"
}
var matchedImagePB = createProgressBar();


var thumbnailList = List {
preferredSize:[300, 230]
hmax: Layout.UNLIMITED_SIZE
vmax: Layout.UNLIMITED_SIZE
}

var selectedImageLabel = Label {
text: "Selected Image"
}
var selectedImagePB = createProgressBar();

var selectedImageDisplay = Label {
preferredSize: [400,300]
hmax: Layout.UNLIMITED_SIZE
vmax: Layout.UNLIMITED_SIZE
}

selectedImageDisplay.getJComponent().setOpaque(true);
selectedImageDisplay.getJComponent().setBackground(Color.WHITE.getAWTColor());
selectedImageDisplay.getJComponent().setBorder(new LineBorder(Color.BLACK.getAWTColor(), 1, true));

SwingFrame {
title: "JavaFX Image Search"
content:
// main panel within the frame
ClusterPanel {

hcluster: SequentialCluster {
content: [
ParallelCluster{ // mainCol
resizable: true
content: [
SequentialCluster{
content: [
ParallelCluster { //searchLabelCol
content: searchLabel
},
ParallelCluster { //searchTextFieldCol
resizable: true
content: searchTextField
}
]},
SequentialCluster {
content: [
ParallelCluster { //lblCol
content: matchedImageLabel
},
ParallelCluster { //progressBarCol
resizable: true
content: matchedImagePB
}
]},
thumbnailList,
SequentialCluster {
content: [
ParallelCluster { //lblCol
content: selectedImageLabel
},
ParallelCluster { //progressBarCol
resizable: true
content: selectedImagePB
}
]},
selectedImageDisplay
]
}
]

}

vcluster: SequentialCluster {
content: [
ParallelCluster{ //searchRow
content: SequentialCluster {
content: [
ParallelCluster { // row
content: [searchLabel, searchTextField]
}
]
}
},
ParallelCluster{ // matchedProgressRow
content: SequentialCluster {
content: [
ParallelCluster { // row
content: [matchedImageLabel, matchedImagePB]
}
]
}
},
ParallelCluster{ // thumbNailRow
resizable:true
content: thumbnailList
},
ParallelCluster{ // selectedProgressRow
content: SequentialCluster {
content: [
ParallelCluster { // row
content: [selectedImageLabel, selectedImagePB]
}
]
}
},
ParallelCluster{ // imageRow
content: selectedImageDisplay
}

]
}

}
visible: true
}


 
이 코드의 결과는 훨씬 보기 좋습니다.
그림 4에 나온 것처럼 구성요소는 이제 프레임의 왼쪽과 오른쪽으로 완벽하게 정렬되었습니다.

그림 4. JavaFX 이미지 검색 UI -- 두 번째 시도

프레임의 주 컨텐츠는 ClusterPanel 구성요소입니다. ClusterPanel 내에서 SequentialCluster 구성요소 그룹의 구성요소는 모두 순서대로 있습니다. ParallelCluster 구성요소 그룹의 구성요소는 병렬로 있습니다. 예를 들어 다음은 구성요소를 프레임의 상단 영역에 정리합니다. 검색 레이블과 검색 텍스트 필드를 병렬 열로 클러스터합니다.


 
 hcluster: SequentialCluster {
      content: [
          ParallelCluster{ // mainCol
              resizable: true
              content: [
                  SequentialCluster{
                      content: [
                          ParallelCluster {  //searchLabelCol
                              content: searchLabel
                          },
                          ParallelCluster { //searchTextFieldCol
                              resizable: true
                              content: searchTextField
                          }
              ]},
 

SequentialClusterSequentialClusterParallelCluster와 같은 ClusterElement 구성요소를 지정할 수 있는 content 속성을 갖습니다. ParallelCluster 구성요소는 크기 조정이 가능하므로 필요에 따라 프레임 너비를 채웁니다.

인터페이스의 나머지도 같은 패턴을 따릅니다. 인터페이스의 각 5개 영역 내에서 구성요소는 SequentialCluster 구성요소 내에서 ParallelCluster 구성요소를 사용하여 그룹화 및 정리됩니다. 예를 들어 다음 코드는 매칭되는 이미지 레이블과 매칭되는 이미지 진행 표시줄을 병렬 열로 클러스터합니다. 클러스터 다음에는 검색과 매칭되는 이미지의 축소판 목록이 나옵니다.


 
SequentialCluster {
      content: [
          ParallelCluster {  //lblCol
              content: matchedImageLabel
          },
          ParallelCluster { //progressBarCol
              resizable: true
              content: matchedImagePB
          }
      ]},
  thumbnailList,
 

한 가지 주목할 점은 javafx.ext.swing 패키지의 Label 구성요소가 테두리 특성, 불투명도 또는 배경 색상의 설정을 위한 속성을 현재 지원하지 않는다는 것입니다. 따라서 이들 설정을 위해 getJComponent 함수에 대한 Label 구성요소의 지원을 활용했습니다. 함수는 JavaFX 스크립트 구성요소로 캡슐화된 Swing jComponent를 반환합니다. 이 경우에는 Swing Label 구성요소를 반환합니다. 다음 코드를 사용하여 필요한 레이블 속성을 정의할 수 있습니다.


var selectedImageDisplay = Label {
         ...
  }

  selectedImageDisplay.getJComponent().setOpaque(true);
  selectedImageDisplay.getJComponent().setBackground(Color.WHITE.getAWTColor());
  selectedImageDisplay.getJComponent().setBorder(new LineBorder(Color.BLACK.getAWTColor(), 1, true));
 

설계 도구 없이 이미지 검색 사용자 인터페이스를 복제하는 것에 대해 처음에 걱정했던 것과 달리 가장 유용하고 필요한 기능은 빠르고 쉽게 액세스가 가능합니다. 또한 NetBeans IDE용 JavaFX 플러그인은 구성요소를 사용하여 작업할 때 사용 가능한 속성을 띄우는 문맥 인식 코드 완성을 제공합니다. 코드 완성을 사용하면 UI의 구현이 처음 생각처럼 어렵지만은 않습니다. 그림 5는 IDE에서 Ctrl+spacebar를 입력할 때 활성화되는 일부 팝업 옵션을 보여줍니다.


그림 5. 옵션


요약

UI 생성을 위한 선언적 구문을 살펴보기 위해 기존 애플리케이션의 UI를 이식했습니다. 원래 애플리케이션에서는 구성요소의 배치 및 정렬에 Swing의 GroupLayout을 사용했습니다. NetBeans IDE 6.1은 아직 JavaFX 스크립트를 위한 그래픽 설계 도구를 지원하지 않지만 수동으로 인터페이스를 레이아웃하는 것은 처음 걱정했던것 만큼 어렵지 않았습니다. ClusterPanel, SequentialClusterParallelCluster 구성요소의 조합을 통해 JavaFX 스크립트 구현은 원래 UI와 사실상 똑같아 보입니다. 이들 조합에 NetBeans IDE용 JavaFX 플러그인 및 문맥 인식 코드 완성이 더해져 작업은 더욱 쉬워졌습니다.


자세한 정보


이 글의 영문 원본은
# Learning Curve Journal, Part 2: Declarative User Interfaces
에서 보실 수 있습니다.

"Java FX" 카테고리의 다른 글

Posted by 1010
98..Etc/JavaFX2008. 11. 12. 17:28
반응형

2007년 8월과 9월에 썬 개발자 네트워크의 John O'Conner는 JavaFX 스크립트 프로그래밍 언어(이 기사에서는 JavaFX 스크립트라고 줄여서 부름)를 시작하는 사용자에게 도움을 주고자 "학습 곡선 일지(Learning Curve Journal)"라는 제목의 시리즈를 기고했습니다.

그 이후로 이 언어의 많은 중요한 부분이 개선되었습니다. 아마도 가장 중요한 변화는 JavaFX 스크립트의 초기 인터프리터 기반 버전을 대신하여 컴파일러 기반 버전을 사용할 수 있게 되었다는 점입니다. 이전의 학습 곡선 일지에서는 인터프리터 기반 버전 사용에 대해 설명했습니다. 업데이트된 학습 곡선 일지에서는 컴파일러 기반 버전의 언어 사용법을 보여줍니다. 최신 내용을 반영하여 다른 변경 사항도 적용되었습니다.

이 전과 마찬가지로 시리즈의 1편은 JavaFX 프로그램, 즉 JavaFX 스크립트 언어로 쓰여진 간단한 프로그램으로 시작합니다. JavaFX 스크립트에서의 프로그래밍을 위한 환경 설정 방법과 JavaFX 프로그램 빌드 및 실행 방법을 배우게 됩니다. 2편은 JavaFX 스크립트에서 사용 가능한 선언적 코딩 스타일에 중점을 둡니다. 이러한 스타일이 어떻게 그래픽 애플리케이션을 더욱 단순하고 직관적으로 만들 수 있는지 볼 수 있을 것입니다. 3편에서는 JavaFX 프로그램에서 작업 구현을 위한 JavaFX 스크립트 함수의 사용 방법을 보여줍니다. 4편에서는 웹 서비스 액세스를 위한 JavaFX 스크립트 사용 방법을 보여줍니다. 그 과정 중에 FX 스크립트에서 Swing 클래스와 같은 자바 기술 슬래스의 액세스가 얼마나 쉬운지도 보여줍니다.

JavaFX 스크립트는 개발자가 동적인 그래픽 컨텐츠 생성에 사용할 수 있는 새로운 스트립팅 언어입니다. 데스크탑에서 언어는 Swing 사용자 인터페이스(UI) 툴킷과 자바 2D API를 편리하게 사용할 수 있는 라이브러리를 제공합니다. Swing 또는 자바 2D를 대체하는 것이 아니고 풍부한 컨텐츠 개발자가 이들 API에 더욱 쉽게 액세스할 수 있도록 하는 것이 목적입니다. 모바일 시스템과 같은 다른 환경에서 JavaFX 스크립트는 Swing 이외의 사용자 인터페이스 기술을 사용합니다. JavaFX 스크립트를 사용하여 여러 가지 플랫폼과 운영 환경에서 실행되는 시각적으로 풍부한 애플리케이션을 만들 수 있습니다.

언어는 선언적 및 절차적 구문을 모두 제공합니다. 선언적으로 풍부한 사용자 인터페이스를 만든 다음 이벤트 처리 루틴과 작업을 추가할 수 있습니다.

그러나 대부분의 사용자는 좀 더 소박하게 시작해야 하며 이 기사의 목적도 그러합니다. 목표는 JavaFX 스크립트를 시작하는 방법을 보여주는 것입니다. 먼저 다음이 필요합니다.



자바 플랫폼 설정

개발자라면 물론 시스템에 JDK가 설치되어 있을 것입니다. 그러나 시스템을 한동안 업데이트하지 않은 경우에는 자바 SE 6이 설치되어 있는지 확인하십시오. 학습 곡선 일지는 JavaFX 스크립트의 컴파일러 기반 버전과 NetBeans IDE 6.1에서의 지원에 중점을 두고 있습니다. JavaFX 기술이 적용된 NetBeans IDE 6.1을 설치 및 사용하려면 시스템에 자바 SE 6의 최신 수준(현재는 자바 SE 6 업데이트 10 베타)을 설치하는 것이 좋습니다. 썬 개발자 네트워크의 자바 SE 다운로드 페이지에서 최신 JDK를 다운로드합니다. Mac OS X를 사용하는 경우에는 Apple Developer Connection의 자바 섹션에서 직접 Apple의 최신 자바 플랫폼 개발 키트(현재는 Mac OS X 10.5, 업데이트 1용 자바)를 다운로드 받을 수 있습니다.


자료 참조

새로운 환경이나 언어를 경험할 때는 교착 상태에 빠지거나 난관에 봉착하게 됩니다. 이는 최첨단 기술을 사용할 때 모두가 겪게 되는 과정입니다. 학습 곡선을 원만하게 하기 위해서는 훌륭한 문서와 예제가 매우 중요합니다. 썬 개발자 네트워크의 JavaFX 기술 허브와 함께 javafx.comProject OpenJFX 웹 사이트는 정확한 정보를 얻을 수 있는 최신 문서와 데모 자료를 제공합니다.

일 부 사용자들은 언어 참조 자료를 읽지도 않고 프로그래밍을 바로 시작하고자 할 수 있습니다. 또다른 사용자들은 JavaFX 스크립트를 실제로 사용하기 전에 모든 자료를 읽을 것입니다. 바로 시작하는 유형의 사용자더라도 일종의 언어 사양이나 자습서부터 시작해야 합니다. 전형적인 "Hello, world" 예제를 쓰기 전에 기본 언어 구문을 알아야 합니다. JavaFX 참조 페이지의 문서부터 시작하는 것이 좋습니다. 여기에서 JavaFX 스크립트 프로그래밍 언어 참조 자료 등의 참조 문서와 JavaFX 기술 시작하기NetBeans IDE를 사용하여 간단한 JavaFX 애플리케이션 생성 등의 많은 기사와 자습서로의 링크를 찾을 수 있습니다.


JavaFX 애플리케이션 생성

일부 언어 참조 문서를 읽었다면 이제는 간단한 JavaFX 애플리케이션을 만들어 볼 차례입니다. 명령줄에서 수동으로 JavaFX 애플리케이션 빌드 및 실행이 가능하긴 하지만 애플리케이션 개발을 단순화하는 많은 기능을 가진 NetBeans IDE 6.1를 사용해 봅시다. NetBeans용 JavaFX 플러그인을 설치해야 합니다.

NetBeans IDE 6.1을 설치하지 않은 경우에는 NetBeans IDE 6.1과 NetBeans용 JavaFX을 포함하는 하나의 패키지인 JavaFX 포함 NetBeans IDE 6.1 다운로드가 가능합니다. NetBeans IDE 6.1을 이미 설치한 경우에는 NetBeans 업데이트 센터에서 JavaFX 플러그인을 설치하여 JavaFX 기술 지원을 추가할 수 있습니다. NetBeans용 JavaFX는 현재 Windows 및 Mac OS/X 환경에서 사용 가능합니다. JavaFX 플러그인을 설치하면 NetBeans IDE 6.1을 사용하여 JavaFX 스크립트의 컴파일러 기반 버전으로 작성된 애플리케이션을 생성, 테스트, 디버그 및 배포할 수 있습니다. 플러그인은 JavaFX 스크립트 파일 포함을 위한 프로젝트 및 편집기 지원을 향상시킵니다. 또한 스크립트 엔진 및 라이브러리를 위한 코어 라이브러리도 제공합니다.

JavaFX 포함 NetBeans IDE 6.1이나 NetBeans용 JavaFX 플러그인을 설치했으면 첫 번째 JavaFX 애플리케이션을 빌드할 준비가 된 것입니다. 물론 "Hello, world!"부터 시작해야겠지요.

다음과 같이 프로젝트 생성을 시작합니다.

  1. 주 메뉴에서 File -> New Project를 선택합니다.
  2. New Project 마법사에서 JavaFX 범주와 JavaFX Script Application 프로젝트 유형을 선택합니다.
  3. Next 버튼을 클릭합니다.
  4. HelloWorldJFX와 같이 프로젝트의 이름을 지정합니다.
  5. 기본 프로젝트 위치를 수락하거나 다른 위치를 선택하여 이동합니다.
  6. Create Main Class 확인란을 선택된 상태로 두고 다른 기본 설정도 변경하지 않습니다.
  7. Finish 버튼을 클릭합니다.

그림 1과 같이 IDE는 지정된 프로젝트 폴더에 프로젝트 디렉토리를 생성하고 프로젝트 이름과 같은 HelloWorldJFX라는 이름을 부여합니다. HelloWorldJFX 프로젝트를 확장합니다. Source Packages 노드의 helloworldjfx 패키지 아래에 Main.fx 클래스 파일이 있습니다. IDE는 프로젝트 생성 시 Create Main Class 확인란이 선택되어 있었으므로 Main.fx 파일을 생성합니다. 이 파일에 애플리케이션의 소스 코드가 들어갑니다.


그림 1.
HelloWorldJFX 프로젝트 파일


  /*
   * Main.fx
   *
   * Created on ...
   */

  package helloworldjfx;

  /**
   * @author ...
   */

  // place your code here
 

// place your code here 라인을 다음 코드로 바꿉니다.

  import javafx.ext.swing.Label;

  Label {
      text: "Hello, world!"
  }
 


JavaFXScript 편집기는 기본 서식 설정과 코드 완성을 제공합니다. 우리와 같이 JavaFX 스크립트에 익숙하지 않은 프로그래머는 언어 구문에 확신이 들지 않을 때도 있으므로 코드 완성이 도움이 됩니다. Ctrl + Space 키를 누르면 편집기에서 코드 완성이 활성화됩니다.

또 한 JavaFX 스크립트 플러그인은 컴파일과 실행을 해 볼 필요 없이 애플리케이션의 결과를 볼 수 있는 미리보기 기능을 제공합니다. 소스 파일에 변경한 내용은 즉시 미리보기 창에 반영됩니다. 미리보기 기능은 현재 Mac OS X 플랫폼에서는 사용할 수 없습니다.

Enable Preview 버튼 을 클릭하여 미리보기 기능을 작동시킵니다. 그림 2와 같이 편집기 바로 위에서 출력을 볼 수 있습니다.



그림 2. 기본적인 "Hello, world!"

별로 놀라지 않으셨나요? 좋습니다. 설정 방법을 보여주려는 것 뿐이었지만 좀 더 재미있는 것을 해보도록 하겠습니다. JavaFX 환경은 모든 Swing UI 구성요소를 구현하므로 레이블에만 한정될 필요는 없습니다. 버튼이나 대화 상자 같은 다른 위젯을 사용할 수도 있습니다.

다음은 버튼의 이벤트 핸들러를 소개하는 예제입니다. 언어 참조 자료에서 actionfunction 구문을 읽었으면 버튼을 누를 때 메시지 상자가 표시되도록 해봅시다.


  import javafx.ext.swing.SwingFrame;
   
import javafx.ext.swing.Button;
   
import javafx.ext.swing.SwingDialog;
   
import javafx.ext.swing.Label;
 
   
SwingFrame {
       content
: Button {
           text
: "Press me!"
           action
: function() {
               
SwingDialog {
                   title
: "You pressed me"
                   content
: Label{ text: "Hey, don't do that!"}
                   visible
: true
               
}
       
}
   
}
 
   visible
: true
   
}



Main.fx 파일에 이를 입력한 후에 Press me! 버튼을 누르면 그림 3과 같은 결과가 나타납니다.

그림 3. "Press me!" 버튼 메시지


앞에서 말한 것처럼 미리보기 기능을 사용하여 코드를 컴파일 및 실행하지 않고도 애플리케이션의 결과를 볼 수 있습니다. 코드를 컴파일하려는 경우에는 Project 창에서 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 Build Project를 선택합니다. 애플리케이션을 실행하려면 Project 창에서 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 Run Project를 선택합니다.


구성요소 기반에서 노드 기반 UI로의 이동

이전 예제에서 Frame과 Dialog의 구성요소가 간단하게 FrameDialog가 아니라 SwingFrameSwingDialog라 는 클래스 이름을 갖는지 궁금하셨을지도 모릅니다. 그 답은 JavaFX 스크립트 개발자가 Swing 기반 구성요소의 계층 구조를 사용하는 기존 접근 방법 대신 노드 기반 접근 방법을 사용하여 UI를 구축하는 향후의 접근 방법에 관련되어 있습니다. 사실 이러한 향후의 접근 방법에 대한 초기 지원은 이미 JavaFX 라이브러리에 포함되어 있습니다. 예를 들면 javafx.application 패키지에는 노드 기반 접근 방법을 지원하는 Frame, DialogWindow 등의 클래스가 포함됩니다. 다른 접근 방법을 지원하는 클래스와의 혼동을 피하기 위해 javafx.application 패키지에 해당 항목이 있는 javafx.ext.swing 패키지는 클래스 이름에 접두어 "Swing"을 추가했습니다.

학습 곡선 시리즈에서는 계층 구조적인 Swing 기반 접근 방법을 사용했지만 javafx.ext.swing 패키지의 SwingFrame, SwingDialogSwingWindow와 같은 클래스는 임시적입니다. JavaFX 팀은 Swing 구성요소와 유사하지만 더욱 유연하고 강력한 새로운 노드 기반 구성요소 집합을 설계 중입니다.

노드 기반 접근 방법을 사용한 UI 구축에 대한 자세한 내용은 장면 그래프를 사용하여 JavaFX 스크립트에서 비주얼 개체 표시 기사를 참조하십시오. NetBeans IDE를 사용하여 간단한 JavaFX 애플리케이션 생성 자습서도 노드 기반 접근 방법을 사용하는 JavaFX 애플리케이션을 설명합니다.


프로파일

JavaFX는 특정 플랫폼이나 장치에서만 사용 가능한 클래스 그룹을 의미하는 프로파일을 지원합니다. javafx.ext.swing 패키지의 클래스는 데스크탑 프로파일에 들어 있으며 데스크탑 환경에서만 가용성이 보장됩니다. 예를 들어 많은 휴대 전화는 Swing 클래스를 갖지 않습니다. 휴대 전화와 TV를 포함한 모든 플랫폼에서 보장되는 클래스를 정의한 일반 프로파일도 있습니다. 새로운 노드 기반 구성요소는 일반 프로파일에 있으므로 모든 화면 및 장치에서 작동합니다.

JavaFX API 문서는 정확한 프로파일 사용을 보장하기 위해 하나의 프로파일에서 다른 프로파일로 전환할 수 있도록 하는 버튼을 제공합니다. 이 기사 시리즈에서는 데스크탑 환경을 위한 애플리케이션을 구축하므로 데스크탑 프로파일의 클래스와 일반 프로파일의 일부 클래스를 사용할 것입니다.


명령줄에서 JavaFX 애플리케이션 빌드 및 실행

다음과 같이 명령줄에서 JavaFX 애플리케이션을 빌드 및 실행할 수 있습니다.

  1. JavaFX Preview SDK 다운로드를 받습니다. SDK에는 JavaFX 스크립트 컴파일러, 문서, 런타임, 라이브러리 및 코드 샘플이 포함됩니다.
  2. 다운로드한 패키지를 확장합니다. 여러 디렉토리 중에 javafxcjavafx 명령을 위한 실행 가능 파일을 포함하는 bin 디렉토리가 보여야 합니다.
  3. fx 확장자를 갖는 파일(예: MyApp.fx)에 애플리케이션의 소스 코드를 저장합니다
  4. 다음과 같이 javafxc 명령을 수행하고 소스 파일을 지정하여 애플리케이션을 컴파일합니다.
       javafxc MyApp.fx

    애플리케이션을 위한 클래스 파일이 생성됩니다.

  5. 다음과 같이 javafx 명령을 수행하고 클래스 파일을 지정하여 애플리케이션을 위한 클래스 파일을 실행합니다.
       javafx MyApp

요약

새로운 기술을 조사할 때는 올바르게 시작하는 것이 중요합니다. 정확한 정보와 도구를 사용하여 시작하도록 하십시오. JavaFX 스크립트에 대한 최선의 방법은 4단계 절차를 따르는 것입니다.

  1. 최신의 Java SE Development Kit를 받습니다.
  2. 정보의 출처로 JavaFX 기술 허브, javafx.com 사이트Project OpenJFX 사이트를 사용합니다.
  3. IDE용 개발 플러그인을 받습니다. JavaFX 포함 NetBeans IDE 6.1은 새로운 JavaFX 스크립트의 컴파일러 기반 버전을 지원합니다. NetBeans IDE 6.1을 이미 설치한 경우에는 NetBeans 업데이트 센터에서 JavaFX 플러그인을 설치하여 JavaFX 기술 지원을 추가할 수 있습니다.
  4. 첫 번째 스크립트 시험에 미리보기 기능을 사용합니다.


자세한 정보

이 시리즈의 2편인 선언적 사용자 인터페이스를 참조하십시오.



이 글의 영문 원본은
Learning Curve Journal, Part 1: Exploring JavaFX Script
에서 보실 수 있습니다.


"Java FX" 카테고리의 다른 글

2008/08/27 10:05 2008/08/27 10:05
Posted by 1010
98..Etc/JavaFX2008. 11. 12. 17:27
반응형

2008년 7월 저는 그래픽 디자이너(Mark Dingman of Malden Labs)와 공동 작업으로 상상 속의 Sound Beans 애플리케이션을 만드는 연속 게시물이 포함된 JFX 사용자 지정 노드 카테고리를 시작했습니다.  이 애플리케이션을 작성하는 목표는 JavaFX 사용자 지정 노드를 만드는 방법을 보여주고, 그래픽 디자이너와 애플리케이션 개발자가 공동으로 JavaFX 애플리케이션을 효과적으로 개발할 수 있는 방법에 관한 사례 연구를 제공하기 위한 것입니다. 

이 연속 게시물의 첫 게시물인 자신만의 JavaFX "사용자 지정 노드" 만들기: 그래픽 메뉴의 예는 JavaFX에서 자신만의 UI를 만드는 방법을 보여줍니다. 해당 게시물에서는 마우스를 갖다댈 경우 밝아지고 확장되는 버튼으로 구성된 메뉴를 쉽게 만들 수 있도록 MenuNodeButtonNode 사용자 지정 노드를 정의했습니다.  이어지는 다음 게시물에서는 다음 내용을 다룹니다.

오늘의 게시물에서는 테이블의 행을 보고 선택할 수 있는 확장 가능한 테이블을 제공할 수 있도록 TableNode라는 이름의 사용자 지정 노드를 작성해보겠습니다. 테이블의 각 셀에는 Node의 하위 클래스를 포함할 수 있으므로 JavaFX SDK 1.0에서 사용할 노드 중심 방식으로 줄에 놓여질 수 있습니다. 또한, JavaFX SDK 1.0에 일종의 테이블 UI 컨트롤을 포함하려고 생각하고 있습니다. 다음은 상상 속의 Sound Beans 프로그램에서 사용하는 TableNode의 스크린샷입니다.

테이블


이것은 Mark Dingman이 제공한 재생 목록 comp(웹 사이트에 대한 종합 이미지, 모형)를 기초로 만든 것입니다(Getting Decked: Another JavaFX Custom Node post 참조). 그 다음에는 Mark에게 모양을 그려(이미지를 사용하는 것과는 다름) 구현할 수 있는 스크롤바 comp를 부탁했습니다. Mark의 comp에는 위에서 보듯이 수평 스크롤바 트랙과 함께 둥근 사각형 모양의 진행률 스크롤바 썸이 있습니다.

상상 속의 Sound Beans 프로그램에 대한 이번 반복에서는 테이블에서 다른 행을 클릭하면 UI의 왼쪽 위 모서리의 숫자가 변경되어 TableNodeselectedIndex 속성을 바인딩할 수 있음을 나타냅니다. 다음의 반복에서는 앨범 그래픽, 제목 등이 바뀌게 하고 왼쪽 위 모서리에 해당 번호가 나타나도록 할 것입니다. 이 Java Web Start 링크를 클릭하여 이 코드를 사용해보십시오. JRE 6 이상이 필요합니다. 또한 자바 SE 6 업데이트 10을 설치하면 배포 시간이 단축됩니다.

Web

다음은 TableNode.fx 파일에 있는 TableNode 사용자 지정 노드의 코드입니다.

/*
*  TableNode.fx -
*  A custom node that contains rows and columns, each cell
*  containing a node.
*
*  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
*  to demonstrate how to create custom nodes in JavaFX
*/


package com.javafxpert.custom_node;

import javafx.input.*;
import javafx.scene.*;
import javafx.scene.geometry.*;
import javafx.scene.paint.*;
import javafx.scene.transform.*;
import java.lang.System;

/*
* A custom node that contains rows and columns, each cell
* containing a node.  Column widths may be set individually,
* and the height of the rows can be set.  In addition, several
* other attributes such as width and color of the scrollbar
* may be set.  The scrollbar will show only when necessary,
* and overlays the right side of each row, so the rightmost
* column should be given plenty of room to display data and
* a scrollbar.
*/

public class TableNode extends CustomNode {

 
/*
   * Contains the height of the table in pixels.
   */

 
public attribute height:Integer = 200;
   
 
/*
   * Contains the height of each row in pixels.
   */

 
public attribute rowHeight:Integer;
   
 
/*
   * A sequence containing the column widths in pixels.  The
   * number of elements in the sequence determines the number of
   * columns in the table.
   */

 
public attribute columnWidths:Integer[];
   
 
/*
   * A sequence containing the nodes in the cells.  The nodes are
   * placed from left to right, continuing to the next row when
   * the current row is filled.
   */

 
public attribute content:Node[];
   
 
/*
   * The selected row number (zero-based)
   */

 
public attribute selectedIndex:Integer;
   
 
/*
   * The height (in pixels) of the space between rows of the table.
   * This space will be filled with the tableFill color.
   */

 
public attribute rowSpacing:Integer = 1;
   
 
/*
   * The background color of the table
   */

 
public attribute tableFill:Paint;
   
 
/*
   * The background color of an unselected row
   */

 
public attribute rowFill:Paint;
   
 
/*
   * The background color of a selected row
   */

 
public attribute selectedRowFill:Paint;
   
 
/*
   * The color or gradient of the vertical scrollbar.
   */

 
public attribute vertScrollbarFill:Paint = Color.BLACK;
   
 
/*
   * The color or gradient of the vertical scrollbar thumb.
   */

 
public attribute vertScrollbarThumbFill:Paint = Color.WHITE;
   
 
/*
   * The width (in pixels) of the vertical scrollbar.
   */

 
public attribute vertScrollbarWidth:Integer = 20;
   
 
/*
   * The number of pixels from the left of a cell to place the node
   */

 
private attribute cellHorizMargin:Integer = 10;
   
 
/*
   * Contains the width of the table in pixels.  This is currently a
   * calculated value based upon the specified column widths
   */

 
private attribute width:Integer = bind
    computePosition
(columnWidths, sizeof columnWidths);
   
 
private function computePosition(sizes:Integer[], element:Integer) {
   
var position = 0;
   
if (sizeof sizes > 1) {
     
for (i in [0..element - 1]) {
        position
+= sizes[i];
     
}
   
}
   
return position;
 
}
 
 
/**
   * The onSelectionChange function attribute that is executed when the
   * a row is selected
   */

 
public attribute onSelectionChange:function(row:Integer):Void;
   
 
/**
   * Create the Node
   */

 
public function create():Node {
   
var numRows = sizeof content / sizeof columnWidths;
   
var tableContentsNode:Group;
   
var needScrollbar:Boolean = bind (rowHeight + rowSpacing) * numRows  > height;
   
Group {
     
var thumbStartY = 0.0;
     
var thumbEndY = 0.0;
     
var thumb:Rectangle;
     
var track:Rectangle;
     
var rowRef:Group;
      content
: [
       
for (row in [0..numRows - 1], colWidth in columnWidths) {
         
Group {
            transform
: bind
             
Translate.translate(computePosition(columnWidths, indexof colWidth) +
                                  cellHorizMargin
,
                                 
((rowHeight + rowSpacing) * row) + (-1.0 * thumbEndY *
                                 
((rowHeight + rowSpacing) * numRows) / height))
            content
: bind [
             
Rectangle {
                width
: colWidth
                height
: rowHeight
                fill
: if (indexof row == selectedIndex)
                        selectedRowFill
                     
else
                        rowFill
             
},
             
Line {
                startX
: 0
                startY
: 0
                endX
: colWidth
                endY
: 0
                strokeWidth
: rowSpacing
                stroke
: tableFill
             
},
              rowRef
= Group {
               
var node =
                  content
[indexof row * (sizeof columnWidths) + indexof colWidth];
                transform
: bind Translate.translate(0, rowHeight / 2 -
                                                       node
.getHeight() / 2)
                content
: node
             
}
           
]
            onMouseClicked
:
             
function (me:MouseEvent) {
                selectedIndex
= row;
                onSelectionChange
(row);
             
}
         
}
       
},
       
// Scrollbar
       
if (needScrollbar)
         
Group {
            transform
: bind Translate.translate(width - vertScrollbarWidth, 0)
            content
: [
              track
= Rectangle {
                x
: 0
                y
: 0
                width
: vertScrollbarWidth
                height
: bind height
                fill
: vertScrollbarFill
             
},
             
//Scrollbar thumb
              thumb
= Rectangle {
                x
: 0
                y
: bind thumbEndY
                width
: vertScrollbarWidth
                height
: bind 1.0 * height / ((rowHeight + rowSpacing) * numRows) * height
                fill
: vertScrollbarThumbFill
                arcHeight
: 10
                arcWidth
: 10
                onMousePressed
: function(e:MouseEvent):Void {  
                  thumbStartY
= e.getDragY() - thumbEndY;  
               
}  
                onMouseDragged
: function(e:MouseEvent):Void {
                 
var tempY = e.getDragY() - thumbStartY;
                 
// Keep the scroll thumb within the bounds of the scrollbar
                 
if (tempY >=0 and tempY + thumb.getHeight() <= track.getHeight()) {
                    thumbEndY
= tempY;  
                 
}
                 
else if (tempY < 0) {
                    thumbEndY
= 0;
                 
}
                 
else {
                    thumbEndY
= track.getHeight() - thumb.getHeight();
                 
}
               
}
                onMouseDragged
: function(e:MouseEvent):Void {
                 
var tempY = e.getDragY() - thumbStartY;
                 
// Keep the scroll thumb within the bounds of the scrollbar
                 
if (tempY >=0 and tempY + thumb.getHeight() <= track.getHeight()) {
                    thumbEndY
= tempY;  
                 
}
                 
else if (tempY < 0) {
                    thumbEndY
= 0;
                 
}
                 
else {
                    thumbEndY
= track.getHeight() - thumb.getHeight();
                 
}
               
}
             
}
           
]
         
}  
       
else
         
null
     
]
      clip
:
       
Rectangle {
          width
: bind width
          height
: bind height
       
}
      onMouseWheelMoved
: function(e:MouseEvent):Void {
       
var tempY = thumbEndY + e.getWheelRotation() * 4;
       
// Keep the scroll thumb within the bounds of the scrollbar
       
if (tempY >=0 and tempY + thumb.getHeight() <= track.getHeight()) {
          thumbEndY
= tempY;  
       
}
       
else if (tempY < 0) {
          thumbEndY
= 0;
       
}
       
else {
          thumbEndY
= track.getHeight() - thumb.getHeight();
       
}
     
}
   
}    
 
}
}
 

public 속성에서 볼 수 있듯이, 테이블 높이, 행 높이, 각 열의 폭, 다양한 UI 요소의 색 또는 그라데이션 등 개발자가 구성할 수 있는 여러 가지 TableNode 속성이 있습니다. 목록 끝의 코드는 마우스 휠 지원을 제공합니다. 이제 The "Play" page로 주석 처리한 섹션을 중심으로 기본 프로그램을 살펴보겠습니다. 이 섹션이 TableNodeExampleMain.fx 파일에 TableNode 인스턴스가 만들어지는 부분입니다.

/*
 *  TableNodeExampleMain.fx -
 *  An example of using the TableNode custom node.  It also demonstrates
 *  the ProgressNode, DeckNode, MenuNode and ButtonNode custom nodes
 *
 *  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
 *  to demonstrate how to create custom nodes in JavaFX
 */

package com.javafxpert.table_node_example.ui;

import javafx.application.*;
import javafx.ext.swing.*;
import javafx.scene.*;
import javafx.scene.geometry.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.scene.text.*;
import javafx.scene.transform.*;
import java.lang.Object;
import java.lang.System;
import com.javafxpert.custom_node.*;
import com.javafxpert.table_node_example.model.*;

var deckRef:DeckNode;

Frame {
 
var model = TableNodeExampleModel.getInstance();
 
var stageRef:Stage;
 
var menuRef:MenuNode;
  title
: "TableNode Example"
  width
: 500
  height
: 400
  visible
: true
  stage
:
    stageRef
= Stage {
      fill
: Color.BLACK
      content
: [
        deckRef
= DeckNode {
          fadeInDur
: 700ms
          content
: [
           
// The "Splash" page
           
Group {
             
var vboxRef:VBox;
             
var splashFont =
               
Font {
                  name
: "Sans serif"
                  style
: FontStyle.BOLD
                  size
: 12
               
};
              id
: "Splash"
              content
: [
               
ImageView {
                  image
:
                   
Image {
                      url
: "{__DIR__}images/splashpage.png"
                   
}
               
},
                vboxRef
= VBox {
                  translateX
: bind stageRef.width - vboxRef.getWidth() - 10
                  translateY
: 215
                  spacing
: 1
                  content
: [
                   
Text {
                      content
: "A Fictitious Audio Application that Demonstrates"
                      fill
: Color.WHITE
                      font
: splashFont
                   
},
                   
Text {
                      content
: "Creating JavaFX Custom Nodes"
                      fill
: Color.WHITE
                      font
: splashFont
                   
},
                   
Text {
                      content
: "Application Developer: Jim Weaver"
                      fill
: Color.WHITE
                      font
: splashFont
                   
},
                   
Text {
                      content
: "Graphics Designer: Mark Dingman"
                      fill
: Color.WHITE
                      font
: splashFont
                   
},
                 
]
               
}
             
]
           
},
           
// The "Play" page
           
VBox {
             
var tableNode:TableNode
              id
: "Play"
              spacing
: 4
              content
: [
               
Group {
                  content
: [
                   
ImageView {
                      image
:
                       
Image {
                          url
: "{__DIR__}images/playing_currently.png"
                       
}
                   
},
                   
Text {
                      textOrigin
: TextOrigin.TOP
                      content
: bind "{tableNode.selectedIndex}"
                      font
: Font {
                        size
: 24
                     
}
                   
}
                 
]
               
},
                tableNode
= TableNode {
                  height
: 135
                  rowHeight
: 25
                  rowSpacing
: 2
                  columnWidths
: [150, 247, 25, 70]
                  tableFill
: Color.BLACK
                  rowFill
: Color.rgb(28, 28, 28)
                  selectedRowFill
: Color.rgb(45, 45, 45)
                  selectedIndex
: -1
                  vertScrollbarWidth
: 20
                  vertScrollbarFill
: LinearGradient {
                    startX
: 0.0
                    startY
: 0.0
                    endX
: 1.0
                    endY
: 0.0
                    stops
: [
                     
Stop {
                        offset
: 0.0
                        color
: Color.rgb(11, 11, 11)
                     
},
                     
Stop {
                        offset
: 1.0
                        color
: Color.rgb(52, 52, 52)
                     
}
                   
]
                 
}
                  vertScrollbarThumbFill
: Color.rgb(239, 239, 239)
                  content
: bind
                   
for (obj in model.playlistObjects) {
                     
if (obj instanceof String)
                       
Text {
                          textOrigin
: TextOrigin.TOP
                          fill
: Color.rgb(183, 183, 183)
                          content
: obj as String
                          font
:
                           
Font {
                              size
: 11
                           
}
                       
}
                     
else if (obj instanceof Image)
                       
ImageView {
                          image
: obj as Image
                       
}
                     
else
                       
null
                   
}
                  onSelectionChange
:
                   
function(row:Integer):Void {
                     
System.out.println("Table row #{row} selected");
                   
}
               
}
             
]
           
},
           
// The "Burn" page
           
Group {
             
var vboxRef:VBox;
              id
: "Burn"
              content
: [
                vboxRef
= VBox {
                  translateX
: bind stageRef.width / 2 - vboxRef.getWidth() / 2
                  translateY
: bind stageRef.height / 2 - vboxRef.getHeight() / 2
                  spacing
: 15
                  content
: [
                   
Text {
                      textOrigin
: TextOrigin.TOP
                      content
: "Burning custom playlist to CD..."
                      font
:
                       
Font {
                          name
: "Sans serif"
                          style
: FontStyle.PLAIN
                          size
: 22
                       
}
                      fill
: Color.rgb(211, 211, 211)
                   
},
                   
ProgressNode {
                      width
: 430
                      height
: 15
                      progressPercentColor
: Color.rgb(191, 223, 239)
                      progressTextColor
: Color.rgb(12, 21, 21)
                      progressText
: bind "{model.remainingBurnTime} Remaining"
                      progressFill
:
                       
LinearGradient {
                          startX
: 0.0
                          startY
: 0.0
                          endX
: 0.0
                          endY
: 1.0
                          stops
: [
                           
Stop {
                              offset
: 0.0
                              color
: Color.rgb(0, 192, 255)
                           
},
                           
Stop {
                              offset
: 0.20
                              color
: Color.rgb(0, 172, 234)
                           
},
                           
Stop {
                              offset
: 1.0
                              color
: Color.rgb(0, 112, 174)
                           
},
                         
]
                       
}
                      barFill
:
                       
LinearGradient {
                          startX
: 0.0
                          startY
: 0.0
                          endX
: 0.0
                          endY
: 1.0
                          stops
: [
                           
Stop {
                              offset
: 0.0
                              color
: Color.rgb(112, 112, 112)
                           
},
                           
Stop {
                              offset
: 1.0
                              color
: Color.rgb(88, 88, 88)
                           
},
                         
]
                       
}
                      progress
: bind model.burnProgressPercent / 100.0
                   
},
                   
ComponentView {
                      component
:
                       
FlowPanel {
                          background
: Color.BLACK
                          content
: [
                           
Label {
                              text
: "Slide to simulate burn progress:"
                              foreground
: Color.rgb(211, 211, 211)
                           
},
                           
Slider {
                              orientation
: Orientation.HORIZONTAL
                              minimum
: 0
                              maximum
: 100
                              value
: bind model.burnProgressPercent with inverse
                              preferredSize
: [200, 20]
                           
}
                         
]
                       
}
                   
}
                 
]
               
}
             
]
           
},
           
// The "Config" page
           
Group {
              id
: "Config"
              content
: [
               
ImageView {
                  image
:
                   
Image {
                      url
: "{__DIR__}images/config.png"
                   
}
               
}
             
]
           
},
           
// The "Help" page
           
Group {
              id
: "Help"
              content
: [
               
ImageView {
                  image
:
                   
Image {
                      url
: "{__DIR__}images/help.png"
                   
}
               
}
             
]
           
}
         
]
       
},
        menuRef
= MenuNode {
          translateX
: bind stageRef.width / 2 - menuRef.getWidth() / 2
          translateY
: bind stageRef.height - menuRef.getHeight()
          buttons
: [
           
ButtonNode {
              title
: "Play"
              imageURL
: "{__DIR__}icons/play.png"
              action
:
               
function():Void {
                  deckRef
.visibleNodeId = "Play";
               
}
           
},
           
ButtonNode {
              title
: "Burn"
              imageURL
: "{__DIR__}icons/burn.png"
              action
:
               
function():Void {
                  deckRef
.visibleNodeId = "Burn";
               
}
           
},
           
ButtonNode {
              title
: "Config"
              imageURL
: "{__DIR__}icons/config.png"
              action
:
               
function():Void {
                  deckRef
.visibleNodeId = "Config";
               
}
           
},
           
ButtonNode {
              title
: "Help"
              imageURL
: "{__DIR__}icons/help.png"
              action
:
               
function():Void {
                  deckRef
.visibleNodeId = "Help";
               
}
           
},
         
]
       
}
     
]
   
}
}

deckRef
.visibleNodeId = "Splash";


The Model Behind the UI

"JavaFX 방식"은 UI 속성을 모델에 바인딩하는 것이므로 위에서 보는 바와 같이 TableNode의 콘텐츠 속성이 모델에 바인딩됩니다. 아래는 현재까지 TableNodeExampleModel.fx 파일에 만들어진 Sound Beans 프로그램의 모델입니다. playlistObjects 시퀀스에는 어떠한 종류의 개체도 포함할 수 있으며, Node 인스턴스를 모델에 포함하지만 않으면 됩니다(이러한 인스턴스는 UI에 속하므로). 그러므로 TableNode,를 채우려면 모델에 앨범 제목 및 이미지 URL 같은 문자열을 포함하는 방식을 사용합니다. 위에 표시된 TableModel의 콘텐츠 속성에 바인딩하는 동안 Node 하위 클래스(예: TextImageView)가 만들어집니다.

/*
 *  TableNodeExampleModel.fx -
 *  The model behind the TableNode example
 *
 *  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
 */

package com.javafxpert.table_node_example.model;

import java.lang.Object;
import javafx.scene.*;
import javafx.scene.image.*;
import javafx.scene.text.*;

/**
 * The model behind the TableNode example
 */

public class TableNodeExampleModel {
 
 
/**
   * The total estimated number of seconds for the burn.
   * For this example program, we'll set it to 10 minutes
   */

 
public attribute estimatedBurnTime:Integer = 600;

 
/**
   * The percent progress of the CD burn, represented by a number
   * between 0 and 100 inclusive.
   */

 
public attribute burnProgressPercent:Integer on replace {
     
var remainingSeconds = estimatedBurnTime * (burnProgressPercent / 100.0) as Integer;
      remainingBurnTime
= "{remainingSeconds / 60}:{%02d (remainingSeconds mod 60)}";
 
};

 
/**
   * The time remaining on the CD burn, expressed as a String in mm:ss
   */

 
public attribute remainingBurnTime:String;

 
/**
   * An image of a play button to be displayed in each row of the table
   */

 
private attribute playBtnImage = Image {url: "{__DIR__}images/play-btn.png"};
   
 
/**
   * The song information in the playlist
   */

 
public attribute playlistObjects:Object[] =
   
["Who'll Stop the Rain", "Three Sides Now", playBtnImage, "2:43",
     
"Jackie Blue", "Ozark Mountain Devils", playBtnImage, "2:15",
     
"Come and Get Your Love", "Redbone", playBtnImage, "3:22",
     
"Love Machine", "Miracles", playBtnImage, "2:56",
     
"25 or 6 to 4", "Chicago", playBtnImage, "3:02",
     
"Free Bird", "Lynard Skynard", playBtnImage, "5:00",
     
"Riding the Storm Out", "REO Speedwagon", playBtnImage, "3:00",
     
"Lay it on the Line", "Triumph", playBtnImage, "2:00",
     
"Secret World", "Peter Gabriel", playBtnImage, "4:00"];
 
 
 
 
//-----------------Use Singleton pattern to get model instance -----------------------
 
private static attribute instance:TableNodeExampleModel;

 
public static function getInstance():TableNodeExampleModel {
   
if (instance == null) {
      instance
= TableNodeExampleModel {};
   
}
   
else {
      instance
;
   
}
 
}
}


언제나처럼 질문이나 의견이 있으면 남겨 주십시오. 그리고 이 기사의 이미지를 다운로드한 후 이 그래픽으로 이 예에서 소개한 대로 작성하고 실행할 수 있습니다. 이 이미지는 프로젝트의 클래스 경로에서 확장할 수 있는 zip 파일입니다. 이 JFX 사용자 지정 노드 연속 게시물 중 이전 게시물에 소개했던 ButtonNode, MenuNode, DeckNode, ProgressNode 코드가 필요합니다.

감사합니다.
Jim Weaver
JavaFXpert.com

이 글의 영문 원본은
Creating a Custom Scrollable Table with JavaFX
에서 보실 수 있습니다.

"Java FX" 카테고리의 다른 글

Posted by 1010
98..Etc/JavaFX2008. 11. 12. 17:26
반응형

이제 JavaFX SDK 기술 Preview가 릴리스되었으므로 자신만의 "사용자 지정 노드"를 빠르게 만드는 방법을 설명하겠습니다. JavaFX에서 사용자 지정 노드는 위젯, 가젯, UI 구성 요소 등 어느 것이나 모두 의미할 수 있으나 목적은 동일합니다. 다시 사용 가능한 JavaFX 프로그램용 UI를 만들 수 있도록 하는 것입니다. 오늘의 예는 사용자 지정 노드(2개)를 만드는 방법을 보여줍니다. 다음 스크린샷을 참조하십시오.

 

그런데 현재 이 예에 구현된 코드가 단순해진 것은 Edgar Merino 덕분입니다. 이 코드를 사용해보려면 Java Web Start 링크를 클릭하십시오. JRE 6 이상이 필요합니다. 또한 자바 SE 6 업데이트 10을 설치하면 배포 시간이 단축됩니다.



JavaFX SDK Packages are Taking Shape 게시물에서 언급한 것처럼 JavaFX는 UI를 개발할 때 그래픽 "노드 중심" 방식을 채택하고 있으므로 JavaFX 사용자 인터페이스의 거의 대부분은 노드(Node)입니다.  사용자 지정 노드를 만들려는 경우 CustomNode 클래스를 확장하여 원하는 특성과 동작을 지정합니다.  아래 코드는 이 예에서 이미지를 표시하고 마우스 이벤트에 응답(예: 마우스를 위에 갖다대면 좀 더 투명해지고 텍스트가 표시되는 이벤트)하는 사용자 지정 노드를 만드는 코드입니다. 

주: javafx.ext.swing 패키지에 있는 Button 클래스를 사용하지 않는 이유가 궁금하실 것입니다. 이유는 Button 클래스는 Node가 아니라 Component이기 때문이며, 위에 언급한 대로 노드 중심 방식으로 변화되는 방향을 따르는 것이 가장 좋다고 생각합니다. 어떤 부분에서는 노드를 하위 클래스로 만드는 버튼이 나타납니다. 이 경우에는 ButtonNode 클래스가 더 이상 필요하지 않을 수 있습니다.

ButtonNode.fx


/*
*  ButtonNode.fx -
*  A node that functions as an image button
*
*  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
*  and Edgar Merino (http://devpower.blogsite.org/) to demonstrate how
*  to create custom nodes in JavaFX
*/


package com.javafxpert.custom_node;

import javafx.animation.*;
import javafx.input.*;
import javafx.scene.*;
import javafx.scene.effect.*;
import javafx.scene.geometry.*;
import javafx.scene.image.*;
import javafx.scene.paint.*;
import javafx.scene.text.*;
import javafx.scene.transform.*;

public class ButtonNode extends CustomNode {
 
/**
   * The title for this button
   */

 
public attribute title:String;

 
/**
   * The Image for this button
   */

 
private attribute btnImage:Image;

 
/**
   * The URL of the image on the button
   */

 
public attribute imageURL:String on replace {
    btnImage
=
     
Image {
        url
: imageURL
     
};
 
}
   
 
/**
   * The percent of the original image size to show when mouse isn't
   * rolling over it.  
   * Note: The image will be its original size when it's being
   * rolled over.
   */

 
public attribute scale:Number = 0.9;

 
/**
   * The opacity of the button when not in a rollover state
   */

 
public attribute opacityValue:Number = 0.8;

 
/**
   * The opacity of the text when not in a rollover state
   */

 
public attribute textOpacityValue:Number = 0.0;

 
/**
   * A Timeline to control fading behavior when mouse enters or exits a button
   */

 
private attribute fadeTimeline =
   
Timeline {
      toggle
: true
      keyFrames
: [
       
KeyFrame {
          time
: 600ms
          values
: [
            scale
=> 1.0 tween Interpolator.LINEAR,
            opacityValue
=> 1.0 tween Interpolator.LINEAR,
            textOpacityValue
=> 1.0 tween Interpolator.LINEAR
         
]
       
}
     
]
   
};

 
/**
   * This attribute is interpolated by a Timeline, and various
   * attributes are bound to it for fade-in behaviors
   */

 
private attribute fade:Number = 1.0;
 
 
/**
   * This attribute represents the state of whether the mouse is inside
   * or outside the button, and is used to help compute opacity values
   * for fade-in and fade-out behavior.
   */

 
private attribute mouseInside:Boolean;

 
/**
   * The action function attribute that is executed when the
   * the button is pressed
   */

 
public attribute action:function():Void;
   
 
/**
   * Create the Node
   */

 
public function create():Node {
   
Group {
     
var textRef:Text;
      content
: [
       
Rectangle {
          width
: bind btnImage.width
          height
: bind btnImage.height
          opacity
: 0.0
       
},
       
ImageView {
          image
: btnImage
          opacity
: bind opacityValue;
          scaleX
: bind scale;
          scaleY
: bind scale;
          translateX
: bind btnImage.width / 2 - btnImage.width * scale / 2
          translateY
: bind btnImage.height - btnImage.height * scale
          onMouseEntered
:
           
function(me:MouseEvent):Void {
              mouseInside
= true;
              fadeTimeline
.start();
           
}
          onMouseExited
:
           
function(me:MouseEvent):Void {
              mouseInside
= false;
              fadeTimeline
.start();
              me
.node.effect = null
           
}
          onMousePressed
:
           
function(me:MouseEvent):Void {
              me
.node.effect = Glow {
                level
: 0.9
             
};
           
}
          onMouseReleased
:
           
function(me:MouseEvent):Void {
              me
.node.effect = null;
           
}
          onMouseClicked
:
           
function(me:MouseEvent):Void {
              action
();
           
}
       
},
        textRef
= Text {
          translateX
: bind btnImage.width / 2 - textRef.getWidth() / 2
          translateY
: bind btnImage.height - textRef.getHeight()
          textOrigin
: TextOrigin.TOP
          content
: title
          fill
: Color.WHITE
          opacity
: bind textOpacityValue
          font
:
           
Font {
              name
: "Sans serif"
              size
: 16
              style
: FontStyle.BOLD
           
}
       
},
     
]
   
};
 
}
}  



위의 ButtonNode.fx 코드 목록에서는 다음 내용을 짚고 넘어가겠습니다.

  • ButtonNode 클래스는 CustomNode를 확장합니다.
  • 이 새로운 클래스는 사용자 지정 노드에 표시될 이미지와 텍스트를 저장하는 속성을 채용합니다.
  • create() 함수는 사용자 지정 노드의 UI 모양과 동작에 관한 선언 표현식을 반환합니다.
  • javafx.scene.effect 패키지의 Glow 효과는 이미지를 클릭할 경우 이미지에 빛나는 효과를 줄 때 사용됩니다.
  • 이미지의 투명도, 이미지의 크기, 사용자 지정 노드의 제목은 마우스를 누르거나 버튼을 놓을 때 전환됩니다. Timeline은 이러한 전환이 점진적으로 이루어지도록 하는 데 사용됩니다.
  • 투명도를 조정하고 Glow 효과를 적용한 후에 onMouseClicked 함수가 목록의 앞 부분에 정의된 action() 함수 속성을 호출합니다. 그러면 사용자 지정 노드가 Button과 유사하게 동작합니다.

"메뉴"에 ButtonNode 인스턴스 배열

Setting the "Stage" for the JavaFX SDK 게시물에서 설명한 것처럼 HBox 클래스는 javafx.scene.layout 패키지에 있으며, 이 패키지 안의 다른 노드를 배열하는 노드입니다. 아래와 같은 MenuNode 사용자 지정 노드는 ButtonNode 인스턴스를 수평으로 배열하고, javafx.scene.effects 패키지의 Reflection 클래스는 해당 버튼 아래에 멋진 반사 효과를 추가합니다. 코드는 다음과 같습니다.

MenuNode.fx

/*
 *  MenuNode.fx -
 *  A custom node that functions as a menu
 *
 *  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
 *  to demonstrate how to create custom nodes in JavaFX
 */


package com.javafxpert.custom_node;
 
import javafx.scene.*;
import javafx.scene.effect.*;
import javafx.scene.layout.*;

public class MenuNode extends CustomNode {

 
/*
   * A sequence containing the ButtonNode instances
   */

 
public attribute buttons:ButtonNode[];
   
 
/**
   * Create the Node
   */

 
public function create():Node {
   
HBox {
      spacing
: 10
      content
: buttons
      effect
:
       
Reflection {
          fraction
: 0.50
          topOpacity
: 0.8
       
}
   
}    
 
}
}  


사용자 지정 노드 사용

이제 사용자 지정 노드를 정의했으므로 간단한 프로그램에서 이 노드를 사용하는 방법을 보여드리겠습니다. 이 블로그를 따라해보신 분은 "JavaFX가 UI와 모델을 바인딩하는 방식"을 알게 되었을 것입니다. 이 간단한 예에서는 사용자 지정 노드를 만드는 방법을 알리는 데 중점을 두기 때문에 모델을 만들어서 이 모델에 UI를 바인딩하는 복잡한 작업까지 보여드리지는 않겠습니다. 대신, ButtonNode 인스턴스를 클릭할 때마다 문자열을 콘솔에 인쇄하는 간단한 작업을 보여드리겠습니다. 이번 예의 기본 프로그램의 코드는 다음과 같습니다.

MenuNodeExampleMain.fx

/*
 *  MenuNodeExampleMain.fx -
 *  An example of using the MenuNode custom node
 *
 *  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
 *  to demonstrate how to create custom nodes in JavaFX
 */

package com.javafxpert.menu_node_example.ui;

import javafx.application.*;
import javafx.scene.paint.*;
import javafx.scene.transform.*;
import java.lang.System;
import com.javafxpert.custom_node.*;

Frame {
 
var stageRef:Stage;
 
var menuRef:MenuNode;
  title
: "MenuNode Example"
  width
: 500
  height
: 400
  visible
: true
  stage
:
    stageRef
= Stage {
      fill
: Color.BLACK
      content
: [
        menuRef
= MenuNode {
          translateX
: bind stageRef.width / 2 - menuRef.getWidth() / 2
          translateY
: bind stageRef.height - menuRef.getHeight()
          buttons
: [
           
ButtonNode {
              title
: "Play"
              imageURL
: "{__DIR__}icons/play.png"
              action
:
               
function():Void {
                 
System.out.println("Play button clicked");
               
}
           
},
           
ButtonNode {
              title
: "Burn"
              imageURL
: "{__DIR__}icons/burn.png"
              action
:
               
function():Void {
                 
System.out.println("Burn button clicked");
               
}
           
},
           
ButtonNode {
              title
: "Config"
              imageURL
: "{__DIR__}icons/config.png"
              action
:
               
function():Void {
                 
System.out.println("Config button clicked");
               
}
           
},
           
ButtonNode {
              title
: "Help"
              imageURL
: "{__DIR__}icons/help.png"
              action
:
               
function():Void {
                 
System.out.println("Help button clicked");
               
}
           
},
         
]
       
}
     
]
   
}
}

앞서 언급한 대로 사용자가 해당 ButtonNode를 마우스로 클릭할 때마다 호출된 함수에 action 속성이 할당됩니다. 그리고 __DIR__ 표현식은 CLASS 파일이 있는 디렉토리로 평가됩니다. 이 경우 그래픽 이미지는 com/javafxpert/menu_node_example/ui/icons 디렉토리에 있습니다.

이 기사의 이미지를 다운로드한 후 이 그래픽으로 이 예에서 소개한 대로 작성하고 실행할 수 있습니다. 이 이미지는 프로젝트의 클래스 경로에서 확장할 수 있는 zip 파일입니다.

이 파일은 JavaFX SDK Technology Preview에 유용한 사용자 지정 노드 라이브러리를 작성하여 이 블로그의 JFX Custom Nodes 카테고리에 게시하기 위해 만든 것입니다. 사용자 지정 노드와 관련하여 아이디어가 있거나 자신이 개발한 사용자 지정 노드를 공유하려면 lat-inc.com의 jim.weaver로 연락해주십시오.

이 게시물을 실행한 후에 Weiqi Gao가 Java WebStart Works On Debian GNU/Linux 4.0 AMD64 게시물에 몇 가지 좋은 소식을 올렸습니다. JavaFX 스크립트 설명서의 기술 검토를 훌륭하게 해주셔서 저는 Weiqi(발음: 웨이치) 씨가 매우 좋습니다. ;-)

감사합니다.
Jim Weaver
JavaFX Script: Dynamic Java Scripting for Rich Internet/Client-side Applications

지금 바로 the book's Apress site에서 eBook(PDF)을 다운로드할 수 있습니다.

이 글의 영문 원본은
Rolling Your Own JavaFX "Custom Nodes": A Graphical Menu Example
에서 보실 수 있습니다.

"Java FX" 카테고리의 다른 글

Posted by 1010
98..Etc/Etc...2008. 11. 12. 17:12
반응형

많은 J2EE개발자들이 환경 변수(environment entries), DataSource 객체, JMS 메시지 수신지(JMS message destinations) 그리고 엔터프라이즈 빈 홈 인터페이스(enterprise bean home interfaces)를 찾고자 Java Naming and Directory Interface (JNDI)를 이용한다. 하지만 많은 사람들은 JNDI에 대한 진정한 이해 없이 이러한 기능을 하는 코드를 단순히 복사해서 붙이고 고칠 뿐이다. 이 팁은 사용자의 엔터프라이즈 시스템에 배포된 리소스를 액세스하기 위해 JNDI를 사용하는 방법을 소개한다.

엔터프라이즈 애플리케이션들은 그것들의 특성상, 비즈니스 오퍼레이션을 지원하기 위해 여러곳에 배포된 리소스들을 한데 모아야 한다. 새로운 시스템이 생성되었다거나, 기존의 시스템이 업그레이드 되었다거나, 오래된 시스템이 더 이상 작동하지 않을 때 서비스들이 오가게 된다. 애플리케이션 서비스를 서로 분리하는 것은 시스템을 쉽게 유지/확장할 수 있게 한다. 하지만 서비스가 분리되었을 때, 각자의 역할을 제대로 수행하기 위해서는 서로를 찾아낼 수 있어야만 한다. 이 때가 바로 명명 서비스(naming services)와 디렉토리가 유용한 시점이다.

명명 서비스는 이름을 이용해서 객체나 객체에 대한 레퍼런스를 검색하는 방법을 제공한다. 그러한 객체로의 예는 메시지 큐(message queues), 데이터베이스 커넥션 팩토리(database connection factories), 환경 파라미터(environment parameters), 그리고 엔터프라이즈 빈과 같은 분산 컴포넌트(distributed components)등이 있다. 애플리케이션 개발자들은 명명 서비스내의 이름에 객체들을 바인딩해서 객체에 이름을 붙인다. 애플리케이션 코드는 이렇게 바인딩된 이름으로 객체들을 검색하기 위해 명명 서비스를 사용할 수가 있다. 이러한 분리(decoupling)는 네트워크 객체들을 사용하는 시스템 컴포넌트에 대한 어떠한 변경없이 유지 보수를 위해 올리거나 내릴 수 있고, 요청들을 리다이렉트(redirect)시킬 수 있으며, 서비스가 다이나믹하게 재조정될 수 있음을 의미한다.

이미 기존의 명명 서비스에 대해 잘 이해하고 있으리라고 생각된다.

  • DNS (Domain Name Service)는 java.sun.com과 같은 호스트네임을 %nslookup java.sun.com%과 같은 IP주로소 매핑한다.
  • CORBA (Common Object Request Broker Architecture)를 위해 쓰이는 COS (Common Object Services) 명명 서비스 는 CORBA 인터페이스 이름(interface names)을 객체 인터페이스로 매핑한다.

사용자는 컴퓨터의 파일시스템을 파일의 경로(pathname)에 파일의 컨텐츠를 매핑하는 일종의 명명 서비스로 생각할 수 있다.

밑의 그림은 명명 서비스가 서비스 네임을 데이터나 서비스 인터페이스로 매핑하는 방법을 보여주고 있다.

figure 1

이름(name)을 객체로 매핑하는 것을 바인딩이라 부른다. 바인딩은 명명 서비스를 형성하는 사람에 의해 생성된다. 대부분의 명명 서비스는 프로그램이 런타임시에 이름을 객체로 바인딩하거나 해제하는 방법도 제공한다.

컨텍스트는 이름을 객체로 바인딩한 집합이다. 예를 들면, 파일시스템에서 경로 /home 는 흔히 시스템의 유저 디렉토리를 포함하는 컨텍스트이다. 컨텍스트는 다른 컨텍스트를 포함할 수도 있다. /home 컨텍스트의 유저 디렉토리는 그 자체가 유저 파일을 포함하는 컨텍스트이다.

컨텍스트는 최소한 명명 규칙(naming convention)과 검색기능(lookup function)을 갖는다. 예를 들면, DNS는 가장 구체적인 스트링은 왼쪽, 도메인은 오른쪽에 나타내면서 스트링을 점으로 분리하는 명명 규칙을 갖는다. DNS의 검색기능은 nslookup 프로그램을 이용해서 커맨드라인으로부터 액세스가 가능하다.(물론, DNS 명명 서비스에 대한 API도 존재한다.) 컨텍스트는 대게 객체들을 바인딩하고 해제하는 방법과 그것들을 열거하는 방법을 제공한다.

때때로 명명 서비스 의 객체들은 다른 프로그램이 필요로 하는 데이터를 포함한다. 가령, J2EE애플리케이션에서 환경 변수를 나타내는 객체들은 대게 명명 서비스 에 저장된다. 하지만 이외에 명명 서비스의 객체는 객체에 대한 레퍼런스를 나타낸다. 예를 들면, 서버에 레퍼런스를 제공하는 객체는 통상적으로 오픈 서버 커넥션이 아닌 서버에 대한 레퍼런스로서 명명 서비스 에 의해 저장된다.명명 서비스 에 의해 리턴된 레퍼런스 객체는 필요시에 서버 커넥션을 생성하기 위해 사용될 수 있다.

다음 그림은 컨텍스트의 개념도이다. top 컨텍스트는 /top로 불리며 객체, 레퍼런스, 그리고 다른 컨텍스트들을 포함한다. 컨텍스트 /top은 subcontexts b 와 g를 갖는다. 컨텍스트 /top/g 는 subcontext "b"를 갖는다. A라고 불리는 객체가 하나 이상 일지라도, 특정 개체 /top/g/b/a는 그 위치가 컨텍스트 /top/g/b 임이 분명하기 때문에 찾을 수가 있다.

figure 2

바인딩된 객체들에 대한 데이터를 제공하는 명명 서비스를 디렉토리라고 부른다. 가령, 파일시스템 디렉토리는 일반적으로 크기, 타입, 접근 허용 그리고 파일을 생성하고 수정한 날짜에 관한 정보를 제공한다. 몇몇 디렉토리는 이름으로 검색, 애트리뷰트의 조합으로 검색 모두를 허용한다.

각각의 명명 서비스들은 각자의 태스크(task)에 잘 맞도록 되어있지만, 그들이 작동하는 방식은 서로 다르다. 각 명명 서비스는 고유의 명명규칙, 검색기능, 바인딩과 디렉토리 프로토콜(directory protocols)과 객체 서비스 인터페이스(object service interfaces)를 갖는다. JNDI 는 네트워크 서비스를 이름짓고 찾기 위해 일관된 방법을 제공한다.

Java Naming and Directory Interface

JDBC 데이터베이스 커넥션(database connections), JMS 큐(JMS queues) 혹은 엔터프라이즈 빈 홈 인터페이스(enterprise bean home interfaces)와 같은 네트워크 객체에 액세스하기 위해 JNDI 를 사용하는 방법을 이미 알고 있을 것이다. 사실 JNDI 는 이름들을 객체로 매핑하지만, JNDI 는 명명 서비스가 아니다. 그보다도 JNDI는 명명 서비스를 표준적인 방법으로 액세스가능하게 하면서 기존의 명명 서비스를 감추는(wrap) 인터페이스들의 집합이다.

다음 그림에서 보는 것과 같이, 자바 애플리케이션은 JNDI인터페이스를 이용해서 감춰진(underlying) 명명 서비스에 액세스한다.

figure 3

애플리케이션내의 코드는 JNDI 인터페이스 메소드를 호출한다. 이러한 메소드를 구현하는 객체들은 JNDI 인터페이스 호출을 감춰진 명명 서비스에 대한 호출로 매핑한다. 또한 JNDI는 통합된 명명 규칙도 정의한다. JNDI 이름들은 JNDI의 명명 관리자(naming manager)에 의해 감춰진 명명 서비스의 명명 규칙을 따르는 이름으로 매핑된다.

javax.naming 패키지는 다음과 같은 명명과 디렉토리에 관련된 인터페이스들을 포함한다.

  • javax.naming.Context는 컨텍스트를 나타내는데, 이것은 바인딩과 서브컨텍스트를 찾고 관리하는 데에 쓰인다.
  • javax.naming.Name는 명명 서비스의 이름을 추상적으로 표현(abstract representation)하게 해준다.
  • javax.naming.Binding은 명명 서비스 이름과 그 이름에 바인딩된 객체의 표현이다.
  • javax.naming.Reference는 객체의 복사본을 얻어낼 수 있게 해준다.

컨텍스트 찾기

이 팁에 포함된 샘플코드는 JNDI컨텍스트의 컨텐츠를 열거하는 방법을 보여준다. 샘플 서블릿 Oct2003Servlet는 사용자가 입력한 이름에 해당하는 JNDI namespace내의 컨텐츠를 찾고 디스플레이한다.

컨텍스트를 얻는 가장 쉬운 방법은 javax.naming.InitialContext 클래스의 인스턴스를 생성하는 것이다. 샘플 서블릿 메소드 jndiList 는 최초의 컨텍스트를 생성하고 명명된 객체를 찾을 때 그것을 사용한다.

   InitialContext ic = new InitialContext();
   Object objFound = ic.lookup(name);

여기에서 name은 사용자가 HTML페이지에서 입력한 HTTP GET 혹은 POST 변수명(vriable name)이다. 만약 리턴된 객체가 Context 라면 jndiListlistContext 메소드를 호출하고, ListContext메소드는 주어진 이름에 해당하는 컨텍스트의 컨텐츠를 열거한다. 객체가 DataSource이면, jndiList 는 명명된 데이터 소스에 관한 정보를 출력한다.

listContext 메소드는 주어진 JNDI 컨텍스트의 컨텐츠를 하나의 테이블로 출력한다. 이를 위해서는 Context 메소드 listBindings 를 이용하는데, 이는 NamingEnumeration 를 리턴한다.

      NamingEnumeration ne = context.listBindings("");

NamingEnumerationjava.util.Enumeration를 구현한 것이다. NamingEnumeration.next 메소드는 javax.naming.Binding 타입의 객체를 리턴하고, 이는 객체의 이름과 객체의 클래스 이름 그리고 저장된 객체 자체를 포함한다.

      
      while (ne.hasMore()) {
         Binding ncp = (Binding)ne.next();
         String objName = ncp.getName();
         String objClass = ncp.getClassName();
         Object objObj = ncp.getObject();

         ...
     }

단순히 Context내의 이름들과 클래스이름을 보고자 한다면 Context.list 메소드를 이용할 수 있다. Context.listNamingEnumeration를 리턴하지만, 그것이 담고있는 컬랙션은 Binding이 아닌 NameClassPair 타입이다. NameClassPair는 이름과 객체 클래스 이름만을 포함한다.

샘플애플리케이션을 배포하고 실행하는 방법은 샘플코드 실행하기 를 참고한다.

애플리케이션을 실행하면, 다음과 같은 시작페이지를 보게 된다.

jndichoice

컨텍스트를 입력하거나, 텍스트 필드를 빈 상태로 놔두고 명명된 컨텍스트의 컨텐츠를 보기 위해 List버튼을 클릭한다. 예를 들면 jdbc 의 엔트리는 다음과 같은 화면을 디스플레이한다.

jndilist

JNDI 에 관한 더 자세한 정보는 JNDI 튜토리얼를 참고한다.

"Java EE" 카테고리의 다른 글

Posted by 1010
98..Etc/Etc...2008. 11. 12. 17:12
반응형

JavaServer Pages (JSP pages)의 커스텀 태그는 HTML 태그와 유사하다. 하지만 커스텀 태그는 태그와 관련된 핸들러 클래스에 의해 런타임시에 텍스트 형식의 출력값으로 대체된다. 지난 테크팁인 Using Custom Tags에서 이와 같은 클래스의 생성방법에 대해 이야기했다. 이번달의 첫번째 팁은 커스텀 태그를 구현하는 더 새롭고 쉬운 방법을 설명한다.

JSP 2.0이전에는 커스텀 태그를 생성하려면 자바 태그 핸들러 클래스로 구현하는 것이 유일한 방법이었다. 또한 핸들러 클래스 개발자는 태그를 웹 컨테이너에게 설명하는 역할을 하는 TLD파일을 생성해야만 했다. 커스텀 태그의 힘은 강력하지만 이를 이용하려면 프로그래밍 스킬이 요구되고 JSP 페이지가 어떻게 HTML로 변환하는지를 확실하게 알고 있어야 한다.

JSP 2.0 태그 파일의 새로운 기능은 비개발자도 재사용이 가능한 커스텀 태그를 작성할 수 있게 할 뿐만 아니라 프로그래머도 더 쉽게 작업할 수 있도록 도와준다. JavaServer Pages Standard Tag Library (JSTL) 과 expression language (EL)으로 이루어진 JSP 2.0 구문을 이용하면, 자바 코드를 작성할 필요없이 커스텀 태그를 생성할 수 있다.

태그 파일은 JSP 페이지에서 재사용이 가능한 컴포넌트이다. 이를 사용하면 다음과 같은 이점이 있다.

  • Scriptlets을 숨기거나 제거하는데 사용될 수 있다.
  • 자르기와 붙이기가 아닌, 레퍼런스로를 이용하여 코드를 재사용가능하도록 만든다.
  • JSP 페이지를 작성하기 쉽고, 매우 논리적이며, 유지하기 쉽도록 만든다.
  • 비개발자에 의해 작성될 수 있다.
  • 태그 파일의 구성은 자바가 아닌 HTML에 더 가깝다. 따라서 JSP 페이지는 단일 언어로 작성된 것처럼 보인다.
  • 태그 파일은 하이 레벨 컴포넌트를 형성하기 때문에 생산성을 높이고 개발속도를 빠르게 한다.
  • 커스텀 태그에 의해 사용되는 TLD파일은 흔히 자동적으로 생성된다.
  • 현존하는 페이지를 리팩토링하기 위해 사용될 수 있다. 코드의 공통 부분은 애플리케이션 뷰간에 공유되는 태그 파일로 통합될 수 있다.

태그 파일이 커스텀 태그 핸들러 클래스를 완벽하게 대체하지는 못한다. 태그 파일은 재사용이 가능한 컨텐츠를 관련된 레이아웃과 프리젠테이션으로 캡슐화할 때 적합하다. 반면 커스텀 태그는 JSP페이지에서 애플리케이션 로직(logic)을 재사용할 때 더 효과적이다. 가령, 페이지 헤더와 풋터(꼬리말)는 태그 파일을 위한 최적의 애플리케이션이다. 이와 비교해서 JSTL의 커스텀 태그는 자바 언어 핸들러 클래스로서 구현된다.

태그 파일의 특징

태그 파일은 사실 태그 핸들러 클래스로 번역/컴파일된다. 태그 핸들러와 태그 핸들러 클래스의 단 한가지 다른 점은 태그 핸들러는 JSP 구문으로 쓰여지고 태그 핸들러 클래스는 자바 언어로 작성된다는 점이다.

JSP 2.0-compliant 컨테이너는 웹 아카이브 디렉토리인 WEB-INF/tags내에서 태그 파일을 찾게 된다. 태그 파일은 WEB-INF/lib의 JAR 파일안에 묶일 수도 있다. JSP 페이지를 구현할 때 웹 컨테이너가 태그 파일과 관련된 태그를 마주치게 되면, 태그 파일의 JSP컨텐츠 출력값은 계산되어서 응답 스트림에 포함되게 된다. 태그 파일은 애트리뷰트를 정의할 수 있고 JSP 2.0 expression language (EL)에 대한 접근이 가능하다. 또한 태그 파일은 실행이 완료된 후에도 존재하는 EL 변수들을 생성할 수 있다.

태그 파일은 애트리뷰트 지시어를 이용해서 애트리뷰트를 선언하게 된다. 다음은 이 팁의 샘플코드로부터 발췌한 예제이다. 태그 파일은 단일 애트리뷰트 지시어로 시작한다.

   <%@ attribute name="format" required="false" %>

날짜를 생성하는 태그는 위의 라인을 이용해서 컨테이너에게 가능한 "format" 애트리뷰트를 찾으라고 명령한다. 필수 애트리뷰트일 경우에는 지시어의 "required" 애트리뷰트가 "true"로 설정된다. 이 지시어들은 전개시에 웹 컨테이너가 고유의 TLD 파일을 생성하도록 해준다.

태그는 애트리뷰트를 통해서 입력값을 받는다. 태그 파일에 의해 생성되는 출력 텍스트이외에도 태그는 EL변수를 생성함으로써 데이터를 "output" 할 수 있다. 태그 파일은 다음과 같이 값을 태그 파일이 호출되었던 페이지에 값을 리턴할 수도 있다.

   <%@ variable name-given="filesincluded" scope="AT_END" %>

"name-given"은 태그가 수행된 후, 페이지내에 설정되는 변수의 이름을 제공한다. "AT_END"는 태그 파일이 완성되면 변수가 설정된다는 것을 말한다.

태그 파일 예제

이번 샘플 코드는 지난 2002/9월의 테크팁 "Using Custom Tags"에서 작성했던 커스텀 태그를 재구현하는 태그 파일을 포함하고 있다. 오리지널 태그는 다음 세 가지 중 한가지 방법으로 서버에 날짜의 포맷을 지정한다.

  • 만약 포맷이 설정되지 않았거나 비어있다면, 태그는 디폴트 포맷으로 날짜를 프린트한다.
  • 포맷 파라미터가 $사인으로 시작되면, 태그는 스트링의 나머지 부분을 환경 엔트리의 이름으로 사용한다. 태그는 지명된 환경 엔트리를 찾아서 그것의 값을 포맷으로 사용하게 된다.
  • java.text.SimpleDateFormat과 호환되는 "format" 파라미터가 포맷 스트링을 포함하고 있다면, 스트링은 날짜의 포맷을 지정하는데 쓰이게 된다.

태그 파일에 의해 지정된 태그는 약간 다르게 작동한다. 포맷 파라미터가 $으로 시작하면, 태그는 환경 엔트리 대신 서블릿 컨텍스트 초기화 파라미터를 찾는다. (JSTL 1.0의 expression language는 환경 엔트리를 액세스할 수 있는 빌트 인 서포트를 포함하지 않았다.)

샘플 태그 파일인 date.tag는 파일이 요구하는 애트리뷰트를 정의하는 몇몇 지시어로 시작한다. 또한 이 태그가 사용하는 다른 태그 라이브러리를 위한 namespaces를 식별해내기도 한다.

   <%@ attribute name="format" required="false" %>
   <%@ taglib uri=
     "http://java.sun.com/jsp/jstl/core" prefix="c" %>
   <%@ taglib uri=
     "http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
   <%@ taglib uri=
     "http://java.sun.com/jsp/jstl/functions" 
     prefix="fn" %>

날짜 태그 파일의 다음 블록은 포맷 스트링을 결정하기 위해 <c:choose>태그를 사용한다. <c:choose>는 JSP페이지에서 if/then/else기능을 선택하기 위한 태그이다. 처음 "when"구문은 포맷이 null이거나 비어있을 때 EL변수 "format"을 디폴트 값으로 설정하기 위한 것이다.

   <c:choose>
     <%-- If format is blank, set default --%>
     <c:when test="${format == null or format == ''}">
       <c:set var="format" 
         value="EEEE, d MMMM yyyy 'at' kk:mm:ss z"/>
     </c:when>
   ...

"format"이 비어있는 상태가 아니라면, 그것은 "$"사인으로 시작하거나 또는 "$"으로 시작하지 않는다. 첫번째 경우에서, <choose> 태그의 <otherwise>절은 첫번째 "$"을 없애버리고 주어진 이름을 이용해서 "format" 변수의 값을 컨텍스트 파라미터의 컨텐츠로 대체하게 된다.

     <c:otherwise>
       <%-- Else if format starts with "$", 
           look up in context param,
           and set "format" to its value. --%>
       <c:if test="${fn:substring(format,0,1) == '$'}">
         <c:set var="format_name" 
           value="${fn:substringAfter(format,'$')}"/>
         <c:set var="format" 
           value="${initParam[format_name]}"/>
       </c:if>

       <%-- Otherwise leave it as it is --%>
     </c:otherwise>
   </c:choose>

코멘트에 적혀있듯이, "format"이 "$"로 시작하지 않으면, 그것의 값은 변하지 않는다.

페이지의 이 지점에서, EL "format"변수의 값은 날짜의 포맷을 지정하기 위해 사용될 스트링으로 설정된다. useBean라인은 현재 시간을 나타내는 Date객체를 생성하고 fmt:formatDate 메소드는 이 날짜를 주어진 "format"에 설정하게 된다.

   <%-- Now actually create and format the date --%>
   <jsp:useBean id="now" class="java.util.Date"/>
   <fmt:formatDate value="${now}" pattern="${format}"/>

이것으로 태그 파일이 완성되었다.

태그 파일을 이용하는 것은 더욱 간단하다. 샘플 페이지 DatePage.jsp 의 윗부분에 있는 지시어는 /WEB-INF/tags 디렉토리에 있는 모든 태그가 접두사 "mytags"를 이용해서 액세스 가능하다는 것을 말한다. 지시어는 다음과 같다.

    <%@ taglib tagdir="/WEB-INF/tags" prefix="mytags" %>

자, 이제 JSP 태그 파일을 다른 커스텀 태그처럼 간단하게 사용할 수 있다. 샘플 페이지 DatePage.jsp에서 발췌한 코드이다.

   The time and date at the server in the default format
      are <b><mytags:date/></b>.<br>
   The time zone at the server is 
      <b><mytags:date format="zzzz"/></b>.<br>
   The server date is 
      <b><mytags:date format="M/d/yyyy"/></b>.<br>
   The server time is 
      <b><mytags:date format="hh:mm:ss a"/></b>.<br>

각각의 는 태그 파일을 호출하는 결과를 낳고, 태그는 서버에 해당 시간과 날짜를 출력하게 된다.

이 예제는 JSP태그 파일을 간단히 소개하는 것에 그친다. 사실 JSP태그 파일은 여기서 언급한 것 이상의 많은 옵션을 갖고 있다. JSP태그 파일에 대한 자세한 정보는 J2EE 1.4 튜토리얼의 "Custom Tags in JSP Pages"장을 참고하기 바란다.

"Java EE" 카테고리의 다른 글

Posted by 1010
98..Etc/Etc...2008. 11. 12. 17:09
반응형

기존 시스템과 J2EE 애플리케이션 서버를 통합하는 작업을 해본 경험이 있다면 그 작업이 결코 쉽지 않다는 것을 알고 있을 것이다. 커넥션을 관리하고 상이한 데이터 타입들을 변환시켜주는 작업, 애플리케이션 서버와 기업 정보 시스템(EIS) 사이의 단순한 메시지 전송조차 자바 프로그래머의 머리를 아프게 만들 수 있다. 하지만 고맙게도 이제 J2EE 커넥터 아키텍처 1.5가 J2EE 1.4 버전에 포함되어 J2EE 플랫폼을 이종 EIS들과 접속시키기 위한 표준 아키텍처를 제공한다.

J2EE 커넥터 아키텍처를 사용하면 EIS 벤더들이 여러 애플리케이션 서버들을 위한 커넥션 소프트웨어를 직접 제작할 필요가 없다. 또한 애플리케이션 서버 벤더들도 다양한 EIS 패키지들을 위해 자신들의 코드를 다시 작성할 필요가 없다. 이제 벤더들은 단순히 J2EE 커넥터 아키텍처 기준에 맞는 "중간" 코드만 패키지 시켜주면 된다. 이 코드는 애플리케이션 서버와 EIS 자원 간의 통신에 필요한 데이터와 메시지를 위해 표준화된 인터페이스와 클래스를 구현하거나 확장 시켜 준다. 이 중간 코드는 애플리케이션 서버에 직접 연결되며 자원 어댑터라 불린다.

자원 어댑터 모듈은 흔히 자원 어댑터 아카이브 (RAR)이라는 명칭을 가지고 있으며 단순한 JAR 파일이다. 보통 RAR은 다음과 같은 사항들을 포함하고 있다.

  • 자원 어댑터 컨트렉트와 클라이언트 API를 구현하는 자바 클래스 및 인터페이스

  • EIS와의 통신을 위해 필요한 모든 고유 라이브러리

  • 애플리케이션 서버가 자원 어댑터를 설정하기 위해 필요한 설치 정의 파일인 ra.xml. 이 파일은 META-INF 디렉토리에 위치

다음 그림은 애플리케이션 서버와 EIS에서 사용되는 자원 어댑터를 도표로 설명한 것이다.

각각의 구성원들이 다른 요소들과 통신하는 방식을 살펴보기 바란다.

J2EE 커넥터 아키텍처를 구성하는 데는 세 가지의 중요한 통신 브릿지가 있다. 각각에 대해 살펴보도록 하자.

클라이언트 API와 공통 클라이언트 인터페이스

애플리케이션 서버에 연결되는 애플리케이션 컴포넌트들은 반드시 자원 어댑터와의 통신 방식을 가지고 있어야 하며, 공통 클라이언트 인터페이스 (CCI)는 이런 통신 방식을 위해 권장되는 API이다. CCI는 javax.resource.cci 패키지에 구현된 API이다. 이 API를 권장하는 이유는 사용하기가 쉬우면서 필수적이지는 않다는 점 때문이다. 만약 CCI가 제공하는 기능이 부족하다면 자원 어댑터 구현자들은 자유롭게 자신만의 클라이언트 API를 제작하여 애플리케이션 컴포넌트와 통신을 할 수도 있다.

컨테이너-컴포넌트 컨트렉트

컨테이너-컴포넌트 컨트렉트는 애플리케이션 서버와 애플리케이션 컴포넌트들 간의 표준 통신 방식이다. JCA에 관련된 내용은 거의 없는데 예를 들어, 만약 웹 애플리케이션이 Enterprise JavaBeans(EJB) 컴포넌트들을 사용한다면 EJB specification은 곧 각각의 EJB 컴포넌트가 애플리케이션과 통신하는 방법을 정의하는 컨테이너-컴포넌트 컨트렉트가 된다.

시스템 컨트렉트

시스템 컨트렉트는 J2EE 커넥터 아키텍처의 주요 부분이다. 이 아키텍처는 자원 어댑터가 애플리케이션 서버와 적절히 통신하기 위해 따라야 하는 몇 가지의 시스템 컨트렉트를 정의하고 있다. 시스템 컨트렉트를 위한 API는 javax.resource.spi 패키지에 구현되어 있다. J2EE 커넥터 아키텍처의 1.0 버전에서는 세 가지의 컨트렉트를 제시하고 있다.

  • 접속 관리 컨트렉트: EIS와 애플리케이션 서버 간의 접속을 가능하게 하는 인터페이스와 클래스 제공하며 애플리케이션 서버가 필요에 따라 이러한 커넥션들을 풀링할 수 있도록 해준다.

  • 트랜젝션 관리 컨트렉트: EIS에 트랜젝션의 모든 부분을 관리할 수 있는 기능을 제공한다. 이 컨트렉트를 이용하여 EIS를 자원 어댑터 혹은 트랜젝션 관리자로 관리할 수 있다. 그러나 두 가지 방법 중 한 가지 방법으로만 사용할 수 있다. 트랜젝션은 반드시 EIS 외부에서 이루어져야 하며 이를 EIS로 전달해야 한다. 그 반대는 성립되지 않는다.

  • 보안 컨트렉트: 애플리케이션 서버와 EIS 간의 적절한 인증이 이루어져 있는지 확인한다.

아키텍처의 1.5 버전은 자원 어댑터의 기능을 확장 시켜 줄 수 있는 4 가지의 새로운 컨트렉트를 제공한다. 이 새로운 컨트렉트들은 다음과 같다.

  • 생명 주기 관리 컨트렉트: 애플리케이션 서버가 깨끗하게 자원 어댑터를 시작 혹은 종료 시킬 수 있는 방법 제공

  • 작업 관리 컨트렉트: 자원 어댑터가 애플리케이션 서버에서 작업을 실행시킬 수 있도록 인터페이스와 클래스 제공

  • 트랜젝션 유입 컨트렉트: EIS에서 애플리케이션 서버로 트랜젝션 전달 가능 (트랜젝션 관리 컨트렉트의 반대 기능) 또한 EIS가 오작동할 경우를 대비하여 트랜젝션 복구 보조

  • 메시지 유입 컨트렉트: 자원 어댑터가 애플리케이션 서버 내에서 동기 혹은 비동기 메시지를 엔드포인트로 전달 가능

이 4 가지의 새로운 기능들을 좀더 자세히 살펴보도록 하자.

생명 주기 관리 및 작업 관리 컨트렉트

javax.resource.spi 패키지 안의 ResourceAdapter 인터페이스가 바로 자원 어댑터이다. ResourceAdapter 인터페이스에서 생명 주기 관리를 하는 메소드는 start(), stop()의 두 가지가 있다. start() 메소드는 애플리케이션 서버가 자원 어댑터를 시작하려 할 때(예:자원 어댑터를 배치할 때) 호출되며, stop() 메소드는 애플리케이션 서버가 자원 어댑터를 해제할 때 (예:자원 어댑터를 배치 해제할 때) 호출된다.

작업 관리 컨트렉트는 javax.resource.spi.work 패키지의 Work 인터페이스를 확장하는 객체를 생성함으로써 자원 어댑터가 애플리케이션 서버에 작업을 전달할 수 있도록 해준다. Work 인터페이스는 Runnable 인터페이스의 확장이다. Work 인터페이스에는 Runnable 인터페이스에서 상속받고 자신의 쓰레드에서 실행시키는 run() 메소드뿐만 아니라 release() 메소드도 포함되어 있다. 애플리케이션 서버는 release() 메소드를 사용하여 쓰레드가 완료되면 그 자원을 가능하면 빨리 해제할 수 있도록 해준다.

다음은 ResourceAdapter 인터페이스를 사용하여 생명 주기 관리 및 작업 관리 컨트렉트를 사용하는 예시이다.

   public class NexesResourceAdapterImpl implements 
           ResourceAdapter {

      // Ten seconds
      public static final long WORK_START_TIMEOUT = 10000L;
      
      public NexesResourceAdapterImpl() {    }
      public void start(BootstrapContext ctx)
      throws ResourceAdapterInternalException
      {
 
          WorkManager workManager = ctx.getWorkManager();
          Work nexesWorkJob = new NexesWorkImpl();
          WorkListener workListener = 
                  new NexesWorkListenerImpl();

          try {

              // Unlike scheduleWork() or doWork(), this call 
              // blocks until the work has started. If it takes 
              // longer than 10 seconds for the work to start, 
              // the call throws a WorkRejectedException.

              workManager.startWork
                      (nexesWorkJob, WORK_START_TIMEOUT, 
                      new ExecutionContext(), workListener);

          } catch (WorkException e) {
              //  Handle the exception
          }
        }

       public void stop()
       {
          //  Do whatever you need to do here to close down the
          //  resource adapter.
       }  
       
          // Transaction Inflow contract methods omitted. 
          // See the section "Message Inflow and Transaction 
          // Inflow Contracts"

      }

BootstrapContext 인터페이스를 구현하는 start() 메소드로 객체가 전달되는 것을 볼 수 있다. 이 객체는 EIS가 트랜젝션 정보와 작업을 애플리케이션 서버에 전달할 수 있도록 해주는 매우 중요한 객체이다. BootstrapContext 인터페이스에 관련된 상세한 정보는 "메시지 유입 및 트랜젝션 유입 컨트렉트" 섹션을 참조하시기 바란다.

또한 WorkListener 인터페이스에 대한 참조도 확인하기 바란다.

   WorkListener workListener = 
           new NexesWorkListenerImpl();

and the startWork method:

   workManager.startWork
           (nexesWorkJob, WORK_START_TIMEOUT, 
           new ExecutionContext(), workListener);

만약 애플리케이션 서버가 처리 중인 작업에 대한 진행 상황을 보고 받고 싶다면 javax.resource.spi.WorkListener 인터페이스를 구현하는 객체를 생성하면 된다. 그 다음 이 객체를 애플리케이션 서버 상의 WorkManager 객체의 startWork() 메소드를 사용하여 등록하면 된다. WorkManager 인터페이스는 Work 인스턴스를 실행 시킬 수 있는 기능을 제공한다. 객체를 등록함으로써 작업이 거절 혹은 수락되었는지, 수락되었다면 언제 작업이 시작되었고 종료되었는지를 서버가 자원 어댑터에게 알려줄 수 있다. 또한 WorkAdapter 클래스를 확장시킬 수 있는데, 이 클래스는 WorkListener 인터페이스를 구현하고 각각에 대해 빈 메소드를 제공한다. 다음은 WorkListener를 구현하는 간략한 코드이다.

   public class NexesWorkListenerImpl implements WorkListener {

      public void workAccepted(WorkEvent e) {
          //  myAppServerLog.log("Work instance " + e + 
          //      " has been accepted."); 
      }

      public void workRejected(WorkEvent e) {
          //  myAppServerLog.log("Work instance " + e + 
          //      " has been rejected."); 
      }

      public void workStarted(WorkEvent e) {
          //  myAppServerLog.log("Work instance " + e + 
          //      " has been started."); 
      }

      public void workCompleted(WorkEvent e) {
          //  myAppServerLog.log("Work instance " + e + 
          //      " has been completed."); 
      }

}

메시지 유입 및 트랜잭션 유입 컨트렉트

메시지 유입 컨트렉트는 애플리케이션 서버가 메시지 엔드포인트를 활성화/비활성화 시키는 호출에 대해 자원 어댑터가 반응할 수 있도록 해준다. ResourceAdapter 인터페이스의 endpointActivation() 메소드가 엔드포인트 활성화시 호출되며, 이는 자원 어댑터가 메시지 엔드포인트에 메시지를 전달할 때 필요한 설정을 하도록 한다. ResourceAdapterendpointDeactivation() 메소드는 메시지 엔드포인트가 비활성화될 때 호출되며, 이는 리소스 어댑터가 메시지 엔드포인트에게 메시지를 전달하는 것을 멈추게 한다. javax.resource.spi.endpoint 패키지의 MessageEndpointFactory 객체가 endpointActivation 메소드에 전달된다. 자원 어댑터는 이 객체를 사용하여 메시지 엔드포인트를 생성하게 되며, 이러한 엔드포인트들에 대한 모든 정보는 endpointDeactivation() 메소드가 호출되면 자원 어댑터에서 제거되야 한다. 마지막으로 ResourceAdaptergetXAResources() 메소드는 시스템에 오류가 생길 경우에 트랜잭션 자원을 복구하는데 사용된다. endpointActivation(), endpointDeactivation(), getXAResources()메소드들은 ResourceAdapter 인터페이스에 위임된다.

   public class NexesResourceAdapterImpl implements 
          ResourceAdapter {

      //  Lifecycle Contract methods from earlier omitted.

      public XAResource[] getXAResources(ActivationSpec[] specs)
      throws ResourceException
      {
          // This method should either return an array of 
          // XAResource objects that uniquely correspond to the 
          // resource manager given the ActivationSpecs passed 
          // in, or null if it does  not support this par 
          // of the Message Inflow contract.
        
          return null;
      }

      public void endpointActivation(MessageEndpointFactory mef, 
          ActivationSpec as) 
      throws NotSupportedException
      {
          // This is also part of the Message Inflow contract.
          // The idea here is to create a message endpoint 
          // using the MEF's createEndpoint() method, which is 
          // then stored in the ActivationSpec class. This binds 
          // the EIS and the application server together so that 
          // the two can communicate independently of the 
          // messaging style of the EIS.
      }

      public void endpointDeactivation(MessageEndpointFactory mef, 
          ActivationSpec as)
      {
          //  This removes any resources that were created by the 
          //  endpointActivation() method above for the specified
          //  messaging endpoint. The resource adapter must notify
          //  any message providers that the endpoint is no longer
          //  valid
      }

   }

ResourceAdapter 메소드에 전달되는 ActivationSpec 클래스는 JavaBean으로써, 다양한 속성들의 정보를 입수/설정하는 메소드들을 구현한다. 이러한 입수/설정 메소드들 이외에도 구현은 반드시 validate() 메소드를 제공하여 모든 속성들이 적법하게 설정되어 있는지 확인해야 한다. 만약 속성이 적절히 설정되어 있지 않다면 메소드는 InvalidPropertyException을 반환하게 된다. ActivationSpec 객체가 equals()를 오버라이드할 수 없다는 점에 유의하기 바란다.

   public class MyActivationSpec implements ActivationSpec, 
           Serializable {

      public void setMyProperty(MyProperty s) { }
      public MyProperty getMyProperty() { }

      public void validate() throws InvalidPropertyException { }

   }

J2EE 커넥터 아키텍처 버전 1.0의 경우, 자원 어댑터는 자기 자신 혹은 외부 트랜잭션 관리자로부터 EIS에만 트랜잭션 정보를 전달할 수 있었다. 그러나 1.5 버전에 포함된 트랜잭션 유입 컨트렉트에 의해 자원 어댑터가 EIS 트랜잭션 요구를 애플리케이션 서버에 전달할 수 있게 됨은 물론, 생명주기 컨트렉트의 start() 메소드에 전달된 BootstrapContext 오브젝트 또한 사용할 수 있게 되었다. BootstrapContext 인터페이스는 생명주기 관리 contract의 부분에서 잠깐 언급된바 있다. 다음은 BootStrapContext 인터페이스 내의 메소드이다.

   public class NexesBootstrapContextImpl implements 
           BootstrapContext {

      public WorkManager getWorkManager() {
          //  Get the work manager from the application server
      }

      public XATerminator getXATerminator() {
          return new NexesXATerminatorImpl();
      }

      public Timer createTimer() {
          return new Timer();
      }

}

이제 XATerminator 인터페이스에 대해 자세히 알아보자. BootStrapContext 인터페이스의 getXATerminator() 메소드의 반환값에 유의하기 바란다. XATerminator 인터페이스는 트랜잭션 터리를 위해 5가지의 간단한 메소드를 제공한다

   public class NexesXATerminatorImpl implements XATerminator {

      public void commit(Xid xid, boolean onePhase)
              throws XAException { }
      public void forget(Xid xid) throws XAException { }
      public int prepare(Xid xid) throws XAException { }
      public Xid[] recover(int flag) throws XAException { }
      public void rollback(Xid xid) throws XAException { }

   }

자원 어댑터 파일

자원 어댑터 디스크립터 파일인 ra.xml은 매우 쉽게 생성할 수 있다. 이는 단순히 ResourceAdapter 인터페이스를 구현하는 클래스를 파일에 가리키는 것만으로 이루어 진다. 그러면 애플리케이션 서버가 이 객체에 접근하게 된다. J2EE Connector Architecture 1.5 specifications을 참조하면 수신 메시지 클래스를 ActivationSpec 클래스와 묶는 방법 등을 포함하여 자원 어댑터의 배치 디스크립터에 대한 상세한 정보를 얻을 수 있다. 모든 배치 디스크립터와 마찬가지로 ra.xml 파일은 WAR 파일의 WEB-INF 디렉토리 내에 위치하고 있어야 한다.

   <?xml version="1.0" encoding="UTF-8"?>
   <connector xmlns="http://java.sun.com/xml/ns/j2ee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
     http://java.sun.com/xml/ns/j2ee/connector_1_5.xsd" 
     version="1.5">

     <display-name>Skeleton Resource Adapter</display-name>
     <vendor-name>Sun Microsystems, Inc.</vendor-name>
     <eis-type>Unknown</eis-type>
     <resourceadapter-version>1.0</resourceadapter-version>

     <resourceadapter>
       <resourceadapter-class>
         com.nexes.ra.NexesResourceAdapterImpl
       </resourceadapter-class>
     </resourceadapter>

   </connector>

J2EE 커넥터 아키텍처에 대한 상세한 정보를 위해서는 J2EE Connector Architecture page를 참조하기 바란다.

"Java EE" 카테고리의 다른 글

Posted by 1010
98..Etc/GlassFish2008. 11. 12. 17:04
반응형

대부분의 엔터프라이즈 애플리케이션은 안전한 환경에서 실행할 필요가 있습니다. TLS(Transport Layer Security)/SSL(Secure Sockets Layer)은 포인트 투 포인트 보안 전송 메커니즘으로, 클라이언트 및 서버 간에 교환되는 메시지를 인증하고 메시지의 무결성 및 기밀성(confidentiality) 보장을 위해 사용할 수 있습니다. TLS/SSL(이 팁에서는 간단히 "SSL")은 대부분의 엔터프라이즈 애플리케이션 환경의 보안 요구사항을 충족하며 널리 채택되고 있습니다.

그러나 SSL에 의해 보호된 메시지 교환을 위해서는 서버가 SSL 서버로서 작동할 수 있어야 합니다. 이 팁에서는 GlassFish v2 애플리케이션 서버를 SSL 서버로 작동시키는 방법을 제시합니다.

각 단계별 설명으로 나아가기 전에, 키와 인증서와 같은 SSL의 기본 개념 몇 가지를 이해해야 하며 프로파일이라는 GlassFish v2의 개념도 이해할 필요가 있습니다.

키와 인증서

SSL에서 두 가지 중요한 개념은 키와 인증서입니다. 키는 클라이언트와 서버 사이의 트랜잭션에서 개인 정보 보호(privacy)와 신뢰(trust)를 구축하는 데 사용됩니다. SSL은 공개 키 암호화를 사용하며 이는 키 페어(key pairs)를 기반으로 합니다. 키 페어에는 하나의 공개 키와 하나의 개인 키가 포함됩니다. 데이터가 하나의 키로 암호화된 경우, 그것은 오직 그 페어의 나머지 한 키로만 해독될 수 있습니다.

인증을 위해서는 인증서가 사용됩니다. SSL을 사용하기 위해서는 서버에 연결할 수 있는 각 클라이언트의 IP 주소에 대해 각기 연관된 인증서가 있어야 합니다. 인증서는 서버 사이트의 소유자를 식별하며 관련 정보를 제공합니다. 인증서는 소유자에 의해 디지털로 암호화한 서명이 포함됩니다. 인증이 증요한 사이트의 경우, 인증서는 잘 알려진 신뢰성 있는 인증 기관으로부터 구입할 수 있습니다. 그러나 인증이 크게 중요하지 않은 사이트의 경우에는 자가 서명 인증서(self-signed certificate)를 사용할 수도 있습니다.

GlassFish v2 프로파일

GlassFish v2는 다양한 용도의 프로파일을 지원합니다. 각 프로파일은 애플리케이션 서버에 대한 구성 매개변수를 미리 설정하여 특정 유형의 용도로 최적화합니다. 세 가지 프로파일에는 개발자(developer), 클러스터(cluster) 및 엔터프라이즈(enterprise)가 있습니다.

개발자 프로파일은 개발 환경에서 사용하기 위해 GlassFish v2를 최적화합니다. 이는 구성 매개변수가 빠른 구동(fast startup)과 같은 목표는 지원하지만 로깅 또는 세션 복제와 같은 기능은 지원하지 않는다는 의미입니다. 클러스터 프로파일은 클러스터 생성 및 세션 복제를 가능하게 하는 구성 매개변수를 설정합니다. 클러스터는 GlassFish v2 인스턴스의 그룹으로 단일 논리 개체로서 관리하고 모니터할 수 있습니다. 엔터프라이즈 프로파일은 프로덕션 환경으로 GlassFish v2를 최적화합니다. 또한 로깅 및 기타 보안 관련 기능을 지원합니다.

GlassFish v2 애플리케이션 서버를 SSL 서버로 작동시키기

GlassFish v2를 SSL 서버로 작동시키는 단계는 애플리케이션 서버를 위해 사용된 프로파일에 따라 결정됩니다. 먼저 개발자 프로파일이 사용되는 경우의 프로세스를 살펴본 다음 엔터프라이즈 프로파일이 사용될 때의 프로세스를 검토합니다.

개발자 프로파일이 사용되는 경우

GlassFish v2 프로파일이 특정 유형의 용도를 위해 구성 매개변수를 미리 설정한다는 점을 상기하십시오. 이들 매개변수 중 하나가 Security Store인데 이것은 인증서와 키와 같은 보안 및 신용 관련 정보가 어떻게 저장되는지를 나타냅니다. 개발자 프로파일의 경우 Security Store 값은 JKS로 설정됩니다. 이 경우 서버에 대한 인증서와 키는 자바 키스토어 파일(keystore.jks)에 저장되며 인증서는 신뢰할 수 있는 CA에 의해 발행되며 인증서 파일(cacerts.jks)에 저장됩니다.

GlassFish v2를 설치할 때 서버 인증서로 자가 서명 인증서가 기본적으로 생성됩니다. 그러나 인증이 사용자의 사이트에서 중요한 경우라면, 자가 서명 인증서를 CA로부터의 디지털 서명 인증서로 교체할 필요가 있습니다. 이 섹션에서는 자가 서명 인증서를 대체하는 방법, CA에서 서버 인증서를 확득하는 방법 및 서버 인증서를 키스토어로 가져오는 방법을 설명합니다.

아래에 기술된 단계에서는 키 및 인증서 관리 툴인 keytool을 사용합니다. Keytool은 여러 버전의 자바 플랫폼, 스탠다드 에디션(자바 SE) 개발 킷(jdk)에서 사용 가능합니다. 한편 자바 SE 6에서는 keytool.에 몇 가지 필수 기능이 추가되었습니다. 아래의 명령은 jdk 6 버전의 keytool을 기반으로 합니다. keytool에 대한 자세한 정보는 JDK 툴 및 유틸리티를 참조하십시오.

다음은 애플리케이션 서버가 개발자 프로파일로 구성될 때 GlassFish v2를 SSL 서버로 작동시키기 위한 명령문입니다.

  1. 다음 명령을 수행하여 기본적으로 설치된 자가서명 인증서를 삭제하십시오(참고: 이 단계와 이후의 단계의 명령문은 포맷을 위해 여러 줄에 걸쳐 표시되었음).        keytool -delete -alias s1as -keystore keystore.jks
           -storepass <store_passwd>

    이 때 <store_passwd>는 키스토어에 대한 비밀번호(예: "mypass")입니다. s1as는 GlassFish v2 키스토어의 디폴트 alias입니다.

  2. 다음 명령을 수행하며 애플리케이션 서버를 위한 새로운 키 페어를 생성하십시오.       keytool -genkeypair -keyalg <key_alg>
          -keystore keystore.jks -validity <val_days> -alias s1as

    이 때 <key_alg>는 키 페어 생성을 위해 사용되는 알고리즘(예: RSA)이며 <val_days>는 인증서의 유효일 수(예: 365)입니다.

    키 페어 생성 외에도 해당 명령문은 공개 키를 자가 서명 인증서로 보호하고 인증서와 비밀 키를 alias에 의해 식별되는 새로운 키스토어 엔트리에 저장한다는 점에 유의하십시오.

    인증서의 이름이 사용자 사이트의 완전한 호스트 이름과 일치하도록 보장하는 것이 중요합니다. 그 이름이 일치하지 않으면 서버에 연결하는 클라이언트는 인증서의 이름이 사이트의 이름과 일치하지 않는다는 보안 경고를 받게 될 것입니다. 기본적으로 설치된 자가서명 인증서의 이름이 완전한 호스트 이름과 일치하는지 알고 있어야 합니다.

  3. 다음 명령을 수행하여 CSR(Certificate Signing Request)을 생성하십시오.       keytool -certreq -alias s1as -file <certreq_file>
          -keystore keystore.jks -storepass <store_passwd>

    여기서 <certreq_file>은 CSR이 저장되는 파일(예: s1as.csr)이며 <store_passwd>는 키스토어에 대한 비밀번호(예: changeit)입니다.

  4. VeriSign과 같은 CA에 CSR을 제출하십시오. 그러면 사용자는 응답으로 서명된 서버 인증서를 받게 될 것입니다. CA의 CA 인증서뿐만 아니라 응답에서 CA가 식별한, 중간에 발생한 모든 인증서를 브라우저로 가져와야 합니다.
  5. CA로부터 받은 서명된 서버 인증서를 마커 -----BEGIN CERTIFICATE-----와 -----END CERTIFICATE----- 를 포함하여 s1as.cert와 같은 파일에 저장하십시오. CA 인증서 및 모든 중간 CA 인증서를 다운로드하고 로컬 파일에 저장하십시오. CA 및 중간 CA 인증서를 브라우저로 가져오는 방법에 대해서는 브라우저 문서를 참조하십시오. Mozilla 및 Internet Explorer와 같은 다양한 브라우저로 CA 인증서를 가져오는 방법에 대한 정보는 CA에서 제공할 수도 있습니다.
  6. 원래의 자가 서명 인증서를 CA로부터 획득한 인증서(s1as.cert와 같은 파일에 저장)로 대체하십시오. 이를 위해 keytool 을 사용할 수 있으나 여러 단계를 필요로 합니다. 다음 자바 프로그램을 수행하면 더 쉽게 대체할 수 있습니다.

          import java.io.*;
          import java.security.Key;
          import java.security.KeyStore;
          import java.security.cert.Certificate;
          import java.security.cert.CertificateFactory;
          import java.security.cert.X509Certificate;
         
           
          public class Main {
              public static void main(String[] args) throws Exception {
                //args[] error checking logic omitted
                //file containing signed cert reply from CA
                String csrReplyFromCA = args[0];    
                //Path to GlassFish keystore.jks
                String keystoreLocation = args[1];  
                //Password for GlassFish keystore.jks
                String keystorePassword = args[2];  
                //The keyalias to be replaced : s1as in our example
                String selfSignedKeyEntry = args[3];
                 
                //create the signed Cert
                Certificate cert = null;
                FileInputStream fis =
                   new FileInputStream(csrReplyFromCA);
                CertificateFactory cf =
                   CertificateFactory.getInstance("X.509");
                cert = cf.generateCertificate(fis);
                 
                //now replace the original entry
                char[] passwordChars =
                   keystorePassword.toCharArray();
                KeyStore keystore = KeyStore.getInstance("JKS");
                keystore.load(new FileInputStream(keystoreLocation),
                   passwordChars);
                Key key = keystore.getKey(selfSignedKeyEntry,
                   passwordChars);
                keystore.setKeyEntry(selfSignedKeyEntry, key,
                   passwordChars, (new Certificate[]{cert}));
                keystore.store(new FileOutputStream(
                   keystoreLocation), passwordChars);
              }
          }

프로그램을 수행한 후에, GlassFish 키스토어 내의 인증서 s1as가 더 이상 원래의 자가 서명 인증서가 아니라 CA로부터 받은 인증서(response certificate)라는 것을 확인해야 합니다. 다음은 VeriSign으로부터 획득한 새 s1as 인증서와 원래의 s1as 인증서를 비교한 예입니다.

원래의 s1as (자가 서명):

Owner: CN=KUMAR, OU=Sun Java System Application Server, O=Sun
Microsystems, L=Santa Clara, ST=California, C=US
Issuer: CN=KUMAR, OU=Sun Java System Application Server, O=Su
n Microsystems, L=Santa Clara, ST=California, C=US
Serial number: 472acd34
Valid from: Fri Nov 02 12:39:40 GMT+05:30 2007 until: Mon Oct
30 12:39:40 GMT+05:30 2017

새로운 s1as (CA로부터 서명된 인증서 포함):

Owner: CN=KUMAR, OU=Terms of use at www.verisign.com/cps/test
ca (c)05, OU=Sun Java System Application Server, O=Sun Micros
ystems, L=Santa Clara, ST=California, C=US
Issuer: CN=VeriSign Trial Secure Server Test CA, OU=Terms of
use at https://www.verisign.com/cps/testca (c)05, OU="For Test
Purposes Only. No assurances.", O="VeriSign, Inc.", C=US
Serial number: 1375de18b223508c2cb0123059d5c440
Valid from: Sun Nov 11 05:30:00 GMT+05:30 2007 until: Mon Nov
26 05:29:59 GMT+05:30 2007

이러한 단계를 수행한 후에 GlassFish v2를 다시 시작하고 CA에 의해 발행된 서명된 서버 인증서를 사용할 수 있습니다.

클러스터 프로파일이 사용되는 경우

애플리케이션 서버가 클러스터 프로파일로 구성되는 경우, GlassFish v2를 SSL 서버로 작동시키려면 개발자 프로파일에 대해 수행했던 것과 동일한 단계를 수행합니다. 그러나 이 경우에 동일한 서버 키가 클러스터 내의 모든 애플리케이션 서버 인스턴스에 복제된다는 것을 확실하게 알아 둘 필요가 있습니다.

엔터프라이즈 프로파일이 사용되는 경우

엔터프라이즈 프로파일을 위한 Security Store 매개변수는 NSS이며 이는 네트워크 보안 서비스(Network Security Services)를 나타냅니다. NSS 보안 인프라에는 JKS 키스토어가 없으며 따라서 디폴트 GlassFish 키스토어가 없습니다.

GlassFish v2 애플리케이션 서버를 SSL 서버로 작동시키는 단계는 개발자 프로파일이 사용될 때와 엔터프라이즈 프로파일이 사용될 때가 대체로 유사합니다. 그러나 두 가지의 차이점이 있습니다. 첫 번째 차이는 프로세스의 첫 단계와 관계가 있습니다. JKS 키스토어가 없기 때문에 사용자는 비어 있는 키스토어(keystore.jks)로 프로세스를 시작합니다. 두 번째 차이는 프로세스의 마지막 단계와 관련이 있습니다. 결과로 얻은 서명 인증서를 JKS 키스토어로 가져오는 대신 사용자는 그것을 NSS 스토어로 가져옵니다. 즉, GlassFish v2 애플리케이션 서버를 SSL 서버로 작동시키려면 위에서 설명한 개발자 프로파일이 사용되는 경우와 동일한 단계를 수행하지만 비어 있는 키스토어로 시작하고 6단계를 다음으로 대체합니다.

  1. 다음 명령을 사용하여 키스토어로부터 서버 인증서를 위한 비밀키를 PEM(Privacy Enhanced Mail) 포맷으로 보내십시오.       keyexport.bat -keyfile serverkey.pem
          -keystore keystore.jks -storepass changeit -alias s1as

    이 명령문은 keyexport 유틸리티를 호출합니다. keyexport 패키지에 keyexport가 있습니다. 이 패키지는 Project Metro의 XWSS 다운로드 페이지에서 다운로드할 수 있습니다.

    위 명령에 대한 응답으로 키스토어 비밀번호 입력 프롬프트가 나타날 것입니다. 키스토어 비밀번호는 키 비밀번호와 동일하므로 리턴키를 누르면 됩니다.

    이것은 serverkey.pem 파일을 생성하며 이 파일에는 마커 -----BEGIN PRIVATE KEY----- 와 -----END PRIVATE KEY----- 아래에 서버 비밀 키가 포함됩니다.

  2. CA로부터 응답으로 온 서명 인증서(signed certificate reply)를 마커 -----BEGIN CERTIFICATE----- 와 -----END CERTIFICATE----- 를 포함하여 servercert.pem 파일에 추가하십시오. 마커 END PRIVATE KEY 아래에 그 응답을 추가하십시오.
  3. serverkey.pem 파일을 PKCS#12 파일(확장자가 .pfx인 파일)로 변환하십시오. "PKCS"는 RSA Security에 의해 고안 및 발행된 공개 키 암호화 표준의 그룹을 가리킵니다. PKCS#12는 비밀키와 그에 수반되며 비밀번호 기반의 대칭 키로 보호되는 공개 키 인증서를 저장하는데 흔히 사용되는 파일 형식을 정의합니다.

    serverkey.pem 파일을 PKCS#12 파일로 변환하는데 사용할 수 있는 툴은 여러가지가 있습니다. openssl 툴은 그러한 것 중 하나입니다. 다음은 openss1을 사용하여 파일을 변환하는 명령문입니다.

          openssl pkcs12  -export  -in serverkey.pem -out s1as.pfx

    위 명령에 대한 응답으로 익스포트 비밀번호 입력 프롬프트가 나타날 것입니다. "changeit"과 같은 비밀번호 또는 GlassFish 마스터 비밀번호를 입력하십시오.

    s1as.pfx 파일에는 이제 서명이 있는 서버 인증서 및 비밀 키가 포함될 것입니다.

  4. 원래의 s1as 자가서명 항목이 있으면 다음 명령을 수행하여 삭제하십시오.       certutil -D -n s1as -d $AS_NSS_DB

  5. pk12util 유틸리티를 사용하여 새 s1as.pfx 파일을 NSS 스토어로 가져오는 명령문은 다음과 같습니다.       pk12util -i s1as.pfx -d $AS_NSS_DB

    pk12util은 엔터프라이즈 프로파일을 위한 GlassFish 설치 임시 디렉토리 내에서 이용 가능한 NSS 유틸리티입니다. 그 유틸리티는 PCKS#12 파일을 NSS 스토어로 가져오거나 스토어에서 내보내는 데 사용됩니다.

    명령문에 대한 응답으로, NSS 소프트 토큰 및 PKCS#12 파일에 대한 비밀번호 입력 프롬프트가 나타날 것입니다. 적절한 비밀번호를 입력하십시오. 그러면 가져오기가 성공적으로 수행되었다는 다음과 같은 메시지를 볼 수 있을 것입니다.

          pk12util: PKCS12 IMPORT SUCCESSFUL  

고려해야 할 두 가지 경우가 있습니다.

  • 애플리케이션 서버 프로파일이 엔터프라이즈 프로파일이며 서버 키 페어가 이미 PKCS#12 파일에 있습니다. 스토어 내에 alias가 s1as인 항목이 이미 있는 경우에는 "엔터프라이즈 프로파일이 사용되는 경우"에서 설명한 대로 4단계를 수행하여 원래의 항목을 삭제하기만 하면 됩니다.      certutil -D -n s1as -d $AS_NSS_DB

    그리고 나서 5단계를 수행하여 새로운 s1as.pfx 파일을 NSS 스토어로 임포트합니다.

          pk12util -i s1as.pfx -d $AS_NSS_DB

    alias가 s1as인 항목이 스토어에 없으면 5단계만 수행하십시오.

  • 애플리케이션 서버 프로파일이 개발자 프로파일이며 서버 키 페어가 이미 PKCS#12 파일에 있습니다. 이러한 경우에 엔터프라이즈 프로파일이 사용되는 경우 에서 설명한 대로 5단계를 수행하여 원래의 s1as 항목을 삭제하기만 하면 됩니다. 그 후 pkcs12import 유틸리티를 사용하여 PCKS#12 파일을 GlassFish 키스토어로 가져오십시오.      pkcs12import.sh -file s1as.pfx -alias s1as
         -keystore keystore.jks -storepass changeit
         -pass <exp_password>

    이 때 <exp_password>는 PKCS#12 파일이 보내졌을 때 사용되었던 비밀번호(예: changeit)입니다.

    pkcs12import 패키지에 pkcs12import 유틸리티가 있으며 이 패키지는 Project Metro의 XWSS 다운로드 페이지에서 다운로드할 수 있습니다.

자세한 정보

GlassFish와 SSL에 대한 더 자세한 정보는 GlassFish v2로 SSL 및 CRL 확인(SSL and CRL Checking with GlassFish v2)를 참조하십시오.

또한 다음 리소스도 참조하십시오.


저자 정보

Kumar Jayanti는 썬마이크로시스템즈의 공학자 직원이며 웹 기술 및 표준 팀에서 일하고 있습니다. 현재 Kumar는 XML과 웹 서비스 보안 구현 부문에서 주역을 맡고 있으며 또한 최근에는 GlassFish 보안 모듈도 책임지게 되었습니다. 그는 2004년 초반부터 썬에서 웹 서비스 보안 분야에 관여해 왔으며 인도 Mumbai의 IIT에서 Computer Science 공학석사(M.Tech) 학위를 취득했습니다. 그의 관심 영역은 분산 컴퓨팅, CORBA, XML, 웹 서비스 및 보안 분야입니다.



이 글의 영문 원본은
http://java.sun.com/mailers/techtips/en ··· v07.html
에서 보실 수 있습니다.

"Java EE" 카테고리의 다른 글

Posted by 1010
98..Etc/GlassFish2008. 11. 12. 17:03
반응형
오픈 소스 소프트웨어는 점점 더 많은 기업과 사내 개발자들의 관심을 끌고 있습니다. 이는 커뮤니티에서 오픈 소스 소프트웨어의 소스 코드를 자유롭게 획득하고 업그레이드할 수 있기 때문입니다. 즉, 이 소프트웨어를 사용하면 상용 소프트웨어보다 빠르게 작업을 처리하고, 기업 및 개발자에게 실제로 필요한 사항에 맞게 업그레이드할 수 있습니다. 또한 일반적으로 오픈 소스 소프트웨어는 무료로 사용할 수 있기 때문에 비용을 절감할 수 있습니다. 따라서 많은 관심이 집중되고 사용 범위가 빠르게 확장되고 있는 추세입니다.

그러나 기업들은 오픈 소스 소프트웨어가 업무에 중요한 애플리케이션을 관리하고 로드 및 트랜잭션이 많은 환경을 처리하는 데에는 적합하지 않다고 생각하고 있습니다. 이는 오픈 소스 소트프웨어가 지원되지 않는 경우가 있으며, 상용 소프트웨어 보다 작동 용이성, 안정성 및 성능면에서 떨어지는 경우가 있기 때문입니다. 특히, 애플리케이션 서버와 같이 중요한 엔터프라이즈 구성요소의 경우 IT 결정자가 위험 수준이 낮고 애플리케이션에 적합하도록 오픈 소스를 다양하게 분류합니다.

기업에서는 오픈 소스 애플리케이션 서버를 사용할 것인지 또는 강력하고 안정적인 기업용 애플리케이션 서버를 사용할 것인지 더 이상 선택할 필요가 없습니다. 두 서버에서 모두 GlassFish v2를 사용할 수 있습니다.

그러나 GlassFish v2를 사용하려면 기업에서는 오픈 소스로 운영되며, 업무에 중요한 애플리케이션과 척박한 프로덕션 환경에 맞는 특성을 갖춘 애플리케이션 서버가 필요합니다. 기업에서는 오픈 소스 애플리케이션 서버를 사용할 것인지 또는 강력하고 안정적인 기업용 애플리케이션 서버를 사용할 것인지 더 이상 선택할 필요가 없습니다. 두 서버에서 모두 GlassFish v2를 사용할 수 있습니다.

이 기사에서는 GlassFish v2를 사용하여 중요한 비즈니스 애플리케이션 및 프로덕션 환경의 요구 사항을 처리하는 기능에 대해 집중적으로 설명합니다.


목차

- GlassFish란 무엇입니까?
- GlassFish v2 및 상용 배포판
- 고가용성 및 확장성
- 엔터프라이즈급 성능
- 중앙 집중화된 관리 및 모니터링
- 프로파일에서의 간단한 구성
- .NET과의 상호 운용성
- JBI 준비
- 뛰어난 메시지 처리 기능
- 매력적인 가격 지원 정책
- 요약
- 자세한 정보
- 저자 정보


GlassFish란 무엇입니까?

사용자 삽입 이미지
썬은 2005년 6월에 Java Platform, Enterprise Edition 5 (Java EE 5)와 호환되는 애플리케이션 서버를 개발하기 위해 자바 커뮤니티에 공개하여 GlassFish 프로젝트를 출시했습니다. 그 후, GlassFish 커뮤니티 라는 적극적인 개발자들의 커뮤니티가 프로젝트에 참여하게 되었습니다. 초창기에 많은 노력을 기울인 결과 첫 번째 오픈 소스이자 Java EE 5 호환 애플리케이션 서버이며 Java EE 5의 참조 구현인 GlassFish v1을 개발했으며, GlassFish 커뮤니티에서는 Java Persistence API의 참조 구현인 Toplink Essentials를 발표했습니다. 또한 커뮤니티에서는 Metro, jMaki, Open Message Queue(Open MQ) , Hudson Grizzly와 같은 다양한 하위 프로젝트의 개발을 촉진합니다.

GlassFish v2에는 GlassFish v1의 기능이 모두 포함되어 있으며, 애플리케이션 서버에서 중요한 프로덕션 환경 문제를 수행할 수 있는 기능이 추가되어 있습니다.

GlassFish v1은 개발자를 위해 만들어졌으며, 개발자가 Java EE 5 애플리케이션을 배포하고 테스트할 수 있는 완전한 Java EE 5 호환 애플리케이션 서버 및 오픈 소스를 제공할 목적으로 만들어졌습니다. 목표는 간단한 배포 즉, GlassFish의 단일 인스턴스에서 애플리케이션을 배포하는 것이었습니다. GlassFish v1은 공공 개발 및 배포 라이센스(CDDL) 하에 사용할 수 있으며, 연간 다운로드 횟수가 3백만 건 이상으로 매우 많이 사용되어 왔습니다. 이는 전 세계에 보급되어 썬에서 지원하는 상용 배포판인 Sun Java System Application Server Platform Edition 9.0을 포함하여 여러 배포판에 사용할 수 있으며, 솔라리스, 윈도우 및 리눅스 운영 체제를 비롯한 여러 플랫폼에서도 사용할 수 있습니다.

2007년 9월, GlassFish 커뮤니티에서 GlassFish v1에서의 모든 기능이 포함되고, 애플리케이션 서버에서 중요한 프로덕션 환경 문제를 수행할 수 있는 기능이 추가된 GlassFish v2를 발표했습니다. 이 기사에서는 이러한 기능에 대해 설명합니다.


GlassFish v2 및 상용 배포판

사용자 삽입 이미지
앞서 설명한 대로, GlassFish v1에는 썬에서 지원하는 상용 배포판이 포함되어 있으며, 이는 GlassFish v2의 경우에도 마찬가지입니다. GlassFish v2에 포함된 썬에서 지원하는 상용 배포판은 Sun Java System Application Server 9.1입니다. GlassFish v2와 Sun Java System Application Server 9.1에서는 동일한 코드 베이스를 사용합니다. 또한, 썬에서 Sun Java System Application Server 9.1에 대한 지원 서비스를 구매할 수 있습니다. 지원 서비스에 대한 자세한 내용은 매력적인 가격 지원 정책을 참조하십시오.

GlassFish v2와 Sun Java System Application Server 9.1는 모두 무료로 배포 및 재배포할 수 있습니다. 그러나 GlassFish v2와 달리, Sun Java System Application Server 9.1에서는 코드를 바이너리 형식으로만 사용할 수 있기 때문에 수정이 불가능합니다. GlassFish v2 소스 코드는 CDDL 또는 클래스 경로 예외가 포함된 GNU 일반 공개 라이센스(GPL) v2에 따라 수정할 수 있습니다.

이 기사에서는 주로 GlassFish v2라는 용어를 사용하여 오픈 소스 애플리케이션 서버, GlassFish v2와 해당 상용 배포판인 Sun Java System Application Server 9.1에 대해 설명합니다. 두 배포판 간의 내용이 다른 경우에 한해 GlassFish v2 또는 Sun Java System Application Server 9.1로 각각 언급합니다.

고가용성 및 확장성

애플리케이션 서버에서 중요한 비즈니스 애플리케이션을 처리하는 경우 해당 애플리케이션을 항상 사용할 수 있어야 합니다. 애플리케이션 서버를 프로덕션 환경의 요구 사항에 맞게 사용하려면 증가된 작업 부하에 맞춰 조정해야 합니다. GlassFish v2는 클러스터링 및 고가용성 데이터베이스(HADB) 기술을 통해 고가용성 및 확장성을 보증합니다.


클러스터링

클러스터는 GlassFish v2 애플리케이션 서버 인스턴스의 그룹으로 단일 논리 개체로서 관리하고 모니터할 수 있습니다. 클러스터를 생성하려면 먼저 클러스터링을 위해 GlassFish v2 도메인을 사용할 수 있어야 합니다. GlassFish v2 도메인 또는 보다 정확하게 관리 도메인은 관리자에 의해 모든 GlassFish v2 엔터티가 제어되는 논리 경계입니다. 런타임 시 도메인은 GlassFish v2 애플리케이션 서버 인스턴스 또는 클러스터와 동일합니다. 따라서 GlassFish v2를 설치할 때 도메인에 대한 클러스터링을 쉽게 수행할 수 있습니다. 예를 들어, GlassFish v2를 설치한 후 다음 명령을 사용하여 도메인을 생성하고 클러스터링을 수행할 수 있습니다.

lib/ant/bin/ant -f setup-cluster.xml

GlassFish v2 관리 콘솔에서 기존 도메인에 대한 클러스터링을 수행할 수도 있으며, 해당 내용은 이 기사의 뒷 부분에 설명되어 있습니다.

클러스터링을 수행하도록 도메인을 설정하면 해당 도메인에 클러스터 프로파일을 지정해야 합니다. 프로파일에 대한 자세한 내용은 프로파일에서의 간단한 구성을 참조하십시오. 도메인에서 클러스터를 유연하게 제거하거나 추가하고 특정 클러스터에서 GlassFish v2 인스턴스를 제거하거나 추가할 수 있습니다. 클러스터에 인스턴스를 추가하거나 도메인 내에 클러스터를 추가하여 증가된 애플리케이션 서버 용량과 속도에 대한 요구 사항에 맞게 조정할 수 있습니다. 클러스터 관리 및 모니터링에 대한 자세한 내용은 중앙 집중화된 관리 및 모니터링을 참조하십시오.

클러스터에서 하나의 애플리케이션 서버 인스터스가 실패한 경우 계속해서 세션을 처리하도록 해당 인스턴스와 상호 작용하는 세션이 클러스터의 다른 인스턴스로 다시 라우팅됩니다.

클러스터링의 가장 중요한 측면은 메모리 복제 입니다. 메모리 복제 시 GlassFish v2 인스턴스에서 배포된 애플리케이션이 있는 사용자 세션의 상태에 대한 정보가 클러스터의 동등 인스턴스로 복제됩니다. 클러스터의 각 GlassFish v2 인스턴스가 클러스터의 다음 인스턴스 즉, 복제 파트너에 세션 상태 정보를 보냅니다. 클러스터에서 인스턴스 순서는 인스턴스의 이름을 기반으로 합니다. 모든 인스턴스에서 배포된 애플리케이션의 세션 상태 정보가 업데이트되면 클러스터 주위에 복제됩니다.

GlassFish v2에서 플러그인으로 사용할 수 있는 로드밸런서는 메모리 복제에서 중요한 역할을 수행합니다. 로드밸런서는 여러 GlassFish v2 인스턴스 간의 작업 부하를 분산시키고, 인스턴스에 실패하면 세션을 다시 라우팅합니다. 클러스터에서 GlassFish v2 인스턴스가 실패한 경우 로드밸런서가 해당 인스턴스와 상호 작용하는 세션을 클러스터의 다른 인스턴스로 다시 라우팅합니다.

사용자 삽입 이미지
그림 1. 클러스터의 장애 조치 처리


그림 1에 표시된 대로, 인스턴스 1이 실패하면 로드밸런서가 인스턴스 1과 상호 작용하는 세션을 다른 인스턴스(그림에서 인스턴스 2)로 라우팅합니다. 라우팅할 대상 인스턴스가 실패한 GlassFish v2 인스턴스의 복제 파트너인 경우 해당 위치에서 세션이 처리됩니다. 그러나 라우팅 대상 인스턴스가 복제 파트너가 아닌 경우에는 복제 파트너가 복제된 세션 데이터를 라우팅 대상 인스턴스에 전송합니다. 다시 말해서, 로드 밸런서가 세션을 복제 파트너가 아닌 인스턴스 3으로 라우팅하면 세션을 처리하기 위해 복제 파트너인 인스턴스 2가 상태 데이터를 인스턴스 3으로 보냅니다.

메모리 복제를 사용하면 GlassFish v2에서 배포된 애플리케이션을 항상 사용할 수 있기 때문에 해당 애플리케이션과의 상호 작용에 방해가 있는 경우에도 사용자는 거의 인지하지 못합니다.

클러스터 인스턴스 및 해당 복제 파트너를 다른 시스템에 배치하여 가용성을 더욱 높일 수 있습니다. 이러한 방식으로 수행하면 시스템 중 하나가 실패하는 경우에도 세션 데이터가 손실되지 않습니다.


고가용성(HADB) 기술


매우 높은 수준의 가용성이 필요한 엔터프라이즈에서는 이전 버전의 썬 자바 시스템 애플리케이션 서버에서 사용되고 버전 9.1에서도 사용할 수 있는 기능인 고가용성 데이터베이스(HADB) 기술을 이용할 수 있습니다. HADB는 99.999%("5-9(five-nines)")의 가용성을 제공하고 세션 상태 정보를 유지관리할 수 있는 영구 데이터베이스 저장소를 제공합니다. HADB는 오픈 소스가 아니지만 작업 시 무료로 사용할 수 있습니다.

그러나 GlassFish v2의 클러스터링 기능을 통해 제공되는 강력한 메모리 내 복제를 수행하는 경우 대부분의 설치에 필요한 고가용성 요건을 충족해야 합니다. 또한 메모리 내 복제를 수행하려면 HADB 또는 해당 오픈 소스보다 설치 및 관리 작업을 줄여야 합니다. 이 외에도 메모리 내 복제를 수행하면 HADB를 능가하는 여러 성능 최적화 기능을 활용할 수 있습니다. 그러나 현재 HADB를 사용하는 작업이 있는 경우 또는 5-9(five-nines) 가용성이 필요한 경우 HADB에서 Sun Java System Application Server 9.1을 선택할 수 있습니다.

클러스터링 및 HADB에 대한 자세한 내용은 GlassFish 버전 2에서의 클러스터링을 참조하십시오.


엔터프라이즈급 성능


사용자 삽입 이미지
조정 범위에 상관없이 애플리케이션 서버를 올바르게 작동할 수 있습니다. 뛰어난 처리량과 응답 시간을 제공하므로 애플리케이션 서버에서 프로세싱 부하를 처리할 수 있습니다. GlassFish v2는 이러한 목표를 충족합니다. 사실, GlassFish v1의 상용 버전인 Sun Java System Application Server 9.0은 SPECjAppServer2004 벤치마크 결과를 공개한 첫 번째 오픈 소스 애플리케이션 서버였습니다.

SPECjAppServer2004(1)는 호환 애플리케이션 서버에서 구현된 모든 주요 Java EE 기술이 실행되는 종단간 애플리케이션으로, 복잡한 애플리케이션 및 엔터프라이즈 환경에서 일반적인 대용량 트랜잭션 처리를 반영하는 방식으로 수행됩니다.

GlassFish v2는 업계 최고의 상용 애플리케이션 서버를 능가하는 성능을 가진 가장 빠른 오픈 소스 애플리케이션 서버입니다.

GlassFish v2는 업계 최고의 상용 애플리케이션 서버를 능가하는 성능을 가진 가장 빠른 오픈 소스 애플리케이션 서버입니다. 2007년 7월에 GlassFish v2는 경쟁자들보다 20% 우수한 SPECjAppServer에서 단일 Sun Fire T2000 서버에 대한 최고 점수를 (2) 기록했습니다.

최근 GlassFish v2의 측정 결과는이 벤치마크에 공개된 점수 중 3위를 (3) 차지했습니다. GlassFish v2는 벤치마크 생산 경쟁 결과에 사용된 것보다 훨씬 적은 하드웨어, 공간 및 전력을 사용하지만 공개된 최고 점수와의 격차는 20% 내입니다.

애플리케이션 서버의 성능은 실행되는 애플리케이션의 조합에 따라 달라집니다. 따라서 사용자의 결과가 SPECjAppServer2004 벤치마크의 결과와 다를 수 있습니다.
 
GlassFish v2에서 크게 성능이 향상된 부문은 웹 서비스 기술입니다. GlassFish v2에서 웹 서비스 기술의 컬렉션을 Metro라고 합니다. Metro에는 Java EE와 Windows .NET 환경 간의 웹 서비스 상호 운용성을 지원하는 기술뿐만 아니라 XML 기반 웹 서비스(JAX-WS)용 Java API 2.1과 같은 핵심 웹 서비스 기술이 포함되어 있습니다. JAXB(Java Architecture for XML Binding)라는 자매 기술과 제휴한 JAX-WS 2.1을 정확한 웹 서비스 벤치마크 에서 테스트했으며, 그 결과 초당 처리 요청 수에 있어 뛰어난 성능을 나타냈습니다.

GlassFish v2 성능에 대한 자세한 내용은 SJSAS 9.1(Glassfish V2)에서 새 SPECjAppServer 2004 결과 게시 및 측정 가능한 SPECjAppServer 2004 제출을 참조하십시오.
 

중앙 집중화된 관리 및 모니터링

관리 콘솔에서는 엔터프라이즈에서 GlassFish 인스턴스 및 클러스터를 제어할 수 있는 중간 지점을 제공합니다.

공식적으로 썬 자바 시스템 애플리케이션 서버 관리 콘솔이라고 하는 단일 GlassFish v2 관리 콘솔 또는 GlassFish v2 명령행 인터페이스(CLI)에서 GlassFish v2 인스턴스 또는 클러스터를 관리하고 모니터할 수 있습니다. 이를 통해 엔터프라이즈에서 GlassFish 인스턴스를 제어할 수 있는 중간 지점을 제공할 뿐만 아니라 각 클러스터를 개별적으로 관리하거나 모니터할 수 있습니다.


사용이 용이한 관리 콘솔

관리 콘솔의 중요한 측면 중 하나는 쉽게 사용할 수 있다는 점입니다. 관리 콘솔에 로그인하면 사용의 용이성에 대해 직접 알 수 있습니다. 표시되는 첫 번째 페이지는 일반 운영 작업이 함께 표시되는 일반 작업 페이지입니다. 그림 2에 클러스터링에 사용할 수 있는 도메인에 대한 일반 작업 페이지가 표시됩니다.

사용자 삽입 이미지
그림 2. 클러스터링에 사용할 수 있는 도메인에 대한 일반 작업 페이지


새 클러스터 생성, 엔터프라이즈 애플리케이션 배포 및 데이터 모니터링과 같은 작업에 대한 버튼이 표시됩니다. 관리 작업을 수행할 수 있는 대체 경로를 제공하는 탐색 트리에 이러한 버튼이 추가됩니다. 운영 작업을 시작하려면 페이지에서 해당 버튼을 클릭하거나 트리에서 노드를 클릭합니다. 예를 들어, 클러스터링에 사용할 수 있는 도메인에 클러스터를 생성하려면 페이지에서 새 클러스터 만들기 버튼을 클릭하거나 탐색 트리에서 클러스터 노드를 클릭합니다.
또는 관리 작업에 대한 지원 문서를 일반 작업 페이지에서 직접 사용할 수 있습니다. 이러한 문서는 썬마이크로시스템즈 문서 페이지에서 사용할 수 있는 광범위한 참조 문서 라이브러리의 일부입니다.

일반 작업 페이지와 관리 콘솔의 여러 기타 요소는 동적입니다. 이러한 요소는 Project Woodstock에서 개발된 차세대 사용자 인터페이스 구성요소 집합의 일부로, Ajax 기능을 활용하여 빠르게 엔트리에 응답하고 디스플레이 간에 부드럽게 전환할 수 있습니다.


포괄적인 모니터링

관리 콘솔을 사용하면 광범위한 애플리케이션 서버 관련 데이터를 쉽게 모니터할 수도 있습니다. 일반 작업 페이지에서 모니터링 데이터 보기 버튼을 클릭하여 각 탭에 애플리케이션 서버의 다른 측면 또는 해당 운영 체제에 대한 데이터가 표시되는 탭 페이지를 표시합니다. 예를 들어, 그림 3에 표시된 대로 호출 플로우 탭에 호출 플로우 데이터가 표시됩니다.

사용자 삽입 이미지
그림 3. 호출 플로우 모니터링 


지정된 트랜잭션의 호출 플로우를 모니터링하여 그림 4에 표시된 대로 다양한 애플리케이션 서버 컨테이너를 통해 이동하는 트랜잭션을 추적할 수 있습니다.
사용자 삽입 이미지

그림 4. 트랜잭션에 대한 호출 플로우 세부사항

JMX(Java Management Extensions) 기술에 GlassFish v2를 사용할 수 있습니다. 이는 기업에서 이미 JMX를 사용하여 리소스를 모니터하고 관리하는 경우 접근 방법을 쉽게 확장할 수 있을 뿐만 아니라 GlassFish v2 리소스를 관리하고 모니터할 수 있습니다. 또한 GlassFish v2를 썬 관리 센터와 할시온의 썬 애플리케이션 서버용 PrimeAlert를 통해 구현된 모니터링 접근 방법 및 종단간 관리로 통합할 수 있습니다.


지능형 명령행 인터페이스(CLI)

CLI를 통해 GlassFish v2와 연관된 관리 작업을 전체적으로 수행할 수도 있습니다. 일반적으로 관리 콘솔 또는 CLI를 통해 거의 모든 GlassFish v2 관련 관리 작업을 수행할 수 있습니다. 예를 들어, CLI를 사용하여 GlassFish v2 도메인을 시작 및 중지하거나 클러스터를 생성하거나 호출 플로우 데이터 수집을 설정 또는 해제할 수 있습니다. 또한 CLI에는 명령을 입력할 때 오류가 발생하는 경우 대체 엔트리를 제안하는 "가장 일치하는 항목" 기능이 포함되어 있습니다. 예를 들어, 다음과 같이 asadmin 명령에 domain 키워드를 잘못 입력하는 경우가 있습니다.

asadmin start-domian

CLI에서 다음과 같이 대체 항목을 제안합니다.

Closest matching command(s):
asadmin start-domain


대규모 배포 관리

GlassFish v2에서 제공하는 관리 콘솔 및 CLI는 단일 인스턴스 또는 클러스터를 배포하고 구성할 수 있는 우수한 도구입니다. 대규모 기업 배포에 썬 N1 서비스 프로비저닝 시스템(N1SPS)을 사용할 수 있습니다. 썬 자바 시스템 애플리케이션 서버용 N1SPS 플러그인을 사용하면 기업 전체에 Sun Java System Application Server 9.1을 쉽게 설치, 구성 및 관리할 수 있습니다. 플러그인을 사용하여 기존 GlassFish v2 설치를 구성하고 관리할 수 있지만 이를 설치할 수는 없습니다. N1SPS에 대한 자세한 내용은 N1SPS을 통한 썬 자바 시스템 애플리케이션 서버 프로비저닝을 참조하십시오.

GlassFish v2의 관리 콘솔에 대한 자세한 내용은 GlassFish 프로젝트 - 관리 콘솔(GUI) 홈 페이지를 참조하십시오. GlassFish v2의 모니터링 기능에 대한 자세한 내용은 GlassFish 버전 2 모니터링 기능을 참조하십시오.


프로파일에서의 간단한 구성

최적화는 애플리케이션 서버의 중요한 요건이며, 각 서버에 각각 다른 유형의 최적화가 필요할 수 있습니다. 예를 들어, 애플리케이션을 빌드하고 테스트하는 개발자는 보안에 관계없이 애플리케이션 서버가 애플리케이션 요청에 응답하는 속도를 최적화하려고 할 수 있습니다. 그에 반해, 프로덕션 환경에서는 보안이 매우 중요하므로 애플리케이션을 배포하는 사람에게 보안은 가장 중요한 문제입니다.

애플리케이션 서버 도메인을 생성할 때 적절한 프로파일을 지정하여 간단하게 특정 유형의 용도를 위한 GlassFish v2를 구성하고 최적화할 수 있습니다.

구성 매개변수를 설정하여 특정 요구사항을 충족하도록 애플리케이션 서버를 수동으로 조정할 수 있지만, 이렇게 하면 시간과 노력이 많이 소비됩니다. 또는 특정 유형의 용도를 위해 미리 구성되어 있는 애플리케이션 서버의 특정 에디션을 사용할 수 있습니다. 사실, 이전 릴리스의 썬 자바 시스템 애플리케이션 서버를 여러 에디션에서 사용할 수 있었습니다. 예를 들어, 플랫폼 에디션은 개발자를 겨냥해 만들어졌으며 엔터프라이즈 에디션은 대기업을 겨냥한 제품입니다. 그러나 각각의 용도에 맞게 사용하기 위해 여러 에디션의 애플리케이션 서버를 설치하고 관리하는 것은 비현실적입니다.

보다 나은 솔루션은 단일 에디션의 애플리케이션 서버를 제공하면서 특정 사용 패턴을 위해 미리 설정된 구성을 제공하는 것입니다. 실제로 이러한 방법으로 GlassFish v2를 배포합니다. 이는 하나의 적절한 크기의 배포 번들에서 사용할 수 있으며, 다양한 사용 프로파일을 지원합니다. 각 프로파일은 특정 유형의 용도를 위해 구성 매개변수를 미리 설정합니다. GlassFish v2에서는 개발자, 클러스터 및 기업과 같은 세 가지 프로파일을 지원합니다.

개발자 프로파일은 개발 환경에서 사용하기 위해 GlassFish v2를 최적화합니다. 이는 구성 매개변수가 빠른 구동(fast startup)과 같은 기능은 지원하지만 로깅 또는 세션 복제와 같은 기능은 지원하지 않는다는 의미입니다. 클러스터 프로파일은 클러스터 생성 및 세션 복제를 가능하게 하는 구성 매개변수를 설정합니다. 엔터프라이즈 프로파일은 프로덕션 환경으로 GlassFish v2를 최적화합니다. 또한 로깅 및 기타 보안 관련 기능을 지원합니다.

표 1에 세 가지 프로파일의 일부 특성에 대해 요약되어 있습니다.

표 1: GlassFish v2 프로파일 특성 및 설정
특징
설명
개발자
프로파일 값
클러스터
프로파일 값
기업
프로파일 값
보안 저장
키 및 인증서와 같은 보안 아티팩트에 사용되는 저장 유형입니다. 두 가지 주요 유형은 썬에서 제공하는 키스토어 구현의 독점 유형인 JKS(Java Key Store)와 보안 설정 클라이언트 및 서버 애플리케이션의 크로스플랫폼 개발을 지원하기 위해 설계된 라이브러리 집합인 NSS(Network Security Services)입니다. 저장 유형은 형식 및 구성하는 데 사용할 수 있는 도구에 따라 다릅니다. NSS는 엔터프라이즈 솔루션에 일반적으로 사용되는 보안 유형입니다.
JKS
JKS
NSS
빠른 시작

애플리케이션 서버를 빠르게 시작할 수 있는 옵션입니다. 빠른 시작은 온 디맨드 서비스 프레임워크의 일부인 자바 NIO 기반 구현을 통해 수행됩니다.
true (사용)
false (사용안함)
false (사용안함)
JVM

자바 가상 머신 구성 매개변수입니다.
핫 스폿 VM 구성 매개변수
핫 스폿 VM 구성 매개변수
JDK에서 확인
세션 복제 메커니즘
세션 복제 메커니즘
없음
메모리 내 복제
HADB
 

도메인을 생성할 때 프로파일을 지정합니다. 예를 들어, 다음 명령은 도메인을 생성하고 해당 도메인에 대한 엔터프라이즈 프로파일을 지정합니다.

asadmin create-domain --user admin --adminport 4848 --profile enterprise

이상, 특정 유형의 용도(이 경우 프로덕션 환경)를 위해 GlassFish v2 애플리케이션 서버 인스턴스를 구성하고 최적화하는 데 필요한 모든 내용에 대해 설명했습니다.

프로파일에 대한 자세한 내용은 자료(One Pager): 애플리케이션 서버용 사용 프로파일 지원을 참조하십시오.


.NET과의 상호 운용성

상호 운용성은 엔터프라이즈에서 중요한 요건입니다. 일반적으로 운영 환경 전체에 엔터프라이즈의 애플리케이션 리소스가 배포되기 때문입니다. 예를 들어, Java EE와 같은 하나의 환경에 애플리케이션의 클라이언트 부분이 있을 수 있고, 웹 서비스에서 해당 클라이언트가 Microsoft의 .NET 프레임워크와 같은 다른 환경에 있어야 할 수 있습니다. GlassFish v2를 사용하면 웹 서비스 기반 애플리케이션에서 Java EE와 .NET 환경 간에 상호 운용할 수 있습니다.


Metro 및 웹 서비스 상호 운용성

GlassFish v2를 사용하면 웹 서비스 기반 애플리케이션에서 안전하고 안정적으로 메시징 및 트랜잭션을 지원하는 동시에 Java EE와 .NET 환경 간에 상호 운용할 수 있습니다.

GlassFish v2에는 웹 서비스에 대한 강력한 기술을 제공하는 Metro가 포함되어 있으며, 이는 Java EE에서 실행되는 웹 서비스에 대한 기술 스택을 능가합니다. 또한 Metro를 사용하면 웹 서비스에서 Microsoft .NET 프레임워크의 웹 서비스 스택인 WCF(Windows Communication Foundation)와 상호 운용할 수 있습니다. Metro와 WCF 모두 일반적으로 WS* 규격(모두 "WS"로 시작)이라는 웹 서비스 규격의 집합을 구현하며, 이를 통해 안전하고 안정적인 트랜잭션 지향 웹 서비스 상호 작용을 수행할 수 있습니다. Metro에서는 WS* 규격의 구현을 WSIT(Web Services Interoperability Technology)라고 합니다. 그림 5에 표시된 대로, WSIT를 사용하여 GlassFish v2의 웹 서비스 클라이언트가 .NET 3.0의 웹 서비스 끝점과 상호 작용하고 .NET 3.0 웹 서비스 클라이언트가 GlassFish v2의 웹 서비스 끝점과 상호 작용할 수 있습니다. GlassFish v2 클라이언트와 GlassFish v2 끝점 간의 통신도 지원됩니다.

사용자 삽입 이미지

그림 5. .NET과 Metro의 상호 운용성

Metro와 WCF가 안전하고 안정적인 트랜잭션 지향 웹 서비스 상호 작용을 지원하므로 웹 서비스 클라이언트가 커밋하거나 롤백할 수 있는 트랜잭션 또는 조합으로 처리되거나 안전하게 수신되는 웹 서비스와 교환하도록 요청할 수 있습니다.


웹 서비스 상호 운용성 구성을 위한 간단한 인터페이스

GlassFish v2의 웹 서비스 끝점에 대한 상호 운용성 특성은 WSIT 구성 파일이라는 XML 파일에서 지정됩니다. 웹 서비스 개발자가 파일의 필수 XML을 코드화할 수 있습니다. 그러나 XML이 장황해지고 WSIT 구성 파일의 컨텐츠가 광범위해질 수 있습니다. 상호 운용 가능한 웹 서비스를 개발하는 보다 간단한 방법은 NetBeans IDE 버전 5.5.1 또는 6.0을 사용하는 것입니다. WSIT에 NetBeans IDE 5.5.1을 사용하려면 WSIT 플러그인 모듈을 설치합니다. NetBeans IDE 6.0에는 플러그인 모듈이 이미 패키징되어 있습니다. 사용 가능한 경우, IDE에 안전한 메시징, 안정적인 메시징 및 트랜잭션 지원과 같은 WSIT 특성과 함께 웹 서비스를 구성할 수 있는 간단한 확인란 인터페이스가 표시됩니다. 그림 6에 NetBeans IDE 6.0에서의 이 인터페이스가 표시됩니다.

사용자 삽입 이미지

그림 6. 상호 운용 가능한 웹 서비스의 안전한 메시지 전달 지정

그림 6에 안전한 메시지 전달 및 정확한 순서로 메시지 전달 확인란이 선택되어 있습니다. 이러한 확인란을 선택하면 웹 서비스에서 안전하게 메시지를 전달할 수 있으며, 클라이언트가 보낸 메시지를 보낸 순서대로 웹 서비스 끝점에 전달할 수 있습니다.
 
NetBeans IDE를 사용하여 GlassFish v2에 웹 서비스를 배포할 수 있습니다. 진행 중에 IDE에서 구성 선택 항목에 적절한 모든 XML 코드와 구성 파일을 포함하여 적절한 아티팩트를 생성합니다.

Java EE 플랫폼과 .NET 프레임워크 간의 웹 서비스 상호 운용성을 구현하는 데 소요되는 시간, 비용 및 난이도를 고려하십시오. 이를 수행하려면 일반적으로 고가의 메시징 인프라뿐만 아니라 많은 사용자 정의 코드가 필요합니다. Metro에서는 추가 비용 없이 이러한 지원을 받을 수 있으며 GlassFish v2에 이미 내장되어 있습니다.

Metro에서 .NET과의 웹 서비스 상호 운용성 지원에 대한 자세한 내용은 Project Tango: 개요(PDF)Metro Project를 참조하십시오.


JBI 준비

GlassFish v2에서는 JBI(Java Business Integration)가 구현된 Open ESB에 대한 지원이 기본적으로 제공됩니다. JSR 208에 지정된 대로 JBI는 서비스 지향 아키텍처(SOA)에 따라 비즈니스 시스템을 구성할 수 있는 자바 표준입니다. SOA 접근 방식에서는 별도의 서비스에서 애플리케이션이 조합될 수 있으며, 각 서비스는 하나 이상의 비즈니스 관련 프로세스를 수행합니다. SOA에서는 하나의 애플리케이션에 사용된 데이터 및 서비스를 다른 애플리케이션에서 공유하고 재사용할 수 있기 때문에 엔터프라이즈에서 이러한 복합 애플리케이션을 매우 빠르게 빌드할 수 있습니다. 새 애플리케이션을 만들기 위해 서비스와 데이터를 통합하는 것과 같은 접근 방법을 통합 애플리케이션 시스템이라고 하는 경우도 있습니다. 이전에는 통합 애플리케이션 시스템을 구현하려면 많은 사용자 정의 코드를 사용하거나 독점적인 시스템에 투자해야 했습니다. JBI은 통합 애플리케이션 시스템을 구성하는 방법을 표준화고 특수 코드화 또는 독점 솔루션을 수행할 필요를 없애줍니다.

JBI는 플러그인 구성요소를 정의하며, 각 플러그인 구성요소는 특정 유형의 서비스를 실행하거나, 서비스가 실행되는 순서를 조정하거나, 데이터 형식 변환과 같은 기타 비즈니스 프로세스 관련 작업을 수행할 수 있는 기술을 제공합니다. 예를 들어, 하나의 JBI 구성요소가 Java EE 엔터프라이즈 아카이브(EAR) 파일로 배포된 서비스를 실행하는 EJB 서비스 엔진일 수 있습니다. 다른 구성요소는 SQL 쿼리를 실행하는 SQL 서비스 엔진일 수 있습니다. 세 번째 구성요소는 비즈니스 프로세스를 조정하는 BPEL 문을 실행하는 비즈니스 프로세스 실행 언어(BPEL) 서비스 엔진일 수 있습니다. 일부 플러그인 구성요소는 서비스를 제공하거나 사용하기 위해 다른 환경과 통신하는 구성요소를 바인딩합니다. 예를 들어, 하나의 바인딩 구성요소에서 SOAP over HTTP를 사용하여 신용 조사를 수행하는 원격 서비스를 실행할 수 있으며, 다른 바인딩 구성요소에서 SMTP를 사용하여 신용 조사에 대한 전자 메일 알림을 보낼 수 있습니다.

즉, 해당 복합 애플리케이션에 통합할 수 있는 광범위한 서비스 유형의 선택 범위를 엔터프라이즈에 제공하고 JBI 기반 시스템을 구성하는 구성요소에 많은 유연성을 제공하는 것입니다. JBI를 구현할 때, Open ESB를 사용하여 서비스를 느슨하게 결합된 복합 애플리케이션에 통합할 수 있습니다.

GlassFish v2에서는 Open ESB의 런타임 환경을 제공합니다. 이는 특정 유형의 서비스를 실행하는 다양한 서비스 엔진 및 서비스를 제공하거나 사용하기 위해 다른 환경과 통신하는 바인딩 구성요소를 제공합니다.


Open ESB 런타임 환경

GlassFish v2에서는 Open ESB의 런타임 환경을 제공합니다. 이는 다양한 서비스 엔진과 바인딩 구성요소를 제공합니다. Open ESB는 JBI를 기반으로 하기 때문에 GlassFish v2에서 제공하는 환경에 JBI 호환 서비스 엔진 및 바인딩 구성요소를 추가할 수 있습니다.

그림 7에 표시된 대로 GlassFish v2 애플리케이션 서버에 배포된 웹 서비스는 Sun Java EE 엔진이라고 하는 구성요소와 JAX-WS를 통해 JBI 런타임 환경과 통신합니다. 일반적으로 기타 JBI 구성요소의 경우 Sun Java EE 엔진에서 표준화된 메시지 라우터(NMR)라고 하는 경량 메시징 인프라를 사용하여 다른 서비스 엔진 및 바인딩 구성요소와 통신합니다. 그림 7에서 SE는 서비스 엔진을 의미하고 BC는 바인딩 구성요소를 의미합니다.

사용자 삽입 이미지

그림 7. GlassFish v2에서 JBI 런타임 환경


Open ESB 구성요소 관리

관리 콘솔 또는 CLI를 사용하여 GlassFish v2에서 기타 Open ESB 구성요소뿐만 아니라 Sun Java EE 엔진을 관리할 수 있습니다. 예를 들어, 일반 작업 페이지에서 JBI(Java Business Integration) 서비스 어셈블리 배포 버튼을 클릭하기만 하면 관리 콘솔을 사용하여 복합 애플리케이션의 일부 또는 전체가 포함되어 있는 JBI 서비스 어셈블리를 배포할 수 있습니다. 관리 콘솔 또는 CLI에서 Sun Java EE 엔진을 시작, 중지, 종료 또는 제거할 수 있습니다. 예를 들어, CLI에 다음 명령을 입력하여 Sun Java EE 엔진을 시작할 수 있습니다.

asadmin start-jbi-component sun-javaee-engine


복합 애플리케이션 구축 도구


개발 측면에서 NetBeans IDE 6.0은 Open ESB 환경에서 실행되는 복합 애플리케이션을 구축할 수 있는 다양한 도구를 제공합니다. 이러한 도구에는 BPEL 설계 도구, 그래픽 WSDL(Web Services Description Language) 편집기, CASA(Composite Application Service Assembly) 편집기 및 스키마와 XSLT 변환을 관리할 수 있는 도구가 포함되어 있습니다.

NetBeans IDE 6.0을 사용하여 복합 애플리케이션을 구축합니다. 그런 다음 GlassFish v2에서 해당 애플리케이션을 배포, 실행 및 관리합니다.

GlassFish v2에서의 Open ESB 지원에 대한 자세한 내용은 Sun Java EE 엔진: Java EE 웹 서비스와 JBI 구성요소 브리징 Open ESB 프로젝트를 참조하십시오.


뛰어난 메시지 처리 기능

효율적인 메시징 서버는 효율적인 엔터프라이즈를 구성하기 위해 비즈니스 소프트웨어를 연결하는 데 있어 매우 중요합니다. GlassFish v2에서는 메시지 지향 시스템 통합을 위한 완전한 JMS(Java Message Service) 구현인 Open Message Queue(Open MQ)를 제공합니다. JMS는 Java EE 기반 애플리케이션 구성요소에서 메시지 작성, 전송, 수신 및 읽기를 수행할 수 있는 메시징 표준입니다. JMS를 구현할 때 Open MQ에서 완전한 메시징 서버를 제공하며, 이는 오픈 소스 버전의 썬 자바 시스템 메시지 대기열 제품 입니다. Open MQ에는 자체 관리 도구 집합이 포함되어 있어 자체적으로 실행하거나 GlassFish v2에 완전히 통합할 수 있습니다.

GlassFish v2에서는 메시지 지향 시스템 통합을 위한 완전한 JMS(Java Message Service) 구현인 Open MQ를 제공합니다.

GlassFish v2와 함께 사용하면 클라이언트에 JMS 기반 메시지 전달 서비스를 제공하는 Open MQ 구성요소인 메시지 브로커가 GlassFish v2와 동일한 프로세스에 있을 수 있습니다. 즉, 둘 모두 동일한 자바 가상 머신에서 실행됩니다. 이러한 애플리케이션 서버에 대한 Open MQ의 관계를 EMBEDDED 모드라고 합니다. 또한 LOCAL 모드에서는 메시지 브로커가 GlassFish v2와 동일한 수명 주기를 공유할 수 있으며, REMOTE 모드에서는 별도로 실행될 수 있습니다.
 

효율적이고 안전한 메시지 전달

Open MQ를 사용하면 안전한 메시지 전달을 보증하면서 기존 및 새 애플리케이션을 연결할 수 있습니다. 메시지 전달이 보장되며 보낸 순서대로 메시지가 전달됩니다. Open MQ에서는 비동기 메시징을 지원합니다. 즉, 애플리케이션에서 메시지를 전송한 후 메시지를 수신하는 동안 기다리지 않고 계속해서 처리할 수 있습니다. 메시지는 게시-구독(Publish-Subscribe) 방식으로 전송됩니다. 이러한 접근 방식에서는 그림 8에 표시된 대로 게시자(publisher)라고 하는 메시지를 발신인이 제목(topic)이라고 하는 중간 대상에 메시지를 전송합니다. 해당 제목을 구독하는 구독자(subscriber)라고 하는 여러 애플리케이션에서 제목에서 메시지를 제거하여 메시지를 사용합니다. 게시자는 구독자와 완전히 독립적입니다. 대신 메시지를 지점 간 즉, 특정 수신자에게 전송할 수 있습니다. 이러한 경우 메시지가 대기열에 전송되고 수신자는 대기열에서 메시지를 제거하여 메시지를 사용합니다.

사용자 삽입 이미지

그림 8. Open MQ에서의 게시-구독 메커니즘

처리 기능 외에도 Open MQ는 쉽게 설치하고 관리할 수 있습니다.openInstaller를 기반으로 하는 GUI 기반 설치 프로그램을 사용하여 이를 설치할 수 있습니다. 또는 아카이브 배포의 압축을 푸는 파일 기반 설치를 수행한 다음 설치 스크립트를 실행하여 사용할 Open MQ를 구성할 수 있습니다. Open MQ에서는 메시지 브로커를 시작하는 것과 같은 Open MQ 관련 작업을 수행할 수 있는 자체 관리 콘솔 및 CLI를 제공합니다. 또한 Open MQ에서는 JAAS(Java Authentication and Authorization Service)를 통해JMX(Java Management Extensions) 기반 모니터링, 클러스터링 및 인증을 지원합니다.


고성능 및 가용성

Open MQ는 독립 실행형 애플리케이션으로 테스트되거나 뛰어난 성능이 포함된 GlassFish와 통합되었습니다. 또한 Open MQ에서는 데이터와 메시지 브로커 모두에 고가용성을 지원합니다. 고가용성 JDBC 공급자와 함께 Open MQ를 사용하면 고가용성 기능이 실행됩니다. Open MQ는 mySQL, Oracle RAC(Real Application Clusters) 및 Sun Java System Application Server 9.1의 HADB 기능으로 테스트되었습니다.

Open MQ에 대한 자세한 내용은 Open Message Queue 프로젝트를 참조하십시오.


매력적인 가격 지원 정책

Sun Java System Application Server 9.1에는 다양한 구독 옵션 집합을 사용할 수 있습니다. 완전한 보증, 온 디맨드 소프트웨어 업데이트 및 업그레이드, 썬 개발 전문가 지원 등이 포함된 서비스를 지원받을 수 있습니다. 소켓 4개에 대한 구독 가격은 연 4500 달러부터 저렴하게 시작합니다. 자세한 내용은 자바 시스템 애플리케이션 서버 구독을 참조하십시오.


요약

고가용성, 확장성, 엔터프라이즈급 성능, 중앙 집중화된 관리, 간단한 구성 및 효율적이고 안전한 메시지 전달과 같은 특성을 가진 GlassFish v2는 프로덕션 환경의 요구를 처리할 수 있는 견고성과 비즈니스 위험 애플리케이션을 처리할 수 있는 안전성이 포함된 엔터프라이즈 품질의 애플리케이션 서버입니다. 웹 서비스 상호 운용성 및 JBI 호환 런타임에 대한 지원을 추가할 경우 엔터프라이즈에 애플리케이션 처리 요구에 맞는 많은 유연성을 제공하는 애플리케이션 서버의 역할을 수행합니다. 오픈 소스로서, GlassFish v2는 GlassFish v2 또는 GlassFish v2의 썬 지원 상용 배포판인 Sun Java System Application Server 9.1인지에 관계없이 비즈니스에 개방되어 있습니다.

(1) SPEC 및 벤치마크 이름인 SPECjAppServer 2004는 Standard Performance Evaluation Corporation의 등록 상표입니다. Sun Java System Application Server 9.0은 521.42 JOPS@Standard(1 Sun Fire T2000 [코어 8개, 칩 1개] 애플리케이션 서버 및 1 Sun Fire T2000 [코어 6개, 칩 1개] 데이터베이스 서버)를 확보했습니다. 최신 SPECjAppServer 2004 벤치마크 결과는 SPEC 웹 사이트를 방문하십시오.

(2) 2007년 7월 10일을 기준으로 단일 Sun Fire T2000을 애플리케이션 서버로 사용하는 모든 SPECjAppServer 2004 점수를 기반으로 비교합니다. 참조 점수: Sun Java Application Server 9.1은 883.66 JOPS@Standard(1 Sun Fire T2000 [칩 1개, 코어 8개] 애플리케이션 서버 및 1 Sun Fire T2000 [칩 1개, 코어 6개] 데이터베이스)을 확보하고, BEA Weblogic 9.1은 801.70 JOPS@Standard(1 Sun Fire T2000 [칩 1개, 코어 8개] 애플리케이션 서버 및 1 Sun Fire T2000 [칩 1개, 코어 6개] 데이터베이스)을 확보했으며, Sun Java Application Server 9.0은 521.42 JOPS@Standard(1 Sun Fire T2000 [칩 1개, 코어 8개] 애플리케이션 서버 및 1 Sun Fire T2000 [칩 1개, 코어 6개] 데이터베이스)을 확보하고, IBM WebSphere는 616.22 JOPS@Standard(1 Sun Fire T2000 [칩 1개, 코어 8개] 애플리케이션 서버 및 1 Sun Fire X4200 [칩 2개, 코어 4개] 데이터베이스 서버)을 확보했으며, BEA Weblogic 9.0은 615.64 JOPS@Standard(1 Sun Fire T2000 [칩 1개, 코어 8개] 애플리케이션 서버 및 1 Sun Fire V490 [칩 4개, 코어 8개] 데이터베이스)을 확보했습니다.

(3) 2007년 11월 23일을 기준으로 공개된 모든 SPECjAppServer 2004 점수를 기반으로 비교합니다. 참조 점수: Sun Java Application Server 9.1은 8439.36 JOPS@Standard(6 Sun SPARC Enterprise T2150 애플리케이션 서버[칩 6개, 코어 48개] 및 1 Sun Fire E6900 데이터베이스[칩 24개, 코어 48개])를 확보하고, Oracle Application Server 10.1은 10519.43 JOPS@Standard(12 HP BL860c 애플리케이션 서버 [칩 24개, 코어 48개] 및 2 HP Superdome 데이터베이스 서버 [칩 40개, 코어 80개])를 확보했으며, Oracle Application Server 10.1은 9459.19 JOPS@Standard(11 HP BL860c 애플리케이션 서버 [칩 22개, 코어 44개] 및 2 HP Superdome 데이터베이스 서버 [칩 40개, 코어 80개])를 확보했습니다.


자세한 정보


GlassFish 커뮤니티 - Java EE 애플리케이션 서버 전달 (PDF)
GlassFish 커뮤니티
Sun Java System Application Server 9.1
GlassFish v2 - 엔터프라이즈 기능 및 오픈 소스
아쿠아리움(The Aquarium)
기사: 실행 중인 썬 기술


저자 정보

Ed Ortjava.sun.com 소속이며 관계형 데이터베이스 기술, 프로그래밍 언어, 웹 서비스 및 Ajax에 대해 폭넓게 저술했습니다.

이 글의 영문 원본은
http://java.sun.com/developer/technicalArticles/glassfish/GFv2OpenforBusiness/index.html

에서 보실 수 있습니다.

"Java EE" 카테고리의 다른 글

Posted by 1010
98..Etc/70.JEUS2008. 10. 30. 10:23
반응형

제우스 설치

  1. JEUS_HOME, JAVA_HOME 설정
  2. CLASS_PATH 설정된거 삭제

제우스 실행

  1. 제우스 실행(2step 부팅)

    1. cmd에서 jeus 입력
    2. jeus webadmin에서 노드명에서 오른쪽 클릭후  노드제어에서 boot 함.


  2. 제우스 shutdown

    1. jeus webadmin에서 down 후 종료시켜줌.


  3. 제우스 1step 부팅

    1. %JEUS_HOME%/bin/jeus.properties.cmd  에서 다음을 설정함.(띄어쓰기 하지 말것) - 74라인 근처
  1. rem Set up administrator name
  2. SET USERNAME=
  3. rem Set up administrator password
  4. SET PASSWORD=

 2. cmd 에서 jeus 실행. cmd 화면에서 one-step 성공했다는 메시지를 볼 수 있음.


Jeus admin 페이지 접속

 http://localhost:9744/webadmin/ : jeus webadmin




수동으로 Context 설정

  1. %JEUS_HOME%\webhome\app_home\ 밑에 context로 사용할 폴더 작성 (여기서 webtest로 작성함)
  2. 사용할 context 폴더 밑에 WEB-INF 폴더 생성 WEB-INF밑에 web.xml 파일을 생성

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee">
    3. <display-name> Welcome </display-name>

    4. <welcome-file-list>

    5. <welcome-file>index.html</welcome-file>

    6. </welcome-file-list>

    7. <session-config>

    8. <session-timeout>30</session-timeout>

    9. </session-config>

    10. </web-app>
  3.  jeus-web-dd_컨테스트명.xml 설정 (여기선 jeus-web-dd_webtest.xml) : 패스 설정을 위한 부분

    1. <?xml version="1.0" encoding="UTF-8"?>
      <jeus-web-dd xmlns="http://www.tmaxsoft.com/xml/ns/jeus">
              <context-path>/webtest</context-path>
              <auto-reload>
                  <enable-reload>true</enable-reload>
                  <check-on-demand>true</check-on-demand>
              </auto-reload>
      </jeus-web-dd>
  4.  3번에 설정한 파일을 WEBMain.xml위치와 같은 위치에 넣어줌. (WEBMain.xml위치 : %JEUS_HOME%/config/PC명/PC명_servlet_engine1)
  5. JEUSMain.xml 수정(JEUSMain.xml 파일 위치 : %JEUS_HOME%/config/컴퓨터이름 에 위치) : application 등록의 의미

    1. <application>
              <name>webtest</name>
              <path>/webtest</path>
              <deployment-target>
               <target>
                      <engine-container-name>passion05_container1</engine-container-name>
                      <web-context-group>
                          <name>MyGroup</name>
                      </web-context-group>
                  </target>
              </deployment-target>
              <deployment-type>EAR</deployment-type>
          </application>

  6. 서버 다운후 재 부트
  7. 부트 콘솔에서 해당 context 이름이 올라가는지 확인.




    Tomcat에서의 설정과 동일.

    1. //web.xml
    2. <servlet>
         <servlet-name>hello</servlet-name>
         <servlet-class>examples.HelloWorldServlet</servlet-class>
      </servlet>
      <servlet-mapping>
         <servlet-name>hello</servlet-name>
         <url-pattern>/hello</url-pattern>
      </servlet-mapping>
Posted by 1010
98..Etc/Etc...2008. 10. 28. 09:20
반응형
원도우 탐색기 시작시 버그

regsvr32 /u shmedia.dll
Posted by 1010
98..Etc/Tomcat2008. 10. 27. 15:01
반응형
톰캣에서 java.lang.IllegalStateException: Post too large 가 발생하는 경우


http://confluence.atlassian.com/display/DOC/Max+size+of+HTTP+POST+request+and+Confluence+page+size

아래는 $TOMCAT_HOME/conf/server.xml에 설정을 해야 하는 옵션이다.
maxPostSize에 필요한 용량제한을 셋팅하면 된다.

<Connector port="8102" minProcessors="1" maxProcessors="5"
            enableLookups="false" redirectPort="8443" acceptCount="100"
            debug="0" connectionTimeout="120000" useBodyEncodingForURI="true"
            maxPostSize="3145728"
            protocol="AJP/1.3" />
Posted by 1010
98..Etc/Etc...2008. 10. 23. 14:04
반응형
=IF(OR(MID(A1,7,1)="1",MID(A1,7,1)="3"),"남자",IF(OR(MID(A1,7,1)="2",MID(A1,7,1)="4"),"여자","모름"))
Posted by 1010
98..Etc/Etc...2008. 10. 20. 23:49
반응형

FTP 서버를 방화벽 내부에서 구동하려면 FTP connection type에 대한 이해가 필요하다.
이러한 원리를 이해하려면 TCP/IP, Firewall에 대한 사전 지식이 필요하다.

FTP connection의 두 type
1. active connection
2. passive connection
    - active mode
    - passive mode

1. active connection
control connection으로 command(명령) 전송시에 사용된다.
FTP client software에 의해 초기화 된다. 즉, client:X에서 server:ftp port 21번으로 접속이 이루어진다.
클라이언트:X -> 서버:ftp port 21번
여기서 X는 1023보다 큰 비사용 중인 포트를 말한다.

2. passive connection
data connection으로 data(파일) 전송시 사용된다.
active mode와 passive mode가 있으며, 일반적인 FTP server는 active mode로 data를 전송한다.

active mode 연결 진행 절차:
1) FTP client는 data 전송시 FTP server에게 passive mode를 사용하는지 여부를 요청하게 된다.
2) active mode를 사용한다면 FTP client는 server가 data 전송을 위해 접속하게 될 자신의 client port(Y라고 가정)를 서버에게 알려준다.
3) FTP 서버는 ftp-data port 20번을 통해 client가 알려준 포트로 접속 시도를 요청한다(syn packet 전송).  
4) 해당 client는 요청에 대한 수신 확인 및 허락을 전송한다(awk + syn packet 전송). 
5) server는 client가 보낸 packet에 대한 수신 확인을 전송한다(awk packet).  
6) 이로써 connection은 형성되고 data를 전송하게 된다.
즉, server:ftp-data port 20번 -> client:Y 형태로 연결된다.

이러한 이유로 방화벽 내부에 FTP server를 운영할 경우 command는 전달되나 실제 data가 전송되지 않는 문제가 발생한다.
또한 firewall 운영시 내부 네트웍에서 외부로 나가는 1023 이상의 포트를 모두 열여 주어야 하는 문제도 발생된다.

passive mode 연결 진행 절차:
1) FTP client는 data 전송시 FTP server에게 passive mode를 사용하는지 여부를 요청하게 된다.
2) passive mode를 사용한다면 FTP server는 client가 data 전송을 위해 Server에 접속할 1023 이상의 port를 알려준다.
3) 이때 사용할 포트를 N 이라고 정하며, N 값은 FTP server 마다 설정이 다르다. 즉, passive mode에서는 ftp-data port 20번를 사용하지 않는다.
4) FTP client는 Server가 알려준 port N으로 접속을 시도하기 위해 syn packet을 자신의 Z(1023 이상의 비사용 중인) port를 열어 전송한다.
5) FTP server는 awk + syn packet을 통해 수신 확인 및 연결을 허락하게 된다.
6) FTP client는 awk packet을 전송하여 수신 확인을 하고 connection을 맺은 후 data를 전송하게 된다.
즉, client:Z -> server:N 형태로 연결된다.

이러한 경우라면 방화벽에서 FTP server가 passive mode로 사용하게 될 port를 열어 정상적으로 data 전송이 가능하다.

3. FTP server를 passive mode로 운영하기 위한 설정
Linux에서 운영하는 대표적은 FTP server인 wu-ftpd와 proftpd에 대해서 언급한다.
설정 방법은 해당 파일에 passive port로 사용할 port 영역을 명시하게 된다. 2000번 이상의 port를 열 것을 권장하며 일반적으로10000번 이하의 포트를 사용한다.

wu-ftpd의 경우:
wu-ftpd에서 제공하는 /etc/ftpaccess 파일에 다음 내용을 추가한다.
passive ports 0.0.0.0/0 15000 17000
즉, wu-ftpd를 passive FTP로 운영하기 위해 15000~17000 포트를 사용하는 것으로 설정한 것이다.
standalone type server라면 반드시 restart한다.

proftpd의 경우:
proftpd에서 제공하는 /etc/proftpd/conf/proftpd.conf 파일에 다음 내용을 추가한다.
PassivePorts 60000 62000
즉, proftpd를 15000~17000 포트를 이용하여 passive FTP로 운영할 것을 설정한 것이다.
standalone type server라면 반드시 restart한다.

passive connect시 client에서 주의할 사항
일반적으로 server를 passive mode로 운영할 경우 client 또한 passive mode로 사용해야 한다. Netscape의 경우 특별한 문제가 발생하지 않으며, ncftp의 경우 접속 후 set passive on 명령어를 수행하면 된다. gftp를 사용한다면 FTP -> Options -> General -> "Passive file transfer" 를 설정기 바란다.



출처 : http://chunter.tistory.com/223

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
98..Etc/Etc...2008. 9. 17. 17:15
반응형
 

이지 웹에디터(DHTML wysiwyg 웹에디터)

소개

개요

  • 게시판, 사용자 입력폼등에 삽입하여 손쉬운 웹문서편집을 도움
  • 타 위지윅 에디터에 비해 가볍고, 간단함 (easy)

특징

  • 원하는 명령만 손쉽게 삽입 가능
  • 버튼이미지 변경, 변수 컬러값 변경등 으로 손쉬운 스킨 변경
  • 동일한 하나의 문서에 여러개의 웹에디터 삽입 가능
  • 자바스크립트로만 개발되어 가볍고 커스트마이징 용이
  • 사용자추가기능 손쉬운 개발 가능 (플러그인 형태)
  • 테스트 브라우저 : IE6, IE7, FF1.5.X
  • 모든 서버사이드스크립트(PHP,ASP,JSP)에 적용 가능

라이센스 관련

  • 누구나,어디서나 무료로 사용 가능
  • 배포,수정 재배포,판매 가능
  • 단, '물음표아이콘(about.gif)' 기능 수정,삭제 불가능

설치 방법

준비작업

기본 파일설명

  • [img] - 이미지파일 디렉토리
  • ex.html - '이지웹에디터' 삽입방법 테스트 파일 (동작과 상관없음)
  • easyEditor.js - 자바스크립트 모듈 파일 (환경변수 참고)
  • table.html - 테이블삽입 폼 HTML 파일

예제 소스

  • 예제 실행
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    <html> <head> <script type="text/javascript">if (!window.T) { window.T = {} } window.T.config = {"TOP_SSL_URL":"https://www.tistory.com","PREVIEW":false,"ROLE":"guest","PREV_PAGE":"","NEXT_PAGE":"","BLOG":{"id":218144,"name":"webprogrammer","title":"개발자(開發者) a developer","isDormancy":false,"nickName":"1010","status":"open","profileStatus":"normal"},"NEED_COMMENT_LOGIN":false,"COMMENT_LOGIN_CONFIRM_MESSAGE":"","LOGIN_URL":"https://www.tistory.com/auth/login/?redirectUrl=http://webprogrammer.tistory.com/category/98..Etc","DEFAULT_URL":"https://webprogrammer.tistory.com","USER":{"name":null,"homepage":null,"id":0,"profileImage":null},"SUBSCRIPTION":{"status":"none","isConnected":false,"isPending":false,"isWait":false,"isProcessing":false,"isNone":true},"IS_LOGIN":false,"HAS_BLOG":false,"IS_SUPPORT":false,"TOP_URL":"http://www.tistory.com","JOIN_URL":"https://www.tistory.com/member/join","ROLE_GROUP":"visitor"}; window.T.entryInfo = null; window.appInfo = {"domain":"tistory.com","topUrl":"https://www.tistory.com","loginUrl":"https://www.tistory.com/auth/login","logoutUrl":"https://www.tistory.com/auth/logout"}; window.initData = {}; window.TistoryBlog = { basePath: "", url: "https://webprogrammer.tistory.com", tistoryUrl: "https://webprogrammer.tistory.com", manageUrl: "https://webprogrammer.tistory.com/manage", token: "244GuRv6lPCa6WiYTnkc1tDAgfK5KBH9OfE0lGF2IE8PzPayKkvBc4tEayPec4X8" }; var servicePath = ""; var blogURL = "";</script> <script> function chkForm(f) { var content = ed.getHtml(); //대체한 textarea에 작성한HTML값 전달 if(content=="") { alert("내용을 적어주세요!"); ed.focus(); return false; } alert(content); //값확인(디버깅) return true; } </script> <link rel="stylesheet" type="text/css" href="https://tistory1.daumcdn.net/tistory_admin/userblog/tistory-e11b6cd63d67e948b9dd33a1d0a60492dd6a0cbf/static/style/revenue.css"/> <link rel="canonical" href="https://webprogrammer.tistory.com"/> <!-- BEGIN STRUCTURED_DATA --> <script type="application/ld+json"> {"@context":"http://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":0,"item":{"@id":"https://webprogrammer.tistory.com/654","name":"#.net 기본개념정리파일."}},{"@type":"ListItem","position":1,"item":{"@id":"https://webprogrammer.tistory.com/629","name":"JSP에서 원하는 Appender 선택하여 쓰기 (처음시작하기...필독)"}},{"@type":"ListItem","position":2,"item":{"@id":"https://webprogrammer.tistory.com/628","name":"Log4j Summary"}},{"@type":"ListItem","position":3,"item":{"@id":"https://webprogrammer.tistory.com/614","name":"Vmware를 이용한 Ubuntu 설치 방법"}},{"@type":"ListItem","position":4,"item":{"@id":"https://webprogrammer.tistory.com/574","name":"학습 곡선 일지 4편: 웹 서비스 액세스"}},{"@type":"ListItem","position":5,"item":{"@id":"https://webprogrammer.tistory.com/573","name":"학습 곡선 일지 3편: JavaFX 스크립트 함수"}},{"@type":"ListItem","position":6,"item":{"@id":"https://webprogrammer.tistory.com/572","name":"학습 곡선 일지 2편: 선언적 사용자 인터페이스"}},{"@type":"ListItem","position":7,"item":{"@id":"https://webprogrammer.tistory.com/571","name":"학습 곡선 일지 1편: JavaFX 스크립트 탐구"}},{"@type":"ListItem","position":8,"item":{"@id":"https://webprogrammer.tistory.com/570","name":"TableNode: JavaFX에서 스크롤 가능한 사용자 지정 테이블 만들기"}},{"@type":"ListItem","position":9,"item":{"@id":"https://webprogrammer.tistory.com/569","name":"자신만의 JavaFX &quot;사용자 지정 노드&quot; 만들기: 그래픽 메뉴의 예"}},{"@type":"ListItem","position":10,"item":{"@id":"https://webprogrammer.tistory.com/559","name":"JNDI의 소개"}},{"@type":"ListItem","position":11,"item":{"@id":"https://webprogrammer.tistory.com/558","name":"커스텀 태그 파일"}},{"@type":"ListItem","position":12,"item":{"@id":"https://webprogrammer.tistory.com/555","name":"J2EE 커넥터 아키텍처 1.5"}},{"@type":"ListItem","position":13,"item":{"@id":"https://webprogrammer.tistory.com/552","name":"GlassFish v2에서 SSL 사용하기"}},{"@type":"ListItem","position":14,"item":{"@id":"https://webprogrammer.tistory.com/551","name":"GlassFish v2: Open for Business"}},{"@type":"ListItem","position":15,"item":{"@id":"https://webprogrammer.tistory.com/501","name":"jeus 설정 및"}},{"@type":"ListItem","position":16,"item":{"@id":"https://webprogrammer.tistory.com/495","name":"원도우 탐색기 오류시 대체방법"}},{"@type":"ListItem","position":17,"item":{"@id":"https://webprogrammer.tistory.com/491","name":"톰캣에서 java.lang.IllegalStateException: Post too large 가 발생하는 경우"}},{"@type":"ListItem","position":18,"item":{"@id":"https://webprogrammer.tistory.com/467","name":"엑셀 주민등록번호 남여 구분"}},{"@type":"ListItem","position":19,"item":{"@id":"https://webprogrammer.tistory.com/445","name":"FTP 서버의 passive mode에 대해"}},{"@type":"ListItem","position":20,"item":{"@id":"https://webprogrammer.tistory.com/416","name":"JavaFX DEMO Applets"}},{"@type":"ListItem","position":21,"item":{"@id":"https://webprogrammer.tistory.com/415","name":"웹표준 가이드 (Asp기초에서 고급까지)"}},{"@type":"ListItem","position":22,"item":{"@id":"https://webprogrammer.tistory.com/414","name":"JavaFX DEMO"}},{"@type":"ListItem","position":23,"item":{"@id":"https://webprogrammer.tistory.com/413","name":"JavaFX Programming Language Reference"}},{"@type":"ListItem","position":24,"item":{"@id":"https://webprogrammer.tistory.com/412","name":"Apache 2.x + Tomcat 4.x + Load Balancing (or Private JVMs)"}},{"@type":"ListItem","position":25,"item":{"@id":"https://webprogrammer.tistory.com/389","name":"이지 웹에디터"}},{"@type":"ListItem","position":26,"item":{"@id":"https://webprogrammer.tistory.com/388","name":"그누보드4 설치방법"}},{"@type":"ListItem","position":27,"item":{"@id":"https://webprogrammer.tistory.com/386","name":"CVS 사용에 대한 FAQ 모음"}},{"@type":"ListItem","position":28,"item":{"@id":"https://webprogrammer.tistory.com/385","name":"linux cvs 설치 및 프로젝트 적용"}},{"@type":"ListItem","position":29,"item":{"@id":"https://webprogrammer.tistory.com/384","name":"CVSNT 서버 설치 매뉴얼"}}]} </script> <!-- END STRUCTURED_DATA --> <link rel="stylesheet" type="text/css" href="https://tistory1.daumcdn.net/tistory_admin/userblog/tistory-e11b6cd63d67e948b9dd33a1d0a60492dd6a0cbf/static/style/dialog.css"/> <link rel="stylesheet" type="text/css" href="//t1.daumcdn.net/tistory_admin/www/style/top/font.css"/> <link rel="stylesheet" type="text/css" href="https://tistory1.daumcdn.net/tistory_admin/userblog/tistory-e11b6cd63d67e948b9dd33a1d0a60492dd6a0cbf/static/style/postBtn.css"/> <link rel="stylesheet" type="text/css" href="https://tistory1.daumcdn.net/tistory_admin/userblog/tistory-e11b6cd63d67e948b9dd33a1d0a60492dd6a0cbf/static/style/comment.css"/> <link rel="stylesheet" type="text/css" href="https://tistory1.daumcdn.net/tistory_admin/userblog/tistory-e11b6cd63d67e948b9dd33a1d0a60492dd6a0cbf/static/style/tistory.css"/> <script type="text/javascript" src="https://tistory1.daumcdn.net/tistory_admin/userblog/tistory-e11b6cd63d67e948b9dd33a1d0a60492dd6a0cbf/static/script/common.js"></script> <script type="text/javascript" src="https://tistory1.daumcdn.net/tistory_admin/userblog/tistory-e11b6cd63d67e948b9dd33a1d0a60492dd6a0cbf/static/script/comment.js" defer=""></script> </head> <body> <form onsubmit="return chkForm(this)"> 제목 : <input type="text" name="title"> <br /> 내용 : <input type="submit" value="전송"> <script> var ed = new easyEditor("content"); //초기화 id속성값 ed.init(); //웹에디터 삽입 </script> </form> <script type="text/javascript">(function($) { $(document).ready(function() { lightbox.options.fadeDuration = 200; lightbox.options.resizeDuration = 200; lightbox.options.wrapAround = false; lightbox.options.albumLabel = "%1 / %2"; }) })(tjQuery);</script> <div style="margin:0; padding:0; border:none; background:none; float:none; clear:none; z-index:0"></div> <script type="text/javascript" src="https://tistory1.daumcdn.net/tistory_admin/userblog/tistory-e11b6cd63d67e948b9dd33a1d0a60492dd6a0cbf/static/script/common.js"></script> <script type="text/javascript">window.roosevelt_params_queue = window.roosevelt_params_queue || [{channel_id: 'dk', channel_label: '{tistory}'}]</script> <script type="text/javascript" src="//t1.daumcdn.net/midas/rt/dk_bt/roosevelt_dk_bt.js" async="async"></script> <script type="text/javascript" src="https://tistory1.daumcdn.net/tistory_admin/userblog/tistory-e11b6cd63d67e948b9dd33a1d0a60492dd6a0cbf/static/script/menubar.min.js"></script> <script>window.tiara = {"svcDomain":"user.tistory.com","section":"기타","trackPage":"글뷰_보기","page":"글뷰","key":"218144","customProps":{"userId":"0","blogId":"218144","entryId":"null","role":"guest","trackPage":"글뷰_보기","filterTarget":false},"entry":null,"kakaoAppKey":"3e6ddd834b023f24221217e370daed18","appUserId":"null"}</script> <script type="module" src="https://t1.daumcdn.net/tistory_admin/frontend/tiara/v1.0.0/index.js"></script> <script src="https://t1.daumcdn.net/tistory_admin/frontend/tiara/v1.0.0/polyfills-legacy.min.js" nomodule="true" defer="true"></script> <script src="https://t1.daumcdn.net/tistory_admin/frontend/tiara/v1.0.0/index-legacy.js" nomodule="true" defer="true"></script> </body> </html>

소스 설명

  • 3 줄: 삽입할 HTML문서내에 자바스크립트 모듈 호출
  • 21 줄: 대체할 textarea 태그에 id 속성 부여 (값은 유니크해야 함, name속성값과 동일 권장)
  • 23~26 줄: id속성값을 인자로 하여 인스턴스 생성후 '이지웹에디터' 삽입스크립트 호출 ( ed 라는 인스턴스명 유니크 해야함)
  • 7 줄: ed.getHtml() 호출하여 대체한 textarea에 편집한 HTML값 전달

사용 예제

게시판 사용예제

변수 사용예제

  • 예제 실행 <script> var ed = new easyEditor("content"); ed.cfg.width = "300px"; //가로 설정 (디폴트 100%) ed.cfg.height = "300px"; //세로 설정 (디폴트 200px) ed.cfg.border = "4px solid green"; //웹에디터 보더 설정 (css) ed.cfg.Btn = easyConfig.BtnTemplate["simple"]; //명령버튼셋 simple로 설정 (디폴트 all) ed.init(); </script>
  • 예제 실행 <script> var ed = new easyEditor("content"); ed.cfg.width = "500px"; //가로 설정 (디폴트 100%) ed.cfg.height = "400px"; //세로 설정 (디폴트 200px) ed.cfg.border = "1px dashed red"; //웹에디터 보더 설정 (css) ed.cfg.Btn = ["bold","underline","strike"]; //명령버튼셋 세팅 ed.init(); </script>
  • 예제 실행 <script> var ed = new easyEditor("content"); ed.cfg.imgpath = "./img/flat"; ed.cfg.over_bordercolor = "#facf98"; //버튼마우스 오버시 border컬러 ed.cfg.over_bgcolor = "#ffffea"; // 버튼 마우스 오버스 bg컬러 ed.cfg.divbtn_bgcolor = "#e7e7e7"; // 버튼 영역 div bg컬러 ed.init(); </script>

명령버튼 추가하기

특징

  • 원하는 기능의 명령버튼 추가 가능 (사용자 생성함수 호출)
  • 사용 가능예) 이모티콘삽입, 특수문자 삽입, 이미지업로드 첨부 등
  • 추가 개발 배포 예정
  • easyEditor.js 파일 하단에 명령추가행 참고

예제소스

  • easyConfig.BtnList.{명령어} = ["{명령어설명}","{버튼이미지명}", {실행함수선언}];
    easyConfig.BtnList.table = ["테이블 삽입","table.gif", function (self){ window.open(easyConfig.filepath+"/table.html","table","width=400,height=220,status=1"); } ];

이미지 업로드 명령 예제





Posted by 1010
98..Etc/Etc...2008. 9. 17. 17:05
반응형

그누보드4 설치방법

그누보드4를 설치하는 방법에는 ftp로 조금 불편하게 설치하는 방법Telnet(또는 SSH)으로 조금 편하게 설치하는 방법이 있습니다.

이 두가지 모두에 대해 설치하는 방법을 알려드립니다. 단, Telnet(또는 SSH)은 서버에 따라 지원되지 않는 경우도 있습니다.

1. ftp로 조금 불편하게 설치하는 방법

ftp 프로그램이 설치되어 있지 않다고 가정하고 ftp 프로그램부터 설치하도록 하겠습니다.

http://sir.co.kr/data/util/FileZilla_2_2_32_setup.exe 에서 파일질라 프로그램을 다운로드 한 후 설치합니다.

다운로드 해 놓은 그누보드4의 압축을 해제합니다.
압축 프로그램은 알집을 사용하였습니다. (http://www.altools.co.kr)

"현재폴더에 압축풀기"하면 gnuboard4 폴더로 압축이 해제됩니다.

ftp 프로그램도 설치가 되었고, 업로드 할 프로그램도 준비가 되었습니다.
이제 프로그램을 설치할 웹서버(웹호스팅)로 업로드 하도록 하겠습니다.
파일질라를 실행합니다.

위와 같이 ftp 주소와 사용자 ID(계정아이디), 비밀번호를 입력한 후 빠른 접속을 클릭합니다.

접속을 한 후 실제 브라우저에서 실행할 폴더로 이동합니다.
보통 www 또는 public_html 폴더라는 이름으로 되어 있습니다.

gnuboard4 폴더를 원격 사이트로 드래그 합니다.

업로드 하는 시간은 그리 길지 않습니다. 인터넷 회선 속도에 따라 차이가 있으며 100M 광랜의 경우 1분정도 걸립니다.

업로드가 다 되었다면 상위 폴더(..)로 이동하여 gnuboard4 폴더가 보이도록 합니다.
오른쪽 마우스 버튼을 누르면 파일 속성이라는 메뉴가 보일 것입니다. 이 메뉴를 클릭합니다.

gnuboard4 폴더(디렉토리)의 속성(퍼미션)을 777 로 설정합니다. 그리고 확인을 클릭합니다.

자 이제 그누보드4를 설치할 준비는 모두 마쳤습니다.
이제 브라우저를 열어 설치를 하도록 하겠습니다.


2. Telnet(또는 SSH)으로 조금 편하게 설치하는 방법

Telnet 과 SSH를 모두 지원하는 Putty(http://the.earth.li/~sgtatham/putty/latest/x86/putty.exe) 라는 프로그램으로 설명 드리겠습니다.
설치형 프로그램이 아니므로 이 파일만 다운로드 하신 후 실행하시면 바로 사용이 가능합니다.

Putty 실행한 후 Host Name 에 도메인 또는 IP 주소를 입력합니다. 그리고 Open 버튼을 누릅니다.

SSH 의 경우 경고창이 나올 수 있습니다. 그냥 "예" 하시면 됩니다.

사용자 아이디와 비밀번호를 입력한 후 로그인 합니다. 웹경로로 이동하기 위해 cd www 명령어를 사용하였습니다.

gnuboard4.tgz 파일을 wget 프로그램을 사용하여 http://sir.co.kr/data/gnuboard4.tgz 으로부터 전송하였습니다.
ls 명령으로 gnuboard4.tgz 파일이 들어있는 것을 확인하실 수 있습니다.

tgz 파일은 보통 tar 와 gunzip 으로 압축을 해제하지만 여기서는 편하게 tar 로 압축을 해제하였습니다.
그리고 gnuboard4 폴더의 퍼미션(속성)을 777 로 변경하였습니다.



자 이제 그누보드4를 설치할 준비는 모두 마쳤습니다.
이제 브라우저를 열어 설치를 하도록 하겠습니다.

브라우저를 열어 그누보드4가 설치된 웹경로를 입력합니다.

위와 같은 메시지를 출력 한 후 확인을 누르면 설치합니다.

라이센스의 내용에는 반드시 동의하셔야 설치가 가능합니다.

MySQL 정보는 모르시는 경우 서버관리자(웹호스팅을 하시는 경우 웹호스팅 회사)에게 문의합니다.
최고관리자의 회원아이디와 패스워드, 이름, 이메일을 입력한 후 "다음" 버튼을 누릅니다.

설치바가 움직이며 설치를 시작합니다. 설치가 끝나면 메인화면을 클릭합니다.

그누보드4의 기본 설치화면입니다. 수고하셨습니다.


[팁] 웹경로에 http://g4.dasir.co.kr/gnuboard4 라는 폴더로 접근이 되고 있습니다. 이것을 http://g4.dasir.co.kr 로 바로 접근하도록 해보겠습니다.

파일질라로 접속 한 후 모두 선택(Ctrl+A)하여 상위 폴더(..)로 드래그 이동합니다.

그리고 gnuboard4 는 빈폴더가 되었으므로 삭제합니다.

[끝]

Posted by 1010
98..Etc/Etc...2008. 9. 5. 12:59
반응형
CVS 사용에 대한 FAQ 모음

한글로 된 CVS 문서들이 여럿 나와 있지만 꼭 필요한 정보들이 여기저기 흩어져 있고 체계적이지 않은 경우가 있어, 처음 CVS를 접하는 분들이 비슷한 질문을 반복적으로 하게 되는 듯 합니다. 오픈소스 프로젝트 개발에 참여하고자 하는 분들에게 필요한 정보를 모아봤으면 합니다. CVS 사용하면서 이 간단한 걸 몰라서 참 고생했었지 싶은게 있으면 언제든지 추가해 주세요.

마침 KLDPconf 주제 응모에도 비슷한 얘기가 나와서 생각난 김에 일단 시작해 봅니다.

질문만 적어주셔도 물론 좋습니다.

Contents

[-]
1 질문과 답
1.1 CVS를 빨리 배워서 써야하는데 어떡하죠?
1.2 CVS가 뭐예요? / 어디에 쓰는 물건인가요?
1.3 CVS를 실제로 개발 과정에 사용하는 프로젝트가 있나요?
1.4 CVS를 쓰면 그래서 뭐가 좋은가요?
1.5 RCS는 또 뭐죠? / RCS 하고는 뭐가 다른가요?
1.6 SourceSafe와는 뭐가 어떻게 다른가요?
1.7 CVS에서 .......한 점이 마음에 들지 않습니다. 다른 프로그램은 없나요?
1.8 Windows에서 쓸 수 있는 CVS 클라이언트가 있나요?
1.9 Windows에서 쓸 수 있는 CVS 서버가 있나요?
1.10 CVSROOT 환경 설정을 어떻게 해야하나요?
1.11 Anonymous checkout 이 뭔가요? 어떻게 하죠?
1.12 로그인을 하라는데 어떻게 하나요?
1.13 저장소(Repository)의 디렉토리 구조를 알고 싶습니다.
1.14 새 Repository는 어떻게 만드나요?
1.15 새 프로젝트는 어떻게 만드나요?
1.16 checkout은 어떻게 하나요?
1.17 checkout한 이후에 Repository에서 바뀐 내용을 확인하고 싶습니다.
1.18 내가 작업한 내용은 어떻게 알 수 있나요?
1.19 지금까지 작업한 내용을 checkin하고 싶습니다.
1.20 Conflict가 생겼습니다! 어떻게 해야하나요?
1.21 소스에서 이 부분을 누가 만든 건지 좀 알아야겠습니다.
1.22 파일을 추가하고 싶습니다.
1.23 파일을 삭제하고 싶습니다.
1.24 파일 이름을 바꾸고 싶습니다.
1.25 디렉토리를 지우고 싶습니다
1.26 실수로 잘못된 소스를 checkin해 버렸습니다. 어떻게 고쳐야하나요?
1.27 checkout 받은 소스를 이제 그만 지워버리고 싶어요.
1.28 현재까지 작업 내역을 보고 싶습니다.
1.29 revision이 뭔가요?
1.30 tag가 뭔가요?
1.30.1 tag는 어떻게 붙이나요?
1.31 branch는 또 뭔가요?
1.31.1 branch는 어떻게 만들죠?
1.31.2 merge는 어떻게 하는 겁니까?
1.32 과거 특정 시점에 소스가 어땠는지 보고 싶습니다.
1.33 CVS 서버에 어떤 module이 있는지 어떻게 알 수 있나요?
1.34 CVSROOT/modules에 모듈 등록은 어떻게 하나요?
1.35 CVSROOT/passwd에 사용자를 어떻게 추가하나요?
1.36 익명 사용자는 어떻게 등록하나요?
1.37 CVS가 /root 아래 파일을 찾으려 듭니다! 이게 뭔가요?
1.38 Repository를 다른 기계로 옮기고 싶습니다.
1.39 CVS 서버에 있는 repository를 미러링할 수 없나요?
1.40 module들을 공유할 수 있는 방법이 있나요?
1.40.1 간단한 방법
1.41 Source file에 강제로 revision을 지정할 수 있나요 ?
1.42 CVS도 VSS처럼 배타적 락(Exclusive Lock)을 걸어 놓고 사용할 수 있나요?
1.43 Repository에 Attic 이란게 있던데 이건 뭔가요?
1.44 Unicode file을 지원하지 못하는가요?
1.45 이미 Text로 업로드 된 파일을 Binary로 바꿀 수 있는가요?
1.46 이미 Binary로 업로드 된 파일을 Text로 바꿀 수 있는가요?
1.47 로그를 잘못 적었는데 고칠 수 없을까요?
1.48 Tag에 comment를 붙이는것은 가능한가요
1.49 Unknown command 라는 에러가 납니다.
1.50 항상 최신버전의 소스를 유지하고 싶어요
1.51 이전버전으로 되돌리고 싶어요(Rollback)
1.52 CVS를 쓸까요 Subversion을 쓸까요?
2 help 사용법
3 용어
4 문서를 만들면서
5 관련 자료


1 질문과 답

1.1 CVS를 빨리 배워서 써야하는데 어떡하죠?

  1. 우선 DocbookSgml/CVS-KLDP 를 보고 한번 그대로 따라해 보세요.
  2. 아래 정리해둔 다른 한글로 된 문서들을 틈틈히 읽어 봅니다.
  3. CVS를 꾸준히 써야 하거나 여러가지 정석적인 사용 방법을 익히고 싶다면 [http]CVS-BestPractices 문서를 정독하시기를 권합니다.
  4. 큰 오픈소스 프로젝트에서 많은 개발자들이 같이 작업할 때 소스 버전 컨트롤이 어떤 방식으로 운영되는지에 관심 있는 분들은 [http]The CVS Book을 한번 보시기 바랍니다.

1.2 CVS가 뭐예요? / 어디에 쓰는 물건인가요?

CVS(Concurrent Versions System)는 프로그램 소스나 문서 파일 버전 관리를 쉽게 할 수 있도록 도와주는 프로그램입니다. 특히 여러 사람들이 동시에 작업을 진행해야하는 규모가 큰 개발 프로젝트에서 큰 효과를 기대할 수 있습니다. 이밖에도 꾸준히 업데이트되는 문서 관리라든가 웹사이트 관리 등에 유용하게 쓸 수 있고, 심지어 /etc 아래에 들어가는 설정 파일을 (원격) 백업하는 용도로도 사용 가능합니다. :-)

동시에 여러 유닉스 장비에서 작업하는 경우 등에 써볼만한 "홈디렉토리 몽땅 CVS에 넣어버리기"에 대한 LinuxJournal 기사([http]CVS homedir)도 한번 읽어 보세요.

1.3 CVS를 실제로 개발 과정에 사용하는 프로젝트가 있나요?

잘 알려진 유명한 오픈소스 프로젝트들은 대개 CVS나 이와 유사한 소스 관리 시스템을 갖추고 있습니다.

  1. OpenBSD : OS 및 시스템 전체 소스를 CVS로 관리하고 있습니다.
  2. OpenOffice : 총 3만 파일에 대략 9백만 라인 이상되는 C++ 코드를 CVS로 관리합니다.
  3. Mozilla : 전체 프로젝트 및 파생 프로젝트 소스 코드 및 릴리스/브랜치 관리를 CVS로 하고 있습니다.
  4. XFree86 : CVS 를 사용하는 유명 프로젝트중 하나입니다.
  5. Apache : 위와 동일합니다.

1.4 CVS를 쓰면 그래서 뭐가 좋은가요?

관리자는 :
  1. 프로젝트 참여자 개개인의 작업을 방해하지 않으면서 전체적인 진행 상황을 조절할 수 있다.
  2. 릴리스된 버전과 개발중인 버전을 뒤섞지 않고 분리해서 관리할 수 있다.
  3. 일정 기간에 진행된 작업 내용에 대한 리포트를 쉽게 만들어 낼 수 있다.
  4. 일정 기간에 진행된 변경 내역을 효과적으로 추적할 수 있다.
  5. 누가 일을 하고 누가 놀고 있는지 쉽게 감시할 수 있다. :-)

개발자는 :
  1. 소스 백업에 신경 쓸 필요가 없다.
  2. 새로운 코드를 작성할 때 기존 작업을 망칠 위험 없이 쉽게 시도할 수 있다.
  3. 문제가 생겼을 때 어느 지점에서 문제가 생겼는지 쉽게 추적해서 찾아낼 수 있다.
  4. 소스나 문서 특정 부분 작업을 누가 언제 했는지 쉽게 알아낼 수 있다.
  5. 별도 리포트 작성 및 문서를 써야하는 건수나 양이 많이 줄어든다.
  6. 맘먹으면 별로 한 일이 없어도 꾸준히 일하고 있는 것처럼 속일 수도 있다. :-)

1.5 RCS는 또 뭐죠? / RCS 하고는 뭐가 다른가요?

CVS는 RCS를 기반으로 작성된 버전 관리 시스템입니다. 쉽게 얘기하자면 RCS는 파일 하나하나에 대해 버전 관리를 해주는 것이고, CVS는 RCS 기능을 이용해 소스나 문서를 프로젝트/모듈 단위로 관리할 수 있도록 확장한 프로그램입니다. 이미 RCS를 쓰고 있고 익숙한 분이 아니라면 굳이 CVS를 새로 배울 필요는 없습니다. RCS로 할 수 있는 모든 것은 CVS로 할 수 있지만 그 역은 성립하지 않기 때문입니다.

CVS에서도 일부 기능(이미 써 놓은 로그 수정 등)은 RCS 명령을 사용해야 합니다. 궁금하다면
 $ cvs -H admin
해서 RCS 관련 명령어를 한번 살펴 보세요.

1.6 SourceSafe와는 뭐가 어떻게 다른가요?

1.7 CVS에서 .......한 점이 마음에 들지 않습니다. 다른 프로그램은 없나요?


대체할 만한 것들... Non-Free

1.8 Windows에서 쓸 수 있는 CVS 클라이언트가 있나요?


CVS를 처음 사용하는 분에게는 TortoiseCVS 를 권합니다. Java를 주로 사용하거나 좋은 IDE 환경을 원하시는 분은 Eclipse를 한번 써보세요.

DeleteMe 윈도우즈 환경에서 CVS를 사용하는 방법에 대해 아직 쉽게 참고할 만한 문서가 없는 것으로 압니다. 누군가 위에 제가 링크해 드린 두 개의 내용을 바탕으로 해서 윈도우즈 환경에서 CVS를 사용하는 방법을 다룬 별도의 문서를 만들어 주시면 참 좋겠네요. -- 권순선
WinCVS 페이지에서 새롭게 문서를 작성해 나갈까 합니다. 많은 관심과 도움 부탁드립니다. -- 쫑아

1.9 Windows에서 쓸 수 있는 CVS 서버가 있나요?

1.10 CVSROOT 환경 설정을 어떻게 해야하나요?

Local Repository
export CVSROOT=/usr/local/cvsroot

Remote Repository
export CVSROOT=:pserver:username@host.domain.com.:/var/cvsroot

Remote Repository w/ SecureShell
export CVS_RSH=ssh
export CVSROOT=:ext:username@host.domain.com.:/var/cvsroot

1.11 Anonymous checkout 이 뭔가요? 어떻게 하죠?

익명 사용자에게 읽기 권한을 제공함으로써 소스나 문서 최신 버전을 손쉽게 업데이트할 수 있도록 해줍니다. 특히 컴파일이 필요없는 스크립트 기반 프로젝트에 유용합니다. [http]MoniWiki를 예로 들자면
$ cvs -d:pserver:anonymous@cvs.kldp.net:/cvsroot/moniwiki login
$ cvs -z3 -d:pserver:anonymous@cvs.kldp.net:/cvsroot/moniwiki co moniwiki
와 같이 하면 됩니다. 이후에 새 버전이 나오거나 패치가 업데이트 되면
$ cvs update -dP
해서 간단히 최신버전으로 업데이트할 수 있습니다.

1.12 로그인을 하라는데 어떻게 하나요?

$ cvs login
(Logging in to user@host.domain.com)
CVS password:

$ cat ~/.cvspass
:pserver:user@host.domain.com:/var/cvsroot XYZ123

$ cvs logout
(Logging out of user@host.domain.com)

1.13 저장소(Repository)의 디렉토리 구조를 알고 싶습니다.

  /home/cvs/ .... (1)
  /home/cvs/CVSROOT/ .... (2)
  /home/cvs/CVSROOT/passwd .... (3)
  /home/cvs/CVSROOT/readers .... (4)
  /home/cvs/module_A/ .... (5)
  /home/cvs/module_B/ .... (6)

(1) $CVSROOT 로 지정되는 CVS의 최상위 디렉토리

(2) CVS 저장소의 설정 파일들이 있는 디렉토리

(3) CVS 사용자 ID와 비밀번호

(4) CVS 읽기만 가능한 사용자

(5), (6) 프로젝트 디렉토리, 프로젝트에 따라 CVS 명령으로 생성됩니다.

1.14 새 Repository는 어떻게 만드나요?

$ export CVSROOT=/home/user/cvsroot
$ cvs init
$ ls /home/user/cvsroot
CVSROOT/
$ ls /home/user/cvsroot/CVSROOT/
Emptydir/       config         editinfo,v  modules,v  taginfo
checkoutlist    config,v       history     notify     taginfo,v
checkoutlist,v  cvswrappers    loginfo     notify,v   val-tags
commitinfo      cvswrappers,v  loginfo,v   rcsinfo    verifymsg
commitinfo,v    editinfo       modules     rcsinfo,v  verifymsg,v

1.15 새 프로젝트는 어떻게 만드나요?

$ ls proj/
README  a.c  a.h
$ cd proj/
$ cvs import -m "this is the project" proj VENDOR INIT
$ ls /var/cvsroot/
CVSROOT/  proj/
$ ls /var/cvsroot/proj/
README,v  a.c,v  a.h,v

1.16 checkout은 어떻게 하나요?

$ cd ~/work
$ cvs co proj
U proj/README
U proj/a.c
U proj/a.h

특정 태그를 지정해서 받고 싶다면 다음과 같이 합니다.
$ cvs co -r RELEASE_1_0_5 moniwiki

1.17 checkout한 이후에 Repository에서 바뀐 내용을 확인하고 싶습니다.

우선 내용 확인 (로컬에 아무 변화도 만들지 않음).
$ cvs -n update

그리고 이상이 없으면 변경된 사항을 받아온다.
$ cvs update -dP

1.18 내가 작업한 내용은 어떻게 알 수 있나요?

$ cvs diff
$ cvs diff -r BASE
$ cvs diff -r BASE -r HEAD
$ cvs diff -c -r1.6 prog.c
$ cvs diff -c -r1.6 -r1.7 prog.c

1.19 지금까지 작업한 내용을 checkin하고 싶습니다.

$ cvs ci -m "fixed bug #12345"
$ cvs com[mit] prog.c
$ cvs ci -m "another bug fix in sheet.c" sheet.c

1.20 Conflict가 생겼습니다! 어떻게 해야하나요?

당황하지 마세요. 소스나 문서에서
<<<<
....
----
....
>>>>
이렇게 생긴 부분을 찾아서 고친 다음 다시 cvs update; cvs ci 하면 됩니다.

1.21 소스에서 이 부분을 누가 만든 건지 좀 알아야겠습니다.

$ cvs annotate a.c

1.22 파일을 추가하고 싶습니다.

$ cvs add newfile
$ cvs add newdir

1.23 파일을 삭제하고 싶습니다.

$ cvs rm oldfile
$ cvs rm -f badfile
$ cvs rm -f olddir/badfiles
$ cvs rm olddir

1.24 파일 이름을 바꾸고 싶습니다.

단순히 파일이름만 바꾸는 방법과 history 까지 보존하는 방법이 있습니다 (매뉴얼에서 발취)

일반적인 방법
$ mv old new
$ cvs remove old
$ cvs add new
$ cvs commit -m "Rename old to new" old new
일반적인 만큼 방법도 쉽습니다. 기존 파일의 이름을 다른 이름으로 바꾼후 기존 파일을 cvs remove 로 제거하고

새로 바뀐 이름의 파일을 cvs add 로 추가합니다. 그 다음엔 remove와 add 만으로 파일이 지워지거나 추가된것이 적용되지 않으므로

이 두파일을 commit 해줘야 합니다

히스토리 까지 보존하는 방법

먼저 이 방법은 CVS repository 를 직접 접근하므로 조금은 위험하다고 메뉴얼에서 밝히고 있네요
$ cd $CVSROOT/module
$ mv old,v new,v
CVS repository 의 수정할 module 디렉토리에서 이름을 변경할 파일의 이름을 직접 바꾸어 주는 방법입니다

이것은 아래와 같은 장단점을 가지고 있습니다 장점
  • change log가 그대로 보존됩니다
  • revision 역시 그대로 유지됩니다
단점
  • module 의 예전 release 나 tag 를 불러오기가 쉽지가 않다.
  • 이름이 변경되었다는 정보가 log 에 남지 않는다
  • 위의 작업($CVSROOT 에 들어가 파일을 직접 rename 하는..)을 하는 동안 누군가 cvs 작업을 한다면 난처한 일이 생긴다.

1.25 디렉토리를 지우고 싶습니다

CVS에서는 디렉토리 단위로 저장을 하기 때문에 히스토리를 유지하기 위해서는 그 디렉토리가 필요합니다. 따라서 진짜로 디렉토리를 지울 수는 없습니다. 대신 update 시에 받지 않는 방법이 있습니다. 먼저 파일을 지우기를 이용해서 해당 디렉토리의 파일을 모두 지웁니다. 그리고 나서 상위 디렉토리로 가서 해당 디렉토리를 지우고 나면 다음부터는 cvs update -P 로 업데이트 하면 해당 디렉토리가 보이지 않게 됩니다.
cd unneeddir
rm *             # 이때 CVS 디렉토리는 남겨져 있어야 합니다.
cvs remove
cvs commit  # 여기서 unneeddir의 모든 파일이 지워집니다
cd ..
cvs remove unneeddir
cvs update -P

또는 CVSROOT에 가서 직접 디렉토리를 지워 버리는 방법이 있습니다. 대신이 방법은 CVSROOT 디렉토리 관리 권한을 가지고 있어야 하고, 히스토리까지 사라진다는 단점이 있습니다.

1.26 실수로 잘못된 소스를 checkin해 버렸습니다. 어떻게 고쳐야하나요?


1.27 checkout 받은 소스를 이제 그만 지워버리고 싶어요.

$ cvs release -d proj

1.28 현재까지 작업 내역을 보고 싶습니다.

$ cvs st[atus] [-v] [prog.c]
$ cvs log [prog.c]
$ cvs ann[otate] [main.c]

1.29 revision이 뭔가요?

파일 하나하나에 붙어 있는 버전 번호를 말합니다.
$ cvs st README
......
   Working revision:    1.1
......

1.30 tag가 뭔가요?

여러 파일이나 모듈에 버전을 표시하기 위해 한꺼번에 붙여둔 표시입니다.
$ cd moniwiki/
$ cvs st -v README
......
   Existing Tags:
        moniwiki-1_1                    (branch: 1.1.2)
        RELEASE_1_0_5                   (revision: 1.1)
......

1.30.1 tag는 어떻게 붙이나요?

$ cvs tag TAGNAME

1.31 branch는 또 뭔가요?

  • Development Branch
  • Release Branch
  • Maintenance Branch

  • Vender Branch

  • (Main) Trunk
  • HEAD

매뉴얼에서 빌려온 그림
                                                     +-------------+
                          Branch 1.2.2.3.2 ->        ! 1.2.2.3.2.1 !
                                                   / +-------------+
                                                  /
                                                 /
                 +---------+    +---------+    +---------+    +---------+
Branch 1.2.2 -> _! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 !----! 1.2.2.4 !
               / +---------+    +---------+    +---------+    +---------+
              /
             /
+-----+    +-----+    +-----+    +-----+    +-----+
! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 !      <- The main trunk
+-----+    +-----+    +-----+    +-----+    +-----+
                !
                !
                !   +---------+    +---------+    +---------+
Branch 1.2.4 -> +---! 1.2.4.1 !----! 1.2.4.2 !----! 1.2.4.3 !
                    +---------+    +---------+    +---------+

1.31.1 branch는 어떻게 만들죠?

$ cvs checkout project; cd project
$ cvs update foo.c
$ cvs tag release-1 .
$ cd ..; cvs release -d project

$ cvs checkout -r release-1 project
$ cvs release -d project

$ cvs rtag -b -r release-1 release-1-patches project
$ cvs checkout -r release-1-patches project
$ cvs commit -m "Fixed printf bug" foo.c
$ cd ..;  cvs release -d project

cvs를 사용할 때 Branch를 해서 버젼을 만들고 메인 버젼이 올라가면 다시 메인버젼과 머지를 하고.. 등의 작업을 수행할 때, 먼저 브랜치를 할 파일들에 태그를 달아주고 태그를 기준으로 브랜치를 만드는 것이 편한 것 같습니다.

명령어는 다음과 같습니다.

cvs rtag -r arab -b arab_xxx ggg

이렇게 하면 ggg라는 프로젝트에서 arab 태그가 붙은 것을 arab_xxx 브랜치로 작성하겠다. 라는 의미가 됩니다. 태그는 먼저 달아주어야 하겠지요.

그리고 태그와 브랜치는 다르다는 점을 미리 아시면 좋겠고.. 만일 wincvs를 사용하신다면 graph를 보시게 되면 tag는 검정색 얇은 선 브랜치는 파란색 굵은 선으로 나뉘는 것을 알 수 있습니다. --최성우 / eatingstars.com

브랜치를 쉽게 만드는 방법입니다.
$ cvs tag -b BRANCHNAME
이 명령을 실행한 작업소는 앞으로 이 브랜치로 작업을 하게 됩니다.

1.31.2 merge는 어떻게 하는 겁니까?

$ cvs checkout -j release-1-patches project
$ cvs commit -m "Merged patch"

1.32 과거 특정 시점에 소스가 어땠는지 보고 싶습니다.

태그를 붙여 두지 않았다면, 날자와 시간을 써서 다음과 같이 작업하는 것도 가능합니다.
$ cvs rtag -b -D "2000-01-01  00:00" first-millenium-release project
$ cvs get -D "3 month ago" myproj
$ cvs get -D "1999-11-23  09:00" oldproj

CVS가 지원하는 날자/시간 지정 형식 몇 가지는 다음과 같습니다.
"1971-04-30  04:35" (ISO format)
"30  Apr  1971  04:35" (Internet format)
"Tue Jan 25 08:45:45 UTC 2000"
"3/31/92 10:00:07 PST"
"January 23, 1987 10:05pm"
"22:00 GMT"
"1 month ago"
"2 hours ago"
"400000 seconds ago"
"last year"
"last Monday"
"yesterday"
"a fortnight ago"

1.33 CVS 서버에 어떤 module이 있는지 어떻게 알 수 있나요?

CVS에서 제공하는 명령어를 통해 정상적으로 알아낼 수 있는 방법은 없습니다. :-( 그렇지만 꼭 필요한 경우에 흔히 사용되는 방법이 몇 가지 있습니다.

  1. 프로젝트 관리자에게 물어보세요 :-)
  2. 프로젝트 관리자가 수동으로 CVSROOT/modules 에 등록해 놓으면 다음 명령으로 module의 목록을 볼 수 있습니다.
      $ cvs co -c
      
  3. 잘 관리되는 프로젝트라면 일반적으로 cvsweb 이나 viewcvs 같은 웹 인터페이스를 제공할 것입니다. 그걸 이용하세요. 만약 없다면 서버 관리자에게 그런 프로그램을 설치해 달라고 요청하세요.
  4. 위 방법이 모두 안된다면, 다음 스크립트를 써서 간접적으로 알아낼 수도 있습니다.
      $ cvsls.sh HEAD .
      
    #!/bin/sh
    
    # lists files and directories in the module(s) on the server without
    # checking them out
    
    # cvsls BranchName modules...
    # for main trunk use 'cvsls HEAD modules...'
    
    branch=$1; shift
    
    cvs rdiff -s -D '01/01/1971' -r $branch "$@"  2>&1 \
        | sed -e 's/File.//' \
                      -e 's/is new; current revision./      (/' \
                      -e 's/(\([0-9][\.0-9]*\)/(\1)/' \
                      -e 's/cvs server: Diffing/cvs server: Listing/'
    
    


1.34 CVSROOT/modules에 모듈 등록은 어떻게 하나요?

cvs co CVSROOT 하여서 modules 파일을 수정하신 후에 commit 하셔야 합니다. 이때 위와 같은 목적으로 활용하실 계획이라면 간단하게 다음과 같이 적으시면 됩니다.
module_A  module_A
module_B  module_B
위의 내용은 module_A라는 것이 repository root에 존재하는 경우 입니다.

1.35 CVSROOT/passwd에 사용자를 어떻게 추가하나요?

몇 가지 방법이 있지만, 가장 간단한 방법 가운데 하나는 apache 패키지에 들어 있는 htpasswd 명령을 이용하는 것입니다.

  $ htpasswd -b passwd username password

1.36 익명 사용자는 어떻게 등록하나요?

$ cat $CVSROOT/CVSROOT/readers
cvs
cvsguest

1.37 CVS가 /root 아래 파일을 찾으려 듭니다! 이게 뭔가요?

pserver 설정을 해줄 때 아래와 같은 에러가 나는 경우가 있습니다.

cvs server: cannot open /root/.cvsignore: Permission denied

이럴 땐 inetd 나 xinetd 설정을 해줄 때 cvs에 넘겨줄 인수에 '-f' 옵션을 추가해주면 해결됩니다. xinetd 라면 /etc/xinetd.d/cvspserver 내용을 아래와 같이 해 주면 됩니다.

# default: on
# description: cvs pserver
service cvspserver
{
        disable         = no
        flags           = REUSE
        socket_type     = stream
        wait            = no
        user            = root
        server          = /usr/bin/cvs
        server_args     = -f --allow-root=/home/cvs pserver
        log_on_failure  += USERID
}

1.38 Repository를 다른 기계로 옮기고 싶습니다.

Q : 만일 A 서버에 있던 repository 를 B 서버로 옮기고 싶다면 그냥 디렉토리를 통채로 복사하면 되려나요? 그게 안 된다면 죄다 update 후 새로 import 를 하라는 얘기인데... -_-;;

A : 네 그냥 옮기면 됩니다. 완벽한(?) 이전을 위해서라면 조금 신경써야할 것들이 더 있긴 하지만, 디렉토리를 통째 tar로 묶어서 새 기계게 풀어준 다음 permission 조절만 해줘도 웬만큼 됩니다.

1.39 CVS 서버에 있는 repository를 미러링할 수 없나요?

단순한 백업 이상을 의미하는 것이라면, CVS는 기본적으로 단일 repository를 바탕으로 설계되었기 때문에 자체적으로는 불가능합니다. 대규모 프로젝트 같은 경우에 전세계 곳곳에 미러를 하기 위해 CVSup 같은 보조도구를 이용하거나, 단순히 rsync 같은 미러링 툴을 이용하기도 합니다. 그러나 이 경우 하위 repository에 commit 한 내용을 다시 상위(upstream)로 merge 하는데 기술적인 어려움이 따릅니다. 그렇지만 경우에 따라 효과적인 개발 브랜치나 로컬 개발자 그룹 지원을 위해서는 꼭 필요한 기능이기 때문에, CVS가 가지는 근본적인 제약을 극복하고자 새로 개발되는 프로그램이 있습니다. 만약 꼭 계층적 repository를 구축해야 하는 상황이라면, 다음 프로그램을 사용하는 것을 고려해 보세요.

최근에 XFree86 프로젝트를 arch를 이용해 fork한 사례가 있습니다. : http://www.xouvert.org/

1.40 module들을 공유할 수 있는 방법이 있나요?

Q : 예를 들어서 libx라는 모듈이 있고, proj_a와 proj_b가 이를 모두 사용합니다. 이때 이 두 프로젝트가 유사하여서 libx를 한쪽에서 수정하면 다른 한쪽에서도 영향을 받아야 하는 경우라면 어떻게 해야 할까요? 서버에서 symbolic link를 걸어주거나, 클라이언트측에서 proj_a, proj_b에 모두 libx를 checkout해주면 되겠지만 다소 불편함이 없지 않아 있을것 같아서 여쭤 봅니다.

A : 가능합니다.

CVS에서는 프로젝트 관리를 위해 어떤 모듈을 checkout할 때 하위 모듈을 선별적으로 checkout하거나 가상 모듈을 만들어 실제 모듈을 여러개 동시에 checkout하는 것 등을 지원합니다. 기본적으로는 CVSROOT/modules 파일을 적절히 구성해서 프로젝트에 참여하는 개발자들이 필요한 부분을 잘 골라 받아갈 수 있도록 관리해줘야 합니다. 한가지 짚어두고 싶은 것은, CVS는 소스 버전 관리 프로그램이지 어떤 특정 프로젝트 구조를 정해둔게 아니기 때문에 실제 해결 방식은 진행하는 프로젝트 구성 및 정책에 따라 달라집니다.

간단하게 두가지 경우를 예로 들어보지요.

1. proj_a 와 proj_b, 그리고 libx를 더 큰 proj 으로 묶을 수 있는 경우

CVSROOT/modules 내용은
proj    proj  proj_a proj_b libx
proj_a  proj  proj_a libx
proj_b  proj  proj_b libx
libx    proj  libx
와 같이 되고, checkout을 하게 되면 proj 디렉토리가 먼저 생기고, 그 아래에 각 모듈이 생깁니다.

2. proj_a 와 proj_b 는 별개 프로젝트이고 libx 도 별개로 관리하는 경우

CVSROOT/modules 내용은
proj_a  -a  proj_a libx
proj_b  -a  proj_b libx
libx    libx
이렇게 되고, 예를 들어 cvs checkout proj_a 를 하게 되면 proj_a와 libx라는 모듈이 각각 생성됩니다. 이 경우 libx에 autotools(libtool)을 채용하든가 proj_a와 proj_b 빌드하는데 연결되도록 적절히 구성해줘야 하겠죠.

두가지가 무슨 차이냐? 라고 혹시 생각하는 분이 있을지 모르겠는데, 전자에서는 최상위 디렉토리에 라이브러리를 포함한 빌드 시스템을 구축 관리할 수 있기 때문에 성격이 많이 달라집니다.

또, 경우에 따라
proj    proj
proj_b  proj  proj_a
proj_a  proj  proj_b
libx    libx
이런 식으로 구성하는 경우도 생기겠지요.

심볼릭 링크를 걸어주는 것도 편법으로 가능은 하지만, 모듈이나 라이브러리 관리라는 측면에서 본다면 그다지 바람직하지는 않습니다. 물론 불가피한 상황이 있을 수도 있으나 대개는 '라이브러리'라는 것 자체가 해당 코드를 별개로 독립시켜야할 만큼 여러 곳에서 쓰는 경우에 한해 만드는 것이므로 위에서 예를 든 두 가지 경우를 적절히 섞어서 구성하고, autotools 등을 잘 이용하면 해결할 수 있습니다. (DeleteMe 이 주제는 CVS/FAQ라는 범위를 벗어나는 것 같아 이정도만 적습니다.)

1.40.1 간단한 방법

단순히 어떤 모듈을 가져올 때 특정 하부 모듈을 같이 가져오도록 하려면 다음과 같이 하면 됩니다.
proj_a proj_a &libx
proj_b proj_b &libx
libx libx
이렇게 하면 proj_a를 체크아웃할 때 proj_a 디렉토리 아래에 추가로 libx 디렉토리가 생깁니다.

1.41 Source file에 강제로 revision을 지정할 수 있나요 ?

Q : 예를 들어서 어떤 소스의 revision #가 1.12라고 할 때 어떤 계기로 인해서 이 번호의 제일 앞자리 숫자를 바꾸려고 하면 어떻게 하면 되나요 ?

A : 가능합니다.
cvs ci -m "revision set to 2.0" -r2.0 ohmysrc.c
해당 프로젝트/모듈 전체를 한번에 바꾸려면, checkout 받은 모듈 최상위 디렉토리에서
cvs ci -m "revision set to 3.1" -r3.1
와 같이 하면 됩니다.

그러나

가능하다고 해서 반드시 이렇게 하는게 좋다는 것은 아닙니다.

그러므로

Tag나 Branch를 써야하는 경우가 아닌지 다시 한번 생각해보세요.

1.42 CVS도 VSS처럼 배타적 락(Exclusive Lock)을 걸어 놓고 사용할 수 있나요?

cvs admin -l filename
을 이용하시면 됩니다. 이 경우 해당하는 사람이 lock을 제거하기 전까지는 commit이 불가능하게 됩니다. 하지만 이렇게 하는 것은 대부분 문서에서 그다지 권장하지 않더군요. cvs watch 이용하기를 권장하고 있습니다.

보통은 cvs edit를 써서 원하는 효과를 얻을 수 있습니다. cvs edit는 동시에 edit하는 것을 방지하지 않지만, cvs edit -c filename 을 모든 사람이 이용하게 된다면 그 순간에는 한 사람만이 작업을 할 수가 있게 됩니다. -c 옵션을 준 것을 reserved edit라고 하며, 이 경우에도 누구나 commit은 가능합니다.

1.43 Repository에 Attic 이란게 있던데 이건 뭔가요?

사용자가 지운(cvs rm) 파일을 보관해두는 곳입니다. Attic이 우리말로 하면 "다락"인데, 자주 쓰지는 않지만 버리긴 아깝고 혹시 필요하게 될지 모르는 물건을 저장한다는 점에서 보면 상당히 잘 지은 이름 같습니다.

사용자가 cvs rm을 해서 파일을 지우게 되면, 해당 파일들이 완전히 삭제되는게 아니라 Attic 아래에 옮겨집니다. 그리고 과거 버전을 checkout 하거나 할때 끄집어내서 쓰는 거지요.

1.44 Unicode file을 지원하지 못하는가요?

Q : 이러한 메시지를 만났습니다.
cvs import: Remote server does not support Unicode files.  Checkin may be invalid.
여러개의 파일을 한꺼번에 import할때 나왔으며, 이를 다시 수정하여 ci할때에도 나타났습니다. 음.. 첫번째 파일에서 이러한 문구가 나타났는데, 평범한 C++ code라서 다른 파일이 아닌가 합니다. 아울러 -ku라고 나타나는 메시지도 무엇인지 모르겠네요.
cvs commit: Remote server does not support Unicode files.  Checkin may be invalid.
Checking in ***.cpp;
cvs server: internal error: unsupported substitution string -ku
/***.cpp,v  <--  ***m.cpp
new revision: 1.2; previous revision: 1.1
done
해당 파일 안에 유니코드로 된 텍스트가 들어있나요? 혹시 RCS keyword substitution 으로 쓰이는 내용이 들어있나요?

1.45 이미 Text로 업로드 된 파일을 Binary로 바꿀 수 있는가요?

바이너리로 업로드하려면 -kb옵션을 사용합니다. 예를들어,
$ echo '$Id: CVS_2fFAQ,v 1.99 2005/08/19 01:21:43 kss Exp kss $' > kotest
$ cvs add -kb -m"A test file" kotest
$ cvs ci -m"First checkin; contains a keyword" kotest
입니다.

만약 실수로 -kb옵션을 빠뜨리고 (텍스트로)업로드 했을경우, 바이너리로 복구하려면 cvs admin 옵션으로 아래의 예처럼 바꾸면 됩니다.
$ echo '$Id: CVS_2fFAQ,v 1.99 2005/08/19 01:21:43 kss Exp kss $' > kotest
$ cvs add -m"A test file" kotest
$ cvs ci -m"First checkin; contains a keyword" kotest
$ cvs admin -kb kotest
$ cvs update -A kotest
# For non-unix systems:
# Copy in a good copy of the file from outside CVS
$ cvs commit -m "make it binary" kotest

1.46 이미 Binary로 업로드 된 파일을 Text로 바꿀 수 있는가요?

한글이 들어있는 파일을 WinCVS를 통해서 add/import를 하게 되면 binary를 권장합니다. 이때, 실수로 Binary로 add/import하게 되면 merge기능을 지원하지 않아 불편하게 되지요. 이럴 때, 위의 Text->Binary와는 반대의 작업이 필요하게 되는데, 위의 내용과 같고, 옵션만 -kb가 아닌 -kkv로 해 주면 됩니다.
$ cvs admin -kkv kotest

-- DeleteMe 이것으로 한참 고민하고 이것 저것 해 본 결과 알아 냈습니다만, 여기서 말하는 keyword라는 게 정확하게 의미하는 바를 모르겠습니다. 아시는 분은 설명 부탁드립니다. (-kkv의 help에는 Generate keywords using the default form.라고 되어 있습니다.) barmi

1.47 로그를 잘못 적었는데 고칠 수 없을까요?

$ cvs admin -m1.2:"new log" myprog.c

태그가 붙어 있는 경우라면
$ cvs admin -mV_1_0:"massive new log"
이렇게 한번에 바꾸는 것도 가능합니다.

1.48 Tag에 comment를 붙이는것은 가능한가요

AnswerMe 질문이 조금 애매한것 같습니다. 제목만 보고는 어떤 상황인지 정확히 알 수 없어 답변이 두루뭉실합니다. 조금더 상황을 설명해 주시지요?

tag를 붙이면서 거기에 대한 로그를 어딘가에 기록해둘 수 없냐는 얘긴가요? 그런거라면 대답은 불가능하다 입니다. CVS는 파일 별로 로그를 붙이게 돼 있는 RCS를 계승하기 때문에 각 checkin 별로 기록을 할 수 없다는 단점이 있습니다. 그래서 Subversion 같은 경우 아예 파일별 revision이 아니라 per-checkin revision을 모듈 단위로 붙여주는 방식을 채택했습니다.

만약 tag 자체에 대해 어딘가에 기록을 남기고 싶은 거라면 ChangeLog 나 README 등에 내용을 적어두는 것으로 대체할 수도 있습니다.

질문자입니다. 말씀해 주신 내용이 정확합니다. 제가 보기에도 file 단위로 log message를 남기는 것 같아서 여쭤 보았던 것입니다. 아직 익숙하지 못해서인지 좀 불편한 점으로 생각되어서 질문을 했던 것입니다. :)

http://www.cvstrac.org/ CVS mod인것 같은데 check-in 단위로 기록을 남길수 있습니다. http://www.sqlite.org 에서 사용 하는걸 보면 괜찮아 보입니다.

1.49 Unknown command 라는 에러가 납니다.

Q: 접속시에
cvs [login aborted]: unrecognized auth response from 127.0.0.1: Unknown command: `/home/cvs'
라고 나오네요.. 강좌대로 했다고 생각했는데.. passwd file 문제인가요? redhat 9.0을 쓰고 있읍니다.

A: -d 옵션 (CVSROOT) 줄 때 사용자@서버명:과 /디렉토리/경로 사이에 빈 칸이 들어가 있는 것 같습니다.
$ cvs -d :pserver:anonymous@anonymous.com:/cvsroot
이렇게 전부 붙여줘야 합니다.

1.50 항상 최신버전의 소스를 유지하고 싶어요

항상 최신의 버전을 유지하지 않고 작업을 하니 Commit시 자주 Conflict가 발생합니다. WinCVSTortoiseCVS를 써 보았는데 최신 버전으로 유지해 주는 기능을 안 보이던데요. 덧붙여 update시 발생하는 conflict를 줄이고 싶습니다. update시 merge를 선택적으로 할 수는 없나요? 예를 들어서 '이 파일은 더 최근의 것이 존재합니다. merge할까요? (Y/n)' 이런식으로요.

* WinCVS에서 우선 update합니다. 그럼 merge나 conflict 되어 있을겁니다. 다시 update하면서 update settings중 Get the clean copy를 체크하시면 됩니다.
Clean copy를 받고 싶은게 아니라 local modify 파일은 update를 받고 싶지 않은 경우를 말씀 드렸답니다. ^^ 그리고 update 명령을 자동으로 수행할 수 있는 방법이 있으면 좋겠다는거였습니다. 2가지가 상충된 질문을 드려서 헷갈리셨나 봅니다. _ 감사합니다.
그런 경우 Update query 해서 저장소에 변경된 파일을 확인한 후 그 파일들만 선택해서 업데이트 하시면 됩니다. 스크립트 하나 만들어 보시는 것도 좋을듯 합니다. :)

1.51 이전버전으로 되돌리고 싶어요(Rollback)

http://bbs.kldp.org/viewtopic.php?t=28936

1.52 CVS를 쓸까요 Subversion을 쓸까요?

Q : 이제서야 CVS라는 것에 대해 알게 되어 배워볼까 했더니 CVS의 불편한 점을 개선한 Subversion이 나왔다고 하네요. 처음 배우는 사람은 바로 Subversion을 익혀야 하나요? 아니면 CVS 를 먼저 익혀야 하나요?

A : 대부분의 오픈소스가 CVS로 진행 되니 CVS를 먼저 익히는것이 좋겠죠. Subversion이 안정적이라고 하긴 하나 공식적인 stable 버전은 언제쯤 나올지는... 요즘 한달에 두번씩 버전이 올라가는데 업데이트 해주기 좀 귀찮더군요. CVS에 불만이 생기면 그때 슬슬 바꾸시면 됩니다.

A : SubVersionCVS의 불편한 점을 개선했다기 보다는 완전히 다른 프로그램으로 보는게 맞습니다. 상호 호환성도 없고, 단지 SubVersion에서 기존에 CVS로 운영되던 프로젝트를 import할 수 있게 해놨을 따름입니다. revision/version 관리 모델 자체도 전혀 다릅니다. 시기상 나중에 만들어졌기 때문에 CVS가 가지는 단점들을 상당 부분 개선한 것은 사실입니다만, 개발 모델 자체에 대한 접근 방식이랄까 철학이랄까 그런게 다른 부분이 있어 보여서 제 경우엔 조금 관망하는 중입니다. 버전 컨트롤 프로그램을 전혀 써보지 않은 사람 입장에서 어느 쪽이 더 익히기 쉽다든가 하는 건 잘 모르겠군요. SubVersionCVS를 쓰던 사람은 쉽게 옮겨갈 수 있다고 얘기합니다만 그거랑은 별개라서 말이죠. --verotas

2 help 사용법

버전 확인
$ cvs --version
Concurrent Versions System (CVS) 1.11.2 (client/server)

그냥 cvs만 치면 help 사용법이 자세히 나온다.
$ cvs
Usage: cvs [cvs-options] command [command-options-and-arguments]
  where cvs-options are -q, -n, etc.
    (specify --help-options for a list of options)
  where command is add, admin, etc.
    (specify --help-commands for a list of commands
     or --help-synonyms for a list of command synonyms)
  where command-options-and-arguments depend on the specific command
    (specify -H followed by a command name for command-specific help)
  Specify --help to receive this message

The Concurrent Versions System (CVS) is a tool for version control.
For CVS updates and additional information, see
    the CVS home page at http://www.cvshome.org/ or
    Pascal Molli's CVS site at http://www.loria.fr/~molli/cvs-index.html

특정 명령어 옵션을 자세히 보려면
$ cvs -H update
Usage: cvs update [-APCdflRp] [-k kopt] [-r rev] [-D date] [-j rev]
    [-I ign] [-W spec] [files...]
......

사용할 수 있는 명령어 생략형은 다음과 같다.
$ cvs --help-synonyms
CVS command synonyms are:
        add          ad new
        admin        adm rcs
        annotate     ann 
        checkout     co get
        commit       ci com
        diff         di dif
        export       exp ex
        history      hi his
        import       im imp
        log          lo 
        login        logon lgn
        rannotate    rann ra
        rdiff        patch pa
        release      re rel
        remove       rm delete
        rlog         rl 
        rtag         rt rfreeze
        status       st stat
        tag          ta freeze
        update       up upd
        version      ve ver
(Specify the --help option for a list of other help options)

3 용어

repository working file working directory (or area) checkout commit (checkin) RCS file modules revision tag branch "the trunk" HEAD / BASE merge conflict

4 문서를 만들면서

개인적으로, 몇 년 전 CVS를 처음 배우면서 제일 어려웠던게 간단한 소개 문서는 한글로 된게 있었지만 조금만 더 상세한 걸 찾아보려면 제대로 된 (영어든 한글이든) HOWTO 같은게 있지도 않았고, (지금도 있는지는 모르겠지만) Faq-O-Matic 으로 된 영어 FAQ 사이트가 레퍼런스로 쓸만한 유일한 곳이었습니다. 그래서 그때부터도 처음 오픈소스 세상을 접하는 개발자에게 CVS라는 장벽을 뛰어 넘는데 보탬이 되는 문서 같은게 꼭 필요하다고 느끼고 있었습니다.

그동안 CVS를 다룬 책도 출간되었고 CVS 다음 세대가 될만한 다른 프로그램들도 나왔고 해서 하려고만 든다면 상대적으로 자료 찾기나 배우기가 더 쉬워진 면도 분명 있습니다. 그렇지만 본래 좋은 HOWTO 들이 그러하듯이 처음 시작하는 사람이 딱 그 문서 하나만 찍어서 옆에 두고 손으로 짚어가며 따라하면 일단 ''시작'은 어떻게든 해볼 수 있는 글이 아쉬웠고, 글 서두에 밝혔듯이 현재 존재하는 한글로 된 CVS 관련 문서들은 담고 있는 정보가 가지는 유용성에 비해 집약도(?)가 떨어지고, 사용자에게 필요한 내용과 관리자에게 필요한 내용이 잘 구분이 되어 있지 않아 결과적으로 처음 접하는 사람에게 문턱을 낮추는 역할에 충실하지 못한 부분이 있다고 생각합니다.

장기적으로는 이런 것들을 해결할 수 있는 좋은 글이 나와야 하겠지만, 아쉬운 대로 "KLDP에 있는 문서를 보고 따라하다 보니 이런 문제에서 걸리는데 어떻게 하면 되는 거냐" 하는 질문에 대한 답 정도라도 생각나는 대로 정리해 보자 라고 생각해서 시작하게 됐습니다. 앞으로도 생각나는 대로 항목들 추가해 나가면서 정리해 나갈 생각입니다. --verotas

Thanks to 권순선, 쫑아, voxel, IrIz, Advanced

5 관련 자료

Posted by 1010
98..Etc/Etc...2008. 9. 5. 12:53
반응형
Posted by 1010
98..Etc/Etc...2008. 9. 5. 09:13
반응형
Posted by 1010