웹사이트에서 탭메뉴를 이용하다가 새로고침을 했을 때 첫 번째 탭으로 돌아가 버려서 불편했던 적 있으신가요?
탭메뉴는 좁은 공간에 많은 내용을 담을 수 있어 웹사이트에서 자주 사용하는 UI 요소입니다. 하지만 기본 탭메뉴는 페이지를 새로고침하면 항상 첫 번째 탭으로 돌아가는 문제점이 있죠. 특히 내용이 많은 탭을 보다가 새로고침이 되면, 사용자는 다시 원하는 탭을 찾아 클릭해야 하는 번거로움을 겪게 됩니다. 이 글에서는 URL 파라미터를 활용해 새로고침 후에도 사용자가 마지막으로 봤던 탭을 그대로 유지하는 방법을 알아보겠습니다.
HTML 구조
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| <div class="tab_wrap">
<!-- 탭메뉴 제목 -->
<ul class="tit_list">
<li><a href="#con01">1번째 탭</a></li>
<li><a href="#con02">2번째 탭</a></li>
<li><a href="#con03">3번째 탭</a></li>
</ul>
<!-- 탭메뉴 컨텐츠 -->
<div class="tab_con">
<div id="con01" class="tab_list">
1번째 컨텐츠
</div>
<div id="con02" class="tab_list">
2번째 컨텐츠
</div>
<div id="con03" class="tab_list">
3번째 컨텐츠
</div>
</div>
</div>
|
탭메뉴 제목 영역
탭 제목을 담은 ul 요소로, 각 탭은 li 안에 a 태그로 구성했습니다.
각 a 태그의 href는 연결된 콘텐츠의 id를 가리키는 앵커 링크로 작성했습니다.
탭메뉴 콘텐츠 영역
각 탭에 해당하는 내용을 담고 있는 영역입니다.
각 콘텐츠는 고유한 id를 가지고 있어 탭 제목의 href와 연결됩니다.
CSS 스타일
1
2
3
4
5
6
7
8
9
10
11
| * {margin: 0;padding: 0;font-family: 'Noto Sans KR', sans-serif;box-sizing: border-box;}
ul, li {list-style: none;}
.tab_wrap {max-width: 800px;margin: 50px auto;padding: 0 15px;}
.tab_wrap .tit_list {position: relative;font-size: 0;}
.tab_wrap .tit_list:before {content:'';position: absolute;bottom: 0;left: 0;width: 100%;height: 1px;background: #ddd;z-index: 1;}
.tab_wrap .tit_list > li {display: inline-block;vertical-align: top;margin-right: 3px;}
.tab_wrap .tit_list > li a {display: inline-block;padding: 10px 15px;border: 1px solid #fff;border-radius:4px 4px 0 0;font-size: 14px;color: #000;text-decoration: none;}
.tab_wrap .tit_list > li a:hover {background: #efefef;border-color: #efefef;}
.tab_wrap .tit_list > li.active a {position: relative;border-color: #ddd;border-bottom: 1px solid #fff;background: #fff;color: #8ab4f8;z-index: 2;}
.tab_wrap .tab_con {border: 1px solid #ddd;border-top: none;}
.tab_wrap .tab_con .tab_list {display: none;height: 200px;padding: 15px;}
|
기본 초기화 및 레이아웃
기본 마진과 패딩을 초기화하고, 폰트와 박스 사이징을 설정했습니다.
탭 전체를 감싸는 .tab_wrap은 중앙 정렬과 최대 너비를 지정해 반응형으로 동작합니다.
탭 제목 스타일링
탭 제목 목록은 상대 위치로 설정하고, 하단에 구분선을 넣었습니다.
각 탭 제목은 인라인 블록으로 배치해 가로로 나열되도록 했습니다.
활성화된 탭 스타일
활성화된 탭(.active)은 하단 테두리가 흰색이 되어 콘텐츠 영역과 자연스럽게 이어지고, 글자색은 파란색으로 바뀝니다.
z-index를 사용해 활성화된 탭이 하단 구분선 위에 표시되도록 했습니다.
탭 콘텐츠 영역
탭 콘텐츠는 기본적으로 숨겨두고(display: none), 활성화될 때만 보이게 했습니다.
고정된 높이와 내부 여백으로 콘텐츠를 보기 좋게 배치했습니다.
jQuery 코드
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
| $(window).on('load', function() {
tab();
})
function tab() {
//탭 구분 파라미터 이름
const paramName = 'tabName';
//탭메뉴 실행 함수
function activateTab(tabId, updateUrlParam) {
//tabId 값이 first 일 때 첫번째 탭 선택
tabId = tabId === 'first' ? $('.tab_wrap .tit_list > li:first-child a').attr('href') : tabId;
//초기화
$(".tab_wrap .tit_list > li").removeClass("active");
$(".tab_wrap .tab_list").hide();
//실행
$(`.tab_wrap .tit_list > li a[href*="${tabId}"]`).parent().addClass("active");
$(tabId).show();
//탭메뉴 클릭할 때 url 파라미터 변경
if (updateUrlParam) {
setUrlParam(tabId);
}
}
//파라미터 값 변경 함수
function setUrlParam(tabId) {
const params = new URLSearchParams(location.search);
params.set(paramName, tabId.slice(1));
history.pushState(null, null, `${location.origin}${location.pathname}?${params.toString()}`);
}
//파라미터 확인 함수
function getUrlParam() {
const urlParams = new URLSearchParams(location.search);
return urlParams.get(paramName);
}
//파라미터 값 확인
const tabName = getUrlParam();
//탭메뉴 클릭할 때 실행
$(".tab_wrap .tit_list > li a").on("click", function(e) {
e.preventDefault();
let tabId = $(this).attr("href");
activateTab(tabId, true);
});
//페이지 로드 했을 때 탭메뉴 선택
if (tabName) {
const tabTop = $('.tab_wrap').offset().top;
requestAnimationFrame(function() {
$('html, body').scrollTop(tabTop - 100);
});
activateTab(`#${tabName}`);
} else {
activateTab('first');
}
//뒤로가기, 앞으로가기 버튼 눌렀을 때 탭메뉴 활성화 복원
$(window).on('popstate', function() {
const newTabName = getUrlParam();
activateTab(newTabName ? `#${newTabName}` : 'first');
});
}
|
초기 설정
페이지 로딩이 끝나면 tab() 함수를 실행해 탭메뉴를 초기화합니다.
URL 파라미터 이름으로는 ’tabName’을 사용합니다.
탭 활성화 함수
activateTab() 함수는 선택한 탭을 활성화하는 핵심 기능을 담당합니다.
tabId가 ‘first’면 첫 번째 탭을 자동 선택합니다.
기존에 활성화된 탭을 초기화하고 새로 선택된 탭과 콘텐츠를 보여줍니다.
updateUrlParam이 true면 URL 주소도 함께 업데이트합니다.
URL 파라미터 관리 함수
setUrlParam() 함수는 현재 선택된 탭 ID를 URL 주소에 기록합니다.
getUrlParam() 함수는 URL에서 탭 파라미터 값을 가져옵니다.
URLSearchParams API로 파라미터를 간편하게 관리합니다.
이벤트 처리
탭 클릭 시 기본 앵커 동작을 막고(e.preventDefault()), 대신 activateTab() 함수를 호출합니다.
페이지 로드 시 URL 파라미터를 확인해서 해당 탭을 활성화합니다.
파라미터가 없으면 첫 번째 탭을 기본값으로 보여줍니다.
브라우저 네비게이션 지원
popstate 이벤트를 감지하여 브라우저의 뒤로가기, 앞으로가기 버튼을 눌렀을 때도 올바른 탭이 표시되도록 합니다.
이 기능 덕분에 사용자가 브라우저의 이동 버튼을 눌러도 이전에 보던 탭이 그대로 유지됩니다. 페이지 이동 후에도 정보를 다시 찾는 번거로움 없이 일관된 화면을 볼 수 있어 훨씬 편리합니다.
스크롤 위치 조정
파라미터로 특정 탭을 열 때는 requestAnimationFrame을 사용해 해당 탭메뉴 위치로 화면을 자동 스크롤합니다.
이렇게 하면 긴 페이지에서도 탭메뉴를 바로 볼 수 있습니다.
결론
이번 글에서는 jQuery로 새로고침 후에도 선택한 탭이 유지되는 탭메뉴를 만드는 방법을 알아보았습니다. URL 파라미터를 활용하면 페이지를 새로고침하거나 브라우저의 뒤로가기/앞으로가기 버튼을 눌러도 선택한 탭이 그대로 유지됩니다. 덕분에 사용자는 페이지를 오가며 탐색할 때도 원하는 정보를 쉽게 다시 찾을 수 있고, 일관된 화면을 경험할 수 있습니다.
이 글이 도움이 되셨나요? 탭메뉴를 구현하면서 겪은 다른 문제나 개선 아이디어가 있으시면 댓글로 공유해주세요!