메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

과소평가된 style.display 객체로 구현한 계층적 메뉴

한빛미디어

|

2002-10-15

|

by HANBIT

9,338

저자: 『Designing with JavaScript, 2nd Edition』의 공동저자 빌 페나(Bill Pena), 역 전순재

내가 가장 흔하게 받는 DHTML 요구중의 하나는 윈도우 익스플로러-스타일의 계층형 메뉴와 관련된 것이다. 그 메뉴에는 주제나 "폴더"를 담은 목록이 있어서 사용자가 클릭하면 하부주제, 또는 그 폴더 안에 있는 "파일"을 볼 수 있다. 계층형 메뉴는 보편적인 데스크탑 메타포(metaphor)로서 웹에서 더욱 필요한 것 같다. 특히 네비게이션 바가 더욱 방대하고 더욱 복잡한 내용들을 실현하면서도 여전히 화면에 맞추려고 시도하는 것을 보면 말이다. 계층적 메뉴는 협소한 공간에 많은 링크들이 있을 때 발생하는 문제들을 보편적으로 해결해줄 수 있는 방법이다.

짐작컨데 여러 웹 사이트에서 방대하고 복잡한 스크립트를 찾아보면 이에 해당하는 계층적 메뉴를 만들 수 있을 것이다. 대신, 아주 쓸모있지만 거의 알려지지 않은 DOM CSS 특성인 style.display.visibility를 사용하여 얼마든지 길고 복잡한 여러분만의 메뉴를 만드는 법을 보여 주겠다. 대부분 DHTML 코더들은 이것을 레이어를 보이거나 감추는데 사용되는 기본적인 CSS 특성으로 알고 있다. 레이어의 visibility가 다른 레이어의 위치에 영향을 미칠 때 style.display.visibility을 사용하는 것은 고통이다. 왜냐하면 가시성은 HTML 요소가 사용자에게 보이는지 아닌지에 대해서만 영향을 미치고 그 요소가 페이지에 렌더링될지 안될지는 영향을 미치지 않기 때문이다.

한 요소를 visibility="hidden"이라고 설정하면, 그 요소는 여전히 페이지 공간을 차지하지만 보이지는 않는다. 마치 투명한 것처럼 말이다. 그렇지만 한 요소를 감추어서 여러분의 의도가 마치 메뉴에서 폴더를 닫을 때 예상하는 것처럼 또다른 요소를 위로 이동시키거나 빈 공간을 채우고자 하는데 있다면, 그 첫 번째 요소를 감추었기 때문에 영향을 받은 각 요소의 위치를 명시적으로 재조정 해주어야 한다. 이 작업은 대단히 지루하다. display를 사용하면 요소를 보여주고 감출 수 있지만, visibility가 그러는 것처럼 그냥 보이지 않도록 만들기 보다는 페이지에서 그 요소를 완전히 뽑아 내기 때문에 웹 브라우저는 마치 그 요소가 존재하지 않았던 것처럼 간격을 모두 메워서 페이지를 렌더링하고 화면에 표시할 것이다. 아주 미묘한 차이로만 보일수도 있겠지만 이는 스크립팅 시간과 복잡도에서 엄청난 차이를 만들어 낸다.

그렇지만 안타깝게도 모든 브라우저가 style.display 객체를 지원하는 것은 아니다. 오직 넷스케이프 6과 인터넷 익스플로러 5.5 이상에서만 이 객체를 지원한다. 그러나 CSS2의 표준 특성으로서, 다른 브라우저 메이커들도 이 객체에 대한 지원을 위해 작업중이다. 그래서 허둥지둥 이 객체를 스크립트에서 사용하기 전에, 브라우저 탐지를 사용해서 비표준-준수 브라우저를 가진 사용자들을 방향전환하는 데서부터 시작하자. 브라우저 탐지와 관련된 더 자세한 사항은 『Designing with JavaScript』의 Chapter 6 "Too Many Browsers? Not Really"를(번역하면, 브라우저가 너무 많다고요? 실제로는 그렇지 않습니다) 참고하기 바란다.

색인이 있는 Houdini

