라디오버튼과 CSS로 만드는 탭(Tab) 인터페이스
라디오버튼은 하나의 그룹으로 묶은 버튼들 중에서 1개만 선택(체크) 상태가 되는 특징이 있습니다.
이런 특징을 활용하면 목록으로 표현되는 컨텐츠를 작은 영역 안에서 탭(Tab)으로 전환해가면서 볼 수 있는 UI를 만들 수 있습니다.
탭 인터페이스는 현재 선택된 탭 1개의 컨텐츠만 보이는 구조이기 때문에 라디오버튼의 특징을 활용하면 자바스크립트 없이도 탭 인터페이스를 구현할 수 있습니다.
<ul class="tabs">
<li class="tab">
/* 첫 번째 탭에는 "checked" 속성을 추가해 활성화 시킴 */
<input type="radio" id="tab-1" name="tab-group-1" checked>
<label for="tab-1">탭1</label>
<div class="content">
<p>컨텐츠1</p>
</div>
</li>
<li class="tab">
<input type="radio" id="tab-2" name="tab-group-1">
<label for="tab-2">탭2</label>
<div class="content">
<p>컨텐츠2</p>
</div>
</li>
<li class="tab">
<input type="radio" id="tab-3" name="tab-group-1">
<label for="tab-3">탭3</label>
<div class="content">
<p>컨텐츠3</p>
</div>
</li>
</ul>
CSS를 작성할 때 ".tab" 클래스는 ".tabs li" 로 접근을 할 수 있지만, 접근하는 뎁스를 줄이기 위해, 또 목록의 아이템 1개에 대한 정의가 전부인 탭 인터페이스기 때문에 개별 탭에 ".tab" 클래스를 부여해서 CSS 선택자 뎁스를 단순화 했습니다.
라디오버튼으로 반응형 UI를 작성하는 기본 구조인 "input + label + .content" 1개를 탭 1개로 구현하며, "<label>" 태그는 클릭해서 탭을 이동하는 탭 헤더로 사용하게 됩니다.
.tabs {
position: relative;
padding: 0;
list-style: none;
}
.tab {
float: left;
padding: 10px 0;
}
.tab label { /* 탭 헤더 */
position: relative;
background: #eee;
padding: 8px 20px;
border: 1px solid #ccc;
}
.tab [type="radio"] {
display: none;
}
.tab .content { /* 탭 컨텐츠 */
display: none;
position: absolute;
background: white;
top: 39px; /*탭 헤더 아래쪽으로 위치 이동 */
left: 0;
right: 0;
padding: 0;
box-sizing: border-box;
border: 1px solid #ccc;
}
.tab [type="radio"]:checked ~ label {
background: white;
border-bottom: 1px solid white;
z-index: 2; /* 선택한 탭 헤더를 앞으로 옮겨 컨텐츠 테두리 선에 가려지지 않도록 처리 */
}
.tab [type="radio"]:checked + label + .content {
z-index: 1;
display: block;
}
표시하는 컨텐츠는 애니메이션 속성을 추가해서 다음처럼 동적인 움직임이 있는 탭 인터페이스를 만들 수 있습니다.
트랜지션 애니메이션을 적용하려면 높이 값이 있어야 하기 때문에 애니메이션 속성을 추가하는 탭 인터페이스를 구현할 때는 탭 컨텐츠 영역 속성에 높이 값을 추가해야 합니다.
높이 값 속성이 탭 인터페이스에 추가되면 탭 컨텐츠의 모든 내용이 표시되지 않기 때문에 세로 스크롤바가 자동으로 표시되도록 속성(overflow-y: auto;)을 추가해야 합니다.
애니메이션 되는 컨텐츠 내용은 왼쪽에서 오른쪽으로 애니메이션 되며, 현재 선택한 탭 컨텐츠를 제외한 나머지 컨텐츠들은 컨텐츠 영역 너비만큼 왼쪽으로 이동("transform: translateX(-100%);")해 있습니다. 따라서 이 컨텐츠들이 보이지 않도록 감추어야 하기 때문에 ".tabs" 클래스에 "overflow: hidden;" 속성을 추가해 탭 인터페이스 외곽에 있는 컨텐츠 들이 보이지 않도록 해야 합니다.
.tabs {
position: relative;
padding: 0;
list-style: none;
min-height: 300px; /* 탭 인터페이스 전체 높이 지정 - 애니메이션에 필수 */
overflow: hidden; /* 탭 외곽에 위치한 나머지 탭 컨텐츠가 보이지 않도록 가림 */
}
.tab {
float: left;
padding: 10px 0;
}
.tab label { /* 탭 헤더 */
position: relative;
background: #eee;
padding: 8px 20px;
border: 1px solid #ccc;
}
.tab [type="radio"] {
display: none;
}
.tab .content { /* 탭 컨텐츠 영역 */
position: absolute;
background: white;
top: 39px;
left: 0;
right: 0;
bottom: 0;
box-sizing: border-box;
border: 1px solid #ccc;
overflow-y: auto;
}
.tab .content > article { /* 컨텐츠 영역 프레임 유지를 위해 내부에 실제 애니메이션 블록 생성 */
transform: translateX(-100%);
transition: all 0.5s ease-in-out;
}
.tab [type="radio"]:checked ~ label {
background: white;
border-bottom: 1px solid white;
z-index: 2; /* 선택한 탭 헤더를 앞으로 옮겨서 컨텐츠 영역 테두리에 가져지지 않도록 함 */
}
.tab [type="radio"]:checked + label + .content {
z-index: 1;
}
.tab [type="radio"]:checked + label + .content > article { /* 실제 컨텐츠 블록 애니메이션 */
display: block;
transform: translateX(0);
}
애니메이션 방향은 원하는대로 설정할 수는 있지만, 애니메이션 효과를 위해 높이를 제한함으로써 예기치 않은 문제가 생길 가능성이 있습니다. 예를 들어 오른쪽에서 왼쪽으로 애니메이션 되도록 할 경우 다음처럼 애니메이션 되는 동안 가로 스크롤바가 생겼다 사라지는 문제가 생깁니다.
완성된 소스는 다음 링크를 클릭해서 다운로드 할 수 있습니다.