SVG favicon, 두 개의 PNG fallback, 그리고 레거시 브라우저용 ICO를 업로드했는데 Safari 탭에서는 계속 ICO가 표시됩니다. 파일은 문제없습니다. 문제는 favicon link 태그의 순서입니다.
브라우저는 보이는 첫 번째 <link> 태그를 그대로 가져가지 않습니다. WHATWG HTML 명세에 따르면 user agent는 sizes, media, type 속성을 기준으로 가장 적합한 아이콘을 선택합니다. 여러 아이콘이 동일하게 매치될 경우 브라우저는 마지막에 선언된 항목을 사용할 수 있습니다. 따라서 link 태그의 순서는 단순한 스타일 선택이 아니라 실제로 작동하는 레버입니다.
Prerequisites
사이트의 HTML <head>에 접근할 수 있어야 하며, 최소 두 개 이상의 favicon 파일(SVG, PNG, ICO)이 준비되어 있어야 합니다. HTML link 태그에 대한 기본적인 이해가 도움이 됩니다. 복습이 필요하면 favicon HTML code 예제 cheat sheet를 참고하세요.
Step-by-step: ordering multiple favicon link tags
Step 1: Understand browser selection rules
브라우저는 현재 컨텍스트(디스플레이 밀도, 탭 크기, 다크 모드 preference, 지원 포맷)를 기준으로 선언된 각 아이콘에 점수를 매깁니다. 가장 잘 맞는 아이콘이 선택됩니다. 동점일 경우 마지막에 선언된 항목이 기본값이 됩니다. 순서가 잘못되면 최신 브라우저가 벡터를 완전히 지원함에도 불구하고 선명한 SVG를 건너뛰고 흐릿한 PNG를 가져갈 수 있습니다.
Step 2: Order from most specific to most general
가장 강력한 포맷을 먼저 두고, 범용 fallback은 마지막에 둡니다.
<link rel='icon' type='image/svg+xml' href='/icon.svg'>
<link rel='icon' type='image/png' sizes='32x32' href='/icon-32.png'>
<link rel='icon' type='image/png' sizes='16x16' href='/icon-16.png'>
<link rel='icon' href='/favicon.ico'>
SVG가 가장 먼저 오는 이유는 모든 픽셀 밀도에 맞춰 스케일링되기 때문입니다. SVG favicon을 지원하지 않는 브라우저를 위해 PNG fallback이 그 뒤를 따릅니다. ICO는 포맷을 선언하지 않는 레거시 시스템을 위한 범용 안전망으로 마지막에 둡니다.
Step 3: Add type attributes to remove ambiguity
type이 없으면 브라우저가 ICO 포맷(역사적인 기본값)으로 가정하고 PNG나 SVG를 완전히 건너뛸 수 있습니다. type='image/svg+xml' 또는 type='image/x-icon'을 추가하면 브라우저가 무엇을 기대해야 할지 정확히 알 수 있어, 호환되지 않는 파일을 다운로드하지 않고 건너뛸 수 있습니다.
Step 4: Use sizes to match real-world contexts
sizes 속성은 각 아이콘이 어떤 렌더링 컨텍스트를 대상으로 하는지 설명합니다. 16×16 PNG는 브라우저 탭에 적합합니다. 32×32 PNG는 작업 표시줄과 high-DPI 북마크 바에 맞습니다. iOS 홈 화면용으로는 별도의 Apple Touch Icon을 선언합니다.
<link rel='apple-touch-icon' sizes='180x180' href='/apple-touch-icon.png'>
Apple Touch Icon은 별도의 선택 경로를 따르며 일반 favicon과 탭 슬롯을 두고 경쟁하지 않습니다. 따라서 메인 favicon 스택 뒤에 배치하세요.
Step 5: Place dark mode SVGs at the top
다크 모드를 지원한다면 media 속성으로 두 가지 SVG 변형을 선언할 수 있습니다.
<link rel='icon' type='image/svg+xml' href='/icon-light.svg' media='(prefers-color-scheme: light)'>
<link rel='icon' type='image/svg+xml' href='/icon-dark.svg' media='(prefers-color-scheme: dark)'>
<link rel='icon' type='image/svg+xml' href='/icon.svg'>
주어진 환경에서는 하나의 media query만 매치되므로 브라우저는 그 항목을 선택합니다. media query를 전혀 지원하지 않는 브라우저를 위한 최종 fallback으로 media 조건이 없는 SVG가 역할을 합니다.
Common pitfalls
- ICO를 가장 먼저 두는 경우. 최신 브라우저가 ICO type을 매치하고 SVG를 평가하기도 전에 ICO를 가져갈 수 있습니다. ICO는 항상 마지막에 두세요.
- type 속성을 누락하는 경우. 브라우저는 기본값으로 ICO를 가정하여 PNG나 SVG를 완전히 가릴 수 있습니다.
rel='shortcut icon'을 사용하는 경우. 이것은 IE 시대의 레거시 속성입니다. WHATWG 명세는rel='icon'을 표준으로 정의합니다. 대부분의 브라우저는 여전히 옛 형식을 파싱하지만, 아무런 이점도 없고 엣지 케이스에서 선택 로직을 혼동시킬 수 있습니다.- 그룹화 없이 sizes를 섞는 경우. 동일한 렌더링 슬롯을 대상으로 한다면 32×32 PNG 뒤에 16×16 PNG를 흩어 두지 마세요. 같은 컨텍스트를 위한 sizes는 함께 묶어 두세요.
- cache busting을 잊는 경우. 브라우저는 favicon을 적극적으로 캐시합니다. 태그 순서를 바꿨는데 아이콘이 갱신되지 않으면
?v=2처럼 버전 쿼리 스트링을 추가하세요. 전체 workflow는 favicon cache busting 가이드를 참고하세요.
Wrap-up
브라우저가 스택에서 가장 잘 매치되는 아이콘을 선택하고 동점일 때 마지막 선언으로 결정하기 때문에 순서가 중요합니다. 최상의 포맷을 먼저 두고, fallback을 그 뒤에 배치하며, type과 sizes 속성을 추가해 모든 모호함을 제거하세요. 순서를 재배치한 뒤에도 아이콘이 갱신되지 않는다면 다음 의심 대상은 보통 cache입니다. Mzu favicondl을 사용해 깔끔하고 올바른 크기의 icon package를 생성하고 수동 리사이즈 단계를 건너뛸 수 있습니다.