조금만 머리를 써서 디자인하면, 왼쪽의 표준적인 네비게이션 바를 단 몇 줄의 자바스크립트로만 사용해서 역동적으로 만들 수 있다. 요점은 어떻게 레이어와 테이블이 내용물을 담은 용기로 행동하는가를 비롯하여 어떻게 레이어와 테이블이 보유한 컨텐츠에 맞추어 그 크기를 자동으로 재조정하는가를 이해하는데 있다. 웹 사이트 디자인에 많은 시간을 소비했다면 테이블에서 컨텐츠가 그 테이블의 크기에 얼마나 중요한지를 충분히 이해할 것이다 "투명, 1-픽셀 GIF" 해킹이 개발되자 웹 디자이너들이 깨달은 것이 있다면 테이블의 내용이 전체 공간을 채우지 않았다면 어떤 브라우저에서는 지정된 너비와 높이의 테이블을 무시하려고 한다는 것이었다.

이제 이 특성을 사용하여 테이블과 레이어를 포함시켜 자동적으로 크기가 조정되어 계층적 메뉴를 만들어 낼 것이다. 요약해서 말하면 필자는 웹 사이트로부터 "Projects"와 "Interests"과 같은 여러 주제 영역을 나열하는 레이어를 만들 것이다. 레이어는 테이블도 담고 있으며, 테이블은 각 영역에 대한 하부-목록을 담고 있다. 각 영역은 처음에 자바스크립트 style.display="none"으로 설정된다. 이 때문에 웹 브라우저는 그 두 주제 링크만을 화면에 표시하고 오직 그 용기 레이어가 그러한 하부링크들을 나열하는데 필요한 높이만을 점유하도록 만든다.

페이지가 적재될 때 테이블의 화면표시 값을 자바스크립트로 변경하면, 그 용기 레이어는 테이블에 맞도록 크기가 조정될 것이다. 그리고 링크들은 마치 전혀 존재하지 않다가 갑자기 존재한 것처럼 나타날 것이다. 성공이다! 그것이 우리 메뉴를 비롯해서 다른 많은 DHTML 트릭의 기본 토대이다! 이렇게 DOM CSS 객체 하나(이 경우에는 style.display)를 간단하게 조작하고 약간의 천재성을 더하면 엄청나게 경이로운 일들을 할 수 있다.

이제 우리가 만들 메뉴를 살펴 보자. 이것이 어떻게 하나로 결합되는지 더 잘 이해할 수 있다.

보시다시피, 먼저 "Projects"와 "Interests"라는 두 개의 링크를 가진 레이어가 하나 있다. "Projects"가 클릭되면 메뉴는 확장되어 "Projects" 아래의 하부링크들을 담은 목록을 화면에 표시한다. HTML에서 보면 상당히 간단하지만 id 속성을 오른쪽에 추가하면 자바스크립트로 이러한 링크들을 따로따로 화면에 표시하고 숨길 수 있는 능력을 가질 수 있다.
Projects Designing with JavaScript Hypercubes ... Interests ...
이 메뉴를 또다른 레벨로 아주 쉽게 확장할 수 있다. 그리고 또다른 테이블을 포함시키면 장들을 『Designing with JavaScript』 링크의 아래에 보여 줄 수 있다.
Projects Designing with JavaScript Chapter 1 Chapter 2 Chapter 3 ...
Hypercubes ... ...
그리고 다음과 같은 결과를 얻는다.

이제 그만, 코드를 보여줘요!

이 스크립트는 단지 서로 보충해 주는 함수 한 쌍만을 요구한다. hideLevel()showLevel()가 그 쌍이다. 각 함수는 "projectlinks"와 "chapters"처럼 자신이 작동할 메뉴 "레벨"의 id를 취한다. 그리고 그 id를 사용하여 그 레벨의 display 설정을 반대로 뒤집는다.
function hideLevel( _levelId) {
    var thisLevel = document.getElementById( _levelId );
    thisLevel.style.display = "none";
    }

function showLevel( _levelId) {
    var thisLevel = document.getElementById( _levelId );
    if ( thisLevel.style.display == "none") {
        thisLevel.style.display = "block";
        }
    else {
        hideLevel( _levelId);
        }
    }
