| name | mobile-seo-pwa |
| description | 모바일 SEO 특수 사항(Mobile-First Indexing, viewport meta, dynamic viewport, iOS safe-area, 인터스티셜 페널티)과 Web App Manifest의 SEO 기여를 한 곳에 정리. seo-static-html 같은 기본 SEO 스킬에서 다루지 않는 모바일·PWA 전용 영역. <example>사용자: "모바일에서 iPhone notch 영역까지 콘텐츠가 차게 만들면서 SEO·접근성 안 깨려면?"</example> <example>사용자: "PWA에 manifest.webmanifest 추가했는데 iOS에서 아이콘이 깨져요. apple-touch-icon도 따로 박아야 하나요?"</example> <example>사용자: "AMP 페이지 만들어둔 거 2026년에도 유지해야 하나요?"</example>
|
Mobile SEO + PWA Manifest
소스:
0. 이 스킬이 다루는 범위
seo-static-html 등 일반 SEO 스킬은 데스크톱·일반 케이스를 다룬다. 이 스킬은 그 위에 얹는 모바일 전용 + PWA 보강 레이어다.
| 다루는 것 | 다루지 않는 것 (다른 스킬) |
|---|
| Mobile-First Indexing 콘텐츠 패리티 | title/description/canonical 등 일반 메타 |
| viewport meta + dvh/svh/lvh | a11y 전반 (a11y-* 스킬) |
| iOS safe-area + apple-touch-icon | 다국어 hreflang (seo-i18n-*) |
| Web App Manifest의 SEO 기여 | Core Web Vitals 최적화 (cwv-*) |
| 모바일 인터스티셜 페널티 | Service Worker 구현 세부 (pwa-service-worker) |
| AMP의 현재 입지 (deprecated 관점) | |
1. Mobile-First Indexing — 2026년 기준 사실
1-1. 완료 시점
- 2024-07-05: Googlebot이 100% 사이트를 mobile 크롤러로 전환 완료
- 2026 현재: 모바일 버전이 인덱싱·랭킹의 유일한 기준. 데스크톱 전용 콘텐츠는 인덱싱되지 않는다고 봐도 무방
- 출처: Google Search Central 공식 문서
1-2. 권장 사이트 구조
| 구조 | Google 권장도 |
|---|
| 반응형 (responsive) | ⭐ 강력 권장. "구현·유지가 가장 쉬움" — 공식 문구 |
| 동적 서빙 (Dynamic Serving) | 허용. Vary: User-Agent 필수 |
M-dot 분리 (m.example.com) | 비권장. 이미 분리돼 있으면 canonical/alternate 양방향 교차 지정 필수 — 방향·코드는 1-4절, 운영 복잡 |
1-3. 콘텐츠 패리티 (Content Parity) — 가장 흔한 함정
모바일에서 빼는 콘텐츠는 인덱싱에서 빠진다.
체크리스트:
주의: "Read more" 접기·아코디언으로 숨겨도 인덱싱은 되지만, lazy-load with intersection observer로 DOM에 늦게 들어오는 콘텐츠는 Googlebot이 못 볼 수 있다. SSR/prerender로 초기 HTML에 포함시켜라.
1-4. 분리 모바일 URL(m-dot) — 이미 m./www.로 나뉜 사이트의 canonical/alternate 교차 지정 (2026-08-26 추가)
소스: https://developers.google.com/search/docs/crawling-indexing/mobile/mobile-sites-mobile-first-indexing (Separate URLs 절)
반응형 단일 URL이 최선이지만, 이미 호스트가 분리된 레거시 커머스·서비스 사이트는 당장 합치기 어렵다. 그 상태에서 Google이 요구하는 것은 양방향 교차 지정이며, 방향을 반대로 넣는 실수가 가장 흔하다.
| 페이지 | 넣어야 할 <link> | 의미 |
|---|
데스크톱 https://www.example.com/products/123 | <link rel="canonical" href="https://www.example.com/products/123"> (자기참조) + <link rel="alternate" media="only screen and (max-width: 640px)" href="https://m.example.com/products/123"> | "모바일 버전은 저기" |
모바일 https://m.example.com/products/123 | <link rel="canonical" href="https://www.example.com/products/123"> | "정본은 데스크톱 URL" |
<link rel="canonical" href="https://www.example.com/products/123">
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://m.example.com/products/123">
<link rel="canonical" href="https://www.example.com/products/123">
규칙:
- 모바일 우선 색인이 완료됐어도 Google은 m-dot URL을 canonical로 바꾸지 말라는 안내를 유지한다. 색인에 쓰이는 콘텐츠는 모바일 버전(Googlebot 스마트폰이 m.을 크롤)이지만, 정본 URL은 데스크톱이다.
media 값은 Google 예시 그대로 only screen and (max-width: 640px). 다른 값을 써도 힌트일 뿐이라 굳이 바꾸지 않는다.
- 모바일 페이지의 canonical이 자기참조(m.) 거나 alternate만 있고 canonical이 없으면 두 URL이 중복 콘텐츠로 경쟁한다 — 감사 시 High.
- 1-3의 콘텐츠 패리티가 여기서 더 중요하다: m.에 없는 본문·구조화 데이터·내부 링크는 색인에서 사라진다. 두 버전이 같은 JSON-LD(Product·BreadcrumbList)를 내야 하며, JSON-LD 안의
url·@id도 데스크톱 URL로 통일한다.
- CSR SPA(react-helmet-async 등)에서
<Helmet>으로 넣는 경우, 페이지마다 흩어 쓰지 말고 공용 SEO 컴포넌트 하나가 현재 호스트를 보고 위 표를 자동 생성하게 한다. 그래야 og:url(카카오·페이스북 공유)도 canonical과 같은 데스크톱 URL로 일관된다.
- Search Console:
m.example.com과 www.example.com은 속성을 각각 등록한다(Domain 속성은 같은 루트 도메인의 서브도메인을 묶지만, 보고서는 분리해서 보는 편이 진단에 낫다). 사이트맵은 각 호스트의 URL만 담는다.
- 장기 경로는 반응형 통합이며, 통합 시 m. → www. 301 + alternate 제거 순서로 진행한다(
frontend/url-canonicalization-redirects 참조).
2. viewport meta — 모바일 SEO·a11y의 기본
2-1. 베이스 라인 (반드시 이것부터)
<meta name="viewport" content="width=device-width, initial-scale=1">
이게 빠지면 모바일에서 데스크톱 너비로 렌더링 → 모바일 친화 점수 0점.
2-2. 주요 옵션
| 옵션 | 값 | 용도 |
|---|
width | device-width | 기기 너비 사용. 거의 항상 이것 |
initial-scale | 1 | 100% 줌으로 시작 |
viewport-fit | cover | iOS notch 영역까지 화면 채움 (3절 참조) |
interactive-widget | resizes-visual (기본) / resizes-content / overlays-content | 키보드 표시 시 viewport 동작 (Chrome 108+, Firefox 132+) |
maximum-scale | — | 건드리지 마라 (a11y 위반) |
user-scalable | — | 건드리지 마라 (a11y 위반) |
2-3. 절대 하면 안 되는 것
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
- 저시력 사용자가 핀치줌으로 확대해서 읽는 것을 막음
- WCAG는 텍스트가 최소 200%까지 확대 가능해야 함을 요구
- Google "모바일 친화" 평가에서 감점
- iOS 10+은 이 설정을 이미 무시함 (있어봤자 a11y 점수만 깎임)
- 출처: Deque axe rule
meta-viewport, W3C ACT Rule b4f0c3
2-4. 가상 키보드 동작 제어 (Chrome 108+)
폼 페이지에서 키보드가 떴을 때 레이아웃이 흐트러지는 문제를 제어:
<meta name="viewport" content="width=device-width, initial-scale=1, interactive-widget=resizes-content">
| 값 | 동작 |
|---|
resizes-visual (기본) | Visual viewport만 줄어듦. Layout viewport는 그대로 |
resizes-content | Layout viewport까지 줄어듦. 100vh도 키보드 위 영역으로 줄어듦 |
overlays-content | 둘 다 안 줄어듦. 키보드가 콘텐츠 위에 덮음 |
주의: iOS Safari는 이 옵션 미지원 (WebKit). iOS는 항상 기본 동작.
3. iOS Notch / Safe Area — viewport-fit + env()
3-1. 문제
iPhone X 이후 기기는 상단 notch / 하단 home indicator가 있다. 기본 상태에서 Safari는 콘텐츠를 안전 영역 안에만 렌더링해서, 상하에 흰 띠가 생긴다.
3-2. 해결 (2단계)
Step 1: viewport-fit=cover로 화면 전체 사용 선언
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
Step 2: safe-area-inset- env()로 콘텐츠 보호*
.app-header {
padding-top: env(safe-area-inset-top);
}
.tab-bar {
padding-bottom: env(safe-area-inset-bottom);
}
.app-content {
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}
.app-header {
padding-top: max(env(safe-area-inset-top), 16px);
}
3-3. 안 했을 때 vs 했을 때
| 시나리오 | 결과 |
|---|
| viewport-fit 안 함 | notch 위쪽이 흰 띠. PWA 같은 몰입감 없음 |
| viewport-fit=cover만 함 | 콘텐츠가 notch에 가림 |
| viewport-fit=cover + safe-area-inset | ✅ 화면 전체 사용 + 콘텐츠 보호 |
참고: env(safe-area-inset-*)는 notch 없는 기기에선 0을 반환하므로 모든 기기에 안전하게 적용 가능.
4. Dynamic Viewport (dvh / svh / lvh) — 100vh 문제
4-1. 100vh의 함정
모바일 Safari/Chrome은 스크롤 시 주소창이 사라진다. 그런데 100vh는 주소창이 사라진 상태(largest viewport)를 기준으로 계산되어, 초기 로드 시점에 화면 하단이 잘린다.
4-2. 2026년 표준 단위
| 단위 | 의미 | 사용처 |
|---|
100svh | Small Viewport Height (UI 모두 보이는 가장 작은 상태) | "절대 안 잘리는" 시작 화면 |
100lvh | Large Viewport Height (UI 다 숨은 가장 큰 상태) | 전체 영역 사용 (스크롤 시) |
100dvh | Dynamic Viewport Height (UI 상태에 따라 동적) | 모달·풀스크린 (가장 흔히 사용) |
4-3. 브라우저 지원 (2026-06 기준)
- Chrome 108+, Firefox 101+, Safari 15.4+, Edge 108+
- 2025-06부터 Baseline Widely Available 등급
- 글로벌 사용자 약 95%가 지원 브라우저 사용
- 출처: caniuse.com/viewport-unit-variants
4-4. 패턴
.hero {
min-height: 100dvh;
}
.hero {
min-height: 100vh;
min-height: 100dvh;
}
.modal {
height: 100svh;
}
주의: dvh는 스크롤 시 값이 계속 변하므로 레이아웃 jank가 발생할 수 있다. 트랜지션이 필요한 요소에는 svh 또는 lvh를 쓰고 padding으로 보정하는 편이 부드럽다.
5. Web App Manifest — 필수·권장 필드
5-1. 스펙 현황 (W3C Working Draft 2026-05-07 기준)
주의: 스펙상 모든 필드는 optional이다. "필수"라는 표현은 PWA로 동작하기 위한 사실상의 필수를 의미한다. (출처: W3C 직접 확인)
5-2. PWA로 동작·설치되려면 필요한 필드
{
"name": "꿈해몽 - AI Dream Interpreter",
"short_name": "꿈해몽",
"description": "AI 기반 꿈 해몽 서비스",
"start_url": "/?source=pwa",
"scope": "/",
"display": "standalone",
"orientation": "portrait",
"background_color": "#ffffff",
"theme_color": "#5b21b6",
"lang": "ko-KR",
"icons": [
{
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose"
| 필드 | 역할 | 빠지면 |
|---|
name | 설치 후 표시 이름 (전체) | 설치 프롬프트가 안 뜸 |
short_name | 홈 화면 아이콘 아래 표시 (12자 이내 권장) | name 전체 노출 |
start_url | 설치 후 실행 시 열리는 URL | 현재 URL 사용 (분석 추적 불가) |
display | standalone / fullscreen / minimal-ui / browser | browser (PWA처럼 안 보임) |
icons | 192px·512px 둘 다 필수 사실상 | 설치 안 됨 |
theme_color | 상태바·탭 색상 | 기본값 |
background_color | 스플래시 화면 배경 | 흰색 |
5-3. display 값 선택
| 값 | 사용처 | 주의 |
|---|
standalone | ⭐ 일반 PWA. 주소창 없음, 상태바는 있음 | 기본 권장 |
minimal-ui | 뒤로/새로고침 정도만 보임 | Chrome Android만 잘 지원 |
fullscreen | 게임·미디어 플레이어 | 시스템 UI까지 숨김. 일반 앱은 사용자 혼란 → 비권장 |
browser | manifest 있지만 일반 탭으로 열기 | PWA 효과 없음 |
5-4. SEO 관점에서 manifest의 의미
- manifest 자체가 랭킹 신호는 아님
- 그러나 PWA 자격을 갖추면 Chrome의 "Add to Home Screen" 프롬프트가 자동 노출 → 재방문률·체류 시간 증가 → 간접 SEO 효과
- Google Search Console에서 "설치 가능한 웹앱"으로 인지됨
5-5. HTML에 연결
<link rel="manifest" href="/manifest.webmanifest">
.webmanifest 확장자 권장 (MIME application/manifest+json). .json도 동작하지만 일부 서버 설정에서 MIME 충돌 우려.
6. iOS Safari 전용 메타 — manifest 보완용
iOS Safari는 Web App Manifest를 부분 지원한다 (2018년 이후). manifest의 display: standalone·icons 일부는 우선 적용되지만, 다음 항목은 여전히 Apple 전용 메타로 박아야 한다.
6-1. apple-touch-icon (가장 중요)
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
- 180×180 PNG 1개로 충분 (iPhone Retina 3x 기준)
- 투명 배경 금지 — 검은 사각형이 됨
- 모서리 둥글기는 iOS가 자동 적용 (사각 PNG로 제작)
- 없으면 홈 화면 추가 시 페이지 스크린샷이 아이콘으로 들어감
6-2. 스플래시·UI 메타
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="꿈해몽">
6-3. iOS 17.4+ EU 제약 (2024-03부터)
주의: 2024-03 Apple은 DMA 컴플라이언스를 이유로 EU 지역에서 PWA 기능 일부를 제한. EU 사용자는 홈 화면에 추가해도 일반 Safari 탭으로 열리고 푸시 알림 미지원. EU 외 지역은 영향 없음. 한국 서비스라면 영향 없음.
6-4. 필수 메타 세트 (한국 서비스 기준)
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<link rel="manifest" href="/manifest.webmanifest">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16.png">
상세 레퍼런스 (예제·고급 패턴·흔한 실수) → references/REFERENCE.md