개발 slecs

갭 드롭다운 KPI 가독성과 스타일 일관성 개선

목차

갭 드롭다운 테이블 하나를 손보는 작업이었는데, 파일은 뷰/스타일 1개짜리였다. 변경 범위가 좁다고 해서 가볍게 넘어갈 수 있는 작업은 아니었다. KPI 숫자를 표시하는 영역이라 잘못 건드리면 숫자가 잘려 보이거나 배경색이 텍스트를 삼켜버리는 상황이 생긴다. 그게 금융/결제 도메인에서 나타나면 단순 디자인 버그가 아니라 사용자 신뢰 문제로 직결된다.

드롭다운 안에 집계 숫자를 보여주는 구조 자체는 이미 있었고, 기능은 동작하고 있었다. 문제는 숫자와 보조 텍스트가 같은 크기로 나란히 있어서 한눈에 뭐가 중요한 수치인지 잡히지 않는다는 거였다. 행간도 좁아서 여러 행이 붙어 보였고, 강조 색상도 없어서 양수/음수 갭이 시각적으로 구분되지 않았다.

무엇을 바꿨고 왜

핵심 변경은 네 가지였다.

  • KPI 숫자 폰트 사이즈를 키워서 시선이 먼저 거기 가도록 계층을 만들었다
  • 행간과 자간을 미세하게 열어서 테이블 행 사이 구분감을 살렸다
  • 날짜, 단위, 괄호 안 보조 정보는 폰트 크기와 opacity를 낮춰서 배경으로 밀었다
  • 갭 수치에 강조 색상을 올려서 양수/음수를 즉시 구별할 수 있게 했다

정보 계층(information hierarchy)을 만드는 게 목적이었다. 모든 텍스트가 같은 크기로 있으면 사람 눈은 어디서부터 읽어야 할지 몰라서 전체를 훑게 된다. 반면 크기와 무게(weight), 색상 대비로 계층을 주면 중요한 숫자가 먼저 눈에 들어오고 보조 정보는 필요할 때만 확인하게 된다.

색상 대비는 WCAG AA 기준 4.5:1을 최소 목표로 잡았다. 보조 텍스트는 opacity를 낮추는 방식을 썼는데, 이때 배경색이 흰색이 아니면 체감 대비가 생각보다 크게 떨어진다. 드롭다운이 카드 위에 떠 있고 카드 배경이 약간 회색 계열이라면 rgba 계산을 실제 배경색 기준으로 다시 해야 한다. 그냥 opacity: 0.5를 올리면 대비가 충분하다고 착각하기 쉽다.

CSS 작성 원칙과 실제 패턴

이런 스타일 작업에서 가장 흔하게 무너지는 게 specificity 관리다. 기존 스타일을 빠르게 덮으려고 !important를 박으면 그 시점에는 동작하는 것처럼 보이지만, 나중에 누가 그 위에 또 !important를 쌓기 시작하면 걷잡을 수 없어진다. 이번 작업에서는 !important 없이 선택자 specificity를 올리는 방식으로만 작성했다.

/* 나쁜 예 — 나중에 덮기 어려워진다 */
.kpi-value {
  font-size: 20px !important;
  color: var(--primary) !important;
}

/* 나은 예 — 컴포넌트 네임스페이스로 specificity 확보 */
.gap-dropdown .kpi-row .kpi-value {
  font-size: 20px;
  color: var(--primary);
}

색상, 폰트 사이즈 기준값은 전부 CSS 커스텀 프로퍼티로 빼뒀다. 한 곳에서 값을 바꾸면 드롭다운 전체에 반영되기 때문에 나중에 디자인 토큰이 바뀌어도 여러 파일을 돌아다닐 필요가 없다.

:root {
  --kpi-primary-size: 18px;
  --kpi-secondary-size: 12px;
  --kpi-secondary-opacity: 0.55;
  --gap-positive: #2ecc71;
  --gap-negative: #e74c3c;
}

.kpi-value {
  font-size: var(--kpi-primary-size);
  font-weight: 600;
  letter-spacing: -0.02em;
}

.kpi-label {
  font-size: var(--kpi-secondary-size);
  opacity: var(--kpi-secondary-opacity);
}

SCSS 환경이라면 반응형 브레이크포인트 mixin을 만들어두는 게 장기적으로 편하다. 모바일/태블릿/데스크톱에서 각각 폰트 사이즈를 다르게 가져가야 할 때, mixin 없이 작성하면 미디어 쿼리가 파일 곳곳에 흩어지고 나중에 브레이크포인트 값 하나 바꾸는 게 대규모 검색/치환 작업이 된다.

@mixin respond-to($breakpoint) {
  @if $breakpoint == 'tablet' {
    @media (max-width: 768px) { @content; }
  } @else if $breakpoint == 'mobile' {
    @media (max-width: 480px) { @content; }
  }
}

.kpi-value {
  font-size: 18px;

  @include respond-to('tablet') {
    font-size: 16px;
  }

  @include respond-to('mobile') {
    font-size: 14px;
  }
}

이번엔 SCSS가 아니라 단일 스타일 파일이어서 mixin까지 갈 필요는 없었지만, 컴포넌트가 여러 해상도에서 쓰인다면 이런 구조가 나중에 훨씬 낫다.

이 정도 작업에서도 놓치기 쉬운 것들

변경 후 확인할 때 같은 케이스로 비교하는 습관이 중요하다. 단순히 "화면이 예쁘게 보이는가"가 아니라, 실제로 숫자가 잘리지 않는지, 긴 텍스트가 줄바꿈될 때 레이아웃이 깨지지 않는지, 드롭다운이 열릴 때 내부 콘텐츠 높이가 의도한 대로 잡히는지를 구체적인 케이스로 확인해야 한다.

확인 항목 방법
긴 텍스트 줄바꿈 실제 긴 데이터나 lorem 텍스트로 강제 확인
색상 대비 DevTools Accessibility 탭 또는 browser extension
모바일 해상도 DevTools 반응형 모드로 375/414/768px 각각
폰트 렌더링 OS별 차이 있으므로 가능하면 macOS/Windows 모두

스타일 파일 하나짜리 커밋이어도 커밋 메시지는 "무엇을 바꿨다"보다 "왜 바꿨다"를 담으려 한다. fix: 갭 드롭다운 KPI 폰트 사이즈 조정보다는 fix: 갭 드롭다운 KPI 가독성 개선 - 정보 계층 명확화가 세 달 후에 git log를 볼 때 훨씬 빠르게 컨텍스트를 복원시켜준다.

사내 서비스를 만들다 보면 파일 하나짜리 변경이 얼마나 많은 층위에 걸쳐 있는지를 계속 느낀다. 스타일 하나 바꾼 것 같지만 SQL 집계 결과가 올바르게 화면에 안착하려면 그 위에 상태 머신, 렌더링 로직, 권한 체크가 다 제대로 돌아야 한다. 어느 하나가 맞지 않으면 숫자가 틀리거나 특정 사용자에게 이상한 화면이 나타난다. 특히 금융/결제 도메인에서는 "대충 맞는 것 같다"로 넘어가면 반드시 다시 돌아온다. 꼼꼼함이 기본값이어야 하는 이유가 거기 있다.

댓글 0

첫 댓글 달아줘.