[회고록] 노트북에서만 발생한 미묘한 폰트 렌더링 이슈 회고
🔎 문제 상황
최근 작업 중, 아주 이상한 현상을 발견했습니다.
- 14인치 / 16인치 노트북에서만 발생
- 텍스트가 살짝 아래에 있다가 중앙으로 이동하는 느낌
- 폰트 굵기가 미세하게 달라 보임
- 애니메이션을 준 적이 없는데도 “움직이는 것처럼” 보임
처음에는 제 눈을 의심했습니다. “이 정도는 그냥 예민한 걸까?”라고 생각했지만, 다시 봐도 분명 움직이고 있었습니다.
특히 고해상도 디스플레이 환경에서만 재현된다는 점이 가장 혼란스러웠습니다.
🧠 원인에 대한 고찰
이 문제를 단순히 “렌더링 이슈겠지”라고 넘기고 싶지 않았습니다. 하나씩 가능성을 좁혀가며 정리해보았습니다.
1️⃣ Subpixel Rendering & Anti-Aliasing
브라우저는 폰트를 픽셀 단위가 아니라 서브픽셀 단위로 렌더링합니다.
고 DPI(2x 스케일링) 환경에서는 0.5px 단위 계산이 발생하고, 브라우저의 반올림 처리 과정에서 초기 레이아웃과 실제 렌더링 위치가 달라질 수 있습니다.
그 결과, 텍스트가 아주 미묘하게 이동하는 것처럼 보일 수 있습니다.
0.5px는 생각보다 강력했습니다.
2️⃣ 폰트 로딩 타이밍 (FOUT / FOIT)
웹폰트를 사용하는 경우:
- 시스템 폰트로 먼저 렌더링
- 웹폰트 로딩 완료
- 폰트 교체
이 과정에서 폰트 메트릭(높이, baseline, 자간 등)이 다르면 텍스트의 위치가 재계산됩니다.
특히 Retina 디스플레이 환경에서는 그 차이가 더 도드라지게 보였습니다.
3️⃣ font-weight 합성 문제
예를 들어 font-weight: 500을 사용했지만
실제 폰트 파일에 500 weight가 없다면 브라우저가 굵기를 합성합니다.
이때:
- 초기 렌더링
- 웹폰트 적용 이후
굵기가 살짝 달라 보이며 “변하는 것 같은 느낌”을 줄 수 있습니다.
4️⃣ transform & GPU 개입
의도치 않게 다음과 같은 속성이 들어가 있는 경우:
transformtranslateZ(0)will-change
GPU 레이어로 승격되면서 텍스트 안티앨리어싱 방식이 바뀌고 굵기나 위치가 달라 보일 수 있습니다.
5️⃣ 반 픽셀 중앙 정렬 문제
top: 50% + translateY(-50%) 방식의 중앙 정렬은
컨테이너 높이가 홀수 픽셀일 경우 0.5px 계산이 발생합니다.
이 미세한 차이가 초기 렌더링과 이후 렌더링 간의 차이를 만들 수 있습니다.
🛠 시도한 해결 방법
하나씩 제거해보며 확인했습니다.
✅ 1. 실제 존재하는 font-weight만 사용
합성 weight 제거
✅ 2. line-height 명시적으로 지정
baseline 흔들림 최소화
✅ 3. font-display 전략 조정
swap 사용으로 폰트 교체 시 레이아웃 점프 완화
✅ 4. transform 제거
GPU 개입 가능성 제거
✅ 5. 중앙 정렬을 flexbox로 변경
반 픽셀 계산 최소화
🎯 결과
완벽하게 “이것 때문이다”라고 단정 짓지는 못했습니다.
하지만,
- 폰트 로딩 전략 개선
- 합성 weight 제거
- 반 픽셀 계산 제거
이 세 가지를 조합하면서 현상은 거의 사라졌습니다.
결국, 하나의 원인이라기보다는 여러 렌더링 요소가 겹친 복합적인 문제였던 것 같습니다.
💡 이번 이슈를 통해 배운 점
1️⃣ 미묘한 어색함은 실제 문제일 가능성이 높다
느낌은 틀리지 않았습니다.
2️⃣ 폰트는 단순한 디자인 요소가 아니다
폰트는 다음과 모두 연결되어 있습니다:
- OS 렌더링 엔진
- 브라우저 엔진
- DPI
- GPU
- 레이아웃 계산
생각보다 훨씬 복잡한 영역이었습니다.
3️⃣ “반응형”은 너비만의 문제가 아니다
이제는 다음도 함께 확인합니다:
- devicePixelRatio
- 디스플레이 스케일링
- 고해상도 환경 테스트
4️⃣ 정렬은 감각이 아니라 수학이다
0.5px는 존재합니다. 그리고 그 0.5px는 꽤 집요합니다.
🧩 앞으로 주의할 점
- 웹폰트 사용 시 실제 weight 파일 확인
- 중앙 정렬에서 translate 남용하지 않기
- 고 DPI 환경 테스트 필수
- “이상한데?”라는 감각을 무시하지 않기
🌿 마무리 회고
이번 이슈는 치명적인 버그는 아니었습니다. 하지만 개발자로서 저를 꽤 오래 붙잡아두었습니다.
해결이 완벽하지 않더라도, 원인을 좁혀가며 논리적으로 추적해보는 과정 자체가 성장이라고 느꼈습니다.
프론트엔드는 ‘보이는 영역’을 다루지만, 그 안에서는 우리가 생각하는 것보다 훨씬 많은 계산이 일어나고 있습니다.
다음에 또 이런 미묘한 렌더링 이슈를 만나더라도, 조금은 덜 당황하고, 조금은 더 차분하게 접근할 수 있을 것 같습니다 😊
댓글남기기