- Published on
페이지네이션 가독성 리디자인 회고 — 파란색 테마 위의 활성 상태 표현
- Authors

- Name
- Hyo814
페이지네이션 가독성 리디자인 회고 — 파란색 테마 위의 활성 상태 표현
게시판 페이지네이션을 Bootstrap 기본 스타일로 붙여뒀더니, 실제 화면에서 활성 페이지 번호가 전혀 눈에 안 띄는 문제가 있었습니다. 원인을 파고 들어가 보니 사이트 전체 테마와의 충돌이었고, 결국 전면 리디자인으로 해결했습니다. 그 과정을 정리합니다.
1. 증상 — 현재 페이지가 어디인지 모르겠다
Bootstrap의 기본 페이지네이션은 활성 상태에 background-color: var(--bs-primary) 를 씁니다. 기본값은 파란색 계열이죠.
문제는 이 서비스의 브랜드 컬러 자체가 파란색이었다는 점입니다. 헤더, 링크, 주요 버튼이 전부 파란색이라, 활성 페이지 번호도 파란 배경에 흰 숫자로 나오는데 주변의 비활성 페이지 번호도 파란 글자라서 색상 대비가 거의 사라졌습니다.
<!-- 기본 Bootstrap -->
<ul class="pagination">
<li class="page-item"><a class="page-link">1</a></li>
<li class="page-item active"><a class="page-link">2</a></li>
<li class="page-item"><a class="page-link">3</a></li>
</ul>
사용자 피드백:
"지금 몇 페이지에 있는지 한눈에 안 들어와요."
"이전/다음 버튼도 그냥 텍스트라 클릭 가능한지 헷갈려요."
2. 원인 분석 — 세 가지가 겹친 문제
단순히 색만 바꾸는 걸로 해결되지 않겠다 싶어서, 문제를 세 개로 분해했습니다.
2.1 색상 충돌
활성 페이지의 파란색이 사이트의 어떤 파란색 인지 구별이 안 됩니다. 헤더도 파랑, 링크도 파랑, 활성 페이지도 파랑.
2.2 모양 차이 없음
활성/비활성이 동일한 모양(직사각형)에 색만 반전되어 있습니다. 시각적 hierarchy가 색 하나에만 의존하는 상태.
2.3 "이전/다음" 의 클릭 가능성 애매
< > 문자만 있어서 버튼이 아니라 구분자처럼 보입니다. 특히 비활성 상태(첫/마지막 페이지)에서는 회색 텍스트라 더 그렇습니다.
3. 리디자인 방향 — 형태·그림자·아이콘 세 축으로
색상 하나가 아니라 형태+그림자+아이콘 세 가지를 동시에 써서 hierarchy를 만들기로 했습니다.
| 요소 | 비활성 | 호버 | 활성 |
|---|---|---|---|
| 배경 | 흰색 | 연한 회색 | 진한 파란색 |
| 테두리 | 회색 1px | 진한 회색 1px | 없음 |
| 그림자 | 없음 | 얕은 그림자 | 진한 그림자 |
| 글자 | 진한 회색 | 검정 | 흰색 |
| 모양 | 평면 | 약간 떠보임 | 카드처럼 떠있음 |
"카드형" 이라고 부른 이유: 활성 페이지가 약간 떠올라 보이는 입체감을 줬습니다. 그림자가 있으면 색만 볼 때보다 훨씬 빠르게 "이게 지금 위치" 임을 인지합니다.
4. 구현 — 커스텀 CSS 클래스
Bootstrap 기본 클래스를 오버라이드하는 대신, 별도 클래스를 만들어서 섞었습니다. 유지보수할 때 "내가 건드린 것" 과 "Bootstrap 기본" 을 구분하기 위해서입니다.
/* static/css/pagination.css */
.pagination--card .page-link {
min-width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #d9d9d9;
border-radius: 8px;
color: #333;
background: #fff;
margin: 0 4px;
transition: all 0.15s ease;
}
.pagination--card .page-link:hover {
background: #f5f5f5;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
color: #000;
}
.pagination--card .page-item.active .page-link {
background: #2a4dd0; /* 사이트 파랑보다 한 톤 진하게 */
border-color: transparent;
color: #fff;
box-shadow: 0 4px 12px rgba(42, 77, 208, 0.35);
transform: translateY(-1px);
}
.pagination--card .page-item.disabled .page-link {
background: #f7f7f7;
color: #bbb;
}
포인트:
- 활성 색은 브랜드 파랑보다 한 톤 진하게. 완전히 다른 색으로 바꾸면 브랜드 일관성이 깨지고, 똑같이 쓰면 본래 문제로 돌아갑니다.
transform: translateY(-1px)— 1px만 띄워도 "지금 여기" 가 확 살아납니다. 과하게 띄우면 버튼이 잘려 보이니 주의.min-width— 숫자 페이지와 아이콘 페이지(<,>)의 너비를 통일해서 라인이 흔들리지 않게.
5. 이전/다음 버튼 — 텍스트에서 아이콘으로
<, > 문자는 대체로 폰트마다 다르게 그려지고, 특히 안티에일리어싱이 어중간할 때 삐뚤어 보입니다. 아이콘으로 교체했습니다.
<li class="page-item {% if not page.has_previous %}disabled{% endif %}">
<a class="page-link" href="?page={{ page.previous_page_number }}" aria-label="이전">
<i class="bi bi-chevron-left"></i>
</a>
</li>
...
<li class="page-item {% if not page.has_next %}disabled{% endif %}">
<a class="page-link" href="?page={{ page.next_page_number }}" aria-label="다음">
<i class="bi bi-chevron-right"></i>
</a>
</li>
aria-label— 아이콘만 있으면 스크린 리더가 읽을 게 없습니다. "이전", "다음" 을 명시합니다.<을<로 직접 쓸 때의 위험: 템플릿 엔진에 따라 이스케이프 동작이 달라집니다. 아이콘 쪽이 안전.
6. 페이지 범위 표시 — "1 ... 4 5 6 ... 20"
글이 많아지면 페이지 번호가 화면을 꽉 채우는 문제가 있어서, 현재 페이지 기준 앞뒤 2개 씩만 보여주고 나머지는 ... 으로 축약했습니다.
# board/templatetags/pagination_extras.py
from django import template
register = template.Library()
@register.simple_tag
def pagination_range(page_obj, window=2):
current = page_obj.number
total = page_obj.paginator.num_pages
start = max(1, current - window)
end = min(total, current + window)
pages = list(range(start, end + 1))
if start > 1:
pages = [1, '...'] + pages
if end < total:
pages = pages + ['...', total]
return pages
템플릿에서는 '...' 이면 클릭 불가한 span으로, 숫자면 링크로 렌더링합니다. 이 패턴은 어느 프레임워크에서나 동일하게 쓸 수 있습니다.
7. 회고 — "기능은 되는데 안 보이는" 것도 버그다
처음에는 이 문제를 "사소한 CSS 이슈" 로 미뤄뒀습니다. 기능적으로는 클릭하면 페이지가 넘어가니까요. 하지만 실제 사용자 테스트를 해 보면 "지금 몇 페이지인지 모르겠다" 는 피드백이 가장 먼저 나왔습니다. 기능이 완성이어도 현재 상태를 인지할 수 없으면 실패입니다.
작업을 마치고 배운 것:
- 색 하나로 상태를 표현하면 테마와 충돌하기 쉽다. 형태·그림자·아이콘을 보조 축으로 가져가면 훨씬 안전.
- Bootstrap 기본 스타일을 오버라이드할 때는 별도 클래스로.
.page-item.active를 직접 덮어쓰지 말고.pagination--card .page-item.active식으로 스코프를 좁히는 편이 유지보수에 유리. - aria-label은 기능 구현의 일부다. 아이콘을 넣는 순간 세트로 들어가야 합니다.
기능이 완성된 이후에 오히려 "지금 여기가 어디인지 보여주는" 작은 UI 가 체감 품질을 크게 끌어올린다는 걸 다시 한 번 확인했습니다.