← 返回文章列表

如何排除禁止轉譯資源,可以如何改善

HTML 代碼特寫 - 網頁轉譯資源優化

Photo by Markus Spiske on Unsplash

當你使用 Google PageSpeed InsightsLighthouse 檢測網站時,經常會看到「排除禁止轉譯的資源」(Eliminate render-blocking resources)這項建議。這項優化對於提升網站的 首次內容繪製(FCP)最大內容繪製(LCP) 至關重要。本文將深入探討什麼是禁止轉譯資源,以及如何有效排除它們來改善網站性能。


目錄


什麼是禁止轉譯資源?

禁止轉譯資源(Render-Blocking Resources) 是指那些會阻止瀏覽器渲染頁面的外部資源,主要是 CSS 樣式表JavaScript 腳本

瀏覽器渲染流程

當瀏覽器載入網頁時,會依序執行以下步驟:

1. HTML 解析 → 建立 DOM 樹
       ↓
2. CSS 解析 → 建立 CSSOM 樹
       ↓
3. 合併 DOM + CSSOM → 渲染樹(Render Tree)
       ↓
4. 佈局(Layout)→ 計算元素位置
       ↓
5. 繪製(Paint)→ 顯示在螢幕上

問題所在:

  • 瀏覽器遇到 <link rel="stylesheet"> 時,會暫停 HTML 解析,等待 CSS 下載並解析完成
  • 瀏覽器遇到 <script> 時,會暫停 HTML 解析,等待腳本下載並執行完成
  • 這段等待時間就是「禁止轉譯」

視覺化說明

無優化情況:
HTML 解析 → [等待 CSS 下載] → [等待 JS 下載執行] → 渲染頁面
            ⬆ 阻塞點            ⬆ 阻塞點
            用戶看到空白         用戶看到空白

優化後:
HTML 解析 → 渲染可見內容
            ⬆ CSS/JS 非阻塞載入
            用戶立即看到內容

為什麼需要排除禁止轉譯資源?

📊 對性能指標的影響

指標 說明 影響程度
FCP(首次內容繪製) 用戶首次看到內容的時間 ⭐⭐⭐⭐⭐
LCP(最大內容繪製) 最大內容元素渲染完成時間 ⭐⭐⭐⭐⭐
SI(速度指數) 頁面可視區域填充速度 ⭐⭐⭐⭐
TTI(可互動時間) 頁面完全可互動的時間 ⭐⭐⭐⭐

📈 對業務的影響

根據 Google 的研究數據:

載入時間變化 跳出率變化 轉換率變化
1 秒 → 3 秒 +32% -20%
1 秒 → 5 秒 +90% -45%
1 秒 → 10 秒 +123% -60%

✅ 優化後的好处

  1. 更快的首次渲染:用戶立即看到內容
  2. 更好的用戶體驗:減少白屏時間
  3. 更高的 SEO 排名:Core Web Vitals 是排名因素
  4. 更低的跳出率:用戶更願意等待
  5. 更高的轉換率:載入越快,轉換越高

常見的禁止轉譯資源類型

1️⃣ CSS 樣式表

阻塞原因: 瀏覽器需要 CSS 來計算樣式,無法在 CSS 載入前渲染頁面

常見情況:

<!-- 阻塞渲染 -->
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="framework.css">
<link rel="stylesheet" href="theme.css">

2️⃣ JavaScript 腳本

阻塞原因: JavaScript 可能修改 DOM,瀏覽器必須等待腳本執行完成

常見情況:

<!-- 阻塞渲染 -->
<script src="jquery.js"></script>
<script src="main.js"></script>
<script src="analytics.js"></script>

3️⃣ Web 字體

阻塞原因: 字體載入前的文字不可見(FOIT)或顯示備用字體(FOUT)

常見情況:

/* 可能導致渲染延遲 */
@font-face {
  font-family: 'CustomFont';
  src: url('font.woff2') format('woff2');
}

4️⃣ 第三方資源

常見阻塞來源:

  • Google Analytics
  • Facebook Pixel
  • Google Ads
  • 社交媒體按鈕
  • 即時聊天工具

檢測工具與分析方法

🔍 Google PageSpeed Insights

網址: https://pagespeed.web.dev/

使用方式:

  1. 輸入網站網址
  2. 點擊「分析」
  3. 查看「排除禁止轉譯的資源」建議

解讀報告:

排除禁止轉譯的資源 估計可節省 1.2 秒

潛在的節省資源:
- /css/styles.css (節省 450ms)
- /js/main.js (節省 380ms)
- /css/framework.css (節省 370ms)

