logo

DowanKim

9. 전시 현장에서 생겼던 방명록 높이계산 알고리즘 문제

2025년 12월 10일

졸업논문 대체 웹사이트

방명록 레이아웃의 높이 계산 알고리즘 개선

졸업 전시 웹사이트의 방명록은 3개 컬럼에 메시지를 배치합니다. 각 메시지는 박스 형태이고, 높이는 내용에 따라 달라집니다. 목표는 세 컬럼의 높이를 최대한 균등하게 유지하는 것이었습니다.

초기 구현은 간단한 추정 알고리즘을 사용했습니다:

// 초기 코드 (문제가 있던 버전) const messageLines = Math.max(1, Math.ceil(msg.message.length / 30)); const estimatedHeight = Math.max( 11.67, 11.67 + (messageLines - 1) * 1.5 );

이 방식은 메시지가 적을 때는 큰 문제가 없었습니다. 하지만 전시가 진행되면서 메시지가 db에 쌓이고, 늘어나자 문제가 생겼습니다.

1. 누적 오차의 증가

각 메시지의 높이를 추정할 때 작은 오차가 발생합니다.(임시로 높이를 추정해서) 메시지가 적을 때는 오차가 작아 보이지만, 메시지가 많아지면 오차가 누적됩니다.

예를 들어:

  • 메시지 10개: 각각 5px 오차 → 총 50px 오차
  • 메시지 100개: 각각 5px 오차 → 총 500px 오차

2. 실제 렌더링과의 차이

추정 알고리즘은 다음과 같은 요소를 정확히 반영하지 못했습니다:

  • 실제 폰트 렌더링 (폰트마다 문자 너비가 다름)
  • 단어 단위 줄바꿈
  • 한글/영문/숫자/특수문자 조합
  • 브라우저별 렌더링 차이

3. 복잡한 텍스트 처리

실제 메시지는:

  • 긴 문장과 짧은 문장이 섞임
  • 줄바꿈이 포함된 경우
  • 이모지나 특수문자 포함

이런 경우 추정이 더 부정확해집니다.

Canvas API 시도 (그리고 포기)

더 정확한 계산을 위해 Canvas API를 사용해 텍스트의 실제 너비를 측정했습니다:

// Canvas API를 사용한 시도 (최종적으로 사용하지 않음) const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); context.font = "400 9px Pretendard"; const metrics = context.measureText(testLine);

하지만 이 방법도 문제가 있었습니다:

  1. 폰트 로딩 타이밍: 폰트가 완전히 로드되기 전에 측정하면 부정확
  2. 실제 DOM 렌더링과의 차이: Canvas 측정과 실제 브라우저 렌더링이 다를 수 있음(실제로 약간 달랐음)
  3. 복잡도 증가: 코드가 복잡해지고 유지보수가 어려워짐

결국 Canvas API 방식은 제외했습니다.

최종 해결책: 실제 DOM 요소로 높이 측정

최종적으로 실제 DOM 요소를 생성해 높이를 측정하는 방식으로 변경했습니다:

// 최종 해결책: 실제 DOM 요소로 높이 측정 const tempContainer = document.createElement("div"); tempContainer.style.position = "absolute"; tempContainer.style.visibility = "hidden"; tempContainer.style.width = isMobile ? `${(containerRef.current.offsetWidth - 8) / 3}px` : `${containerRef.current.offsetWidth * 0.2}px`; document.body.appendChild(tempContainer); // 실제 스타일을 적용한 임시 박스 생성 const tempBox = document.createElement("div"); tempBox.style.width = "100%"; tempBox.style.padding = isMobile ? "12px" : `${containerRef.current!.offsetWidth * 0.0167}px`; // ... 실제 사용되는 모든 스타일 적용 // 높이 측정 const height = tempBox.offsetHeight;
  1. 정확성: 실제 브라우저 렌더링 결과를 그대로 사용
  2. 신뢰성: 폰트 로딩, 브라우저 차이 등이 자동으로 반영

구현 흐름

  1. 임시 컨테이너 생성: 보이지 않는 위치에 실제 너비의 컨테이너 생성
  2. 실제 스타일 적용: 실제 컴포넌트와 동일한 스타일 적용
  3. 높이 측정: offsetHeight로 실제 렌더링 높이 측정
  4. 정리: 측정 후 임시 요소 제거

결과

  • 메시지가 많아져도 컬럼 높이 차이가 크게 줄어듦
  • 다양한 텍스트 길이와 내용에서도 안정적으로 동작
  • CSS 변경 시 자동으로 반영되어 유지보수가 쉬움

주의해야할 점

  1. 추정 알고리즘의 한계: 작은 오차도 누적되면 큰 문제가 됨.. 혹시나 임시로 추정 알고리즘을 적용해 두었다면 무조건 추후에 기억하고 완전한 알고리즘 구현해야함
  2. 복잡한 Canvas 계산보다 실제 DOM 측정이 더 단순하고 효과적