SEO 最佳實踐
Swift Web 業務以內容驅動,搜尋引擎流量是廣告收入的命脈,SEO 不是附加項,而是產品的一等公民。本指南面向 Swift Web 全體開發人員,從 useSeo 長度告警一直講到 Core Web Vitals 與 GEO,配套 framework 內部最佳實踐。
引言
為什麼我們要把 SEO 做透:
- 公司業務靠網站內容吸引使用者、靠搜尋引擎自然流量賺廣告費
- 一個頁面 SEO 做好 vs 做差,自然流量可以差 5–10 倍
- 現代搜尋引擎(Google / Bing)+ AI 答案引擎(ChatGPT Search、Perplexity、Bing Copilot)對內容品質、結構化、效能、可存取性的要求只增不減
本指南涵蓋 12 個章節 + 2 個附錄,第一章與 useSeo dev console 告警直接掛勾(開發者從 console 告警點連結第一眼看到),後面章節是面向開發者的 SEO 知識小課堂,讓你「原來 SEO 學問這麼多」。
權威來源:Google Search Central / Bing Webmaster Guidelines / Schema.org / web.dev (Core Web Vitals) / W3C WCAG。
一、TDK 欄位:title / description / keywords
這是 useSeo 在 dev 環境的 console 告警直接相關章節。
1.1 長度建議來自哪裡
| 欄位 | 軟建議 | 硬上限 | 來源 |
|---|---|---|---|
| title | 10–60 顯示寬度 | > 70 觸發關鍵字堆砌 | Google SERP ~60、Bing ~65 截斷 |
| description | 50–160 顯示寬度 | > 200 觸發反作用 | Google SERP ~155、社交平台 ~200 |
| keywords | ≤10 個、≤200 字元 | 現代 SEO 不重視 | 反向觸發關鍵字堆砌偵測 |
title / description 在 SERP(搜尋結果頁)有視覺截斷閾值,超過會被搜尋引擎自動截斷;過短則點擊率(CTR)受損。keywords meta 現代搜尋引擎已不參與排名權重,但堆砌仍會觸發反作弊。
::: tip 單位是「顯示寬度」,不是字元數
表裡的數字單位是 顯示寬度(visual width),不是 JS .length:
- ASCII 字元(英文 / 數字 / 半形符號)算 1
- CJK 字元(中文 / 繁體 / 全形符號 / CJK 標點)算 2
閾值數字按英文 SERP 業界標準設計,中文文案目標長度要減半:
| 語言 | title 軟建議 | description 軟建議 |
|---|---|---|
| 英文 | 10–60 字元 | 50–160 字元 |
| 中文 / 繁體 | 5–30 字 | 25–80 字 |
為什麼這麼算:CJK 字元在 SERP 摘要中視覺寬度約為英文 2 倍,按 .length 一刀切會讓
中文文案「實際超長」仍不報警、英文短文案「實際正常」反被判偏短。useSeo
內部用 displayWidth 演算法(已匯出供單測使用),警告文案中也直接顯示 (顯示寬度 N) 提醒開發者。
:::
1.2 短不一定不好(silenceLengthWarnings 用法)
工具型 / 私有頁(登入、註冊、個人中心、中轉頁、demo)天然簡短:
- title
登入比使用者登入入口 - Swift Web更直接 - description 同理,強行堆 50 字會稀釋資訊密度
這類頁通常已標 robots: 'noindex' | 'private',不參與搜尋引擎收錄,長度告警在它們身上無意義。
對策:傳 silenceLengthWarnings: true 一次性靜音長度類告警。
useSeo({
title: '登入',
description: '帳號登入',
robots: 'private',
silenceLengthWarnings: true,
})
1.3 但「過長」不一樣 —— 那是反作用告警
帶 ⚠️ 的告警(title > 70、description > 200、keywords > 10 個)是真有反作用的:現代搜尋引擎會判定為關鍵字堆砌(keyword stuffing),降低排名甚至觸發懲罰。
silenceLengthWarnings: true 雖然會一併屏蔽這類提示文字,但行為本身是開發者要避免的 —— 靜音不代表「沒事了」。
1.4 公開頁該補就補,別偷懶靜音
indexable 公開頁(首頁、詳情頁、列表頁)description 偏短是真實的 SEO 最佳化機會,應該補長(說清楚頁面賣點 + 關鍵搜尋詞)。不要用 silenceLengthWarnings 應付了事。
例如:
// 改前(24 字,觸發偏短)
useSeo({
title: '應用中心 - 禁漫天堂',
description: '禁漫天堂應用中心,精選博彩、娛樂、棋牌等優質應用',
})
// 改後(~80 字,覆蓋搜尋意圖)
useSeo({
title: '應用中心 - 禁漫天堂',
description: '禁漫天堂應用中心精選博彩、娛樂、棋牌等優質 app,安全可靠免下載,支援秒級登入與跨裝置同步,更多手遊推薦持續更新中',
})
詳情頁要用後端 SEO 節點兜底鏈:
useSeo({
title: data?.seo?.title ?? data?.name,
description: data?.seo?.description ?? data?.summary,
image: data?.seo?.image ?? data?.cover,
type: 'article',
})
二、內容品質:E-E-A-T 與 GEO(AI 搜尋時代)
2.1 E-E-A-T 框架
Google 2026 搜尋品質評估指南強調 E-E-A-T:
- Experience — 第一手經驗、親身使用過、真實測評
- Expertise — 專業知識、學術背景、行業經驗
- Authoritativeness — 權威性,被同行/媒體引用
- Trustworthiness — 可信度,事實可驗證、來源可追溯
E-E-A-T 不是直接排名因子,但 Google 演算法更新("helpful content update"、"core update")會把它放入打分。業務表現:廣告產品頁講清楚「為什麼我們的應用安全/合法/有使用者口碑」;編輯性內容(評測、攻略)署名作者並展示作者資質。
2.2 AI 生成內容:能用,但要加人類價值
Google 2026 立場:「AI 生成內容是 OK 的,前提是它為使用者提供真實價值」。
- ✅ 用 AI 起草 + 人工修訂、加事實核查、加親身體驗、加專業判斷
- ❌ 大量低品質 AI 內容刷 SEO(scaled content abuse)—— 演算法直接降權或剔除
- ❌ 收購過期網域掛垃圾內容(expired domain abuse)
- ❌ 借用大站權威發垃圾子網域 / 子目錄(site reputation abuse)
2.3 GEO:Generative Engine Optimization
Bing 2026 webmaster 指南首次正式定義 GEO:讓內容能被 AI 答案引擎(Copilot / ChatGPT Search / Perplexity)「grounding」(引用作為來源)。
實操:
- NOARCHIVE meta 阻止內容被 AI 引用(如內部草稿、付費內容)
- 結構化資料(見第八章)讓 AI 更容易抽取事實
- 清晰的標題層級 + 段落 topic sentence,方便 AI 摘要
- 可驗證的事實聲明(帶連結、帶日期、帶資料來源)
<!-- 拒絕 AI 引用:僅服務於人類訪問者 -->
<meta name="robots" content="noarchive">
三、渲染策略與 Crawlability
3.1 渲染模式決策樹
Nuxt 4 透過 defineRouteRules() 顯式宣告每個頁面的渲染策略 —— Swift Web 強制要求每個頁面都宣告(否則 ESLint 報錯)。
| 模式 | 適用場景 | SEO 影響 |
|---|---|---|
| isr (ISR) | 列表頁、詳情頁、首頁 | ✅ 快取友善,SEO 一等公民 |
| ssr | 使用者態強相關頁(購物車、結帳) | ✅ 完整 SEO,但伺服器壓力大 |
csr (ssr: false) | 個人中心、後台、登入態頁 | ❌ 失去 SEO,僅在不需要被索引時用 |
| prerender (SSG) | 真靜態頁(關於、協議)—— 但預設建議改用 isr: 3600,見下 | ✅ 最快;不能用於動態參數頁 [id].vue |
注意:prerender: true 用在 [id].vue 會全量爆炸(每個 id 產生一個靜態檔案)。
3.2 失去 SEO 的代價
ssr: false 等於把頁面交給用戶端 JS 渲染,搜尋引擎爬蟲看到的是空 HTML 骨架,沒有 title / description / 主體內容。Google 雖然支援 JS 渲染("two-wave indexing"),但延遲 + 不穩定,禁止用於公開內容頁。
只有以下場景可以用 csr:
- 強登入態頁(個人中心、訂單、錢包)
- 臨時活動入口(不需要被索引的營運頁)
3.3 robots:noindex / private 簡寫
Swift Web useSeo 暴露三種 robots 簡寫:
useSeo({ robots: 'noindex' }) // 等價 'noindex, follow',中轉頁 / 站內搜尋結果頁用
useSeo({ robots: 'private' }) // 等價 'noindex, nofollow',登入 / 個人中心 / 後台用
useSeo({ robots: 'noindex, nofollow, noarchive' }) // 原始字串(高階用法)
⚠️ 不要給同一私有 path 再加
robots.txtDisallow:robots.txt 攔掉抓取後,爬蟲讀不到 page 上的noindex,URL 反而可能被「無 snippet」索引。要 deindex 就保持可抓取 +noindex;純不想被爬、不在乎索引的路徑(/api/等)才用 robots.txtDisallow。詳見 framework SEO 指南。
四、HTML 語意化:標籤選對就是一半 SEO
4.1 HTML5 Landmark 元素
W3C WCAG H101 強制要求用語意元素標識頁面區域。
<body>
<header>
<nav>...</nav>
</header>
<main>
<article>
<h1>頁面主標題</h1>
<section>
<h2>章節</h2>
</section>
</article>
<aside>側欄</aside>
</main>
<footer>...</footer>
</body>
| 元素 | 用途 |
|---|---|
<header> | 頁面 / 區域頂部(logo、導覽) |
<nav> | 主要導覽連結組 |
<main> | 主內容區(每頁一個) |
<article> | 獨立完整的內容(一篇文章、一個商品) |
<section> | 主題相關的內容分組(帶 heading) |
<aside> | 與主內容相關但可獨立的內容(側欄) |
<footer> | 頁面 / 區域底部 |
爬蟲和螢幕閱讀器都用這些 landmark 理解頁面結構。<div> 嵌一堆沒語意的層級 = 讓爬蟲和螢幕閱讀器懵逼。
4.2 H1–H6 標題層級
鐵律:每頁只一個 <h1>(頁面主標題),且是視覺與語意最重要的那個。
層級清晰、不跳級:
- ✅
h1→h2→h3→h2→h3 - ❌
h1→h3→h2(中間跳過 h2) - ❌ 把
<h3>當樣式用(「我想要小一點的字」),應該用class控制視覺
業務實踐:
- 列表頁:
<h1>是分類名(如「動漫」);列表項卡片用<h2>或<h3> - 詳情頁:
<h1>是作品名;章節用<h2> - 首頁:
<h1>可以是站名或主 slogan
4.3 不要 <div> 濫用
<!-- ❌ -->
<div class="header">
<div class="nav">
<div class="link">首頁</div>
</div>
</div>
<!-- ✅ -->
<header>
<nav>
<NuxtLink to="/">首頁</NuxtLink>
</nav>
</header>
工具:axe DevTools 瀏覽器外掛可以掃語意問題。
五、連結:ahref 是爬蟲的命脈
5.1 NuxtLink / SwLink,不要 onClick + router.push
爬蟲只跟 <a href="...">。@click + router.push() 跳轉的連結對搜尋引擎完全不可達。
<!-- ❌ 爬蟲看不到這個連結 -->
<button @click="$router.push('/movie/123')">詳情</button>
<!-- ✅ 爬蟲可達,且支援 prefetch / 中鍵打開 / 使用者右鍵複製連結 -->
<NuxtLink to="/movie/123">詳情</NuxtLink>
<!-- ✅ Swift Web 推薦:SwLink 內建爬蟲語意 + 視覺樣式 -->
<SwLink to="/movie/123">詳情</SwLink>
例外:純 UI 操作(展開折疊、切換 tab)才用 button + onClick。任何路由跳轉必須 a 標籤。
5.2 Anchor text(錨文字)要描述性
<!-- ❌ -->
<NuxtLink to="/article/seo">點選這裡</NuxtLink>
<NuxtLink to="/article/seo">了解更多</NuxtLink>
<!-- ✅ -->
<NuxtLink to="/article/seo">SEO 最佳化技巧詳解</NuxtLink>
爬蟲用 anchor text 理解目標頁面主題,「點選這裡」等於浪費一次排名機會。
5.3 內鏈結構 = 網站地圖
- 重要頁面要有多入口(首頁、分類、相關推薦、麵包屑都指向)
- 次要頁面(私有 / 工具頁)不要在主流量路徑放連結
- 死連結 / 404 連結要清理(爬蟲預算浪費)
5.4 外鏈:rel 屬性
<!-- 不要給外鏈投票(避免被低品質站拖累) -->
<a href="https://other.com" rel="nofollow">參考資料</a>
<!-- 使用者產生內容裡的外鏈:sponsored / ugc -->
<a href="https://ad.com" rel="sponsored">廣告連結</a>
<a href="https://example.com" rel="ugc">使用者分享的連結</a>
<!-- 在新視窗打開的外鏈:noopener 防止 tab 劫持 + noreferrer 不傳 referer -->
<a href="https://other.com" target="_blank" rel="noopener noreferrer">外部站點</a>
六、可存取性 WCAG 2.2 = SEO 加成
W3C WCAG 2.2 是 2026 實戰標準。可存取性與 SEO 共享同一基礎:螢幕閱讀器和搜尋引擎爬蟲看的是同一份語意。
6.1 圖片 alt(必填)
<!-- ❌ -->
<img src="/cover.jpg">
<!-- ✅ -->
<img src="/cover.jpg" alt="《某動漫》第 1 集封面,主角持劍站立">
<!-- ✅ Swift Web 推薦:SwImage 強制 alt 參數 -->
<SwImage src="/cover.jpg" alt="..." :ratio="16/9" />
alt 描述圖片內容/語意,不是檔名。裝飾性圖片用 alt="" 表示「忽略我」,不要省略 attribute。
6.2 表單 label 關聯
<!-- ❌ placeholder 不能取代 label -->
<input type="email" placeholder="信箱">
<!-- ✅ -->
<label for="email">信箱</label>
<input id="email" type="email" placeholder="user@example.com">
<!-- ✅ 包裹式 -->
<label>
信箱
<input type="email">
</label>
6.3 ARIA:補充 HTML 缺失的語意
ARIA 不是替代 HTML 語意元素,而是當 HTML 沒合適標籤時補。
<!-- ✅ 切換按鈕的狀態 -->
<button aria-expanded="true" aria-controls="menu">選單</button>
<ul id="menu">...</ul>
<!-- ✅ 自訂對話框 -->
<div role="dialog" aria-labelledby="dlg-title" aria-modal="true">
<h2 id="dlg-title">確認刪除</h2>
...
</div>
6.4 鍵盤導覽 + Touch Target
WCAG 2.2 新增:
- 鍵盤可見焦點(focus indicator 不能靠 hover)
- Touch target ≥ 24×24 px(行動端)—— 實戰推薦 ≥ 44×44 px
- 重複輸入(使用者不應被要求重複輸入相同資訊)
- 可存取的認證(不要強制記憶類驗證)
6.5 顏色對比
正文文字對比度 ≥ 4.5:1;大文字(≥18px 或 ≥14px 加粗)≥ 3:1。工具:WebAIM Contrast Checker。
七、URL / 路由 / canonical
7.1 語意化路徑
✅ /movie/spirited-away
✅ /movie/123-spirited-away (id + slug 雙保險)
❌ /detail?id=123 (query 參數不語意化)
❌ /m/123 (太精簡,無資訊)
URL 路徑中的關鍵字是輕量級排名訊號。爬蟲和使用者都能從 URL 看出頁面主題。
7.2 重要內容用 path,過濾參數用 query
/movie/list 主資源(被索引)
/movie/list?genre=action 過濾參數(不一定每個組合都被索引)
/movie/list?page=2 分頁(rel="next"/"prev")
爬蟲預算(crawl budget)有限,無意義的 query 組合會浪費爬蟲資源。配合 robots.txt 的 Disallow: /*?utm_* 屏蔽行銷參數 URL 被索引。
7.3 canonical:規範化重複內容
同一內容多個 URL(多副網域 / 大小寫 / 結尾斜槓 / 行銷參數)會被搜尋引擎判定為 duplicate content。<link rel="canonical"> 告訴搜尋引擎「以這個 URL 為準」。
// useSeo 自動寫 canonical
useSeo({
title: '...',
description: '...',
// 預設 canonical = `${siteUrl}${currentPathname}`
canonicalPath: '/movie/123', // 顯式覆蓋(罕見)
siteUrl: 'https://main.example.com', // 多副網域場景顯式覆蓋
})
7.4 避免動態參數過深
❌ /shop/cat/sub/sub/sub/item/123 太深,權重稀釋
✅ /shop/item/123 扁平結構
八、結構化資料 Schema.org / JSON-LD
Schema.org 是 Google / Bing / Yandex 共建的結構化詞彙表,2026 含 823 類型 / 1529 屬性。讓搜尋引擎和 AI 答案引擎「讀懂」頁面結構 → 觸發豐富結果(Rich Results) 與 AI Overview 引用。
8.1 JSON-LD 是 Google 推薦格式
三種格式:JSON-LD / Microdata / RDFa。Google 明確推薦 JSON-LD:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "SEO 最佳化技巧",
"author": { "@type": "Person", "name": "張三" },
"datePublished": "2026-04-28"
}
</script>
JSON-LD 與 DOM 解耦,便於模板化、易於 AI 抓取。
8.2 useSeo 自動輸出
Swift Web useSeo 預設輸出 WebSite + WebPage 兩個 schema 節點:
useSeo({
title: '...',
description: '...',
})
// 等價輸出:
// {
// "@context": "https://schema.org",
// "@graph": [
// { "@type": "WebSite", "name": "...", "url": "..." },
// { "@type": "WebPage", "name": "...", "description": "..." }
// ]
// }
詳情頁傳 type: 'article' 即輸出 Article schema(article 欄位可選,但缺 datePublished 時 schema 殘缺、富摘要不識別,務必一併傳):
useSeo({
title: data.value?.name,
description: data.value?.summary,
image: data.value?.cover,
type: 'article',
article: {
author: data.value?.author,
datePublished: data.value?.created_at,
dateModified: data.value?.updated_at,
},
})
8.3 常用 Schema 類型
| 類型 | 適用 | Swift Web 實作 |
|---|---|---|
| WebSite | 站點級(一站一份) | useSeo 自動 |
| WebPage | 頁面級(每頁一份) | useSeo 自動 |
| Article / NewsArticle / BlogPosting | 文章 / 新聞 / 部落格 | useSeo({ type: 'article' }) |
| BreadcrumbList | 麵包屑導覽 | 待加(建議組件級) |
| FAQ | FAQ 頁 | 業務自實作 schema-org/vue 呼叫 |
| Product | 商品 / 應用 | 業務自實作 |
| Organization | 機構資訊 | 業務自實作(首頁) |
8.4 豐富結果觸發條件
Google 豐富結果的展示由演算法決定(不保證),但必要條件:
- 必填欄位齊全(每種 type 不同,Rich Results Test 驗證)
- 資料真實(與頁面可見內容一致,不能藏起來)
- 頁面被索引
8.5 GEO 維度:讓 AI 引用
JSON-LD 是 AI 答案引擎抽取事實的主要資料來源。結構化越清晰,被 grounding 的機率越高。
九、Core Web Vitals 2026(最影響排名)
Core Web Vitals 是 Google 公開的使用者體驗排名訊號,Google Search 用 75% 真實使用者資料評估(不是實驗室資料)。
9.1 三大指標 + 閾值
| 指標 | Good | Needs Improvement | Poor |
|---|---|---|---|
| LCP(最大內容渲染) | ≤ 2.5s | 2.5–4.0s | > 4.0s |
| INP(互動回應延遲) | ≤ 200ms | 200–500ms | > 500ms |
| CLS(累計版面位移) | ≤ 0.1 | 0.1–0.25 | > 0.25 |
INP 在 2024 年取代 FID,更全面反映互動流暢度。所有 click / tap / keypress 後的下一幀延遲都被測量,p98 即為 INP。
9.2 LCP 最佳化(最大內容渲染)
LCP 元素通常是首屏的大圖或大段文字。最佳化方向:
<!-- ✅ Swift Web 實踐:首屏 hero 圖 -->
<SwImage
src="/hero.jpg"
:ratio="16/9"
alt="..."
preload <!-- 加 <link rel="preload"> -->
fetchpriority="high" <!-- 提升優先順序 -->
loading="eager" <!-- 不延遲載入 -->
/>
伺服器端:
- 用 ISR / SSR 而不是 CSR(HTML 預渲染減少 LCP)
- CDN 快取靜態資源
- 字型子集化 +
font-display: swap
9.3 INP 最佳化(互動回應延遲)
<!-- ✅ Swift Web 實踐:SwButton + :loading 狀態機防 double-submit -->
<SwButton :loading="submitting" @click="handleSubmit">提交</SwButton>
<!-- :loading 狀態機父元件管,async 期間停用按鈕 -->
程式碼層:
- 避免 main thread 長任務(> 50ms 的 JS 計算)—— 重計算用
Web Worker - 用
requestIdleCallback排程非緊急任務 - 減少同步 React/Vue 重渲染(精確 reactivity)
9.4 CLS 最佳化(累計版面位移)
版面位移來源:
- 圖片 / 影片 / 廣告位沒佔位,載入完才撐開
- 字型 swap 導致文字寬高變化(FOIT/FOUT)
- 非同步插入的內容(toast、modal)頂開主內容
<!-- ✅ Swift Web 實踐:SwImage 強制 ratio -->
<SwImage src="..." :ratio="16/9" />
<!-- 佔位框先撐開 16:9 容器,圖片載入完無位移 -->
字型:
/* ✅ font-display: swap + size-adjust 微調 */
@font-face {
font-family: 'BrandFont';
src: url('/font.woff2');
font-display: swap;
size-adjust: 100%;
ascent-override: 90%;
}
9.5 監控
- Search Console Core Web Vitals 報告(真實使用者資料,p75)
- PageSpeed Insights(實驗室 + 真實使用者)
- CrUX Dashboard(Chrome User Experience Report)
- 業務 RUM(Real User Monitoring):可選自建
十、sitemap.xml / robots.txt
10.1 sitemap.xml:告訴爬蟲有哪些頁
Swift Web 用 @nuxtjs/sitemap(在 framework 裡預設啟用)自動產生 /sitemap.xml:
- 列出所有可索引的 URL(
swiftConfig.seo.sitemap.exclude追加排除私有 path;framework 已預設排除/login、/mine/**等通用私有路徑) - 包含
<lastmod>時間戳,加速增量爬取 - 多語言 hreflang 互連(
<xhtml:link rel="alternate" hreflang="...">)規劃中(framework#88,等真實 prefix strategy applier 落地後啟動)
提交 sitemap:在 Google Search Console 和 Bing Webmaster Tools 各自提交一次(一次性設定)。
10.2 robots.txt:爬蟲第一站
# /public/robots.txt(或由 @nuxtjs/robots 動態產生)
User-agent: *
Disallow: /api/
Disallow: /*?utm_*
Allow: /
Sitemap: https://example.com/sitemap.xml
欄位含義:
User-agent: *— 適用所有爬蟲Disallow: /api/— 禁止爬 API 介面路徑Disallow: /*?utm_*— 屏蔽行銷參數 URLSitemap:— 指向 sitemap.xml(可多個)
⚠️
Disallow與 metanoindex不要疊加在同一路徑:robots.txt 攔抓取 → 爬蟲看不到noindex→ 可能「無 snippet」索引。按目標二選一:要 deindex / 排除私有頁用 page metarobots: 'private'(保持可抓取);純屏蔽抓取(/api/、utm 參數)用 robots.txtDisallow。
10.3 AI 爬蟲策略
2024 起 GPTBot / ClaudeBot / Google-Extended / PerplexityBot 等 AI 爬蟲陸續出現。Swift Web seo.aiBotPolicy 選項控制:
// nuxt.config.ts → @nuxtjs/robots
swiftConfig: {
seo: { aiBotPolicy: 'allow' | 'disallow' }
}
// disallow: 在 robots.txt 加 User-agent: GPTBot/ClaudeBot/... + Disallow: /
業務決策:
- 內容希望被 AI 引用(增加曝光)→ allow
- 付費 / 內部內容 → disallow + meta noarchive
十一、Open Graph / Twitter Card / 社交分享
11.1 og:* 讓分享更精美
Facebook / LinkedIn / 微信 / Slack / Discord 等共用 Open Graph 協議。Twitter 用 Twitter Cards(語意類似)。
// useSeo 自動寫完整 og:* 與 twitter:*
useSeo({
title: '...', // → og:title, twitter:title
description: '...', // → og:description, twitter:description
image: '/cover.jpg', // → og:image, twitter:image
type: 'article', // → og:type
locale: 'zh_TW', // → og:locale
})
// 自動加:og:url, twitter:card='summary_large_image'
// 站點名不走 og:site_name —— 進 WebSite JSON-LD(取 runtimeConfig.public.siteName)
// og:image:width=1200, og:image:height=630
11.2 og:image 標準尺寸
1200 × 630 px(1.91:1)是 Facebook / Twitter / LinkedIn 通用標準;最小 200 × 200。
Swift Web 兜底鏈:input.image → /og-image.png(專案級 prebuild 強制存在;#89 起不再讀後端 header.og_image / header.img)。
11.3 偵錯工具
- Facebook 分享偵錯工具
- Twitter Card Validator
- LinkedIn Post Inspector
- 微信:開發者工具內建 OG 偵測(開發者網頁)
十二、國際化 / hreflang
多語言站(zh-CN / en / zh-TW)用 hreflang 告訴搜尋引擎:「我有這頁的不同語言版本」,避免被判定為 duplicate content。
12.1 hreflang 標註
<link rel="alternate" hreflang="zh-CN" href="https://example.com/zh/movie/1">
<link rel="alternate" hreflang="en" href="https://example.com/en/movie/1">
<link rel="alternate" hreflang="zh-TW" href="https://example.com/tw/movie/1">
<link rel="alternate" hreflang="x-default" href="https://example.com/movie/1">
x-default 給「語言不匹配時的預設版本」。
12.2 Swift Web 實踐
@nuxtjs/i18n + useSeo 自動處理:
// nuxt.config.ts
swiftConfig: {
i18n: {
enabled: true,
defaultLocale: 'zh-CN',
locales: ['zh-CN', 'en', 'zh-TW'],
},
}
// → hreflang 自動設定規劃中(framework#88,等真實 prefix strategy applier 落地後啟動)
// → og:locale 需頁面顯式傳 useSeo({ locale }),不會自動取目前 i18n locale
12.3 i18n strategy 必填,禁用 no_prefix(強約束)
啟用 @nuxtjs/i18n 時必須用 strategy: 'prefix' 或 'prefix_except_default',禁用 'no_prefix':
'no_prefix'讓三語共用同一 URL(/about既是 zh-CN 又是 en)→ sitemap.xml 無法輸出<xhtml:link rel="alternate" hreflang>互連 → 搜尋引擎判 duplicate content → 多語言 SEO 歸零。- framework 在 dev 期偵測到
no_prefix且 locales ≥ 2 會console.warn,提示改用prefix_except_default。 - 僅當業務明確不在乎多語言 SEO(純內部系統 / 登入態後台)才允許
no_prefix。
i18n: {
strategy: 'prefix_except_default', // 預設語言無前綴,其它語言帶 /en/、/zh-TW/ 前綴
locales: [
{ code: 'zh-CN', file: 'zh-CN.json' },
{ code: 'zh-TW', file: 'zh-TW.json' },
{ code: 'en', file: 'en.json' },
],
}
12.4 注意事項
- 每個語言版本必須互相引用(self-referential 也要寫)
- canonical 不跨語言(每個語言各自 canonical 自己)
- URL 策略:path prefix(/zh/...)優於 query(?lang=zh),優於子網域(zh.example.com)
- 避免機翻 SEO 災難:低品質機翻被演算法識別為低價值內容
附錄 A:MR Review SEO 自檢清單
每個 page / component PR 提交前,開發者自查 + reviewer 重點檢查項:
必查(必改)
-
app/pages/**/*.vue和app/error.vue是否有useSeo()呼叫?(ESLintswift-web/require-useSeo-in-pages兜底,fw#240 起覆蓋 error.vue) - TDK 長度達標?description 中文 25-80 字 / 英文 50-160 字元,title 中文 5-30 字(字面量由 ESLint
swift-web/seo-tdk-length靜態預檢;工具/私有頁改robots: 'private'+silenceLengthWarnings: true) - 私有頁(login / register / mine / profile/* / admin / demo / creator)是否標
robots: 'private'? - 中轉 / 重新導向頁 / 站內搜尋結果頁是否標
robots: 'noindex'? - 私有頁是否加
silenceLengthWarnings: true(避免 dev console 噪音)? - 詳情頁是否傳
image(用data?.cover,不用站點預設佔位)? - 詳情頁是否走後端 SEO 兜底鏈(
data?.seo?.title ?? data?.name)? - 詳情頁是否設
type: 'article'+article欄位? - 渲染策略是否合理(
defineRouteRules強制宣告,詳情頁 isr / 內容頁不用 csr)?
重要(討論)
- 路由跳轉是否用
<NuxtLink>/<SwLink>,沒有@click + router.push? - 圖片是否用
<SwImage>,包含alt+ratio,首屏圖加preload+fetchpriority="high"? - 表單
<input>是否有關聯的<label>? - 頁面只有一個
<h1>?層級 h1→h2→h3 不跳級? - 用語意元素(
<header>/<nav>/<main>/<article>/<section>/<footer>)而非<div>堆? - 外鏈有
rel="nofollow"/"noopener noreferrer"?
次要(提及)
- anchor text 是否描述性(不是「點這裡」)?
- URL 路徑是否語意化(
/movie/123而不是/detail?id=123)? - 顏色對比度滿足 WCAG(正文 ≥4.5:1,大字 ≥3:1)?
Comment 模板
必改 / 重要:用 GitLab Discussion(帶 position 關聯程式碼行)
次要:review 總結裡提一嘴,不開 Discussion
附錄 B:權威參考資料
- Google Search Central 文件主頁
- SEO Starter Guide
- Search Quality Rater Guidelines(PDF)
- Core Web Vitals / LCP / INP / CLS
- Rich Results Test
- PageSpeed Insights
Bing
Schema.org
W3C / WCAG
- WCAG 2.2 — 現行可存取性標準
- H101 語意元素技術
- WAI-ARIA 1.3
工具
- axe DevTools — 可存取性掃描
- WebAIM Contrast Checker — 顏色對比偵測
- Facebook 分享偵錯工具
- Twitter Card Validator
Swift Web 內部
framework/CLAUDE.mdSEO 章節- standards 倉
rulesSEO Review 規則 - useSeo.ts JSDoc