🔍 Chrome DevTools Lighthouse

開啟方式:

  1. 開啟網頁
  2. F12 開啟 DevTools
  3. 切換到 Lighthouse 標籤
  4. 點擊「分析頁面載入效能」

優勢:

  • 本地測試,無需上傳
  • 可測試需要登入的頁面
  • 提供詳細的水線圖(Waterfall)

🔍 Chrome DevTools Coverage

使用方式:

  1. 開啟 DevTools(F12)
  2. Ctrl+Shift+P(Mac: Cmd+Shift+P
  3. 輸入「Coverage」並選擇 Show Coverage
  4. 點擊重新載入按鈕

功能: 顯示 CSS/JS 的使用率,找出未使用的程式碼

🔍 WebPageTest

網址: https://www.webpagetest.org/

優勢:

  • 全球多地測試節點
  • 詳細的水線圖分析
  • 影片回放功能
  • 可模擬不同網路速度

優化 CSS 的實用技巧

方法一:內聯關鍵 CSS(Critical CSS)

原理: 將首屏(Above the Fold)所需的 CSS 直接嵌入 HTML

實作:

<head>
  <!-- 關鍵 CSS 內聯 -->
  <style>
    /* 首屏所需的樣式 */
    body { font-family: Arial, sans-serif; margin: 0; }
    .header { background: #333; color: white; }
    .hero { height: 100vh; display: flex; align-items: center; }
  </style>
  
  <!-- 非關鍵 CSS 非同步載入 -->
  <link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
  <noscript><link rel="stylesheet" href="styles.css"></noscript>
</head>

工具推薦:

  • Critical(npm 套件):自動提取關鍵 CSS
  • Penthouse:基於 URL 的關鍵 CSS 生成
  • Critters(Webpack 插件):自動內聯關鍵 CSS

使用 Critical 範例:

npm install critical
const critical = require('critical');

critical.generate({
  inline: true,
  base: 'dist/',
  src: 'index.html',
  dest: 'index.html',
  minify: true,
  width: 1920,
  height: 1080
});

方法二:非同步載入 CSS

原理: 使用 preloadmedia 屬性避免阻塞

實作方式 A:preload + onload

<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>

實作方式 B:media 屬性

<link rel="stylesheet" href="styles.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>

實作方式 C:JavaScript 動態載入

<script>
  const link = document.createElement('link');
  link.rel = 'stylesheet';
  link.href = 'styles.css';
  document.head.appendChild(link);
</script>

方法三:CSS 拆分與延遲載入

原理: 將 CSS 拆分為關鍵和非關鍵部分

實作:

<head>
  <!-- 關鍵 CSS(內聯) -->
  <style>/* 首屏樣式 */</style>
  
  <!-- 非關鍵 CSS(非同步) -->
  <link rel="preload" href="non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
</head>

CSS 拆分策略:

/* critical.css - 首屏樣式 */
.header, .hero, .nav { ... }

/* non-critical.css - 其他樣式 */
.footer, .sidebar, .comments { ... }

方法四:移除未使用的 CSS

原理: 減少 CSS 檔案大小,加快載入速度

工具推薦:

  • PurgeCSS:掃描 HTML/JS,移除未使用的 CSS
  • UnCSS:類似 PurgeCSS
  • Webpack + PurgeCSS:自動化流程

使用 PurgeCSS 範例:

npm install purgecss
const { PurgeCSS } = require('purgecss');

(async () => {
  const purgeCSSResults = await new PurgeCSS().purge({
    content: ['*.html', './src/**/*.js'],
    css: ['*.css']
  });
  console.log(purgeCSSResults);
})();

效果: 通常可減少 70-90% 的 CSS 大小


優化 JavaScript 的實用技巧

方法一:使用 async 屬性

原理: 腳本非同步下載,下載完成後立即執行(不等待 HTML 解析)

實作:

<!-- 阻塞 -->
<script src="analytics.js"></script>

<!-- 非阻塞(推薦用於獨立腳本) -->
<script src="analytics.js" async></script>

適用場景:

  • Google Analytics
  • 廣告腳本
  • 社交媒體按鈕
  • 不依賴 DOM 的腳本

執行順序:

HTML 解析 → 遇到 <script async>
              ↓
          非同步下載
              ↓
          下載完成 → 立即執行
              ↓
HTML 解析繼續(可能被打斷)

方法二:使用 defer 屬性

原理: 腳本非同步下載,但等到 HTML 解析完成後才執行

實作:

<!-- 阻塞 -->
<script src="main.js"></script>

<!-- 非阻塞(推薦用於依賴 DOM 的腳本) -->
<script src="main.js" defer></script>

適用場景:

  • 依賴 DOM 的腳本
  • 需要按順序執行的腳本
  • 主要的應用程式腳本

執行順序:

HTML 解析 → 遇到 <script defer>
              ↓
          非同步下載
              ↓
HTML 解析完成 → 按順序執行
              ↓
DOMContentLoaded 事件

方法三:將腳本移至底部

原理:<script> 標籤放在 </body> 之前

實作:

<body>
  <!-- 頁面內容 -->
  <div id="app">...</div>
  
  <!-- 腳本放在底部 -->
  <script src="main.js"></script>
</body>

優點:

  • 簡單易用
  • 無需修改腳本內容

缺點:

  • 腳本下載仍會延遲
  • 不如 defer 現代化

方法四:代碼拆分(Code Splitting)

原理: 將大型腳本拆分為多個小塊,按需載入

Webpack 實作:

// 動態導入
const module = await import('./heavy-module.js');

// 或使用 magic comments
const module = await import(
  /* webpackChunkName: "heavy-module" */
  './heavy-module.js'
);

效果:

  • 初始載入更快
  • 按需載入功能模組
  • 改善快取效率

方法五:Tree Shaking

原理: 移除未使用的程式碼

Webpack 設定:

// webpack.config.js
module.exports = {
  mode: 'production', // 自動啟用 Tree Shaking
  optimization: {
    usedExports: true, // 標記未使用的 exports
    sideEffects: false // 標記無副作用的模組
  }
};

套件設定(package.json):

{
  "sideEffects": [
    "*.css",
    "*.scss"
  ]
}

進階優化策略

策略一:資源提示(Resource Hints)

preload: 預先載入當前頁面必需的資源

<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="main.js" as="script">

prefetch: 預先載入下一頁可能需要的資源

<link rel="prefetch" href="next-page.js">

preconnect: 預先建立連線

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.example.com">

dns-prefetch: 預先解析 DNS

<link rel="dns-prefetch" href="https://analytics.google.com">

策略二:服務_worker 快取

原理: 使用 Service Worker 快取資源,減少網路請求

基本實作:

// sw.js
const CACHE_NAME = 'v1';
const ASSETS = [
  '/',
  '/styles.css',
  '/main.js',
  '/font.woff2'
];

self.addEventListener('install', (e) => {
  e.waitUntil(
    caches.open(CACHE_NAME).then((cache) => cache.addAll(ASSETS))
  );
});

self.addEventListener('fetch', (e) => {
  e.respondWith(
    caches.match(e.request).then((response) => response || fetch(e.request))
  );
});

註冊 Service Worker:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js');
}

策略三:HTTP/2 與 HTTP/3

優勢:

  • 多路復用(Multiplexing):單一連線傳輸多個資源
  • 伺服器推送(Server Push):主動推送資源
  • 標頭壓縮:減少傳輸大小

Nginx 設定:

server {
  listen 443 ssl http2;
  
  ssl_certificate /path/to/cert.pem;
  ssl_certificate_key /path/to/key.pem;
  
  # 啟用 HTTP/2 Push
  http2_push /styles.css;
  http2_push /main.js;
}

策略四:CDN 加速

推薦 CDN:

  • Cloudflare:免費方案、全球節點
  • Fastly:高性能、即時失效
  • Akamai:企業級、最大網路
  • AWS CloudFront:與 AWS 整合

優化效果:

  • 減少延遲(更近的節點)
  • 分擔源站負載
  • 內建壓縮與優化

策略五:現代化構建工具

Vite: 基於 ESM 的現代構建工具

npm create vite@latest

優勢:

  • 開發時無需打包
  • 生產時使用 Rollup 優化
  • 內建代碼拆分
  • 更快的熱更新

實際案例與效果對比

案例一:電商網站首頁

優化前:

  • FCP: 3.2 秒
  • LCP: 4.8 秒
  • 阻塞資源:8 個(5 CSS + 3 JS)
  • 總大小:2.4 MB

優化措施:

  1. 內聯關鍵 CSS(節省 800ms)
  2. 非同步載入非關鍵 CSS(節省 600ms)
  3. 使用 defer 載入 JS(節省 1.2 秒)
  4. 移除未使用 CSS(減少 60% 大小)
  5. 啟用 CDN(減少 40% 延遲)

優化後:

  • FCP: 1.1 秒(-66%)
  • LCP: 1.8 秒(-63%)
  • 阻塞資源:0 個
  • 總大小:800 KB(-67%)

業務影響:

  • 跳出率:-25%
  • 轉換率:+18%
  • 平均訂單金額:+12%

案例二:新聞媒體網站

優化前:

  • FCP: 2.8 秒
  • LCP: 4.2 秒
  • 阻塞資源:6 個(4 CSS + 2 JS)

優化措施:

  1. 使用 Critical CSS
  2. 第三方腳本改用 async
  3. 圖片延遲載入(Lazy Load)
  4. 啟用 HTTP/2

優化後:

  • FCP: 0.9 秒(-68%)
  • LCP: 1.5 秒(-64%)
  • Google PageSpeed 分數:45 → 92

案例三:SaaS 應用後台

優化前:

  • TTI: 5.6 秒
  • 阻塞資源:12 個

優化措施:

  1. 代碼拆分(Code Splitting)
  2. 路由層級 lazy loading
  3. Tree Shaking
  4. Service Worker 快取

優化後:

  • TTI: 1.8 秒(-68%)
  • 阻塞資源:2 個
  • 用戶滿意度:+35%

常見問題與解答

Q1:內聯 CSS 會增加 HTML 大小嗎?

答: 會,但只內聯關鍵 CSS(通常 10-15KB),遠小於完整 CSS 檔案。

最佳實踐:

  • 只內聯首屏所需的 CSS
  • 非關鍵 CSS 非同步載入
  • 使用工具自動提取關鍵 CSS

Q2:async 和 defer 有什麼差別?

特性 async defer
下載 非同步 非同步
執行時機 下載完成立即執行 HTML 解析完成後執行
執行順序 不保證 按順序
適用場景 獨立腳本(如分析) 依賴 DOM 的腳本

建議: 優先使用 defer,除非腳本完全獨立


Q3:如何處理第三方腳本的阻塞?

解決方案:

<!-- 方案 1:async -->
<script async src="https://www.googletagmanager.com/gtag/js"></script>

<!-- 方案 2:延遲載入 -->
<script>
  setTimeout(() => {
    const script = document.createElement('script');
    script.src = 'https://third-party.js';
    document.body.appendChild(script);
  }, 3000);
</script>

<!-- 方案 3:使用者互動後載入 -->
<script>
  document.addEventListener('click', () => {
    const script = document.createElement('script');
    script.src = 'https://chat-widget.js';
    document.body.appendChild(script);
  }, { once: true });
</script>

Q4:優化後樣式跑掉了怎麼辦?

可能原因:

  1. 關鍵 CSS 提取不完整
  2. CSS 載入順序錯誤
  3. specificity 改變

解決方案:

  1. 使用工具完整提取關鍵 CSS
  2. 確保非關鍵 CSS 在非同步載入後應用
  3. 測試不同視窗大小

測試清單:

  • [ ] 桌面版(1920px)
  • [ ] 平板版(768px)
  • [ ] 手機版(375px)
  • [ ] 滾動頁面檢查樣式

Q5:如何持續監控性能?

推薦工具:

  1. Google Search Console:Core Web Vitals 報告
  2. Chrome UX Report:真實用戶數據
  3. Web Vitals Library:前端監控
  4. Lighthouse CI:自動化測試

Web Vitals 監控實作:

import { onFCP, onLCP, onCLS } from 'web-vitals';

onFCP(console.log);
onLCP(console.log);
onCLS(console.log);

結論

排除禁止轉譯資源是提升網站性能的最有效方法之一。透過正確的優化策略,可以顯著改善用戶體驗、提高 SEO 排名,並帶來實際的業務成長。

快速開始清單

  1. 檢測:使用 PageSpeed Insights 找出阻塞資源
  2. CSS 優化:內聯關鍵 CSS + 非同步載入剩餘 CSS
  3. JS 優化:使用 deferasync
  4. 移除冗餘:刪除未使用的 CSS/JS
  5. 監控:持續追蹤 Core Web Vitals 指標

優先順序建議

優先級 優化項目 預期效果
🔴 高 內聯關鍵 CSS FCP -40%
🔴 高 JS 使用 defer/async FCP -30%
🟡 中 移除未使用 CSS 大小 -60%
🟡 中 代碼拆分 TTI -40%
🟢 低 HTTP/2 Push 延遲 -20%

最終建議

  • 從最影響的優化開始:關鍵 CSS + JS defer
  • 測試每一個改動:確保功能正常
  • 持續監控:性能優化是持續過程
  • 平衡複雜度:不要過度優化

記住:最快的資源是無需載入的資源。優先考慮移除不必要的資源,其次才是優化載入方式。


參考資源