lifecarelog
프론트엔드

감정 기록 잔디 히트맵, CSS grid로 만들고 스크린리더까지

한 해의 감정 기록을 잔디처럼 한 화면에 보여주는 히트맵을 CSS grid로 만들고, 색맹·스크린리더 사용자까지 챙기는 접근성 처리를 정리했어요.

5분 읽기

한 해 동안 감정을 매일 기록하면, 그 흐름을 한 화면에서 보고 싶어질 때가 있어요. 깃허브 잔디처럼 요일은 세로로, 주는 가로로 쌓아 올린 그 격자 말이에요. 라이브러리를 붙이면 금방이지만, 이건 CSS grid 몇 줄이면 충분한 화면이라 직접 만들어 봤어요.

왜 굳이 grid인가

잔디 히트맵은 규칙이 단순해요. 세로 7칸(요일), 가로로 약 52~53주. 이 구조는 좌표가 정확히 떨어지는 격자라서 <table>이나 별도 차트 라이브러리보다 CSS grid가 더 잘 맞아요. 값 하나당 칸 하나, 색 하나. 애니메이션도 없고 축 계산도 필요 없으니 그림 라이브러리를 하나 더 얹을 이유가 없더라고요.

뼈대는 세 줄이면 돼요

핵심은 grid-auto-flow를 열 방향으로 돌리는 거예요. 이렇게 하면 데이터를 날짜 순서대로 넣기만 해도 세로 7칸을 채우고 자동으로 다음 주 열로 넘어가요.

.heatmap {
  display: grid;
  grid-template-rows: repeat(7, 1fr);
  grid-auto-flow: column;
  gap: 3px;
}
.cell { aspect-ratio: 1; border-radius: 2px; }

직접 돌려 보니 데이터 배열 순서만 맞추면 별도 좌표 계산 없이 정렬이 딱 맞았어요. 색은 기록 강도에 따라 5단계로 나눴어요. 0회는 옅은 회색, 많을수록 진하게. 여기까지는 10분이면 화면에 뜨더라고요.

날짜순 데이터 배열grid 자동 배치강도별 색 매핑

색만으로 말하면 안 돼요

문제는 여기부터예요. 색 강도로만 정보를 주면 색각 이상이 있는 사용자에게는 옅은 색과 진한 색이 거의 같아 보일 수 있어요. 테스트해 보니 명도 차이를 충분히 벌리는 게 첫 번째 안전장치였어요. 강도를 색조가 아니라 밝기 단계로 설계하면 흑백으로 봐도 구분이 남아요. 보조로 각 칸에 기록 횟수를 데이터 속성으로 넣어두면 색이 무너져도 정보는 살아 있어요.

스크린리더가 읽을 수 있게

CSS grid로 그린 div 격자는 의미가 없는 네모의 나열일 뿐이에요. 스크린리더에는 아무 뜻도 전달되지 않아요. 그래서 칸마다 상태를 문장으로 붙여줬어요.

<div class="cell" role="img"
     aria-label="8월 6일, 기록 3회, 강도 높음">
</div>

role="img"aria-label 조합이면 시각 정보를 짧은 문장으로 대체할 수 있어요. 다만 칸이 수백 개라 하나하나 다 읽히면 오히려 방해가 돼요. 만들어 보면서 느낀 건, 전체 격자는 요약 하나만 읽어주고 개별 칸은 초점을 맞췄을 때만 읽히도록 나누는 편이 낫다는 거예요. 색·명도·문장 이렇게 세 겹으로 정보를 겹쳐 두면, 어떤 감각으로 보든 같은 내용이 전해져요.

  • 명도 5단계
  • 데이터 속성 백업
  • aria-label 문장

감정 기록은 숫자가 아니라 흐름이라 이런 시각화가 잘 어울려요. 지금 만들고 있는 플랜티(plan-t)에서도 이 히트맵 방식을 감정 흐름 화면에 적용해 보는 중이에요. 화면을 예쁘게 만드는 것과 모두가 읽을 수 있게 만드는 건 따로가 아니더라고요. 색을 고를 때 명도 차이 한 번, 칸을 만들 때 문장 한 줄. 그 작은 습관이 결국 접근성을 만들어요.

#CSS grid#접근성#히트맵

라이프케어로그 서비스가 궁금하신가요?

AI 기반 건강·일정·재활 관리 앱을 직접 써보세요.

서비스 살펴보기

관련 글

댓글

아직 댓글이 없어요. 첫 댓글을 남겨주세요.