데스크톱에서는 멀쩡해 보이는데 Safari 탭 바에서만 하얀 빈칸으로 나오는 경험, 다들 한 번쯤 있으실 겁니다. 십중팔구 favicon 설정이 잘못됐을 확률이 높습니다. 코드 리뷰를 하다 보면 정말 자주 발견되는 실수가 바로 favicon link tag를 body가 아닌 head에 넣지 않은 경우입니다. 브라우저는 이 규칙을 은근히 엄격하게 따릅니다.

증상: 아이콘이 없거나 기본 아이콘만 노출

link tag도 추가하고, 파일 경로도 확인했고, 캐시까지 날렸는데도 여전히 지구본 아이콘이 나오거나 아예 아무것도 안 나옵니다. DOM을 검사해보면 tag가 <body> 안에 편하게 자리 잡고 있는 걸 발견하게 됩니다. 범인은 바로 이 녀석입니다.

빠른 해결책: head로 올리기

HTML 파일을 열어서 body 안에 있는 favicon link tag를 잘라냅니다. 그리고 <head> 안 아무 곳에나 붙여넣습니다. 끝입니다. 브라우저를 새로고침하면 아이콘이 바로 나타날 겁니다.

<!-- WRONG: Browsers ignore this -->
<body>
  <link rel='icon' href='/favicon.ico'>
  <h1>My Website</h1>
</body>

<!-- CORRECT: Place it here -->
<head>
  <link rel='icon' href='/favicon.ico'>
</head>

브라우저가 body의 tag를 무시하는 이유

HTML 스펙에 명확하게 정의되어 있습니다: <link> 요소는 <head>에 속합니다. 최신 브라우저들은 잘못된 HTML에 대해 관대하게 동작하지만, body 안에서 resource link를 만나면 parser 동작이 예측 불가능해집니다.

Parser가 body 렌더링을 중단

브라우저의 HTML parser가 body 안에서 <link> tag를 발견하면, 보통 이 tag를 head로 강제로 올려버립니다. 하지만 JavaScript 프레임워크가 페이지 로드 후 동적으로 tag를 주입하는 경우, 브라우저가 아이콘의 재요청을 트리거하지 않을 수 있습니다. 탭이 그냥 빈 상태로 남는 거죠.

Flash of Unstyled Content (FOUC)

favicon link가 늦게 파싱되면, 브라우저가 아이콘 다운로드 전에 탭을 먼저 렌더링해버릴 수 있습니다. 아이콘이 나타나기 전에 빈 탭이 잠깐 깜빡이는 현상이 발생합니다. 사용자 경험 측면에서 꽤 어색해 보입니다.

실제 사례: GitHub는 어떻게 처리할까

GitHub의 소스 코드를 한번 보세요. 모든 아이콘 관련 로직을 철저하게 <head> 안에 모아두었습니다. 구형 브라우저용 ICO fallback, 최신 브라우저용 SVG, 그리고 Apple Touch Icon까지 전부 head 안에 선언합니다. 이 tag들을 DOM 여기저기에 흩어놓지 않습니다. 엄격한 배치가 렌더링 레이스 컨디션을 방지한다는 걸 알고 있기 때문입니다. 우리도 이 방식을 따르는 게 좋습니다.

2026년을 위한 예방 가이드

프레임워크 개발자들이 component 기반 레이아웃을 사용하다 보니 이런 실수를 자주 합니다. 이 문제를 원천 차단하는 방법은 다음과 같습니다:

아이콘은 있을 자리에 두세요. head는 metadata를 위한 공간이고, body는 content를 위한 공간입니다. 이 경계를 지키면 브라우저 탭이 항상 완벽하게 렌더링됩니다.