자질구레한 것을 좀 줄여 보기 위해 필자는 showLevel()이 레벨을 보여주고 감추는 두 상황 모두를 다룰 수 있도록 만들기로 결정하였다. if 서술문을 포함시켜 그 레벨이 이미 화면에 표시되었는지 아닌지 점검한다. 이렇게 하면 링크들이 항상 showLevel()을 호출하도록 만들 수 있지만 스크립트에게 어느 함수가 적절한지 알려 주어야 하고 올바른 함수를 실행하도록 만들어야 한다. 만약 예를 들어 『Designing with JavaScript』 아래에 장들을 담은 목록을 이미 볼 수 있다면, 그 링크를 클릭하면 장들을 보여주는 대신에 감출 것이다.
Designing with JavaScript, 2nd Edition

참고 도서

Designing with JavaScript, 2nd Edition
Nick Heinle & Bill Pena




솔직히 말해, 스크립트는 이보다 약간 더 복잡하다. 위의 스크린 샷에서 눈치챘겠지만 링크들 옆에 덧셈기호와 뺄셈기호를 포함시켜서 레벨의 상태를 나타내었다. 이런 시각적 도움은 계층적 메뉴라는 메타포를 보충한 것인데, 기본적으로 윈도우 익스플로러의 "폴더 보기"를 흉내낸 것이다. 이런 기능을 추가하는 것은 어렵지 않다. 이미지 롤오버(image rollover)를 만들어 본 경험이 있다면, 이미 어떻게 하는지 알고 있는 셈이다.

먼저 한 쌍의 이미지 객체를 만들고 이미지들을 스크립트 안으로 적재한다.
var plusImg = new Image();
    plusImg.src = "./images/plus.png"
var minusImg = new Image();
    minusImg.src = "./images/minus.png"
그리고나서, 이전의 hideLevel() 함수와 showLevel() 함수를 약간 변경해서 클릭되는 링크 옆에다 덧셈기호 또는 뺄셈기호를 서로 전환하도록 만들기만 하면 된다.
function hideLevel( _levelId, _imgId ) {
    var thisLevel = document.getElementById( _levelId );
    var thisImg = document.getElementById( _imgId );
    thisLevel.style.display = "none";
    thisImg.src = plusImg.src;
    }

function showLevel( _levelId, _imgId ) {
    var thisLevel = document.getElementById( _levelId );
    var thisImg = document.getElementById( _imgId );
    if ( thisLevel.style.display == "none") {
        thisLevel.style.display = "block";
        thisImg.src = minusImg.src;
        }
    else {
        hideLevel( _levelId, _imgId);
        }
    }
이전에는 함수에다 조작될 레벨인 id 한 개를 그저 건냈을 뿐이지만 이제 다음 링크의 이미지 id를 건네줄 필요가 있다. 그래서 링크는 이제 다음과 같이 보인다.
Projects
마지막이지만 결코 무시할 수 없는 것이 남았다. 우리는 페이지가 적재될 때 메뉴가 완전히 닫혀 있기를 원하며 모든 링크들이 화면에 표시된 채로 열려 있기를 원하지 않는다. 그렇게 되면 메뉴를 만드는 지점을 잃어 버리게 되기 때문이다. 그래서 함수 하나가 더 필요하다. hideAll() 함수가 그것인데 페이지가 모든 링크들을 한 번에 적재하거나 감출 때 이 함수가 호출된다. 남은 일은 이제 메뉴의 각 레벨에 대하여 한번씩, 여러 번 hideLevel() 함수를 호출하는 함수를 하나 만드는 일 뿐이다.
function hideAll() {
    hideLevel("chapters", "chapImg");
    hideLevel("projectlinks", "projImg");
    hideLevel("interestlinks", "intsImg");
    }
그리고 다음과 같이 페이지가 적재될 때 hideAll()에 대한 호출을 하나 추가하라:

이게 다이다.

이제 어떻게 이 스크립트가 작동하는지 분석하여 보았으므로, 완성된 제품을 살펴 보자. 그리고 자유롭게 필요에 따라 응용해보자. 브라우저 탐지를 사용하는 것을 잊지마라! style.display를 사용하여 탐험해 보았다면 나에게 여러분의 경험을 알려달라. 그리고 쓸모를 발견하면 나에게 알려달라.


빌 페나(Bill Pena)는 프리랜서 웹/정보 디자이너겸 저자이다. 그는 오라일리의 온라인 북 서비스인 safari: Tech Books Online을 디자인하기도 하였다.
TAG :
댓글 입력
자료실

최근 본 책0