<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="pretty-atom-feed.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hant">
  <title>光輝咖碼</title>
  <subtitle>沒有一杯咖啡解決不了的問題；如果有，就交給 AI 吧。這裡分享網站架設、前端開發與各種技術筆記，然後再來一杯。</subtitle>
  <link href="https://kamadiam.com/feed/feed.xml" rel="self" />
  <link href="https://kamadiam.com/" />
  <updated>2026-08-10T06:12:00Z</updated>
  <id>https://kamadiam.com/</id>
  <author>
    <name>huihere</name>
  </author>
  <entry>
    <title>VPN 跟 HTTPS 差在哪？公共 Wi-Fi 上到底要開哪一個？</title>
    <link href="https://kamadiam.com/vpn-vs-https-difference/" />
    <updated>2026-08-10T06:12:00Z</updated>
    <id>https://kamadiam.com/vpn-vs-https-difference/</id>
    <content type="html">&lt;p&gt;咖啡店連上 Wi-Fi，網址列出現鎖頭，很多人就以為「這台手機已經安全了」——鎖頭很可愛，但它只管你和&lt;strong&gt;某一個網站&lt;/strong&gt;之間的傳輸，不是整台手機的保護罩。也有人聽說 VPN 很神，開了以為能防釣魚、防病毒；結果在假網站輸入密碼，VPN 還是會很盡責地把資料加密送到那個假網站。唉。&lt;p&gt;其實 &lt;strong&gt;HTTPS 和 VPN 保護的是不同層次&lt;/strong&gt;：一個管你和「某個網站」之間的內容，一個管你和「整段網路」之間的連線。搞懂差異，你才能判斷：看新聞可能不用 VPN，但登入信箱或網銀時，光靠鎖頭可能不夠。讀完這篇，你應該能用一張表快速決定「現在這件事，HTTPS 夠嗎？要不要加 VPN？」&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/vpn-vs-https-difference/#%E4%B8%80%E5%8F%A5%E8%A9%B1%E8%A8%98%E4%BD%8F%E5%85%A9%E8%80%85%E4%BF%9D%E8%AD%B7%E7%9A%84%E7%AF%84%E5%9C%8D%E4%B8%8D%E5%90%8C&quot;&gt;一句話記住：兩者保護的範圍不同&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/vpn-vs-https-difference/#HTTPS-%E4%BF%9D%E8%AD%B7%E4%BB%80%E9%BA%BC?%E9%8E%96%E9%A0%AD%E4%BB%A3%E8%A1%A8%E4%BB%80%E9%BA%BC?&quot;&gt;HTTPS 保護什麼？鎖頭代表什麼？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/vpn-vs-https-difference/#VPN-%E8%A3%9C%E4%B8%8A%E5%93%AA%E4%B8%80%E5%A1%8A?%E7%82%BA%E4%BB%80%E9%BA%BC-HTTPS-%E5%A4%A0%E4%BA%86%E9%82%84%E6%9C%89%E4%BA%BA%E9%96%8B-VPN?&quot;&gt;VPN 補上哪一塊？為什麼 HTTPS 夠了還有人開 VPN？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/vpn-vs-https-difference/#%E6%83%85%E5%A2%83%E6%B1%BA%E7%AD%96%E8%A1%A8%E6%88%91%E7%8F%BE%E5%9C%A8%E8%A6%81%E5%81%9A%E7%9A%84%E4%BA%8B,%E8%A6%81%E9%96%8B-VPN-%E5%97%8E?&quot;&gt;情境決策表：我現在要做的事，要開 VPN 嗎？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/vpn-vs-https-difference/#%E5%B8%B8%E8%A6%8B%E8%AA%A4%E8%A7%A3%E5%88%A5%E6%8A%8A%E9%8E%96%E9%A0%AD%E6%88%96-VPN-%E7%95%B6%E8%90%AC%E8%83%BD%E8%97%A5&quot;&gt;常見誤解：別把鎖頭或 VPN 當萬能藥&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/vpn-vs-https-difference/#%E4%B8%89%E5%88%86%E9%90%98%E5%AE%89%E5%85%A8%E6%AA%A2%E6%9F%A5%E6%B8%85%E5%96%AE&quot;&gt;三分鐘安全檢查清單&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/vpn-vs-https-difference/#%E6%8E%A8%E8%96%A6%E5%B7%A5%E5%85%B7%E8%88%87%E8%B3%87%E6%BA%90&quot;&gt;推薦工具與資源&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/vpn-vs-https-difference/#%E7%B5%90%E8%AA%9E%E5%85%88%E6%90%9E%E6%87%82%E5%B1%A4%E6%AC%A1,%E5%86%8D%E6%B1%BA%E5%AE%9A%E8%A6%81%E4%B8%8D%E8%A6%81%E9%96%8B-VPN&quot;&gt;結語：先搞懂層次，再決定要不要開 VPN&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/vpn-vs-https-difference/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;一句話記住兩者保護的範圍不同&quot;&gt;一句話記住：兩者保護的範圍不同&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;th&gt;HTTPS&lt;th&gt;VPN&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;保護對象&lt;/strong&gt;&lt;td&gt;你和&lt;strong&gt;某一個網站&lt;/strong&gt;之間的連線&lt;td&gt;你的裝置到 &lt;strong&gt;VPN 伺服器&lt;/strong&gt;之間的&lt;strong&gt;整段流量&lt;/strong&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;主要功能&lt;/strong&gt;&lt;td&gt;加密內容、防止竄改、驗證網站身分&lt;td&gt;把本地網路／ISP 能看到的活動藏起來，換成 VPN 業者成為信任對象&lt;tr&gt;&lt;td&gt;&lt;strong&gt;典型比喻&lt;/strong&gt;&lt;td&gt;寄信時用密封信封，只有收信人能打開&lt;td&gt;整條路都走加密隧道，路邊的人較難看你去了哪裡&lt;tr&gt;&lt;td&gt;&lt;strong&gt;不能做的事&lt;/strong&gt;&lt;td&gt;不能證明網站不是假的；不保護其他 App 流量&lt;td&gt;不能防釣魚、不能防病毒；目的地若沒 HTTPS 仍可能明文&lt;/table&gt;&lt;p&gt;記這四句就夠（比背 VPN 協定名稱實用多了）：&lt;ul&gt;&lt;li&gt;&lt;strong&gt;沒有 HTTPS&lt;/strong&gt;：別人可能看到或修改你與網站交換的內容。&lt;li&gt;&lt;strong&gt;有 HTTPS、沒有 VPN&lt;/strong&gt;：內容通常受保護，但本地網路仍可能知道你連到哪些網域。&lt;li&gt;&lt;strong&gt;有 VPN、沒有 HTTPS&lt;/strong&gt;：裝置到 VPN 這一段受保護，但網站端與 VPN 業者仍是信任問題。&lt;li&gt;&lt;strong&gt;兩者都有&lt;/strong&gt;：公共網路上較完整的組合，但仍不能取代防詐、更新、強密碼與 MFA。&lt;/ul&gt;&lt;h2 id=&quot;HTTPS-保護什麼?鎖頭代表什麼?&quot;&gt;HTTPS 保護什麼？鎖頭代表什麼？&lt;/h2&gt;&lt;p&gt;HTTPS 是 HTTP 加上 TLS 加密。依 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Transport_Layer_Security&quot;&gt;Mozilla&lt;/a&gt; 等官方說明，它主要做三件事：&lt;ol&gt;&lt;li&gt;&lt;strong&gt;加密&lt;/strong&gt;：傳輸中的資料不容易被旁觀者讀取。&lt;li&gt;&lt;strong&gt;完整性&lt;/strong&gt;：攻擊者不能在途中悄悄改內容而不被發現。&lt;li&gt;&lt;strong&gt;伺服器驗證&lt;/strong&gt;：瀏覽器透過憑證確認自己連到的是宣稱的網域。&lt;/ol&gt;&lt;p&gt;所以在沒有 HTTPS 的網站上（網址仍是 &lt;code&gt;http://&lt;/code&gt;），公共 Wi-Fi 上的其他人可能看到帳號、密碼或表單內容，也可能改頁面。&lt;strong&gt;千萬不要在 HTTP 網站輸入信用卡或登入資料&lt;/strong&gt;——那就像用透明信封寄密碼，鎖頭還沒上場。&lt;p&gt;但 HTTPS &lt;strong&gt;不是整台裝置的加密罩&lt;/strong&gt;：&lt;ul&gt;&lt;li&gt;它通常只保護&lt;strong&gt;瀏覽器與特定網站&lt;/strong&gt;之間的連線，不會自動保護其他 App。&lt;li&gt;網路觀察者通常仍可能知道你連到哪個&lt;strong&gt;網域&lt;/strong&gt;、連線時間與流量大小；不一定能看到具體頁面內容。&lt;li&gt;&lt;strong&gt;有 HTTPS 不代表網站可信&lt;/strong&gt;。假網站也可能申請有效憑證——鎖頭只代表傳輸加密，不代表這家公司是真的（證書不會幫你審核商業道德）。&lt;li&gt;若頁面載入未加密的圖片、腳本等混合內容，整體安全性可能被削弱。&lt;/ul&gt;&lt;p&gt;現代網站大多已強制 HTTPS，Google 也把它當 SEO 因素；Chrome 會把純 HTTP 標成「不安全」。對&lt;strong&gt;站長&lt;/strong&gt;來說，HTTPS 是建站基本功；對&lt;strong&gt;一般使用者&lt;/strong&gt;來說，重點是：敏感操作前確認網址是 &lt;code&gt;https://&lt;/code&gt;，並核對網域拼字——&lt;code&gt;g00gle.com&lt;/code&gt; 有鎖頭也沒用。&lt;h2 id=&quot;VPN-補上哪一塊?為什麼-HTTPS-夠了還有人開-VPN?&quot;&gt;VPN 補上哪一塊？為什麼 HTTPS 夠了還有人開 VPN？&lt;/h2&gt;&lt;p&gt;VPN 會在裝置與 VPN 伺服器之間建立加密通道。對公共 Wi-Fi 業者或 ISP 而言，較難直接看到你通道內的瀏覽目的地；網站看到的來源 IP 也通常會變成 VPN 伺服器的 IP。&lt;p&gt;VPN 比較適合這些情境：&lt;ul&gt;&lt;li&gt;你不信任目前的網路（旅館、機場、咖啡店 Wi-Fi）。&lt;li&gt;你不希望本地網路業者直接看到你的瀏覽網域或 DNS 查詢。&lt;li&gt;你需要連回公司或家中的私有網路。&lt;/ul&gt;&lt;p&gt;但 VPN &lt;strong&gt;不是匿名按鈕&lt;/strong&gt;，也不是防毒軟體：&lt;ul&gt;&lt;li&gt;VPN 業者本身成為新的信任對象，可能看見部分連線資訊；挑選時要查隱私政策、商業模式與獨立稽核。&lt;li&gt;VPN 不會阻止釣魚網站、惡意下載、Cookie、帳號登入或裝置指紋追蹤。&lt;li&gt;若目的地網站沒有 HTTPS，VPN 伺服器到網站之間的內容仍可能沒有端對端保護。&lt;li&gt;連線中斷、設定錯誤或未更新時，保護效果可能不如預期。&lt;/ul&gt;&lt;p&gt;&lt;a href=&quot;https://ssd.eff.org/module/choosing-vpn-thats-right-you&quot;&gt;EFF&lt;/a&gt; 在 2026 年更新的 VPN 指南也提醒：現代網路大多已使用 HTTPS，因此 VPN &lt;strong&gt;不一定是&lt;/strong&gt;防公共 Wi-Fi 大多數威脅的&lt;strong&gt;必要條件&lt;/strong&gt;；它更主要是在保護&lt;strong&gt;網路中繼資料&lt;/strong&gt;（例如你連了哪些網域），以及把信任從 ISP／本地網路&lt;strong&gt;轉移&lt;/strong&gt;到 VPN 業者——不是讓你完全隱形，只是換一個你要信任的人。&lt;h2 id=&quot;情境決策表我現在要做的事,要開-VPN-嗎?&quot;&gt;情境決策表：我現在要做的事，要開 VPN 嗎？&lt;/h2&gt;&lt;p&gt;把「內容、網域、整台裝置流量」分開想，就不會亂開或亂關 VPN——也不會在查地圖時硬開 VPN 然後抱怨速度變慢。&lt;h3 id=&quot;公共-Wi-Fi-常見情境&quot;&gt;公共 Wi-Fi 常見情境&lt;/h3&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;情境&lt;th&gt;沒有 HTTPS 的風險&lt;th&gt;沒有 VPN 的限制&lt;th&gt;較實際的做法&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;咖啡店登入銀行或信箱&lt;td&gt;他人可能讀取或竄改登入內容&lt;td&gt;Wi-Fi 業者仍可能看到你連到哪些網域&lt;td&gt;優先改用手機行動網路；必須用公共 Wi-Fi 時，確認 HTTPS &lt;strong&gt;再加&lt;/strong&gt;可信任 VPN&lt;tr&gt;&lt;td&gt;在家瀏覽一般 HTTPS 網站&lt;td&gt;若網站只用 HTTP，內容可能被窺看&lt;td&gt;ISP 通常仍能看到網域；網站也能用 Cookie 辨識你&lt;td&gt;不在 HTTP 網站輸入敏感資料；需要隱私時用 VPN，並保持系統更新&lt;/table&gt;&lt;h3 id=&quot;我要做什麼-→-怎麼連線一頁帶走&quot;&gt;我要做什麼 → 怎麼連線（一頁帶走）&lt;/h3&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;我要做什麼&lt;th&gt;建議連線方式&lt;th&gt;要 VPN 嗎&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;看新聞、查地圖&lt;td&gt;公共 Wi-Fi 或 eSIM&lt;td&gt;可選&lt;tr&gt;&lt;td&gt;機場查航班&lt;td&gt;公共 Wi-Fi 或 eSIM&lt;td&gt;可選&lt;tr&gt;&lt;td&gt;飯店 Wi-Fi 看 YouTube&lt;td&gt;飯店 Wi-Fi + VPN&lt;td&gt;建議&lt;tr&gt;&lt;td&gt;登入信箱、社群&lt;td&gt;Wi-Fi 或 eSIM + VPN&lt;td&gt;✅ 建議&lt;tr&gt;&lt;td&gt;咖啡廳寄信&lt;td&gt;Wi-Fi 或 eSIM + VPN&lt;td&gt;✅ 建議&lt;tr&gt;&lt;td&gt;eSIM 登入銀行 App&lt;td&gt;旅遊 eSIM + VPN&lt;td&gt;✅&lt;tr&gt;&lt;td&gt;網銀轉帳&lt;td&gt;&lt;strong&gt;手機 eSIM／個人熱點&lt;/strong&gt; + VPN&lt;td&gt;✅ 必開&lt;/table&gt;&lt;h3 id=&quot;只有-HTTPS-夠嗎?快速對照&quot;&gt;只有 HTTPS 夠嗎？快速對照&lt;/h3&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;只做這件事&lt;th&gt;HTTPS 夠嗎&lt;th&gt;要 VPN 嗎&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;看新聞、查地圖&lt;td&gt;通常夠&lt;td&gt;可選&lt;tr&gt;&lt;td&gt;登入信箱、社群&lt;td&gt;建議加 VPN&lt;td&gt;✅&lt;tr&gt;&lt;td&gt;網銀、購物、公司系統&lt;td&gt;不建議只靠公共 Wi-Fi&lt;td&gt;✅ 必開&lt;/table&gt;&lt;p&gt;&lt;strong&gt;Q：有 HTTPS 了，還需要 VPN 嗎？&lt;/strong&gt;&lt;p&gt;短答：敏感操作（銀行、信箱、公司系統）&lt;strong&gt;建議還是要&lt;/strong&gt;。&lt;p&gt;HTTPS 保護你和&lt;strong&gt;正確網站&lt;/strong&gt;之間的傳輸加密；但它不能證明你連的是真網站，也不能阻止別人在公共網路上看到你的 DNS 查詢或流量模式。VPN 多一層從裝置到 VPN 伺服器的加密——兩層疊起來，至少不會只靠一把鎖頭硬撐。&lt;h2 id=&quot;常見誤解別把鎖頭或-VPN-當萬能藥&quot;&gt;常見誤解：別把鎖頭或 VPN 當萬能藥&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;「有鎖頭就安全」&lt;/strong&gt; — 假網站也可能有 HTTPS；要看網域是否正確，必要時用書籤或官方 App。&lt;li&gt;&lt;strong&gt;「開了 VPN 就不會被駭」&lt;/strong&gt; — VPN 不防釣魚；你若在仿冒 HTTPS 網站輸入密碼，VPN 仍會把資料加密送到那個假網站（加密很盡責，方向錯了）。&lt;li&gt;&lt;strong&gt;「飯店 Wi-Fi 有密碼就安全」&lt;/strong&gt; — 密碼通常只防路過的人；同飯店其他住客或被入侵的路由器仍有風險。敏感操作用 eSIM 或個人熱點更穩。&lt;li&gt;&lt;strong&gt;「VPN 可以取代防毒、MFA、更新」&lt;/strong&gt; — 不能。完整防線還需要強密碼、多因素驗證、系統與瀏覽器更新。&lt;/ol&gt;&lt;h2 id=&quot;三分鐘安全檢查清單&quot;&gt;三分鐘安全檢查清單&lt;/h2&gt;&lt;p&gt;出門連陌生 Wi-Fi 前，照這六步做（比多下載三個「Wi-Fi 加速器」實用）：&lt;ol&gt;&lt;li&gt;&lt;strong&gt;先確認網路名稱&lt;/strong&gt;：向店家或櫃檯確認 SSID，不要只選訊號最強的同名網路。&lt;li&gt;&lt;strong&gt;先看網址&lt;/strong&gt;：敏感操作前確認是 &lt;code&gt;https://&lt;/code&gt;，不要因為有鎖頭就忽略網域拼字。&lt;li&gt;&lt;strong&gt;能不用公共 Wi-Fi 就不用&lt;/strong&gt;：金融交易、工作機密或重要帳號，優先用手機行動網路或個人熱點。&lt;li&gt;&lt;strong&gt;需要隱藏網路活動時才加 VPN&lt;/strong&gt;：選可信任、持續更新且有清楚隱私政策的服務。&lt;li&gt;&lt;strong&gt;關閉自動連線與檔案分享&lt;/strong&gt;：公共網路上關閉自動加入 Wi-Fi、AirDrop／檔案分享等不需要的功能。&lt;li&gt;&lt;strong&gt;補上其他防線&lt;/strong&gt;：更新系統與瀏覽器、使用獨立強密碼、開啟 MFA，並保留裝置防毒與備份。&lt;/ol&gt;&lt;h2 id=&quot;推薦工具與資源&quot;&gt;推薦工具與資源&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;工具&lt;th&gt;適合誰&lt;th&gt;說明&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https://pr.tn/ref/SZX2CCB0&quot;&gt;Proton VPN&lt;/a&gt;&lt;/strong&gt;（主推）&lt;td&gt;常在公共 Wi-Fi、旅行、需要免費入門的人&lt;td&gt;免費版已有 Kill Switch、無日誌政策與不限流量；公共網路上是 HTTPS 之外合理的一步。付費版解鎖更多國家、串流與進階功能。&lt;tr&gt;&lt;td&gt;手機行動網路／個人熱點&lt;td&gt;網銀、轉帳、公司系統&lt;td&gt;不依賴陌生路由器；敏感操作時往往比「公共 Wi-Fi + 任何工具」更穩。&lt;tr&gt;&lt;td&gt;密碼管理器 + MFA&lt;td&gt;所有有帳號的人&lt;td&gt;VPN 與 HTTPS 都不防帳號被盜；強密碼與驗證器 App 是基本配。&lt;/table&gt;&lt;p&gt;若你還在猶豫免費版夠不夠用，可參考站內 &lt;a href=&quot;https://kamadiam.com/proton-vpn-paid-review/&quot;&gt;Proton VPN 付費版評價&lt;/a&gt; 或 &lt;a href=&quot;https://kamadiam.com/proton-vpn-free-vs-paid-review/&quot;&gt;免費版與付費版完整解析&lt;/a&gt;。&lt;h2 id=&quot;結語先搞懂層次,再決定要不要開-VPN&quot;&gt;結語：先搞懂層次，再決定要不要開 VPN&lt;/h2&gt;&lt;p&gt;HTTPS 和 VPN 不是二選一，而是&lt;strong&gt;疊加不同層次的保護&lt;/strong&gt;：&lt;ul&gt;&lt;li&gt;HTTPS 管你和網站之間的&lt;strong&gt;內容&lt;/strong&gt;有沒有被看見、被改掉。&lt;li&gt;VPN 管本地網路／ISP &lt;strong&gt;能不能輕易知道你去了哪裡&lt;/strong&gt;。&lt;/ul&gt;&lt;p&gt;看地圖、刷新聞，HTTPS 通常就夠；登入信箱、網銀或在飯店 Wi-Fi 上工作，建議 &lt;strong&gt;HTTPS + 可信任 VPN&lt;/strong&gt;，敏感金融操作則優先 &lt;strong&gt;行動網路 + VPN&lt;/strong&gt;。&lt;p&gt;若你常在咖啡店、機場或旅館上網，又不想一開始就付月費，可以先從 &lt;a href=&quot;https://pr.tn/ref/SZX2CCB0&quot;&gt;Proton VPN&lt;/a&gt; 免費版試起——在家連一次、開好 Kill Switch，下次出門就知道 HTTPS 之外還差哪一塊。沒有一杯咖啡解決不了的網路焦慮；如果有，就加一層 VPN——然後記得，咖啡還是要自己付。&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;聯盟揭露：&lt;/strong&gt; 本文包含 Proton VPN 推薦連結。如果你透過連結註冊或購買，我可能獲得推薦回饋；這不會增加你的費用。&lt;/blockquote&gt;&lt;p&gt;👉 &lt;a href=&quot;https://pr.tn/ref/SZX2CCB0&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer sponsored&quot;&gt;&lt;strong&gt;免費申請 Proton VPN 帳號 →&lt;/strong&gt;&lt;/a&gt;&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Transport_Layer_Security&quot;&gt;Mozilla MDN：Transport Layer Security (TLS)&lt;/a&gt; — TLS 的加密、完整性、驗證與混合內容說明。&lt;li&gt;&lt;a href=&quot;https://ssd.eff.org/module/choosing-vpn-thats-right-you&quot;&gt;EFF Surveillance Self-Defense：Choosing the VPN That&#39;s Right for You&lt;/a&gt; — VPN 用途、限制、信任轉移與選擇準則。&lt;li&gt;&lt;a href=&quot;https://www.cisa.gov/news-events/news/securing-wireless-networks&quot;&gt;CISA：Securing Wireless Networks&lt;/a&gt; — 公共 Wi-Fi、假基地台與流量監聽風險。&lt;li&gt;&lt;a href=&quot;https://consumer.ftc.gov/articles/are-public-wi-fi-networks-safe-what-you-need-know&quot;&gt;FTC：Are Public Wi-Fi Networks Safe?&lt;/a&gt; — 公共 Wi-Fi、HTTPS 與假網站提醒。&lt;li&gt;&lt;a href=&quot;https://protonvpn.com/blog/public-wifi-and-https&quot;&gt;Proton VPN：Why you need VPN to stay safe on public WiFi&lt;/a&gt; — DNS 查詢、公共 Wi-Fi 與 VPN 的差異說明。&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Proton VPN 付費版評價（2026）：VPN Plus 值得訂閱嗎？</title>
    <link href="https://kamadiam.com/proton-vpn-paid-review/" />
    <updated>2026-08-10T05:18:00Z</updated>
    <id>https://kamadiam.com/proton-vpn-paid-review/</id>
    <content type="html">&lt;p&gt;你已經用 &lt;a href=&quot;https://pr.tn/ref/SZX2CCB0&quot;&gt;Proton VPN&lt;/a&gt; 免費版一陣子了——不限流量、沒廣告，在咖啡店連公共 Wi‑Fi 還算安心。結果一到尖峰時段，影片轉圈圈、不能自己選國家、串流跟 BT 下載通通說再見，你就會開始想：&lt;strong&gt;付費版到底值不值得？還是免費版已經夠我這杯咖啡的預算？&lt;/strong&gt;&lt;p&gt;這篇不談「VPN 是什麼」（那篇留給入門文），專攻 &lt;strong&gt;VPN Plus 付費版評價&lt;/strong&gt;：速度差多少、哪些功能只有付費才有、跟 NordVPN、Surfshark 比怎麼選，以及訂閱前該確認的價格與退款條件。若你想先看免費版全貌，可搭配站內另一篇 &lt;a href=&quot;https://kamadiam.com/proton-vpn-free-vs-paid-review/&quot;&gt;Proton VPN 值得買嗎？免費版與付費版功能完整解析&lt;/a&gt;。&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/proton-vpn-paid-review/#%E5%85%88%E8%AC%9B%E7%B5%90%E8%AB%96%E4%BB%98%E8%B2%BB%E7%89%88%E9%81%A9%E5%90%88%E8%AA%B0?&quot;&gt;先講結論：付費版適合誰？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/proton-vpn-paid-review/#%E4%BB%98%E8%B2%BB%E7%89%88%E5%A4%9A%E4%BA%86%E4%BB%80%E9%BA%BC?VPN-Plus-%E5%8A%9F%E8%83%BD%E8%A9%95%E5%83%B9&quot;&gt;付費版多了什麼？（VPN Plus 功能評價）&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/proton-vpn-paid-review/#%E4%BB%98%E8%B2%BB%E7%89%88%E5%80%BC%E5%BE%97%E8%B2%B7%E5%97%8E?%E6%B1%BA%E7%AD%96%E8%A1%A8&quot;&gt;付費版值得買嗎？決策表&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/proton-vpn-paid-review/#%E5%83%B9%E6%A0%BC%E8%88%87%E6%96%B9%E6%A1%88%E5%88%A5%E5%8F%AA%E7%9C%8B%E4%BF%83%E9%8A%B7%E6%A8%99%E8%AA%9E&quot;&gt;價格與方案：別只看促銷標語&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/proton-vpn-paid-review/#%E8%B7%9F-NordVPNSurfshark-%E6%AF%94%E4%BB%98%E8%B2%BB%E7%89%88%E7%AB%99%E5%BE%97%E4%BD%8F%E5%97%8E?&quot;&gt;跟 NordVPN、Surfshark 比：付費版站得住嗎？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/proton-vpn-paid-review/#%E4%B8%B2%E6%B5%81%E5%AF%A6%E9%9A%9B%E8%A1%A8%E7%8F%BE%E4%BB%98%E8%B2%BB%E7%89%88%E7%9A%84%E7%9C%9F%E5%AF%A6%E6%9C%9F%E5%BE%85&quot;&gt;串流實際表現：付費版的真實期待&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/proton-vpn-paid-review/#%E8%A8%82%E9%96%B1%E5%89%8D%E6%AA%A2%E6%9F%A5%E6%B8%85%E5%96%AE&quot;&gt;訂閱前檢查清單&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/proton-vpn-paid-review/#%E6%8E%A8%E8%96%A6%E5%B7%A5%E5%85%B7/%E8%B3%87%E6%BA%90&quot;&gt;推薦工具／資源&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/proton-vpn-paid-review/#%E7%B5%90%E8%AA%9E%E6%88%91%E7%9A%84%E8%A9%95%E5%83%B9&quot;&gt;結語：我的評價&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/proton-vpn-paid-review/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;hr&gt;&lt;h2 id=&quot;先講結論付費版適合誰?&quot;&gt;先講結論：付費版適合誰？&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;你的情境&lt;th&gt;建議&lt;th&gt;原因&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;只在咖啡店偶爾上網、1 台裝置就夠&lt;td&gt;&lt;strong&gt;先維持免費版&lt;/strong&gt;&lt;td&gt;免費版已有 Kill Switch、無日誌、不限流量；付費的串流／選國家你用不到&lt;tr&gt;&lt;td&gt;想看 Netflix、Disney+ 等地區片庫&lt;td&gt;&lt;strong&gt;VPN Plus&lt;/strong&gt;&lt;td&gt;官方串流支援僅限付費方案；免費版不包含&lt;tr&gt;&lt;td&gt;需要 BT／P2P 下載&lt;td&gt;&lt;strong&gt;VPN Plus&lt;/strong&gt;&lt;td&gt;免費版不支援 P2P；Plus 有專用高速伺服器&lt;tr&gt;&lt;td&gt;家中 2–10 台裝置同時連線&lt;td&gt;&lt;strong&gt;VPN Plus&lt;/strong&gt;&lt;td&gt;最多 10 個同時連線（每個使用中的瀏覽器擴充也算 1 個）&lt;tr&gt;&lt;td&gt;重視可驗證的隱私證據，偶爾需要 Secure Core&lt;td&gt;&lt;strong&gt;VPN Plus&lt;/strong&gt;&lt;td&gt;Secure Core、NetShield、Stealth 混淆協定都是付費功能&lt;tr&gt;&lt;td&gt;同時需要 Proton Mail、Drive、Pass&lt;td&gt;&lt;strong&gt;Proton Unlimited&lt;/strong&gt;&lt;td&gt;別只用 VPN 月費比；把整個生態系需求一起算&lt;tr&gt;&lt;td&gt;家中超過 10 台裝置常同時連線&lt;td&gt;&lt;strong&gt;先比 Surfshark&lt;/strong&gt;&lt;td&gt;Surfshark 付費方案不限同時連線；Proton Plus 上限 10 台&lt;tr&gt;&lt;td&gt;主要追求最低月費或電視 Smart DNS 便利&lt;td&gt;&lt;strong&gt;先比 NordVPN&lt;/strong&gt;&lt;td&gt;NordVPN 在串流設備與近距離延遲上常有優勢，但隱私透明度呈現方式不同&lt;/table&gt;&lt;p&gt;&lt;strong&gt;一句話總結&lt;/strong&gt;：付費版的核心價值不是「比免費版快一點點」——那是把 VPN 當成咖啡濃縮，其實你缺的是整杯。完整伺服器選擇、串流／P2P、多裝置，加上 Secure Core 等進階功能，才是升級理由。若你只用免費版做基本加密，其實已經比多數免費 VPN 安全；付費是為了解除那些「剛好卡住你」的限制。&lt;h2 id=&quot;付費版多了什麼?VPN-Plus-功能評價&quot;&gt;付費版多了什麼？（VPN Plus 功能評價）&lt;/h2&gt;&lt;h3 id=&quot;速度差距比你想的大&quot;&gt;速度：差距比你想的大&lt;/h3&gt;&lt;p&gt;Proton 不對免費版人工限速，但免費伺服器（美國、荷蘭、日本）負載高，尖峰時段常擠——就像尖峰時段只有三條免費高速公路可選，還不能自己挑出口。第三方測試與社群實測的參考區間如下：&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;指標&lt;th&gt;免費版&lt;th&gt;VPN Plus 付費版&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;典型下載速度&lt;td&gt;50–150 Mbps（尖峰可能 &amp;lt;30 Mbps）&lt;td&gt;950–1,500+ Mbps&lt;tr&gt;&lt;td&gt;典型上傳速度&lt;td&gt;30–80 Mbps&lt;td&gt;800–1,200+ Mbps&lt;tr&gt;&lt;td&gt;延遲（Ping）&lt;td&gt;20–200+ ms&lt;td&gt;本地 5–30 ms；跨國 80–150 ms&lt;tr&gt;&lt;td&gt;伺服器&lt;td&gt;3 國自動分配&lt;td&gt;140+ 國、20,000+ 台 10 Gbps 伺服器&lt;tr&gt;&lt;td&gt;網路優先權&lt;td&gt;低（排隊等頻寬）&lt;td&gt;高（Priority Access）&lt;/table&gt;&lt;p&gt;付費版還有 &lt;strong&gt;VPN Accelerator&lt;/strong&gt;：透過優化 TCP 擁塞控制，長途連線速度可提升數倍。日常 4K 串流、大檔下載、視訊會議，付費版的穩定度通常明顯好一截。&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;誠實提醒&lt;/strong&gt;：以上數字來自第三方基準測試，你的實際結果會受 ISP、地理位置、伺服器負載與協定影響。訂閱前建議自己測——別讓評測文替你喝這杯苦澀的現實咖啡。&lt;/blockquote&gt;&lt;h3 id=&quot;只有付費版才有的功能&quot;&gt;只有付費版才有的功能&lt;/h3&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;功能&lt;th&gt;做什麼&lt;th&gt;適合誰&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;完整伺服器選擇&lt;/strong&gt;&lt;td&gt;自由選 140+ 國家，不再被系統分配到美／荷／日&lt;td&gt;需要特定地區 IP 的人&lt;tr&gt;&lt;td&gt;&lt;strong&gt;串流支援&lt;/strong&gt;&lt;td&gt;官方列出的 Netflix、Disney+ 等 Plus 伺服器&lt;td&gt;旅行或跨區看自有訂閱的片庫&lt;tr&gt;&lt;td&gt;&lt;strong&gt;P2P／BT&lt;/strong&gt;&lt;td&gt;專用高速伺服器&lt;td&gt;合法的大檔傳輸需求&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Secure Core&lt;/strong&gt;&lt;td&gt;流量先經瑞士／冰島／瑞典入口，再到出口國&lt;td&gt;高風險地區出口、重視實體防禦的使用者&lt;tr&gt;&lt;td&gt;&lt;strong&gt;NetShield&lt;/strong&gt;&lt;td&gt;DNS 級別擋惡意網域、廣告與追蹤器&lt;td&gt;想少裝一個廣告攔截器的人&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Stealth 協議&lt;/strong&gt;&lt;td&gt;把 VPN 流量偽裝成 HTTPS，繞過 DPI 審查&lt;td&gt;在嚴格網路環境需要連線的人&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Split Tunneling&lt;/strong&gt;&lt;td&gt;指定哪些 App 走 VPN、哪些走直連&lt;td&gt;同時要本地銀行 App 與 VPN 的場景&lt;tr&gt;&lt;td&gt;&lt;strong&gt;瀏覽器擴充&lt;/strong&gt;&lt;td&gt;Chrome／Firefox 一鍵連線&lt;td&gt;只想保護瀏覽器、不想全機 VPN 的人&lt;/table&gt;&lt;p&gt;Secure Core 和 Stealth 是 Proton 付費版較有特色的進階功能，多數競品沒有同等架構。但若你只是在家看串流，這兩個功能不是必開——Secure Core 還會讓速度更慢，官方也不建議拿它來排串流。開 Secure Core 看 Netflix，就像穿三層雨衣去海邊——很安全，但你不會因此游得比較快。&lt;h3 id=&quot;隱私與安全付費版有比較安全嗎?&quot;&gt;隱私與安全：付費版有比較安全嗎？&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;加密標準免費與付費相同&lt;/strong&gt;（AES-256、WireGuard 等），差別在進階功能與伺服器架構：&lt;ul&gt;&lt;li&gt;&lt;strong&gt;無日誌政策&lt;/strong&gt;：免費與付費共用同一套政策；Securitum 已連續第五年稽核，2026 年報告未發現伺服器記錄瀏覽活動或連線中繼資料。&lt;li&gt;&lt;strong&gt;瑞士管轄&lt;/strong&gt;：截至 2026 年 6 月的透明度報告，47 件外國請求全部標為無法提供資料——因為沒有紀錄可交。&lt;li&gt;&lt;strong&gt;開源 App&lt;/strong&gt;：程式碼公開在 GitHub，任何人可審計。&lt;li&gt;&lt;strong&gt;Kill Switch&lt;/strong&gt;：免費版也有；但 macOS 切換伺服器時可能有短暫 IP 暴露，各平台限制不同。&lt;/ul&gt;&lt;p&gt;付費版真正的安全加值是 &lt;strong&gt;Secure Core&lt;/strong&gt;（多一跳、實體防禦入口）和 &lt;strong&gt;NetShield&lt;/strong&gt;（擋已知惡意網域），不是「付費才加密」。若你重視可驗證的隱私證據，Proton 在公開稽核與開源這點上，確實比多數競品透明。&lt;h2 id=&quot;付費版值得買嗎?決策表&quot;&gt;付費版值得買嗎？決策表&lt;/h2&gt;&lt;p&gt;把「要不要付費」拆成可勾選的條件：&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;你的需求&lt;th&gt;免費版夠嗎？&lt;th&gt;付費版加分多少？&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;公共 Wi‑Fi 基本加密&lt;td&gt;✅ 夠&lt;td&gt;付費主要是速度與穩定度&lt;tr&gt;&lt;td&gt;自己選伺服器國家&lt;td&gt;❌ 不夠&lt;td&gt;⭐⭐⭐ 必要&lt;tr&gt;&lt;td&gt;Netflix／Disney+ 串流&lt;td&gt;❌ 不夠&lt;td&gt;⭐⭐⭐ 必要（但仍不保證每部片）&lt;tr&gt;&lt;td&gt;BT／P2P 下載&lt;td&gt;❌ 不夠&lt;td&gt;⭐⭐⭐ 必要&lt;tr&gt;&lt;td&gt;同時 2 台以上裝置&lt;td&gt;❌ 免費只有 1 台&lt;td&gt;⭐⭐⭐ 必要&lt;tr&gt;&lt;td&gt;擋廣告／惡意網域&lt;td&gt;❌ 沒有 NetShield&lt;td&gt;⭐⭐ 加分&lt;tr&gt;&lt;td&gt;繞過嚴格網路審查&lt;td&gt;❌ 沒有 Stealth&lt;td&gt;⭐⭐ 加分&lt;tr&gt;&lt;td&gt;高風險出口監控&lt;td&gt;❌ 沒有 Secure Core&lt;td&gt;⭐⭐ 加分（少數人需要）&lt;tr&gt;&lt;td&gt;只要最低月費&lt;td&gt;✅ 免費 $0&lt;td&gt;付費未必最便宜——見下方競品比較&lt;/table&gt;&lt;p&gt;&lt;strong&gt;勾選 3 項以上「付費版必要」&lt;/strong&gt; → 升級 VPN Plus 很合理。&lt;br&gt;&lt;strong&gt;只勾 1 項「速度」&lt;/strong&gt; → 建議先在自己網路實測免費版尖峰速度，再決定。別為了「感覺比較快」付年費，結果發現瓶頸其實是你家 Wi‑Fi——那杯咖啡就白喝了。&lt;h2 id=&quot;價格與方案別只看促銷標語&quot;&gt;價格與方案：別只看促銷標語&lt;/h2&gt;&lt;p&gt;官方結帳頁價格會依幣別、地區與促銷變動，以下為研究時的快照，&lt;strong&gt;訂閱前請直接查官方頁面&lt;/strong&gt;：&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;方案&lt;th&gt;計費方式&lt;th&gt;參考價格（快照）&lt;th&gt;適合誰&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Proton Free&lt;td&gt;—&lt;td&gt;$0&lt;td&gt;輕度使用者、先建立信任&lt;tr&gt;&lt;td&gt;VPN Plus&lt;td&gt;月繳&lt;td&gt;約 US$9.99／月&lt;td&gt;短期試用、不想一次付兩年&lt;tr&gt;&lt;td&gt;VPN Plus&lt;td&gt;年繳&lt;td&gt;約 US$3.99／月（一次 US$47.88）&lt;td&gt;確定會用滿一年&lt;tr&gt;&lt;td&gt;VPN Plus&lt;td&gt;兩年繳&lt;td&gt;約 US$2.99／月（一次 US$71.76）&lt;td&gt;長期使用者、單看 VPN 最划算&lt;tr&gt;&lt;td&gt;Proton Unlimited&lt;td&gt;依官方頁&lt;td&gt;含 Mail、Drive、Pass、VPN&lt;td&gt;本來就要用 Proton 全家桶&lt;/table&gt;&lt;p&gt;結帳前三件事：&lt;ol&gt;&lt;li&gt;&lt;strong&gt;看「今天要付多少」&lt;/strong&gt;，不是只看每月折算價。&lt;li&gt;&lt;strong&gt;記下續費價格&lt;/strong&gt;——促銷期過後可能不同。&lt;li&gt;&lt;strong&gt;確認付款管道&lt;/strong&gt;——官網、App Store、Google Play 的退款入口不一樣。&lt;/ol&gt;&lt;h3 id=&quot;30-天退款訂閱前的安全網&quot;&gt;30 天退款：訂閱前的安全網&lt;/h3&gt;&lt;p&gt;首次直接向 Proton 購買，可在 &lt;strong&gt;30 天內&lt;/strong&gt;取消並申請退款（每位使用者退款選項通常只能用一次）。重點：&lt;ul&gt;&lt;li&gt;&lt;strong&gt;取消 ≠ 退款&lt;/strong&gt;：兩個動作都要做。&lt;li&gt;&lt;strong&gt;刪除 App 不會停扣款&lt;/strong&gt;：必須在原付款管道取消續訂。&lt;li&gt;&lt;strong&gt;App Store／Google Play 購買&lt;/strong&gt;：退款要走 Apple 或 Google 的流程，不是 Proton 網站。&lt;li&gt;取消後通常仍可用到目前計費週期結束，之後降回免費版。&lt;/ul&gt;&lt;p&gt;若你只是不確定付費版好不好用，善用 30 天退款期在自己網路實測，比看十篇評測文更有說服力——畢竟你的 ISP 不會因為別人測速漂亮就對你特別溫柔。&lt;h2 id=&quot;跟-NordVPNSurfshark-比付費版站得住嗎?&quot;&gt;跟 NordVPN、Surfshark 比：付費版站得住嗎？&lt;/h2&gt;&lt;p&gt;若你已經決定要付費 VPN，但還在猶豫品牌：&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;比較面向&lt;th&gt;Proton VPN Plus&lt;th&gt;NordVPN&lt;th&gt;Surfshark&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;同時連線數&lt;td&gt;10 台&lt;td&gt;10 台&lt;td&gt;不限&lt;tr&gt;&lt;td&gt;隱私透明度&lt;td&gt;Securitum 稽核公開、App 開源、瑞士管轄&lt;td&gt;Deloitte 查核（報告需登入查閱）、巴拿馬公司&lt;td&gt;Deloitte 查核、荷蘭管轄&lt;tr&gt;&lt;td&gt;免費入門&lt;td&gt;✅ 不限流量免費版&lt;td&gt;❌ 無&lt;td&gt;❌ 無&lt;tr&gt;&lt;td&gt;串流設備便利&lt;td&gt;路由器／支援的 App&lt;td&gt;Smart DNS 對電視較方便&lt;td&gt;Fire TV、Android TV 等官方支援完整&lt;tr&gt;&lt;td&gt;獨特功能&lt;td&gt;Secure Core、Stealth、NetShield&lt;td&gt;NordLynx、威脅防護套件&lt;td&gt;不限裝置、RAM-only 伺服器&lt;tr&gt;&lt;td&gt;30 天退款&lt;td&gt;✅（依付款管道）&lt;td&gt;✅（續費不在內）&lt;td&gt;✅（依方案與管道）&lt;/table&gt;&lt;p&gt;&lt;strong&gt;選 Proton 付費版&lt;/strong&gt;，若你已經用免費版、想無縫升級；重視公開稽核報告與開源；裝置數 ≤10 台；需要 Secure Core 或 Stealth。&lt;p&gt;&lt;strong&gt;先試 NordVPN&lt;/strong&gt;，若你主要在智慧電視／遊戲主機看串流（Smart DNS 較省事）；重視近距離低延遲；不在意沒有免費版可長期使用。&lt;p&gt;&lt;strong&gt;先試 Surfshark&lt;/strong&gt;，若你家中同時連線超過 10 台；預算優先、想要不限裝置。&lt;p&gt;沒有絕對贏家——兩家都有獨立無日誌查核，差別在證據呈現方式、功能取向與你的使用情境。建議在 30 天退款期內各測自己常用的串流服務與網路環境。&lt;h2 id=&quot;串流實際表現付費版的真實期待&quot;&gt;串流實際表現：付費版的真實期待&lt;/h2&gt;&lt;p&gt;付費版才支援官方串流伺服器，但這不代表「買了就能看全世界」：&lt;ul&gt;&lt;li&gt;Netflix、Disney+ 仍需&lt;strong&gt;另外訂閱&lt;/strong&gt;；VPN 訂閱不包含串流會員。&lt;li&gt;Netflix &lt;strong&gt;廣告方案&lt;/strong&gt;與&lt;strong&gt;直播活動&lt;/strong&gt;官方明確不支援 VPN。&lt;li&gt;串流平台會更新封鎖規則，&lt;strong&gt;不能保證永久解鎖&lt;/strong&gt;任何片名。&lt;li&gt;排串流問題時，&lt;strong&gt;不要用 Secure Core&lt;/strong&gt;——它為安全設計，不是為速度。&lt;li&gt;遇到「使用 VPN 或 Proxy」錯誤：換 Plus 伺服器 → 重開 App → 清快取 → 暫時關 NetShield 測試 → 用 ipleak.net 查 IP／DNS 洩漏。&lt;/ul&gt;&lt;p&gt;合理期待：付費版讓你在旅行或跨區時，&lt;strong&gt;有機會&lt;/strong&gt;用自有訂閱看原本的片庫；不是繞過版權的萬能鑰匙。VPN 不是 Netflix 會員卡的加購醬料包。&lt;h2 id=&quot;訂閱前檢查清單&quot;&gt;訂閱前檢查清單&lt;/h2&gt;&lt;p&gt;在按下付款前，逐項確認：&lt;ul&gt;&lt;li&gt;[ ] 我需要的功能（串流／P2P／多裝置／選國家）免費版確實做不到&lt;li&gt;[ ] 同時連線裝置數 ≤10（含瀏覽器擴充）&lt;li&gt;[ ] 已看過官方當下價格與&lt;strong&gt;續費價格&lt;/strong&gt;&lt;li&gt;[ ] 知道退款入口（官網／Apple／Google）&lt;li&gt;[ ] 會在 30 天內實測常用服務與網路速度&lt;li&gt;[ ] 不把 VPN 當成防毒或完全匿名工具&lt;/ul&gt;&lt;h2 id=&quot;推薦工具/資源&quot;&gt;推薦工具／資源&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;產品&lt;th&gt;適合誰&lt;th&gt;說明&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https://pr.tn/ref/SZX2CCB0&quot;&gt;Proton VPN Plus&lt;/a&gt;&lt;/strong&gt;（主推）&lt;td&gt;已用免費版、需要串流／P2P／多裝置／完整伺服器&lt;td&gt;30 天退款可實測；開源 App + 公開無日誌稽核&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Proton Unlimited&lt;/strong&gt;&lt;td&gt;同時需要 Mail、Drive、Pass 的 Proton 生態系使用者&lt;td&gt;別只用 VPN 單價比，把全家桶需求一起算&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Proton Free&lt;/strong&gt;&lt;td&gt;輕度使用者、還不確定要不要付費&lt;td&gt;先建立信任，確認限制再升級&lt;tr&gt;&lt;td&gt;NordVPN&lt;td&gt;重視電視串流便利（Smart DNS）、近距離低延遲&lt;td&gt;隱私查核報告需登入查閱；無免費版&lt;tr&gt;&lt;td&gt;Surfshark&lt;td&gt;家中超過 10 台裝置同時連線&lt;td&gt;不限同時連線；荷蘭管轄、Deloitte 查核&lt;/table&gt;&lt;h2 id=&quot;結語我的評價&quot;&gt;結語：我的評價&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Proton VPN 付費版（VPN Plus）值得訂閱嗎？&lt;/strong&gt;——若你已經被免費版的「不能選國家、不能串流、只有 1 台裝置、尖峰變慢」卡住，&lt;strong&gt;值得&lt;/strong&gt;。付費版解的不只是速度，而是把 VPN 從「偶爾用用的安全網」變成「日常可用的完整工具」。&lt;p&gt;但若你只是偶爾在咖啡店上網、一台手機就夠，&lt;strong&gt;免費版已經是市場上少數真正可信的選擇&lt;/strong&gt;，不必為了「付費比較安心」而多花錢——加密標準是一樣的，你的錢包不會因為多付而多一層 AES-256。&lt;p&gt;三個重點帶走：&lt;ol&gt;&lt;li&gt;&lt;strong&gt;付費版的核心價值&lt;/strong&gt;是串流、P2P、多裝置、完整伺服器與 Secure Core／NetShield／Stealth，不是「付費才安全」。&lt;li&gt;&lt;strong&gt;價格要看續費與付款管道&lt;/strong&gt;，善用 30 天退款在自己網路實測。&lt;li&gt;&lt;strong&gt;競品不是全面輸贏&lt;/strong&gt;——裝置數 &amp;gt;10 看 Surfshark，電視串流便利看 NordVPN，隱私透明度與免費漏斗看 Proton。&lt;/ol&gt;&lt;p&gt;若你確認需要 Plus 的功能，建議先到 &lt;a href=&quot;https://pr.tn/ref/SZX2CCB0&quot;&gt;Proton 官網&lt;/a&gt; 領免費帳號（若還沒有）→ 在 30 天退款期內升級 VPN Plus 實測 → 不合適就依付款管道申請退款。決定好了再來一杯慶祝——或繼續喝免費版也沒關係，至少你的連線有加密。&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;聯盟揭露：&lt;/strong&gt; 本文包含 Proton VPN 推薦連結。若你透過連結註冊或購買，我可能獲得推薦回饋；這不會增加你的費用。本文依研究筆記與官方文件撰寫，請依你的實際需求與測試結果做最終決定。&lt;/blockquote&gt;&lt;p&gt;👉 &lt;a href=&quot;https://pr.tn/ref/SZX2CCB0&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer sponsored&quot;&gt;&lt;strong&gt;免費申請 Proton 帳號 →&lt;/strong&gt;&lt;/a&gt;&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://protonvpn.com/support/proton-vpn-plans&quot;&gt;Proton VPN plans explained&lt;/a&gt; — 官方方案類型、Free 與 Plus 功能差異。&lt;li&gt;&lt;a href=&quot;https://account.protonvpn.com/pricing&quot;&gt;Proton VPN official pricing&lt;/a&gt; — 結帳時的方案、幣別與促銷價格（以當日頁面為準）。&lt;li&gt;&lt;a href=&quot;https://protonvpn.com/support/cancel-vpn-subscription&quot;&gt;How to cancel a Proton VPN subscription&lt;/a&gt; — 取消步驟、退款管道與處理時間。&lt;li&gt;&lt;a href=&quot;https://protonvpn.com/support/no-logs-vpn&quot;&gt;Does Proton VPN keep logs?&lt;/a&gt; — 無日誌政策說明。&lt;li&gt;&lt;a href=&quot;https://protonvpn.com/blog/no-logs-audit&quot;&gt;Proton VPN passes 5th annual external audit&lt;/a&gt; — 2026 年 Securitum 無日誌稽核。&lt;li&gt;&lt;a href=&quot;https://protonvpn.com/support/watch-netflix-with-proton-vpn&quot;&gt;How to watch Netflix with Proton VPN&lt;/a&gt; — 串流支援範圍與限制。&lt;li&gt;&lt;a href=&quot;https://protonvpn.com/support/protonvpn-features&quot;&gt;Proton VPN Features&lt;/a&gt; — Secure Core、NetShield、Stealth 等功能說明。&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>為什麼要發明 Pi？從作者角度理解 Pi vs Claude Code 該怎麼選</title>
    <link href="https://kamadiam.com/pi-vs-claude-code-why-author-built-pi/" />
    <updated>2026-08-07T03:32:15Z</updated>
    <id>https://kamadiam.com/pi-vs-claude-code-why-author-built-pi/</id>
    <content type="html">&lt;p&gt;終端裡的 AI 程式助手越來越多：Claude Code、Cursor，還有各種「多代理＋Plan Mode＋MCP」大禮包。功能清單看起來很強，但你有沒有遇過這種感覺——&lt;strong&gt;工具一更新，行為就變了&lt;/strong&gt;；你以為它在「幫你想」，其實有一段上下文是介面看不到的；出錯時又不知道該查哪一層？&lt;p&gt;（有點像咖啡店改菜單：你點的還叫同名，內容卻換了豆。AI 工具也會這樣，而且通常不會在杯子上貼告示。）&lt;p&gt;Pi Coding Agent 的作者 Mario Zechner，正是從這類痛點出發，選擇&lt;strong&gt;重做一個極小核心&lt;/strong&gt;，而不是繼續往既有工具堆功能。這篇不做沒有實測根據的「誰比較強」評比，也不喊誰全面勝利；目標很單純：用&lt;strong&gt;作者為什麼要發明 Pi&lt;/strong&gt; 當鏡頭，幫你看懂兩種哲學，再決定自己要的是 &lt;strong&gt;Pi 的可控性&lt;/strong&gt;，還是 &lt;strong&gt;Claude Code 的現成工作流&lt;/strong&gt;。&lt;p&gt;讀完你會帶走：作者動機怎麼對到設計、四個原則怎麼想、一張決策表幫你 30 秒對號入座。&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pi-vs-claude-code-why-author-built-pi/#%E5%85%88%E8%AC%9B%E6%B8%85%E6%A5%9A%E9%80%99%E4%B8%8D%E6%98%AF%E3%80%8CClaude-Code-%E4%B8%8D%E5%A5%BD%E3%80%8D&quot;&gt;先講清楚：這不是「Claude Code 不好」&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pi-vs-claude-code-why-author-built-pi/#%E4%BD%9C%E8%80%85%E7%82%BA%E4%BB%80%E9%BA%BC%E8%A6%81%E9%87%8D%E6%96%B0%E5%81%9A%E4%B8%80%E5%80%8B-Coding-Agent?&quot;&gt;作者為什麼要重新做一個 Coding Agent？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pi-vs-claude-code-why-author-built-pi/#Pi-%E7%9A%84%E5%9B%9B%E5%80%8B%E8%A8%AD%E8%A8%88%E5%8E%9F%E5%89%87%E5%B0%8D%E7%85%A7-Claude-Code-%E6%80%8E%E9%BA%BC%E6%83%B3&quot;&gt;Pi 的四個設計原則（對照 Claude Code 怎麼想）&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pi-vs-claude-code-why-author-built-pi/#%E6%B1%BA%E7%AD%96%E8%A1%A8%E6%88%91%E8%A9%B2%E9%81%B8-Pi-%E9%82%84%E6%98%AF-Claude-Code?&quot;&gt;決策表：我該選 Pi 還是 Claude Code？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pi-vs-claude-code-why-author-built-pi/#%E6%8E%A8%E8%96%A6%E5%B7%A5%E5%85%B7/%E8%B3%87%E6%BA%90&quot;&gt;推薦工具／資源&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pi-vs-claude-code-why-author-built-pi/#%E7%B5%90%E8%AA%9E%E9%81%B8%E5%93%B2%E5%AD%B8,%E5%86%8D%E9%81%B8%E6%8C%89%E9%88%95&quot;&gt;結語：選哲學，再選按鈕&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pi-vs-claude-code-why-author-built-pi/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;先講清楚這不是「Claude-Code-不好」&quot;&gt;先講清楚：這不是「Claude Code 不好」&lt;/h2&gt;&lt;p&gt;作者的公開文章把 Claude Code 當成「既有 Coding Agent 逐漸變複雜」的對照例子——但那是&lt;strong&gt;他對自己工作流的取捨&lt;/strong&gt;，不是對所有人的判決。以下的功能描述以相關官方文件與文章目前列出的內容為準；這類工具更新很快，實際行為仍要以你使用的版本和設定為準。&lt;ul&gt;&lt;li&gt;Claude Code 適合：想要內建 Plan、子代理、MCP、斜線指令，少自己組裝。&lt;li&gt;Pi 適合：想看見上下文與中間產物、把工作流放在檔案／CLI／tmux，願意自己決定要加什麼。&lt;/ul&gt;&lt;p&gt;讀完這篇，你應該能回答一句話：「我比較怕&lt;strong&gt;黑箱變動&lt;/strong&gt;，還是比較怕&lt;strong&gt;自己組工具的成本&lt;/strong&gt;？」&lt;p&gt;答得出來，比背一百個功能還有用——功能清單只告訴你「有什麼」；真正幫你判斷怎麼修、怎麼選的，是你對工具的使用原則。&lt;h2 id=&quot;作者為什麼要重新做一個-Coding-Agent?&quot;&gt;作者為什麼要重新做一個 Coding Agent？&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;既有工具遇到的問題（作者說法）&lt;th&gt;Pi 的設計回應&lt;th&gt;你實際可以怎麼用&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Claude Code 從早期較簡單，逐漸變成作者用不到很多功能的複雜工具；發布常改 system prompt／工具定義，既有工作流與模型行為跟著變&lt;td&gt;核心「不需要就不建」；短 system prompt；差異放到外部擴充&lt;td&gt;固定自己的提示、&lt;code&gt;AGENTS.md&lt;/code&gt;、驗證流程；升級後重新檢查，不要假設行為永遠不變&lt;tr&gt;&lt;td&gt;Context engineering 很重要，但其他 harness 可能在 UI 看不到的地方注入上下文&lt;td&gt;Session、工具呼叫、來源與產物保持可見；規劃寫成檔案，不藏在黑箱代理裡&lt;td&gt;要求 Agent 把研究／計畫／檢查結果寫成可讀檔，人工看完再進下一階段&lt;tr&gt;&lt;td&gt;內建子代理把上下文傳遞與錯誤藏在另一層，出錯難追查&lt;td&gt;不提供專用子代理工具；需要時用 bash 再開一個 Pi，或用 Extension／Package 自己組&lt;td&gt;任務邊界與輸出格式清楚才拆 session，中間產物一律存檔&lt;/table&gt;&lt;p&gt;一句話總結作者動機：&lt;blockquote&gt;&lt;p&gt;當 Coding Agent 變得複雜、常改又不透明時，最可靠的回應不是再加一層功能——而是&lt;strong&gt;縮小核心、提高可觀測性，讓使用者自己決定要加什麼&lt;/strong&gt;。&lt;/blockquote&gt;&lt;p&gt;官方定位也呼應這點：「讓 Pi 適應你的工作流，而不是反過來。」——翻成口語：工具來遷就你的終端習慣，不是你遷就它的儀式流程。咖啡機有預設模式很方便；但如果你想自己調研磨度，誰也不能禁止你拿出手沖壺。&lt;h2 id=&quot;Pi-的四個設計原則對照-Claude-Code-怎麼想&quot;&gt;Pi 的四個設計原則（對照 Claude Code 怎麼想）&lt;/h2&gt;&lt;h3 id=&quot;1.-極簡核心,不是功能競賽&quot;&gt;1. 極簡核心，不是功能競賽&lt;/h3&gt;&lt;p&gt;作者文章描述：Pi 的 system prompt 與預設工具定義合計可低於約 1,000 tokens；預設核心大致是讀、寫、編輯與 bash。極簡&lt;strong&gt;不是&lt;/strong&gt;叫大家永遠只用四個工具，而是把 MCP、子代理、Plan Mode 等能力移到 Extensions、Skills、Prompt Templates、Packages——&lt;strong&gt;按痛點再加&lt;/strong&gt;。這裡的「四個」是核心設計的概括，不代表每個版本或擴充後都只剩四項能力。&lt;p&gt;Claude Code 走另一條路：代理人循環（收集上下文 → 執行動作 → 驗證結果）＋較豐富的內建工具與斜線指令（如 &lt;code&gt;/compact&lt;/code&gt;、&lt;code&gt;/diff&lt;/code&gt;、&lt;code&gt;/model&lt;/code&gt;），並以 &lt;code&gt;CLAUDE.md&lt;/code&gt;、Skills、MCP 擴充。對「我想立刻開工」的人，這通常比較省事。&lt;p&gt;白話對照：Claude Code 像開箱即用的咖啡機；Pi 像手沖壺——多一步，但你看得見水溫、粉量和時間。&lt;h3 id=&quot;2.-可觀測性優先&quot;&gt;2. 可觀測性優先&lt;/h3&gt;&lt;p&gt;Pi 偏好把計畫寫成 Markdown：人可以編、跨 session 重用，也能進版本控制。「Agent 做了什麼」變成可檢查的產物，而不是只信最後一句摘要。換句話說，規格、計畫和進度先落檔，人工過目再寫碼；這種做法也比較容易留下日後能追溯的線索。&lt;p&gt;Claude Code 也有規範檔與驗證迴圈，但作者批評的重點是：若規劃與子工作藏在內部狀態，除錯成本會變高。你若本來就習慣「先看 diff／計畫再准執行」，兩套都能做；差別在於&lt;strong&gt;狀態預設放在哪&lt;/strong&gt;——檔案系統，還是工具內建流程。&lt;h3 id=&quot;3.-用組合取代內建一體化&quot;&gt;3. 用組合取代內建一體化&lt;/h3&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pi 刻意不內建&lt;th&gt;官方建議替代&lt;th&gt;什麼時候值得自己組&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;MCP&lt;td&gt;小型 CLI＋README，或自行加 Extension&lt;td&gt;工具少、要控 token、輸出想直接寫檔串接&lt;tr&gt;&lt;td&gt;子代理&lt;td&gt;tmux 再開 Pi、Extension、Package&lt;td&gt;要看見子過程，或真的要平行任務&lt;tr&gt;&lt;td&gt;Plan Mode&lt;td&gt;計畫寫入檔案，或自行擴充&lt;td&gt;計畫要跨 session、共同編輯、版控&lt;tr&gt;&lt;td&gt;背景 bash&lt;td&gt;tmux&lt;td&gt;長跑測試、開發伺服器、互動除錯&lt;tr&gt;&lt;td&gt;權限彈窗&lt;td&gt;容器／隔離帳號／自訂確認&lt;td&gt;不可信程式碼或機密資料&lt;/table&gt;&lt;p&gt;作者對大型 MCP 的具體顧慮是：工具說明每次塞進上下文，token 貴，輸出還常得繞回 Agent 才能保存。他提的替代是「小型 CLI + README + bash」——需要時才讀，輸出可直寫檔。&lt;p&gt;Claude Code 官方文件列有 MCP 整合，對「接資料庫／瀏覽器／外部服務、不想自己包 CLI」的人是加分。你要選的是：&lt;strong&gt;內建方便&lt;/strong&gt; vs &lt;strong&gt;按需載入、看得見成本&lt;/strong&gt;。&lt;h3 id=&quot;4.-安全責任放回執行環境&quot;&gt;4. 安全責任放回執行環境&lt;/h3&gt;&lt;p&gt;Pi 預設不走「權限彈窗＝安全」這條路；作者認為 Agent 一旦能讀寫檔、跑指令，單靠彈窗很難形成完整邊界。這&lt;strong&gt;不是&lt;/strong&gt;宣稱 Pi 比較安全，而是要求你用容器、隔離帳號、網路限制等&lt;strong&gt;真邊界&lt;/strong&gt;。含機密的主機開 YOLO，風險在你，不能照抄作者個人設定。&lt;p&gt;Claude Code 提供權限確認與相關隔離選項；對不想自己從零設計沙箱的人，通常比較「有提示、有流程」。兩邊都不是魔法盾——差在&lt;strong&gt;預設假設誰負責安全&lt;/strong&gt;，而且最後仍要由你確認實際的執行環境。&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;比喻&lt;th&gt;對應的做法&lt;th&gt;實際效果&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;門上貼「請勿打擾」&lt;td&gt;Agent 跳出權限彈窗，你點「允許」&lt;td&gt;只是&lt;strong&gt;提醒／確認&lt;/strong&gt;，對方真要闖還是進得去&lt;tr&gt;&lt;td&gt;門鎖上了&lt;td&gt;容器、隔離帳號、網路限制&lt;td&gt;&lt;strong&gt;物理／技術邊界&lt;/strong&gt;，進不去才是真隔離&lt;/table&gt;&lt;p&gt;彈窗是禮貌的提示；隔離才是真的鎖門。兩者看起來都在「管安全」，保護力差很多。&lt;h2 id=&quot;決策表我該選-Pi-還是-Claude-Code?&quot;&gt;決策表：我該選 Pi 還是 Claude Code？&lt;/h2&gt;&lt;p&gt;用這張表做決定（可以兩邊都裝，但同一目錄不要同時寫檔；要並行請用不同 worktree 或其他隔離方式）：&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;你的情境&lt;th&gt;較適合&lt;th&gt;先確認這件事&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;想快速使用整合好的流程，不想自己組工具&lt;td&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;&lt;td&gt;能否接受 system prompt、工具與版本變動&lt;tr&gt;&lt;td&gt;想逐步檢查上下文與中間產物、計畫要進 Git&lt;td&gt;&lt;strong&gt;Pi&lt;/strong&gt;（或同等可觀測工作流）&lt;td&gt;是否願意維護 markdown、CLI、tmux&lt;tr&gt;&lt;td&gt;已在使用 Anthropic 生態、愛斜線指令與內建任務工作流&lt;td&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;&lt;td&gt;MCP／Skills 的 token 與權限範圍&lt;tr&gt;&lt;td&gt;本地模型、控 token、設定要可移植（&lt;code&gt;AGENTS.md&lt;/code&gt;、&lt;code&gt;.pi/&lt;/code&gt;）&lt;td&gt;&lt;strong&gt;Pi&lt;/strong&gt;&lt;td&gt;短 prompt 在你的模型／專案規模是否夠用（要實測）&lt;tr&gt;&lt;td&gt;要查瀏覽器、資料庫、外部服務，且想少寫 glue code&lt;td&gt;Claude Code＋MCP，或 Pi＋按需 CLI／Extension&lt;td&gt;工具描述成本、輸出能否存檔&lt;tr&gt;&lt;td&gt;不可信程式碼或機密檔案&lt;td&gt;先隔離，再選任一 Agent&lt;td&gt;隔離是否真限制檔案與網路，而不只是警告&lt;/table&gt;&lt;h3 id=&quot;30-秒口訣&quot;&gt;30 秒口訣&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;怕&lt;strong&gt;黑箱與升級打破工作流&lt;/strong&gt; → 先試 &lt;strong&gt;Pi&lt;/strong&gt;。&lt;li&gt;怕&lt;strong&gt;自己組裝與維護成本&lt;/strong&gt; → 先用 &lt;strong&gt;Claude Code&lt;/strong&gt;。&lt;li&gt;都要一點 → 主流程用 Claude Code／IDE；終端批次、低成本實驗、可版控的 Agent 設定用 Pi。&lt;/ul&gt;&lt;h2 id=&quot;推薦工具/資源&quot;&gt;推薦工具／資源&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;工具&lt;th&gt;適合誰&lt;th&gt;備註&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https://pi.dev/&quot;&gt;Pi Coding Agent&lt;/a&gt;&lt;/strong&gt;&lt;td&gt;想要極簡核心、可觀測產物、按需擴充的終端使用者&lt;td&gt;先用裸 Pi 跑通小任務，再加 Package／Extension&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code/overview&quot;&gt;Claude Code&lt;/a&gt;&lt;/strong&gt;&lt;td&gt;想要整合代理人工作流、MCP 與專案規範的 Anthropic 生態使用者&lt;td&gt;用 &lt;code&gt;CLAUDE.md&lt;/code&gt; 固定專案規範；升級後抽查行為&lt;tr&gt;&lt;td&gt;延伸閱讀&lt;td&gt;想系統學 Pi 工作流&lt;td&gt;站內：&lt;a href=&quot;https://kamadiam.com/blog/pi-coding-agent/&quot;&gt;Pi Coding Agent 完整指南&lt;/a&gt;&lt;/table&gt;&lt;p&gt;客觀取捨：Pi 把「省心的一體化」換成「可控、但需要自己組合」；Claude Code 則把更多流程先整合好，換取較低的起步成本。Pi 和 Claude Code 各有取捨，誰贏取決於你的風險與願不願意自己維護，不是全世界都該選同一個。&lt;h2 id=&quot;結語選哲學,再選按鈕&quot;&gt;結語：選哲學，再選按鈕&lt;/h2&gt;&lt;p&gt;作者發明 Pi，不是為了「功能贏過 Claude Code」，而是為了在&lt;strong&gt;複雜、常改、不透明&lt;/strong&gt;的 Coding Agent 浪潮裡，留下一個&lt;strong&gt;看得見、擴得動、核心夠小&lt;/strong&gt;的 harness。這個選擇不一定讓每個人都更省事，卻讓取捨本身變得比較清楚。&lt;p&gt;帶走三點：&lt;ol&gt;&lt;li&gt;&lt;strong&gt;動機&lt;/strong&gt;：縮小核心＋可觀測性，對抗黑箱與工作流被升級拆掉。&lt;li&gt;&lt;strong&gt;取捨&lt;/strong&gt;：Claude Code 用整合換省心；Pi 用組合換控制權。&lt;li&gt;&lt;strong&gt;下一步&lt;/strong&gt;：用上面的決策表對號入座，不要只比功能勾選清單。&lt;/ol&gt;&lt;p&gt;先挑一個小任務（例如修一個測試失敗）——若你要「開箱即用」，用 Claude Code 跑完並檢查差異；若你要「計畫與驗證都落檔」，用 Pi 把計畫寫成 Markdown 再改碼。跑完一次，比再讀十篇比較文更準。畢竟工具比較文可以收藏，失敗的測試不會因為被收藏就自己修好。&lt;p&gt;審完再來一杯。下一杯建議：直接動手，別再收藏文章了。&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://mariozechner.at/posts/2025-11-30-pi-coding-agent/&quot;&gt;What I learned building an opinionated and minimal coding agent&lt;/a&gt; — Mario Zechner 說明為何做極簡 Pi、對照既有 Coding Agent 的痛點&lt;li&gt;&lt;a href=&quot;https://mariozechner.at/posts/2025-11-02-what-if-you-dont-need-mcp/&quot;&gt;What if you don&#39;t need MCP at all?&lt;/a&gt; — 作者對大型 MCP 成本與「小型 CLI + README」替代方案的論點&lt;li&gt;&lt;a href=&quot;https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/README.md&quot;&gt;Pi coding agent README&lt;/a&gt; — 官方定位、刻意不內建項目與擴充方向&lt;li&gt;&lt;a href=&quot;https://pi.dev/&quot;&gt;Pi Coding Agent 官網&lt;/a&gt; — 產品入口與文件入口&lt;li&gt;&lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code/overview&quot;&gt;Anthropic Claude Code 官方指南&lt;/a&gt; — Claude Code 的工作方式、MCP、&lt;code&gt;CLAUDE.md&lt;/code&gt; 與擴充能力&lt;li&gt;&lt;a href=&quot;https://newsletter.pragmaticengineer.com/p/building-pi-and-what-makes-self-modifying&quot;&gt;Building Pi, and what makes self-modifying software so fascinating&lt;/a&gt; — Pragmatic Engineer 訪談／整理，補作者背景脈絡&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>我如何用 PageSpeed Insights 優化 11ty 網站：為什麼比 WordPress 更容易直接修</title>
    <link href="https://kamadiam.com/11ty-pagespeed-insights-optimization-workflow/" />
    <updated>2026-08-06T01:25:00Z</updated>
    <id>https://kamadiam.com/11ty-pagespeed-insights-optimization-workflow/</id>
    <content type="html">&lt;p&gt;沒有一杯咖啡解決不了的效能問題；如果有，就先把 PageSpeed Insights 的診斷報告打開，看看是哪個資源在拖後腿。&lt;p&gt;我做 11ty 網站效能優化時，通常會先把網址丟進 &lt;a href=&quot;https://pagespeed.web.dev/&quot;&gt;PageSpeed Insights&lt;/a&gt;，看它指出的具體問題，再回到 11ty 的模板、CSS、圖片設定或 JavaScript 原始碼逐項修正。很多「改 HTML 屬性、補尺寸、延後腳本」這類步驟，其實可以交給 AI 動手；你負責寫清楚提示詞，再審核 diff 與實際結果。&lt;p&gt;這個流程在 11ty 上很直接：首圖太大，就處理首圖；圖片沒有明確寬高，就改 HTML 或圖片管道；第三方 JavaScript 阻塞主執行緒，就延後或移除那支腳本。改完重新 build、部署，再用相同條件測一次。&lt;p&gt;WordPress 當然也能優化，但問題有時藏在佈景主題、頁面編輯器、快取外掛和圖片外掛互相疊加的結果。你可能知道 PageSpeed Insights 要求什麼，卻不知道哪一層才是可以安全修改的地方。&lt;p&gt;這篇記錄我如何把 PageSpeed Insights 的建議轉成 11ty 的實際修改。重點不是宣稱哪個框架永遠比較快，而是：在 11ty 裡，診斷結果通常可以直接對應到你能控制的模板、資產或腳本。&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-pagespeed-insights-optimization-workflow/#%E5%85%88%E8%AA%AA%E7%B5%90%E8%AB%96PageSpeed-Insights-%E6%98%AF%E8%A8%BA%E6%96%B7%E5%B7%A5%E5%85%B7,%E4%B8%8D%E6%98%AF%E6%A1%86%E6%9E%B6%E8%A9%95%E5%88%86%E8%A1%A8&quot;&gt;先說結論：PageSpeed Insights 是診斷工具，不是框架評分表&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-pagespeed-insights-optimization-workflow/#%E6%88%91%E7%9A%84-11ty-%E5%84%AA%E5%8C%96%E5%BE%AA%E7%92%B0%E6%B8%AC%E9%87%8F%E5%AE%9A%E4%BD%8D%E7%9B%B4%E6%8E%A5%E4%BF%AE%E6%94%B9%E5%86%8D%E9%A9%97%E8%AD%89&quot;&gt;我的 11ty 優化循環：測量、定位、直接修改、再驗證&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-pagespeed-insights-optimization-workflow/#PageSpeed-Insights-%E6%8C%87%E5%87%BA-LCP-%E6%85%A2%E5%85%88%E6%89%BE%E7%9C%9F%E6%AD%A3%E7%9A%84%E6%9C%80%E5%A4%A7%E5%85%83%E7%B4%A0&quot;&gt;PageSpeed Insights 指出 LCP 慢：先找真正的最大元素&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-pagespeed-insights-optimization-workflow/#PageSpeed-Insights-%E6%8C%87%E5%87%BA-CLS%E5%85%88%E8%A3%9C%E5%B0%BA%E5%AF%B8,%E4%B8%8D%E8%A6%81%E5%8F%AA%E8%AA%BF%E5%88%86%E6%95%B8&quot;&gt;PageSpeed Insights 指出 CLS：先補尺寸，不要只調分數&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-pagespeed-insights-optimization-workflow/#PageSpeed-Insights-%E6%8C%87%E5%87%BA-JavaScript-%E5%A4%AA%E5%A4%9A%E5%85%88%E5%95%8F%E9%80%99%E6%94%AF%E8%85%B3%E6%9C%AC%E7%9C%9F%E7%9A%84%E9%9C%80%E8%A6%81%E5%97%8E?&quot;&gt;PageSpeed Insights 指出 JavaScript 太多：先問這支腳本真的需要嗎？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-pagespeed-insights-optimization-workflow/#%E7%82%BA%E4%BB%80%E9%BA%BC%E5%90%8C%E4%B8%80%E5%80%8B%E5%BB%BA%E8%AD%B0,%E5%9C%A8-WordPress-%E4%B8%8A%E5%B8%B8%E5%B8%B8%E6%AF%94%E8%BC%83%E9%9B%A3%E8%90%BD%E5%9C%B0?&quot;&gt;為什麼同一個建議，在 WordPress 上常常比較難落地？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-pagespeed-insights-optimization-workflow/#%E6%88%91%E6%9C%83%E7%94%A8-AI-%E5%8A%A0%E9%80%9F%E4%BF%AE%E6%AD%A3,%E4%BD%86%E4%B8%8D%E6%9C%83%E8%AE%93-AI-%E7%9B%B4%E6%8E%A5%E4%BA%82%E6%94%B9%E6%95%B4%E7%AB%99&quot;&gt;我會用 AI 加速修正，但不會讓 AI 直接亂改整站&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-pagespeed-insights-optimization-workflow/#%E4%BB%80%E9%BA%BC%E6%83%85%E6%B3%81%E4%B8%8D%E8%A9%B2%E5%8F%AA%E7%82%BA%E4%BA%86-PageSpeed-Insights-%E6%8F%9B%E6%88%90-11ty?&quot;&gt;什麼情況不該只為了 PageSpeed Insights 換成 11ty？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-pagespeed-insights-optimization-workflow/#%E7%B5%90%E8%AA%9E%E6%8A%8A%E8%A8%BA%E6%96%B7%E5%BB%BA%E8%AD%B0%E8%AE%8A%E6%88%90%E5%8F%AF%E5%9F%B7%E8%A1%8C%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%B8%85%E5%96%AE&quot;&gt;結語：把診斷建議變成可執行的工作清單&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-pagespeed-insights-optimization-workflow/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;先說結論PageSpeed-Insights-是診斷工具,不是框架評分表&quot;&gt;先說結論：PageSpeed Insights 是診斷工具，不是框架評分表&lt;/h2&gt;&lt;p&gt;PageSpeed Insights 不能單獨拿來比較 11ty 和 WordPress 誰比較快。它會提供實驗室資料與欄位資料，兩者用途不同：&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Lighthouse 實驗室資料&lt;/strong&gt;：適合重現問題、觀察剛做的改動。&lt;li&gt;&lt;strong&gt;Chrome 使用者體驗報告（CrUX）欄位資料&lt;/strong&gt;：反映真實使用者的體驗，通常看第 75 百分位。&lt;/ul&gt;&lt;p&gt;新網站流量不足時，可能暫時沒有 CrUX 資料。這時仍然可以先用 PageSpeed Insights 和 Lighthouse 做預防性優化，但不要把一次測試的分數當成網站的永久成績單。&lt;p&gt;我會先看這三個 Core Web Vitals 指標：&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;指標&lt;th&gt;它在看什麼&lt;th&gt;我通常先檢查什麼&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;LCP&lt;td&gt;首屏最大文字或圖片多久出現&lt;td&gt;hero 圖片、TTFB、阻塞 CSS、圖片是否被 lazy-load&lt;tr&gt;&lt;td&gt;CLS&lt;td&gt;頁面載入時是否跳動&lt;td&gt;圖片寬高、字體、嵌入內容和廣告預留空間&lt;tr&gt;&lt;td&gt;INP&lt;td&gt;使用者點擊或輸入後多久得到回應&lt;td&gt;第三方腳本、GTM、搜尋或互動元件&lt;/table&gt;&lt;p&gt;如果 PageSpeed Insights 顯示 95 分，但 Search Console 的 Core Web Vitals 仍有大量需要改善的 URL，我不會只看著實驗室分數自我安慰，而會回頭確認真實裝置和真實網路條件。&lt;h2 id=&quot;我的-11ty-優化循環測量定位直接修改再驗證&quot;&gt;我的 11ty 優化循環：測量、定位、直接修改、再驗證&lt;/h2&gt;&lt;p&gt;我通常照下面的順序做：&lt;ol&gt;&lt;li&gt;固定同一個 URL 或首頁當測試條件，先跑 PageSpeed Insights，記下 LCP、CLS、INP、FCP 和診斷項目。&lt;li&gt;找出問題對應的實際 HTML 元素或網路請求，例如「LCP 元素」是哪張圖，或是哪支腳本造成長任務。&lt;li&gt;把診斷原文貼給 AI，一次只請它改一類問題（例如只修 LCP 首圖），並寫清楚「不要動哪些檔案」。&lt;li&gt;在本機 build，檢查輸出的網頁是否真的產生預期的 HTML 和資產。&lt;li&gt;部署後用相同 URL 重跑 PageSpeed Insights，記錄改了什麼、分數和診斷如何變化。&lt;li&gt;如果是 GTM 或分析工具，除了看效能，也確認事件和轉換追蹤沒有被犧牲。&lt;/ol&gt;&lt;p&gt;一次只改一類問題，比較容易判斷因果。這一輪只處理圖片，下一輪再處理第三方腳本；如果同時換模板、換 CDN、刪掉五個外掛，最後就算分數變好，也很難知道真正有效的是什麼。&lt;p&gt;如果要在本機重現，先讓網站用和正式環境接近的方式完成 build，再用 Lighthouse 測試可存取的 URL。不要直接拿開發伺服器的熱更新狀態和正式網站比較，否則很容易把「開發工具的噪音」誤認成效能問題。&lt;pre class=&quot;language-shell&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; run build
&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;exec&lt;/span&gt; lighthouse https://example.com/某篇文章/ &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
	&lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;html &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
	--output-path&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;./lighthouse-report.html &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
	--chrome-flags&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;--headless&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;PageSpeed Insights 適合看整體診斷與欄位資料；Lighthouse 則適合在你能控制的測試環境裡重現問題。兩者不是互相競爭的咖啡師，而是不同杯型的量杯。&lt;h3 id=&quot;通用提示詞骨架可複製後改診斷內容&quot;&gt;通用提示詞骨架（可複製後改診斷內容）&lt;/h3&gt;&lt;p&gt;無論修 LCP、CLS 還是腳本，我都會先用類似這樣的骨架：&lt;pre class=&quot;language-text&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;這是一個 11ty（Eleventy）網站專案。請依 PageSpeed Insights 診斷修正，一次只處理一類問題。

【目標頁面】
https://example.com/某篇文章/

【這次只要處理】
（例如：LCP 首圖太慢 / CLS 圖片缺尺寸 / 第三方 JS 長任務）

【PageSpeed Insights 原文診斷】
（把 Opportunities、Diagnostics、LCP element、相關 network request 整段貼上）

【專案限制】
- 只改與這次問題直接相關的模板、CSS、圖片設定或 JS
- 不要改 URL、permalink、追蹤 ID、部署腳本、與效能無關的內容文案
- 不要一次「整站優化到 100 分」
- 改完請說明改了哪些檔案、為什麼這樣改，並列出我應手動驗證的項目

請先定位對應檔案與輸出 HTML，再提出最小修改。改完請跑本機 build（若專案有現成指令），確認沒有 build 錯誤。&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;提示詞寫得越具體，AI 越不會順便重構半個站。咖啡加太多糖也不好喝；優化提示詞也一樣，甜度要剛好。&lt;h2 id=&quot;PageSpeed-Insights-指出-LCP-慢先找真正的最大元素&quot;&gt;PageSpeed Insights 指出 LCP 慢：先找真正的最大元素&lt;/h2&gt;&lt;p&gt;LCP 常常是文章首圖、hero 圖或 H1，但不能只憑猜測決定。先在報告裡確認 LCP element，再針對那個元素處理。最常見的錯誤，是把首屏圖片也加上 &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt;。懶載入適合視窗外的圖片，但會讓瀏覽器更晚發現 LCP 資源。&lt;p&gt;我會先做幾件事：&lt;ul&gt;&lt;li&gt;把圖片轉成 WebP 或 AVIF。&lt;li&gt;讓圖片尺寸接近實際顯示寬度，不要把幾千像素的原圖直接送給手機。&lt;li&gt;為圖片寫上正確的 &lt;code&gt;width&lt;/code&gt; 和 &lt;code&gt;height&lt;/code&gt;。&lt;li&gt;首屏圖片視情況使用 &lt;code&gt;loading=&amp;quot;eager&amp;quot;&lt;/code&gt; 和 &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt;。&lt;li&gt;只有最重要的一、兩個資源使用高優先權，不要所有圖片都搶同一個優先級。&lt;/ul&gt;&lt;p&gt;例如首圖可以像這樣：&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/img/hero.webp&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;630&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;文章主視覺&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;eager&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;fetchpriority&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;high&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果網站圖片很多，我會再導入 &lt;a href=&quot;https://www.11ty.dev/docs/plugins/image/&quot;&gt;&lt;code&gt;@11ty/eleventy-img&lt;/code&gt;&lt;/a&gt;。它可以在 build 時產生多種格式和寬度，並依產生的圖片資料協助輸出尺寸與 &lt;code&gt;srcset&lt;/code&gt;。這比每次寫文章都手動處理圖片可靠。&lt;p&gt;不過圖片管道的輸出仍要檢查：即使圖片工具產生了 &lt;code&gt;srcset&lt;/code&gt;，也不代表瀏覽器一定會用到最適合的候選檔案；而且 hero 圖的載入策略仍要個別確認。&lt;h3 id=&quot;給-AI-的提示詞範例LCP&quot;&gt;給 AI 的提示詞範例（LCP）&lt;/h3&gt;&lt;pre class=&quot;language-text&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;請只處理 LCP，不要動第三方腳本，也不要順便改 CLS 版面預留。

PageSpeed Insights 指出 LCP 元素是：（貼上 LCP element 截圖或文字，例如 article hero img）
目前問題可能包含：圖片過大、格式不是 WebP/AVIF、誤用 loading=&quot;lazy&quot;、缺少 fetchpriority、缺少明確 width/height。

請在這個 11ty 專案中：
1. 找出產生該 LCP 圖片的 Markdown / layout / Image Transform 設定
2. 讓首屏圖片改為 loading=&quot;eager&quot;、fetchpriority=&quot;high&quot;，並確保有 width/height
3. 確認視窗外圖片仍可 lazy-load，不要全站改成 eager
4. 若已使用 @11ty/eleventy-img，優先在既有管道調整，不要另開一套圖片流程
5. 改完說明輸出 HTML 應長什麼樣子，並列出我要驗證的項目&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;AI-做完後,你要審核什麼LCP&quot;&gt;AI 做完後，你要審核什麼（LCP）&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;diff 範圍&lt;/strong&gt;：是不是只動了首圖／hero 相關模板或圖片設定，沒有順便改追蹤碼或全站 CSS。&lt;li&gt;&lt;strong&gt;輸出 HTML&lt;/strong&gt;：本機 build 後打開該頁原始碼，確認 LCP 圖真的是 &lt;code&gt;eager&lt;/code&gt; + &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt;，且有 &lt;code&gt;width&lt;/code&gt;/&lt;code&gt;height&lt;/code&gt;。&lt;li&gt;&lt;strong&gt;不要誤傷下文圖片&lt;/strong&gt;：文章中段、側欄、相關文章縮圖仍應 lazy；若全部變 eager，會反而搶頻寬。&lt;li&gt;&lt;strong&gt;實際載入&lt;/strong&gt;：用瀏覽器 DevTools Network，確認首屏圖優先被請求，且尺寸合理（不是幾千像素原圖硬塞手機）。&lt;li&gt;&lt;strong&gt;重測&lt;/strong&gt;：同一 URL 再跑 PageSpeed Insights，看 LCP 與「Improve image delivery」類診斷是否改善。&lt;/ul&gt;&lt;h2 id=&quot;PageSpeed-Insights-指出-CLS先補尺寸,不要只調分數&quot;&gt;PageSpeed Insights 指出 CLS：先補尺寸，不要只調分數&lt;/h2&gt;&lt;p&gt;CLS 的問題常常不是 11ty 本身造成，而是輸出的 HTML 沒有告訴瀏覽器圖片會佔多大空間。圖片載入後才撐開版面，讀者原本要點的按鈕就可能被推走。&lt;p&gt;我的檢查順序是：&lt;ol&gt;&lt;li&gt;找出全站 &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;，確認是否都有真實的 &lt;code&gt;width&lt;/code&gt; 和 &lt;code&gt;height&lt;/code&gt;，或有可預期的 &lt;code&gt;aspect-ratio&lt;/code&gt;。&lt;li&gt;檢查 YouTube、社群貼文和其他 iframe 是否有固定比例或預留高度。&lt;li&gt;檢查 web font 載入後是否造成文字換行和版面位移。&lt;li&gt;檢查 cookie、聯盟揭露或廣告區塊是否在內容上方突然插入。&lt;/ol&gt;&lt;p&gt;這也是 11ty 好處很明顯的地方：我可以在共用 layout、shortcode 或 Image Transform 統一修正，不必逐頁打開 WordPress 編輯器，也不必猜某個外掛會不會在前端再次改寫 HTML。&lt;h3 id=&quot;給-AI-的提示詞範例CLS&quot;&gt;給 AI 的提示詞範例（CLS）&lt;/h3&gt;&lt;pre class=&quot;language-text&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;請只處理 CLS（版面位移），不要改 LCP 優先權策略，也不要動分析／GTM 載入時機。

PageSpeed Insights 診斷：（貼上 layout shift 相關項目、受影響元素）

請在這個 11ty 專案中：
1. 找出缺少 width/height 的 &amp;lt;img&amp;gt;，以及可能造成位移的 iframe、字體、上方橫幅
2. 在 layout、shortcode 或 Image Transform 統一補上真實尺寸或 aspect-ratio
3. 若有 YouTube／社群嵌入，請用固定比例容器預留空間
4. 不要用「把內容延後載入」這種方式假裝解決 CLS
5. 改完列出改動檔案，並告訴我應在哪些頁面用肉眼看載入過程有沒有跳動&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;AI-做完後,你要審核什麼CLS&quot;&gt;AI 做完後，你要審核什麼（CLS）&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;尺寸是真的，不是亂填&lt;/strong&gt;：&lt;code&gt;width&lt;/code&gt;/&lt;code&gt;height&lt;/code&gt; 要對應實際比例；亂填會讓圖片被壓扁或裁切。&lt;li&gt;&lt;strong&gt;全站一致性&lt;/strong&gt;：共用 layout／Transform 改過後，抽查首頁、文章頁、分類頁各一頁，確認不是只修了示範頁。&lt;li&gt;&lt;strong&gt;字體與橫幅&lt;/strong&gt;：若 AI 只補了圖片尺寸，但診斷點的是 web font 或頂部通知條，要退回請它對準真正元素。&lt;li&gt;&lt;strong&gt;肉眼驗證&lt;/strong&gt;：硬重新整理時盯著標題與按鈕位置，載入過程不應上下跳；必要時開 DevTools 的 Layout Shift regions。&lt;li&gt;&lt;strong&gt;重測&lt;/strong&gt;：同一條件重跑 PageSpeed Insights，確認 CLS 下降，且沒有為了 CLS 把首圖又改回有害的 lazy。&lt;/ul&gt;&lt;h2 id=&quot;PageSpeed-Insights-指出-JavaScript-太多先問這支腳本真的需要嗎?&quot;&gt;PageSpeed Insights 指出 JavaScript 太多：先問這支腳本真的需要嗎？&lt;/h2&gt;&lt;p&gt;純文章型 11ty 網站可以預設不載入 JavaScript，但只要加上 GA4、GTM、聊天工具、社群分享 SDK 或搜尋功能，INP 和主執行緒就可能開始變差。這裡的重點不是看到一支腳本就立刻刪掉，而是確認它在什麼時機、做了多少工作，以及功能是否真的需要它。&lt;p&gt;我會先做腳本盤點：&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;腳本類型&lt;th&gt;我的處理方式&lt;th&gt;需要注意的取捨&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;不再使用的追蹤或聊天工具&lt;td&gt;直接移除&lt;td&gt;先確認沒有業務依賴&lt;tr&gt;&lt;td&gt;非關鍵分析&lt;td&gt;延後到 &lt;code&gt;window&lt;/code&gt; loaded 或 idle&lt;td&gt;早期 pageview 可能遺失&lt;tr&gt;&lt;td&gt;使用者點擊後才需要的功能&lt;td&gt;點擊時才載入&lt;td&gt;第一次互動可能需要等待&lt;tr&gt;&lt;td&gt;需要精準記錄的轉換事件&lt;td&gt;保留即時路徑或精簡標籤&lt;td&gt;不能只為了效能犧牲轉換資料&lt;tr&gt;&lt;td&gt;社群分享&lt;td&gt;優先用普通連結取代 SDK&lt;td&gt;互動效果較少，但前端更輕&lt;/table&gt;&lt;p&gt;GTM 不能只看 &lt;code&gt;gtm.js&lt;/code&gt; 檔案大小。真正的成本可能來自容器裡的 Facebook Pixel、Hotjar、GA4 或其他標籤執行後造成的長任務。&lt;p&gt;如果採用 &lt;code&gt;requestIdleCallback&lt;/code&gt; 或互動後載入，也要測試事件是否仍能在導向前送出，不能只看分數變好了就算完成。瀏覽器分數變漂亮了，分析資料卻少一半，這種優化就像把咖啡杯擦得發亮，結果裡面根本沒有咖啡。&lt;p&gt;下面是概念範例，不是可以直接套到所有分析工具的通用初始化碼。實際使用前，仍要依工具文件確認初始化順序、事件佇列和瀏覽器支援情況：&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;loadAnalytics&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// 在這裡載入或初始化非關鍵分析工具。&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;requestIdleCallback&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;requestIdleCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;loadAnalytics&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;loadAnalytics&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;requestIdleCallback&lt;/code&gt; 是「有空再做」的安排，不是「一定在某個時間完成」的保證；&lt;code&gt;timeout&lt;/code&gt; 也不是分析事件送達的保證。若事件很重要，應該設計可接受的備援，並用瀏覽器 Network 或工具的除錯模式確認它真的送出。&lt;h3 id=&quot;給-AI-的提示詞範例第三方-JavaScript&quot;&gt;給 AI 的提示詞範例（第三方 JavaScript）&lt;/h3&gt;&lt;pre class=&quot;language-text&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;請只處理第三方／非關鍵 JavaScript 對 INP 與主執行緒的影響，不要改圖片與版面尺寸。

PageSpeed Insights 診斷：（貼上 Unused JavaScript、Reduce JavaScript execution time、長任務、相關 URL）

腳本盤點現況（請先對照專案後再改）：
- 必須保留且需準確的：（例如 GA4 轉換、主要 pageview）
- 可延後的：（例如非關鍵分析）
- 可改為點擊才載入或改成普通連結的：（例如社群 SDK）
- 可移除的：（例如已停用的聊天工具）

請提出最小修改：
1. 先盤點 layout／site.js 實際載入了哪些腳本
2. 依上表延後、互動後載入或移除；不要默默刪掉我標記為必須保留的追蹤
3. 若使用 requestIdleCallback 或 loaded 後載入，請說明對早期 pageview 的取捨
4. 改完列出我應如何驗證：效能重測 + 分析事件是否仍會送出&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;AI-做完後,你要審核什麼JavaScript&quot;&gt;AI 做完後，你要審核什麼（JavaScript）&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;業務依賴&lt;/strong&gt;：確認沒有刪掉仍在用的聊天、廣告、轉換標籤；diff 裡出現追蹤 ID 變更要特別小心。&lt;li&gt;&lt;strong&gt;載入時機&lt;/strong&gt;：非關鍵腳本是否真的延後；關鍵轉換路徑是否仍即時或有可接受的備援。&lt;li&gt;&lt;strong&gt;功能回歸&lt;/strong&gt;：搜尋、主題切換、表單、分享按鈕在本機點一輪，確認第一次互動不會整頁壞掉。&lt;li&gt;&lt;strong&gt;分析驗證&lt;/strong&gt;：開 GA4／GTM 預覽或 Network 過濾相關請求，確認 pageview／轉換在典型瀏覽路徑仍會送出。&lt;li&gt;&lt;strong&gt;重測&lt;/strong&gt;：同一 URL 看 INP／主執行緒診斷是否改善；分數變好但事件消失，這輪算失敗，要回滾或縮小範圍。&lt;/ul&gt;&lt;h2 id=&quot;為什麼同一個建議,在-WordPress-上常常比較難落地?&quot;&gt;為什麼同一個建議，在 WordPress 上常常比較難落地？&lt;/h2&gt;&lt;p&gt;這不是說 WordPress 完全不能優化。簡單、乾淨的 WordPress 站也可能有很好的效能；反過來，11ty 如果塞滿大圖、第三方腳本和錯誤模板，也一樣會拿到差分數。&lt;p&gt;差異在於問題的可控程度：&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;PageSpeed Insights 顯示的問題&lt;th&gt;11ty 常見修改位置&lt;th&gt;WordPress 常見限制&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;LCP 圖片太慢&lt;td&gt;Markdown、template、&lt;code&gt;eleventy-img&lt;/code&gt;、HTML 屬性&lt;td&gt;佈景主題、圖片外掛、頁面編輯器可能都有關聯&lt;tr&gt;&lt;td&gt;CLS 版面位移&lt;td&gt;layout、CSS、Image Transform&lt;td&gt;主題元件、廣告或外掛動態插入內容&lt;tr&gt;&lt;td&gt;CSS 太多&lt;td&gt;直接整理模板和 CSS&lt;td&gt;主題與外掛各自載入，停用可能影響版面&lt;tr&gt;&lt;td&gt;JavaScript 阻塞&lt;td&gt;直接刪除、延後或修改載入策略&lt;td&gt;外掛可能依賴特定順序，更新後又重新注入&lt;tr&gt;&lt;td&gt;TTFB 偏高&lt;td&gt;靜態輸出、CDN、快取設定&lt;td&gt;PHP、資料庫、主機和快取外掛互相影響&lt;/table&gt;&lt;p&gt;簡單說，WordPress 的問題常是「我知道哪裡慢，但改了會不會破壞整個站？」；11ty 比較常是「我知道哪個檔案要改，改完 build 驗證就好」。&lt;h2 id=&quot;我會用-AI-加速修正,但不會讓-AI-直接亂改整站&quot;&gt;我會用 AI 加速修正，但不會讓 AI 直接亂改整站&lt;/h2&gt;&lt;p&gt;AI 很適合把 PageSpeed Insights 的診斷轉成候選 patch，例如：&lt;ul&gt;&lt;li&gt;找出 layout 中所有沒有尺寸的圖片。&lt;li&gt;檢查 hero 圖是否誤用了 lazy-loading。&lt;li&gt;依目前的模板補上 &lt;code&gt;fetchpriority&lt;/code&gt; 或 &lt;code&gt;srcset&lt;/code&gt;。&lt;li&gt;找出可能重複載入的 CSS 和 JavaScript。&lt;li&gt;產生一個小範圍的 CSS 或模板修改。&lt;/ul&gt;&lt;p&gt;但我會把 AI 當成能快速工作的實習生，而不是自動批准的部署工具。我的流程是：&lt;ol&gt;&lt;li&gt;先把 PageSpeed Insights 的原文診斷、目標指標和不能改動的範圍講清楚。&lt;li&gt;要 AI 一次只改一個檔案或一類問題。&lt;li&gt;讀 diff，確認它沒有順便改掉 URL、追蹤 ID 或其他不相關設定。&lt;li&gt;本機 build，檢查輸出 HTML。&lt;li&gt;用瀏覽器實際點一輪，確認圖片、選單、搜尋功能正常。&lt;li&gt;重新跑 PageSpeed Insights，並把改動和結果記錄下來。&lt;/ol&gt;&lt;h3 id=&quot;提示詞要寫清楚的五件事&quot;&gt;提示詞要寫清楚的五件事&lt;/h3&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;要寫清楚&lt;th&gt;為什麼重要&lt;th&gt;壞例子&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;目標頁面 URL&lt;td&gt;避免 AI 改到不相干的模板&lt;td&gt;「把網站變快」&lt;tr&gt;&lt;td&gt;只處理哪一個指標／診斷&lt;td&gt;方便對照前後測結果&lt;td&gt;「LCP、CLS、JS 一次修完」&lt;tr&gt;&lt;td&gt;診斷原文或截圖重點&lt;td&gt;讓 AI 對準真實元素，不是猜&lt;td&gt;「感覺首圖有點慢」&lt;tr&gt;&lt;td&gt;禁止改動的範圍&lt;td&gt;防止誤改追蹤、部署、文案&lt;td&gt;完全不設限制&lt;tr&gt;&lt;td&gt;完成後要回報什麼&lt;td&gt;你審核時有檢查清單&lt;td&gt;「改好跟我說一聲」&lt;/table&gt;&lt;h3 id=&quot;AI-交卷後的總審核清單&quot;&gt;AI 交卷後的總審核清單&lt;/h3&gt;&lt;p&gt;不管這輪修的是圖片還是腳本，我都會用同一張清單過一遍：&lt;ol&gt;&lt;li&gt;&lt;strong&gt;範圍&lt;/strong&gt;：diff 是否只涵蓋這次約定的問題？有沒有「順便重構」？&lt;li&gt;&lt;strong&gt;正確性&lt;/strong&gt;：輸出 HTML／CSS／JS 是否真的對應診斷（例如修 LCP 卻只改了下文 lazy 圖）？&lt;li&gt;&lt;strong&gt;回歸&lt;/strong&gt;：導覽、搜尋、深色模式、表單、內嵌內容是否仍可用？&lt;li&gt;&lt;strong&gt;資料&lt;/strong&gt;：若動過 GTM／分析，事件與轉換是否仍正確？&lt;li&gt;&lt;strong&gt;驗證&lt;/strong&gt;：同一 URL、相近條件重測後，目標指標是否改善？有沒有其他指標明顯變差？&lt;li&gt;&lt;strong&gt;紀錄&lt;/strong&gt;：這輪改了什麼、前後分數／診斷差異寫下來，方便之後回顧或回滾。&lt;/ol&gt;&lt;p&gt;AI 可以幫我縮短「從診斷到修改」的時間，但不能替我判斷該不該犧牲分析資料，也不能保證它產生的 HTML 一定符合這個網站的模板結構，最好是本機開發審核做完再部署。&lt;p&gt;先上線再祈禱，比較像賭咖啡因，不像做優化。&lt;h2 id=&quot;什麼情況不該只為了-PageSpeed-Insights-換成-11ty?&quot;&gt;什麼情況不該只為了 PageSpeed Insights 換成 11ty？&lt;/h2&gt;&lt;p&gt;如果網站核心是 WooCommerce、會員、論壇、即時資料或複雜表單，WordPress 的動態能力可能比純靜態效能更重要。若團隊每天都需要非技術人員從後台發文，也要把編輯效率算進去。&lt;p&gt;我會把選擇簡化成這樣：&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;如果你的情況是&lt;th&gt;比較合理的方向&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;文章和教學為主，願意用 Git，PageSpeed Insights 長期有明確問題&lt;td&gt;評估 11ty，或先把部分頁面靜態化&lt;tr&gt;&lt;td&gt;WordPress 站很簡單，只是圖片和腳本沒整理&lt;td&gt;先做圖片、快取、外掛和第三方腳本盤點&lt;tr&gt;&lt;td&gt;每天靠後台編輯，沒有技術人員維護 build&lt;td&gt;留在 WordPress，優先找出可安全調整的瓶頸&lt;tr&gt;&lt;td&gt;電商、會員和複雜表單是核心&lt;td&gt;留 WordPress，或評估 headless WordPress 加靜態前台&lt;/table&gt;&lt;p&gt;換成 11ty 也不是 SEO 自動升級。URL、301、sitemap、canonical、內容品質和內部連結仍然要維護。11ty 解決的是「前端和輸出 HTML 更容易控制」，不是替你完成整套 SEO。&lt;h2 id=&quot;結語把診斷建議變成可執行的工作清單&quot;&gt;結語：把診斷建議變成可執行的工作清單&lt;/h2&gt;&lt;p&gt;我喜歡用 11ty 做效能優化，並不是因為它能保證每個網站都拿到滿分，而是因為 PageSpeed Insights 指出問題後，通常可以直接找到對應的模板、CSS、圖片或腳本來修改。&lt;p&gt;最值得記住的三件事：&lt;ul&gt;&lt;li&gt;LCP 先找真正的最大元素，首圖不要盲目 lazy-load；提示詞要貼診斷原文，審核輸出 HTML 的 &lt;code&gt;eager&lt;/code&gt;／&lt;code&gt;fetchpriority&lt;/code&gt;。&lt;li&gt;CLS 先補圖片尺寸和版面預留；審核時確認尺寸是真比例，並用肉眼看載入有沒有跳。&lt;li&gt;INP 先盤點第三方 JavaScript；AI 延後腳本後，一定要驗證分析和轉換資料還在。&lt;/ul&gt;&lt;p&gt;如果你也在維護 11ty 網站，可以先選一個代表性頁面跑一次 &lt;a href=&quot;https://pagespeed.web.dev/&quot;&gt;PageSpeed Insights&lt;/a&gt;，把第一個最具體的診斷貼進上面的提示詞骨架，讓 AI 做最小修改，再用同一張審核清單過完、相同條件重測。先從一個問題開始，通常比一次叫 AI「把整站優化到 100 分」更容易得到可驗證的結果。審完，再來一杯咖啡。&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://pagespeed.web.dev/&quot;&gt;PageSpeed Insights&lt;/a&gt; — Google 的網頁效能檢測工具，可查看 Lighthouse 實驗室資料與 CrUX 欄位資料。&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/overview&quot;&gt;Lighthouse 文件&lt;/a&gt; — Lighthouse 的用途、報告與本機測試說明。&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/vitals&quot;&gt;Web Vitals（web.dev）&lt;/a&gt; — LCP、CLS、INP 等 Core Web Vitals 的定義與評估方式。&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/lcp&quot;&gt;Largest Contentful Paint（web.dev）&lt;/a&gt; — LCP 的計算方式與常見優化方向。&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/cls&quot;&gt;Cumulative Layout Shift（web.dev）&lt;/a&gt; — CLS 的成因、計算方式與版面穩定性建議。&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/plugins/image/&quot;&gt;Eleventy Image&lt;/a&gt; — &lt;code&gt;@11ty/eleventy-img&lt;/code&gt; 的官方文件，說明圖片格式、尺寸與 &lt;code&gt;srcset&lt;/code&gt; 產生方式。&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Pagefind 教學：如何為 Eleventy 靜態網站加入純前端搜尋</title>
    <link href="https://kamadiam.com/pagefind-eleventy-static-site-search/" />
    <updated>2026-08-04T06:51:00Z</updated>
    <id>https://kamadiam.com/pagefind-eleventy-static-site-search/</id>
    <content type="html">&lt;h1 id=&quot;Pagefind-教學如何為-Eleventy-靜態網站加入純前端搜尋&quot;&gt;Pagefind 教學：如何為 Eleventy 靜態網站加入純前端搜尋&lt;/h1&gt;&lt;p&gt;文章一多，讀者只靠導覽列和分類頁，找舊文就像在咖啡渣裡找關鍵字。這時先別急著架資料庫：對以文章為主的 Eleventy 靜態網站來說，Pagefind 通常已經很夠用。&lt;p&gt;這篇會帶你弄懂 Pagefind 的工作方式，接著完成 layout 標記、build 後建立索引，以及繁體中文搜尋的驗收。讀完後，你應該能判斷 Pagefind 是否適合自己的網站，也知道搜尋失靈時該從哪裡查起。&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagefind-eleventy-static-site-search/#Pagefind-%E6%98%AF%E4%BB%80%E9%BA%BC?&quot;&gt;Pagefind 是什麼？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagefind-eleventy-static-site-search/#%E9%96%8B%E5%A7%8B%E5%89%8D%E5%85%88%E7%A2%BA%E8%AA%8D%E4%B8%89%E4%BB%B6%E4%BA%8B&quot;&gt;開始前先確認三件事&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagefind-eleventy-static-site-search/#%E7%AC%AC%E4%B8%80%E6%AD%A5%E9%81%B8%E6%93%87-Pagefind-UI-%E7%89%88%E6%9C%AC&quot;&gt;第一步：選擇 Pagefind UI 版本&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagefind-eleventy-static-site-search/#%E7%AC%AC%E4%BA%8C%E6%AD%A5%E5%91%8A%E8%A8%B4-Pagefind-%E8%A6%81%E7%B4%A2%E5%BC%95%E4%BB%80%E9%BA%BC&quot;&gt;第二步：告訴 Pagefind 要索引什麼&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagefind-eleventy-static-site-search/#%E7%AC%AC%E4%B8%89%E6%AD%A5%E5%9C%A8-Eleventy-build-%E5%BE%8C%E5%BB%BA%E7%AB%8B%E7%B4%A2%E5%BC%95&quot;&gt;第三步：在 Eleventy build 後建立索引&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagefind-eleventy-static-site-search/#%E7%AC%AC%E5%9B%9B%E6%AD%A5%E6%8A%8A%E6%B5%81%E7%A8%8B%E6%8E%A5%E9%80%B2-package.json&quot;&gt;第四步：把流程接進 package.json&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagefind-eleventy-static-site-search/#%E7%B9%81%E9%AB%94%E4%B8%AD%E6%96%87%E6%90%9C%E5%B0%8B%E8%A6%81%E6%80%8E%E9%BA%BC%E9%A9%97%E6%94%B6?&quot;&gt;繁體中文搜尋要怎麼驗收？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagefind-eleventy-static-site-search/#%E5%B8%B8%E8%A6%8B%E5%95%8F%E9%A1%8C%E6%8E%92%E6%9F%A5&quot;&gt;常見問題排查&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagefind-eleventy-static-site-search/#%E7%B5%90%E8%AA%9E%E5%85%88%E8%A7%A3%E6%B1%BA%E6%90%9C%E5%B0%8B,%E5%86%8D%E8%80%83%E6%85%AE%E5%8D%87%E7%B4%9A&quot;&gt;結語：先解決搜尋，再考慮升級&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagefind-eleventy-static-site-search/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;Pagefind-是什麼?&quot;&gt;Pagefind 是什麼？&lt;/h2&gt;&lt;p&gt;Pagefind 是在 build 後處理靜態 HTML 的搜尋工具。它會讀取網站輸出的 HTML，建立一組可由瀏覽器載入的索引檔；訪客搜尋時，結果在前端計算，不需要另開一個搜尋 API 或資料庫伺服器。&lt;p&gt;所以它很適合個人部落格、文件站和產品說明站。文章更新後重新 build，索引也跟著重建。反過來說，如果你的資料需要登入權限、個人化結果或即時更新，Pagefind 不是後端搜尋的替代品——咖啡濾紙也不能拿來當資料庫。&lt;h2 id=&quot;開始前先確認三件事&quot;&gt;開始前先確認三件事&lt;/h2&gt;&lt;p&gt;你需要一個能正常輸出 &lt;code&gt;_site/&lt;/code&gt; 的 Eleventy 專案，並確認共用 layout 的 &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; 有語言標記：&lt;pre class=&quot;language-njk&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-njk&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;!&lt;span class=&quot;token variable&quot;&gt;doctype&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;zh-Hant&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
	&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
		
	&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
	&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
		
	&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;語言標記不是裝飾。Pagefind 會在索引時讀取 &lt;code&gt;&amp;lt;html lang&amp;gt;&lt;/code&gt;，依語言分開建立索引；瀏覽器初始化搜尋時，也會依目前頁面的語言載入對應索引。繁體中文網站通常可以使用 &lt;code&gt;zh-Hant&lt;/code&gt;，但仍應用實際文章內容測試。&lt;p&gt;另外，請先單獨確認 Eleventy build 沒有錯誤。Pagefind 只能處理已經產生的靜態檔案，不能替你修好前一步的模板錯誤。&lt;h2 id=&quot;第一步選擇-Pagefind-UI-版本&quot;&gt;第一步：選擇 Pagefind UI 版本&lt;/h2&gt;&lt;p&gt;Pagefind 的搜尋索引和搜尋介面是兩件事。索引先由 CLI 建立，UI 再載入 &lt;code&gt;/pagefind/&lt;/code&gt; 裡產生的資產。&lt;p&gt;目前常見的兩種 UI 寫法，不能直接混在一起：&lt;ul&gt;&lt;li&gt;Pagefind 1.4 及更早版本常用 Default UI：載入 &lt;code&gt;pagefind-ui.css&lt;/code&gt;、&lt;code&gt;pagefind-ui.js&lt;/code&gt;，再用 &lt;code&gt;new PagefindUI(...)&lt;/code&gt; 初始化。&lt;li&gt;Pagefind 1.5 開始提供 Component UI：使用 &lt;code&gt;pagefind-component-ui.css&lt;/code&gt;、&lt;code&gt;pagefind-component-ui.js&lt;/code&gt; 和自訂元素，例如 &lt;code&gt;&amp;lt;pagefind-modal&amp;gt;&lt;/code&gt;。&lt;/ul&gt;&lt;p&gt;先看專案的 &lt;code&gt;package.json&lt;/code&gt; 版本，再照對應文件操作。本文以 Pagefind 1.4 的 Default UI 示範，因為這是目前專案使用的版本。&lt;p&gt;在共用 layout 放入 CSS 與搜尋容器：&lt;pre class=&quot;language-njk&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-njk&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/pagefind/pagefind-ui.css&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;search&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;接著在 JavaScript 中載入並初始化 UI：&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pagefindScript &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;script&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
pagefindScript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/pagefind/pagefind-ui.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
pagefindScript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onload&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PagefindUI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;#search&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;showSubResults&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pagefindScript&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;你也可以在頁面載入時直接用 &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; 載入；只有在訪客打開搜尋時才載入，則能避免每個頁面一開始都下載搜尋程式。重點是：不論採用哪種載入時機，索引尚未建立前，&lt;code&gt;/pagefind/&lt;/code&gt; 下的檔案都不存在，看到 404 不一定是 UI 寫錯。&lt;h2 id=&quot;第二步告訴-Pagefind-要索引什麼&quot;&gt;第二步：告訴 Pagefind 要索引什麼&lt;/h2&gt;&lt;p&gt;Pagefind 預設會處理頁面內容，但你可以用 &lt;code&gt;data-pagefind-body&lt;/code&gt; 把範圍縮小，用 &lt;code&gt;data-pagefind-ignore&lt;/code&gt; 排除固定介面：&lt;pre class=&quot;language-njk&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-njk&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
	&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;header&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;pagefind&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;ignore&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
		網站導覽
	&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

	&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;pagefind&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
		
	&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

	&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;footer&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;pagefind&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;ignore&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
		頁尾資訊
	&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;footer&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;這三個標記各自做一件事：&lt;ol&gt;&lt;li&gt;&lt;code&gt;lang=&amp;quot;zh-Hant&amp;quot;&lt;/code&gt; 提供語言資訊，讓 Pagefind 進行對應的語言處理。&lt;li&gt;&lt;code&gt;data-pagefind-body&lt;/code&gt; 指定頁面真正要被搜尋的內容。&lt;li&gt;&lt;code&gt;data-pagefind-ignore&lt;/code&gt; 排除導覽列、頁尾或分享按鈕，避免固定文字污染每一筆結果。&lt;/ol&gt;&lt;p&gt;有一個容易漏掉的規則：只要網站任何頁面使用了 &lt;code&gt;data-pagefind-body&lt;/code&gt;，沒有這個標記的頁面就不會被索引。因此，如果首頁、分類頁也要出現在搜尋結果裡，它們同樣要標記搜尋主體。&lt;p&gt;&lt;code&gt;data-pagefind-ignore&lt;/code&gt; 是「排除元素」；它不會讓整頁消失。把它放在 header 或 footer 上，文章正文仍然會被索引。&lt;h2 id=&quot;第三步在-Eleventy-build-後建立索引&quot;&gt;第三步：在 Eleventy build 後建立索引&lt;/h2&gt;&lt;p&gt;先建立網站，再把輸出目錄交給 Pagefind。使用專案已安裝並鎖定版本的 CLI，通常比每次用 &lt;code&gt;npx -y&lt;/code&gt; 下載最新版更容易重現：&lt;pre class=&quot;language-shell&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;exec&lt;/span&gt; eleventy
&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;exec&lt;/span&gt; pagefind &lt;span class=&quot;token parameter variable&quot;&gt;--site&lt;/span&gt; _site &lt;span class=&quot;token parameter variable&quot;&gt;--glob&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;**/*.html&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;成功後，輸出目錄會出現 &lt;code&gt;_site/pagefind/&lt;/code&gt;，裡面包含索引資料，以及 UI 需要的 JavaScript 和 CSS。Pagefind 本身沒有搜尋後端；這些檔案部署到同一個靜態網站後，瀏覽器就能載入它們。&lt;p&gt;如果想快速測試，也可以讓 Pagefind 在建立索引後提供本機靜態伺服器：&lt;pre class=&quot;language-shell&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;exec&lt;/span&gt; pagefind &lt;span class=&quot;token parameter variable&quot;&gt;--site&lt;/span&gt; _site &lt;span class=&quot;token parameter variable&quot;&gt;--glob&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;**/*.html&#39;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--serve&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;這個 &lt;code&gt;--serve&lt;/code&gt; 是方便開發時測試的本機伺服器，不是正式環境必須部署的服務。不要直接用 &lt;code&gt;file://&lt;/code&gt; 開啟 HTML，因為瀏覽器的模組載入和 fetch 請求可能受到本機檔案權限限制。&lt;h2 id=&quot;第四步把流程接進-package.json&quot;&gt;第四步：把流程接進 package.json&lt;/h2&gt;&lt;p&gt;手動跑兩個指令可以驗證概念，但很容易忘記第二個。把 Pagefind 接在 Eleventy 後面，每次 build 就會自動更新索引：&lt;pre class=&quot;language-json&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;build&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NODE_ENV=production ELEVENTY_PROFILE=true pnpm exec eleventy &amp;amp;&amp;amp; pnpm exec pagefind --site _site --glob &#92;&quot;**/*.html&#92;&quot;&quot;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;實際專案的 build script 可能還有清理、Vite 或其他收尾步驟；請把 Pagefind 放在「所有 HTML 都完成之後」。如果部署平台只執行 Eleventy，卻沒有執行 Pagefind，正式站自然不會憑空長出搜尋索引。&lt;p&gt;也可以在 Eleventy 的 &lt;code&gt;eleventy.after&lt;/code&gt; 事件裡呼叫 Pagefind，但這會讓 Eleventy 設定檔同時負責建站和啟動外部程序。對多數專案而言，&lt;code&gt;package.json&lt;/code&gt; 用 &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; 串接比較容易看懂、除錯，也能確保前一步失敗時不會誤把舊索引當成新成果。&lt;h2 id=&quot;繁體中文搜尋要怎麼驗收?&quot;&gt;繁體中文搜尋要怎麼驗收？&lt;/h2&gt;&lt;p&gt;Pagefind 支援中文的分詞處理，但中文不像英文那樣以空白分隔；搜尋結果仍然取決於索引內容和查詢方式。這不是「加上 &lt;code&gt;lang&lt;/code&gt; 就保證什麼都找得到」，所以請用真正的文章做測試。&lt;p&gt;部署前至少走過這份清單：&lt;ul&gt;&lt;li&gt;[ ] Eleventy build 成功，沒有模板或資產錯誤。&lt;li&gt;[ ] &lt;code&gt;_site/pagefind/&lt;/code&gt; 存在，且正式網址能載入 &lt;code&gt;/pagefind/&lt;/code&gt; 下的檔案。&lt;li&gt;[ ] 搜尋一個確定存在的文章標題，可以回傳結果。&lt;li&gt;[ ] 搜尋兩三個繁體中文詞組，例如「網站安全」或「靜態網站」。&lt;li&gt;[ ] 搜尋結果沒有被導覽列、頁尾或分享按鈕的固定文字洗版。&lt;li&gt;[ ] 修改文章後重新 build，結果中的摘要已更新。&lt;/ul&gt;&lt;p&gt;若網站同時有多種語言，請讓每個頁面的 &lt;code&gt;&amp;lt;html lang&amp;gt;&lt;/code&gt; 正確反映內容，不要全部硬寫成同一種語言。Pagefind 會依語言分開索引；標記錯誤，等於把書放進錯的書架，搜尋當然會繞遠路。&lt;h2 id=&quot;常見問題排查&quot;&gt;常見問題排查&lt;/h2&gt;&lt;h3 id=&quot;搜尋框出現,卻沒有結果&quot;&gt;搜尋框出現，卻沒有結果&lt;/h3&gt;&lt;p&gt;先看瀏覽器 Network 面板：&lt;code&gt;/pagefind/pagefind-ui.js&lt;/code&gt;、&lt;code&gt;/pagefind/pagefind-ui.css&lt;/code&gt; 和索引檔是否回傳 404。再確認 Pagefind 指向的是包含 HTML 的輸出目錄，而不是專案原始碼目錄。&lt;h3 id=&quot;中文結果很少&quot;&gt;中文結果很少&lt;/h3&gt;&lt;p&gt;檢查 &lt;code&gt;&amp;lt;html lang&amp;gt;&lt;/code&gt; 是否存在且寫對，並用文章內確實出現的詞組測試。也檢查 &lt;code&gt;data-pagefind-body&lt;/code&gt; 是否誤放在空容器，或文章所在頁面根本沒有這個標記。不要只因為終端機出現 stemming 相關提示就移除語言標記：中文搜尋仍可運作，只是 Pagefind 不會以英文詞幹還原的方式處理中文。&lt;h3 id=&quot;首頁或分類頁沒有出現在結果裡&quot;&gt;首頁或分類頁沒有出現在結果裡&lt;/h3&gt;&lt;p&gt;這通常是 &lt;code&gt;data-pagefind-body&lt;/code&gt; 的範圍規則造成的。只標記文章 layout 時，沒有標記的首頁和分類頁會被排除；在同樣希望被搜尋的頁面補上搜尋主體即可。&lt;h3 id=&quot;搜尋結果一直出現導覽列文字&quot;&gt;搜尋結果一直出現導覽列文字&lt;/h3&gt;&lt;p&gt;將不需要搜尋的固定區塊加上 &lt;code&gt;data-pagefind-ignore&lt;/code&gt;，刪除舊的 &lt;code&gt;_site/pagefind/&lt;/code&gt; 後重新 build。只改模板、不重建索引，搜尋結果不會自己更新——索引沒有讀心術，只有讀檔術。&lt;h3 id=&quot;本機測試看起來壞掉&quot;&gt;本機測試看起來壞掉&lt;/h3&gt;&lt;p&gt;確認不是用 &lt;code&gt;file://&lt;/code&gt; 開啟 HTML，也確認 Pagefind 產出的 &lt;code&gt;/pagefind/&lt;/code&gt; 路徑和網站部署的 base path 一致。使用 &lt;code&gt;--serve&lt;/code&gt; 或其他靜態檔案伺服器重新測試，通常很快就能分辨是瀏覽器載入問題還是索引內容問題。&lt;h2 id=&quot;結語先解決搜尋,再考慮升級&quot;&gt;結語：先解決搜尋，再考慮升級&lt;/h2&gt;&lt;p&gt;對大多數 Eleventy 部落格來說，第一版站內搜尋不需要資料庫。你只要：&lt;ol&gt;&lt;li&gt;在 layout 加入與 Pagefind 版本相符的 UI。&lt;li&gt;設定正確的 &lt;code&gt;lang&lt;/code&gt;、&lt;code&gt;data-pagefind-body&lt;/code&gt; 和 &lt;code&gt;data-pagefind-ignore&lt;/code&gt;。&lt;li&gt;在每次 Eleventy build 後執行 Pagefind。&lt;li&gt;用實際的繁體中文查詢驗收。&lt;/ol&gt;&lt;p&gt;這樣就能讓讀者搜尋已部署的文章。未來若真的需要會員權限、個人化排序或即時資料，再評估後端或託管搜尋服務；先把今天的搜尋做好，咖啡才不會冷得太有深度。&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://pagefind.app/docs/&quot;&gt;Pagefind 官方文件&lt;/a&gt;：總覽、安裝與基本整合方式。&lt;li&gt;&lt;a href=&quot;https://pagefind.app/docs/running-pagefind/&quot;&gt;Running Pagefind&lt;/a&gt;：說明 &lt;code&gt;--site&lt;/code&gt;、&lt;code&gt;--serve&lt;/code&gt; 等 CLI 用法。&lt;li&gt;&lt;a href=&quot;https://pagefind.app/docs/indexing/&quot;&gt;Customizing the index&lt;/a&gt;：說明 &lt;code&gt;data-pagefind-body&lt;/code&gt; 與 &lt;code&gt;data-pagefind-ignore&lt;/code&gt;。&lt;li&gt;&lt;a href=&quot;https://pagefind.app/docs/multilingual/&quot;&gt;Multilingual Search&lt;/a&gt;：說明 &lt;code&gt;lang&lt;/code&gt;、多語言索引與中文分詞。&lt;li&gt;&lt;a href=&quot;https://pagefind.app/docs/ui-usage/&quot;&gt;Pagefind UI Usage&lt;/a&gt;：說明 Default UI 的載入和初始化方式。&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/events/&quot;&gt;Eleventy Configuration Events&lt;/a&gt;：查閱 &lt;code&gt;eleventy.after&lt;/code&gt; 等 Eleventy 事件。&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>11ty 與 Hostinger 快取怎麼設定？從 .htaccess 到更新驗收</title>
    <link href="https://kamadiam.com/11ty-hostinger-cache-setup/" />
    <updated>2026-08-04T03:44:00Z</updated>
    <id>https://kamadiam.com/11ty-hostinger-cache-setup/</id>
    <content type="html">&lt;p&gt;你把新文章部署上去，自己看得到最新版，讀者卻還在看昨天的內容？先別急著重跑 11ty，也別一杯接一杯咖啡地清快取。很多時候，問題不是建置失敗，而是瀏覽器、Hostinger、CDN 或 HTTP headers 還在提供舊檔案。&lt;p&gt;這篇會帶你用 11ty 建置 &lt;code&gt;_site&lt;/code&gt;，再依檔案類型安排 HTML、CSS、JavaScript、圖片、字型和 Pagefind 搜尋資產的快取策略。你也會看到如何在 Hostinger hPanel 清除快取，以及用 &lt;code&gt;curl&lt;/code&gt; 檢查公開網站實際回傳的 headers。快取不是壞掉的記憶體，只是它記得比你久了一點。&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-hostinger-cache-setup/#%E5%85%88%E8%A8%98%E4%BD%8F%E5%BF%AB%E5%8F%96%E5%8E%9F%E5%89%87&quot;&gt;先記住快取原則&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-hostinger-cache-setup/#11ty-%E8%88%87-Hostinger-%E5%90%84%E8%87%AA%E8%B2%A0%E8%B2%AC%E4%BB%80%E9%BA%BC?&quot;&gt;11ty 與 Hostinger 各自負責什麼？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-hostinger-cache-setup/#%E9%83%A8%E7%BD%B2%E5%89%8D%E5%85%88%E7%A2%BA%E8%AA%8D-_site&quot;&gt;部署前先確認 _site&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-hostinger-cache-setup/#%E4%BE%9D%E5%B0%88%E6%A1%88%E8%A8%AD%E5%AE%9A-public/.htaccess&quot;&gt;依專案設定 public/.htaccess&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-hostinger-cache-setup/#%E9%99%A4%E4%BA%86%E5%BF%AB%E5%8F%96,.htaccess-%E9%82%84%E8%83%BD%E8%B2%A0%E8%B2%AC%E5%93%AA%E4%BA%9B%E4%BA%8B%E6%83%85?&quot;&gt;除了快取，.htaccess 還能負責哪些事情？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-hostinger-cache-setup/#HSTS-%E4%B8%8D%E6%98%AF%E6%AA%94%E6%A1%88%E5%BF%AB%E5%8F%96&quot;&gt;HSTS 不是檔案快取&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-hostinger-cache-setup/#%E9%83%A8%E7%BD%B2%E5%BE%8C%E5%88%B0-hPanel-%E6%B8%85%E9%99%A4%E5%BF%AB%E5%8F%96&quot;&gt;部署後到 hPanel 清除快取&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-hostinger-cache-setup/#%E7%94%A8-curl-%E9%A9%97%E6%94%B6-response-headers&quot;&gt;用 curl 驗收 response headers&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-hostinger-cache-setup/#%E5%BF%AB%E5%8F%96%E8%A8%AD%E5%AE%9A%E6%B1%BA%E7%AD%96%E8%A1%A8&quot;&gt;快取設定決策表&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-hostinger-cache-setup/#%E5%B8%B8%E8%A6%8B%E5%95%8F%E9%A1%8C&quot;&gt;常見問題&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-hostinger-cache-setup/#%E9%83%A8%E7%BD%B2%E9%A9%97%E6%94%B6%E5%B7%A5%E5%85%B7&quot;&gt;部署驗收工具&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-hostinger-cache-setup/#%E7%B5%90%E8%AA%9E%E5%85%88%E5%88%86%E5%B1%A4,%E5%86%8D%E6%B1%BA%E5%AE%9A-TTL&quot;&gt;結語：先分層，再決定 TTL&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/11ty-hostinger-cache-setup/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;先記住快取原則&quot;&gt;先記住快取原則&lt;/h2&gt;&lt;p&gt;不要把所有檔案都快取一年。比較穩定的分法是：&lt;ul&gt;&lt;li&gt;&lt;strong&gt;HTML&lt;/strong&gt;：短時間快取，或要求瀏覽器重新驗證，因為文章和首頁會更新。&lt;li&gt;&lt;strong&gt;CSS、JavaScript、圖片、字型&lt;/strong&gt;：如果檔名包含版本號或內容指紋，可以長效快取。&lt;li&gt;&lt;strong&gt;Pagefind 搜尋資產&lt;/strong&gt;：搜尋索引會隨文章更新，不能直接套用一般靜態資產的一年 TTL。&lt;/ul&gt;&lt;p&gt;簡單說，內容頁要容易更新；URL 已經跟著內容改變的資產，才適合快取久一點。&lt;h2 id=&quot;11ty-與-Hostinger-各自負責什麼?&quot;&gt;11ty 與 Hostinger 各自負責什麼？&lt;/h2&gt;&lt;p&gt;11ty 負責把 Markdown、模板和資產建置成 &lt;code&gt;_site&lt;/code&gt; 裡的靜態檔案。它不會替你決定訪客的瀏覽器或 Hostinger CDN 要快取多久。&lt;p&gt;上線後的快取主要分成三層：&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;快取層級&lt;th&gt;作用&lt;th&gt;更新不生效時先檢查什麼&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;瀏覽器&lt;td&gt;減少訪客重複下載檔案&lt;td&gt;用無痕視窗測試&lt;tr&gt;&lt;td&gt;Hostinger 快取&lt;td&gt;減少來源站重複處理請求&lt;td&gt;hPanel 的 Clear cache 或 Cache Manager&lt;tr&gt;&lt;td&gt;CDN&lt;td&gt;讓訪客從較近的節點取得檔案&lt;td&gt;依 CDN 介面執行 Purge／Flush&lt;/table&gt;&lt;p&gt;所以，重新執行 11ty 只會更新輸出檔案，不能保證所有快取層立刻換成新版本。&lt;h2 id=&quot;部署前先確認-_site&quot;&gt;部署前先確認 &lt;code&gt;_site&lt;/code&gt;&lt;/h2&gt;&lt;p&gt;在專案根目錄執行：&lt;pre class=&quot;language-bash&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx @11ty/eleventy&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;本專案的 &lt;code&gt;pnpm run build&lt;/code&gt; 還會在 Eleventy 完成後執行 Pagefind，並寫入 &lt;code&gt;_site/pagefind/&lt;/code&gt;。如果只是先檢查 Eleventy 輸出，可以執行上面的指令；正式部署則建議直接執行：&lt;pre class=&quot;language-bash&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; run build&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;接著確認 &lt;code&gt;_site&lt;/code&gt; 裡有：&lt;ul&gt;&lt;li&gt;&lt;code&gt;_site/index.html&lt;/code&gt;&lt;li&gt;最新文章的 HTML&lt;li&gt;CSS 和 JavaScript&lt;li&gt;圖片與字型&lt;li&gt;&lt;code&gt;pagefind/&lt;/code&gt; 搜尋資產（如果網站有使用 Pagefind）&lt;/ul&gt;&lt;p&gt;上傳時，要把 &lt;code&gt;_site&lt;/code&gt; &lt;strong&gt;裡面的內容&lt;/strong&gt;放到 Hostinger 的網站根目錄，常見位置是 &lt;code&gt;public_html&lt;/code&gt;。不要把整個專案原始碼上傳到公開目錄，也不要多包一層 &lt;code&gt;_site&lt;/code&gt; 資料夾。&lt;h2 id=&quot;依專案設定-public/.htaccess&quot;&gt;依專案設定 &lt;code&gt;public/.htaccess&lt;/code&gt;&lt;/h2&gt;&lt;p&gt;本專案的 &lt;code&gt;public/.htaccess&lt;/code&gt; 使用 Apache 的 &lt;code&gt;mod_expires&lt;/code&gt;、&lt;code&gt;mod_headers&lt;/code&gt; 和 &lt;code&gt;mod_setenvif&lt;/code&gt; 管理快取與 response headers。下面是與目前設定相同的重點片段；完整檔案還包含重新導向、安全標頭、Gzip 和目錄列表設定。&lt;pre class=&quot;language-apache&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-apache&quot;&gt;&amp;lt;IfModule mod_expires.c&gt;
  ExpiresActive On
  ExpiresDefault &quot;access plus 5 minutes&quot;
  ExpiresByType text/html &quot;access plus 3 minutes&quot;
  ExpiresByType text/css &quot;access plus 1 month&quot;
  ExpiresByType application/javascript &quot;access plus 1 month&quot;
  ExpiresByType application/x-javascript &quot;access plus 1 month&quot;
  ExpiresByType image/jpeg &quot;access plus 1 month&quot;
  ExpiresByType image/gif &quot;access plus 1 month&quot;
  ExpiresByType image/png &quot;access plus 1 month&quot;
  ExpiresByType image/webp &quot;access plus 1 month&quot;
  ExpiresByType image/svg+xml &quot;access plus 1 month&quot;
  ExpiresByType font/ttf &quot;access plus 1 month&quot;
  ExpiresByType font/otf &quot;access plus 1 month&quot;
  ExpiresByType font/woff &quot;access plus 1 month&quot;
  ExpiresByType font/woff2 &quot;access plus 1 month&quot;
&amp;lt;/IfModule&gt;

&amp;lt;IfModule mod_headers.c&gt;
  &amp;lt;FilesMatch &quot;&#92;.(?:html?)$&quot;&gt;
    Header set Cache-Control &quot;public, max-age=180&quot;
  &amp;lt;/FilesMatch&gt;
  &amp;lt;FilesMatch &quot;&#92;.(?:css|js|gif|jpe?g|png|webp|svg|ico|woff2?)$&quot;&gt;
    Header set Cache-Control &quot;public, max-age=31536000, immutable&quot;
  &amp;lt;/FilesMatch&gt;
  Header always set Strict-Transport-Security &quot;max-age=31536000; includeSubDomains&quot;
&amp;lt;/IfModule&gt;

&amp;lt;IfModule mod_setenvif.c&gt;
  SetEnvIfNoCase Request_URI &quot;^/pagefind/&quot; pagefind_asset
&amp;lt;/IfModule&gt;
&amp;lt;IfModule mod_headers.c&gt;
  Header set Cache-Control &quot;no-cache, must-revalidate&quot; env=pagefind_asset
&amp;lt;/IfModule&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;這些設定分別做什麼?&quot;&gt;這些設定分別做什麼？&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;ExpiresActive On&lt;/code&gt;：啟用 Apache 的過期時間設定。&lt;li&gt;&lt;code&gt;ExpiresDefault &amp;quot;access plus 5 minutes&amp;quot;&lt;/code&gt;：沒有特別指定類型的檔案，預設快取五分鐘。&lt;li&gt;&lt;code&gt;ExpiresByType text/html &amp;quot;access plus 3 minutes&amp;quot;&lt;/code&gt;：HTML 的 &lt;code&gt;Expires&lt;/code&gt; 基準為三分鐘。&lt;li&gt;CSS、JavaScript、圖片和字型的 &lt;code&gt;ExpiresByType&lt;/code&gt;：先設定為快取一個月，之後資產規則會再設定明確的 &lt;code&gt;Cache-Control&lt;/code&gt;。&lt;li&gt;&lt;code&gt;Cache-Control: public, max-age=31536000, immutable&lt;/code&gt;：把符合檔名規則的 CSS、JavaScript、部分圖片、圖示與 woff 字型實際設定為快取一年。&lt;li&gt;&lt;code&gt;SetEnvIfNoCase Request_URI &amp;quot;^/pagefind/&amp;quot; pagefind_asset&lt;/code&gt;：找出 &lt;code&gt;/pagefind/&lt;/code&gt; 開頭的檔案。&lt;li&gt;&lt;code&gt;Header set Cache-Control &amp;quot;no-cache, must-revalidate&amp;quot; env=pagefind_asset&lt;/code&gt;：讓 Pagefind 更新後立即重新驗證。&lt;li&gt;&lt;code&gt;Strict-Transport-Security&lt;/code&gt;：不是檔案快取，而是告訴瀏覽器未來一年都使用 HTTPS；目前也包含 &lt;code&gt;includeSubDomains&lt;/code&gt;。&lt;/ul&gt;&lt;h3 id=&quot;一年快取有一個容易忽略的風險&quot;&gt;一年快取有一個容易忽略的風險&lt;/h3&gt;&lt;p&gt;目前的 &lt;code&gt;&amp;lt;FilesMatch&amp;gt;&lt;/code&gt; 是按照副檔名套用一年快取，並沒有檢查檔名是否真的含有內容雜湊。因此沒有版本號的 &lt;code&gt;style.css&lt;/code&gt; 或 &lt;code&gt;app.js&lt;/code&gt; 也會進入一年快取。如果這些檔案在原 URL 直接更新，訪客可能長時間拿到舊版本。&lt;p&gt;另一方面，&lt;code&gt;mjs&lt;/code&gt;、&lt;code&gt;avif&lt;/code&gt;、&lt;code&gt;ttf&lt;/code&gt; 和 &lt;code&gt;otf&lt;/code&gt; 雖然有一個月的 &lt;code&gt;ExpiresByType&lt;/code&gt;，卻不符合目前的 &lt;code&gt;&amp;lt;FilesMatch&amp;gt;&lt;/code&gt;，不會拿到一年期的 &lt;code&gt;Cache-Control&lt;/code&gt;。要維持一年 TTL，部署流程就必須確保資產 URL 會隨內容改變，或另外為未版本化資產加上較短的規則。&lt;h3 id=&quot;為什麼-Pagefind-需要單獨設定?&quot;&gt;為什麼 Pagefind 需要單獨設定？&lt;/h3&gt;&lt;p&gt;Pagefind 的檔案可能同時符合一般 JavaScript 或資產檔案規則，因此先拿到一年的長效快取。接著，&lt;code&gt;env=pagefind_asset&lt;/code&gt; 條件會再套用重新驗證的 &lt;code&gt;Cache-Control&lt;/code&gt;：&lt;pre class=&quot;language-http&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Cache-Control&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;no-cache, must-revalidate&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;這個例外很重要：一般資產可以快取一年，但搜尋索引不應該跟著使用同樣長的 TTL。&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;Header&lt;/code&gt; 需要 Apache &lt;code&gt;mod_headers&lt;/code&gt;，&lt;code&gt;ExpiresByType&lt;/code&gt; 需要 &lt;code&gt;mod_expires&lt;/code&gt;，Pagefind 的環境變數需要 &lt;code&gt;mod_setenvif&lt;/code&gt;。如果修改 &lt;code&gt;.htaccess&lt;/code&gt; 後出現 500 錯誤，先還原修改，再逐段確認 Hostinger 是否支援相關模組與語法。&lt;/blockquote&gt;&lt;h2 id=&quot;除了快取,.htaccess-還能負責哪些事情?&quot;&gt;除了快取，&lt;code&gt;.htaccess&lt;/code&gt; 還能負責哪些事情？&lt;/h2&gt;&lt;p&gt;&lt;code&gt;.htaccess&lt;/code&gt; 不只是快取設定檔，也可以集中管理 Apache 網站常見的伺服器規則。以下功能不一定全部都要啟用，應依網站需求和主機支援的 Apache 模組決定：&lt;ul&gt;&lt;li&gt;&lt;strong&gt;靜態網站路由&lt;/strong&gt;：使用 &lt;code&gt;mod_rewrite&lt;/code&gt; 管理重新導向或找不到頁面的處理方式。11ty 已經產生檔案式路由時，不要直接套用 SPA 的「全部導向 &lt;code&gt;/index.html&lt;/code&gt;」規則，否則原本的 404 和文章路徑可能一起被煮成一鍋。&lt;li&gt;&lt;strong&gt;301 重新導向&lt;/strong&gt;：將舊網址導向新網址，適合網站改版、文章改名或網址結構變更時使用。大量重定向最好由腳本產生，避免手動維護時遺漏或重複。&lt;li&gt;&lt;strong&gt;安全標頭&lt;/strong&gt;：可設定 &lt;code&gt;X-Frame-Options&lt;/code&gt;、&lt;code&gt;X-Content-Type-Options&lt;/code&gt; 等 response headers，降低點擊劫持和 MIME 類型嗅探等風險。新增標頭前，應先確認不會影響網站嵌入或第三方服務。&lt;li&gt;&lt;strong&gt;Gzip 壓縮&lt;/strong&gt;：使用 &lt;code&gt;mod_deflate&lt;/code&gt; 壓縮 HTML、CSS、JavaScript 和 XML 等文字檔，減少傳輸量。JPEG、PNG、WebP 等通常已經壓縮，不需要再次壓縮。&lt;li&gt;&lt;strong&gt;目錄保護&lt;/strong&gt;：&lt;code&gt;Options -Indexes&lt;/code&gt; 可避免訪客直接看到沒有首頁檔案的資料夾列表。&lt;li&gt;&lt;strong&gt;HTTP 導向 HTTPS&lt;/strong&gt;：使用 &lt;code&gt;mod_rewrite&lt;/code&gt; 將 HTTP 請求重新導向 HTTPS。啟用前要先確認 SSL 憑證正常；HSTS 只會要求瀏覽器後續使用 HTTPS，不會代替 HTTP → HTTPS 的重新導向。&lt;/ul&gt;&lt;p&gt;修改 &lt;code&gt;.htaccess&lt;/code&gt; 前，先確認 Hostinger 支援所需的 Apache 模組與語法。建議一次只加入一個功能，修改後用 &lt;code&gt;curl -I&lt;/code&gt; 和瀏覽器測試；若出現 500 錯誤，先還原最近一次修改，再逐段排查。&lt;h2 id=&quot;HSTS-不是檔案快取&quot;&gt;HSTS 不是檔案快取&lt;/h2&gt;&lt;p&gt;這一行：&lt;pre class=&quot;language-apache&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-apache&quot;&gt;Header always set Strict-Transport-Security &quot;max-age=31536000; includeSubDomains&quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;意思是瀏覽器在接下來一年內，連線到這個網站時優先使用 HTTPS。它不會決定 HTML、CSS 或圖片要存多久，因此不要把 HSTS 和 &lt;code&gt;Cache-Control&lt;/code&gt; 當成同一種設定。&lt;p&gt;只有在 HTTPS 已經完全正常，而且所有會使用到的子網域也都能使用 HTTPS 時，才適合啟用較長的 HSTS 期限。&lt;h2 id=&quot;部署後到-hPanel-清除快取&quot;&gt;部署後到 hPanel 清除快取&lt;/h2&gt;&lt;p&gt;每次部署後，依序做以下檢查：&lt;ol&gt;&lt;li&gt;進入 Hostinger hPanel 的網站 Dashboard，執行 &lt;strong&gt;Clear cache&lt;/strong&gt;。不同方案或 hPanel 版本的選單名稱可能略有不同。&lt;li&gt;如果只想處理單一頁面，到 &lt;strong&gt;Advanced → Cache Manager&lt;/strong&gt; 輸入 URL 後執行 &lt;strong&gt;Purge&lt;/strong&gt;。&lt;li&gt;如果網站啟用了 Hostinger CDN，到 &lt;strong&gt;Performance → CDN&lt;/strong&gt; 檢查 CDN 狀態，並依介面提供的選項清除快取。&lt;li&gt;用無痕視窗重新開啟首頁和剛更新的文章。&lt;/ol&gt;&lt;p&gt;不要一開始只清除自己的瀏覽器快取。如果所有訪客都看到舊版本，問題更可能在 Hostinger 快取、CDN 或部署檔案，而不是單一瀏覽器。&lt;h2 id=&quot;用-curl-驗收-response-headers&quot;&gt;用 &lt;code&gt;curl&lt;/code&gt; 驗收 response headers&lt;/h2&gt;&lt;p&gt;檢查首頁：&lt;pre class=&quot;language-bash&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-I&lt;/span&gt; https://example.com/&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;檢查一個版本化資產：&lt;pre class=&quot;language-bash&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-I&lt;/span&gt; https://example.com/assets/app.8f31c.css&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;你可以觀察 &lt;code&gt;Cache-Control&lt;/code&gt;、&lt;code&gt;Expires&lt;/code&gt;、&lt;code&gt;ETag&lt;/code&gt;、&lt;code&gt;Last-Modified&lt;/code&gt;、&lt;code&gt;Age&lt;/code&gt; 和 &lt;code&gt;Content-Type&lt;/code&gt;。&lt;p&gt;依本專案目前設定，首頁通常會看到三分鐘的 &lt;code&gt;max-age&lt;/code&gt;；符合資產副檔名規則的 CSS 則可能看到一年的 &lt;code&gt;max-age&lt;/code&gt;。Pagefind URL 則應該要求重新驗證：&lt;pre class=&quot;language-bash&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-I&lt;/span&gt; https://example.com/pagefind/pagefind.js&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果重新請求時內容沒有改變，伺服器可能回傳 &lt;code&gt;304 Not Modified&lt;/code&gt;，代表條件式快取正常運作。若 &lt;code&gt;curl&lt;/code&gt; 已經拿到新內容，但瀏覽器仍是舊內容，再用無痕視窗、另一個網路和 DevTools Network 交叉確認。&lt;h2 id=&quot;快取設定決策表&quot;&gt;快取設定決策表&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;你的情況&lt;th&gt;HTML&lt;th&gt;CSS／JS／圖片／字型&lt;th&gt;建議&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;文章常更新，檔名沒有版本號&lt;td&gt;&lt;code&gt;no-cache&lt;/code&gt; 或短 TTL&lt;td&gt;短 TTL，例如 5–30 分鐘&lt;td&gt;先確保更新穩定，再逐步延長&lt;tr&gt;&lt;td&gt;CSS／JS 有內容指紋&lt;td&gt;&lt;code&gt;no-cache&lt;/code&gt; 或一天&lt;td&gt;一年＋&lt;code&gt;immutable&lt;/code&gt;&lt;td&gt;適合穩定的 production 靜態站&lt;tr&gt;&lt;td&gt;正在除錯快取問題&lt;td&gt;&lt;code&gt;no-cache&lt;/code&gt;&lt;td&gt;&lt;code&gt;no-cache&lt;/code&gt; 或短 TTL&lt;td&gt;驗收完成後再恢復長效快取&lt;tr&gt;&lt;td&gt;Pagefind 搜尋索引會更新&lt;td&gt;短 TTL&lt;td&gt;Pagefind 使用 &lt;code&gt;no-cache&lt;/code&gt;；其他資產依版本策略&lt;td&gt;避免搜尋索引長時間未更新&lt;tr&gt;&lt;td&gt;CDN 剛啟用或剛清除&lt;td&gt;短 TTL&lt;td&gt;依 CDN 規則&lt;td&gt;等待節點更新，再用不同網路測試&lt;/table&gt;&lt;p&gt;這張表主要根據兩個問題決定快取時間：檔案多久會更新，以及檔案的 URL 是否會隨內容改變。&lt;ul&gt;&lt;li&gt;&lt;strong&gt;HTML 通常使用短 TTL&lt;/strong&gt;：首頁和文章內容可能經常更新，因此使用短時間快取，讓瀏覽器較快向伺服器確認。本專案目前設定為三分鐘；&lt;code&gt;no-cache&lt;/code&gt; 則是另一種要求使用前重新驗證的策略。&lt;li&gt;&lt;strong&gt;有內容指紋的靜態資產可以快取一年&lt;/strong&gt;：例如 &lt;code&gt;app.8f31c.css&lt;/code&gt;。CSS 或 JavaScript 更新後，檔名也會改變，瀏覽器會把它視為全新的檔案，因此適合搭配 &lt;code&gt;immutable&lt;/code&gt; 使用一年 TTL。&lt;li&gt;&lt;strong&gt;固定檔名的資產應使用短 TTL&lt;/strong&gt;：例如 &lt;code&gt;style.css&lt;/code&gt; 或 &lt;code&gt;app.js&lt;/code&gt;。如果內容更新但 URL 不變，長效快取可能讓訪客持續取得舊檔案；在尚未完成版本化時，可先使用 5–30 分鐘。&lt;li&gt;&lt;strong&gt;Pagefind 使用 &lt;code&gt;no-cache&lt;/code&gt;&lt;/strong&gt;：搜尋索引會隨文章更新，但 URL 通常不一定包含內容指紋，因此每次使用前都應重新驗證。&lt;li&gt;&lt;strong&gt;正在除錯時全部縮短 TTL&lt;/strong&gt;：先讓 HTML、CSS 和 JavaScript 使用 &lt;code&gt;no-cache&lt;/code&gt; 或短 TTL，確認部署與 response headers 正常後，再恢復長效快取。&lt;/ul&gt;&lt;p&gt;要注意的是，這張表是判斷原則，不代表目前 &lt;code&gt;.htaccess&lt;/code&gt; 已經自動檢查檔名是否含有內容指紋。目前的 &lt;code&gt;&amp;lt;FilesMatch&amp;gt;&lt;/code&gt; 是按照副檔名設定一年快取，所以固定名稱的 &lt;code&gt;style.css&lt;/code&gt; 或 &lt;code&gt;app.js&lt;/code&gt; 也可能被快取一年。只有在部署流程確實會讓資產 URL 隨內容改變時，才適合使用一年 TTL 和 &lt;code&gt;immutable&lt;/code&gt;。&lt;h2 id=&quot;常見問題&quot;&gt;常見問題&lt;/h2&gt;&lt;h3 id=&quot;重新建置後,網站為什麼還是舊頁面?&quot;&gt;重新建置後，網站為什麼還是舊頁面？&lt;/h3&gt;&lt;p&gt;先確認 &lt;code&gt;_site&lt;/code&gt; 裡真的有新內容，再確認上傳的是 &lt;code&gt;_site&lt;/code&gt; 內容，而不是原始 Markdown。接著依序檢查 Hostinger 快取、CDN 和瀏覽器，不要只重跑 11ty。&lt;h3 id=&quot;可以把所有檔案都設定成快取一年嗎?&quot;&gt;可以把所有檔案都設定成快取一年嗎？&lt;/h3&gt;&lt;p&gt;不建議。沒有版本化的 HTML、&lt;code&gt;style.css&lt;/code&gt; 或 &lt;code&gt;app.js&lt;/code&gt; 可能長時間讓訪客拿到舊內容。只有 URL 會隨內容改變的資產，才適合搭配 &lt;code&gt;immutable&lt;/code&gt; 使用一年 TTL。&lt;h3 id=&quot;為什麼-Pagefind-搜尋不到剛發布的文章?&quot;&gt;為什麼 Pagefind 搜尋不到剛發布的文章？&lt;/h3&gt;&lt;p&gt;可能是 Pagefind 索引本身沒有重新建置，也可能是 &lt;code&gt;/pagefind/&lt;/code&gt; 資產仍被舊快取提供。先確認部署輸出有最新索引，再用 &lt;code&gt;curl -I&lt;/code&gt; 檢查 Pagefind URL 是否真的要求重新驗證，最後清除 Hostinger 或 CDN 快取。&lt;h3 id=&quot;改-.htaccess-後網站出現-500-怎麼辦?&quot;&gt;改 &lt;code&gt;.htaccess&lt;/code&gt; 後網站出現 500 怎麼辦？&lt;/h3&gt;&lt;p&gt;先還原最後一次修改，確認 Hostinger 支援 &lt;code&gt;mod_headers&lt;/code&gt;、&lt;code&gt;mod_expires&lt;/code&gt; 和相關語法，再逐段加入設定。不要在未驗證前，直接把同一份 &lt;code&gt;.htaccess&lt;/code&gt; 複製到其他網站。&lt;h2 id=&quot;部署驗收工具&quot;&gt;部署驗收工具&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Hostinger hPanel&lt;/strong&gt;：用來清除網站快取、管理 Cache Manager，以及依方案管理 CDN。&lt;li&gt;&lt;strong&gt;&lt;code&gt;curl&lt;/code&gt;&lt;/strong&gt;：直接查看公開網站的 response headers，先確認伺服器實際回傳什麼，再判斷是不是瀏覽器問題。&lt;li&gt;&lt;strong&gt;Chrome DevTools Network&lt;/strong&gt;：查看 &lt;code&gt;Age&lt;/code&gt;、&lt;code&gt;ETag&lt;/code&gt;、&lt;code&gt;Cache-Control&lt;/code&gt; 和 response body，交叉確認不同資產是否使用預期的 TTL。&lt;/ul&gt;&lt;h2 id=&quot;結語先分層,再決定-TTL&quot;&gt;結語：先分層，再決定 TTL&lt;/h2&gt;&lt;p&gt;11ty 快取問題的重點不是把數字設得越大越好，而是讓不同檔案採用適合自己的更新策略：&lt;ol&gt;&lt;li&gt;HTML 使用短 TTL，保持容易更新。&lt;li&gt;版本化 CSS、JavaScript、圖片和字型使用長效快取。&lt;li&gt;Pagefind 搜尋資產使用 &lt;code&gt;no-cache&lt;/code&gt;，避免索引更新被卡住。&lt;li&gt;每次部署後用 hPanel、&lt;code&gt;curl&lt;/code&gt; 和無痕視窗驗收。&lt;/ol&gt;&lt;p&gt;完成設定後，下一步是到 Hostinger hPanel 清除快取，再用 &lt;code&gt;curl -I&lt;/code&gt; 確認公開網站真的回傳預期的 headers。快取驗收完，再來一杯咖啡；這次咖啡和 HTML 都應該是熱的。&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://httpd.apache.org/docs/2.4/mod/mod_expires.html&quot;&gt;Apache &lt;code&gt;mod_expires&lt;/code&gt; 官方文件&lt;/a&gt;：說明 &lt;code&gt;ExpiresActive&lt;/code&gt;、&lt;code&gt;ExpiresDefault&lt;/code&gt; 和 &lt;code&gt;ExpiresByType&lt;/code&gt; 如何產生快取標頭。&lt;li&gt;&lt;a href=&quot;https://httpd.apache.org/docs/2.4/mod/mod_headers.html&quot;&gt;Apache &lt;code&gt;mod_headers&lt;/code&gt; 官方文件&lt;/a&gt;：查閱 &lt;code&gt;.htaccess&lt;/code&gt; 中設定與修改 response headers 的 &lt;code&gt;Header&lt;/code&gt; 指令。&lt;li&gt;&lt;a href=&quot;https://pagefind.app/docs/running-pagefind/&quot;&gt;Pagefind Running Pagefind&lt;/a&gt;：說明在靜態網站建置後產生 &lt;code&gt;pagefind/&lt;/code&gt; 搜尋資產的流程。&lt;li&gt;&lt;a href=&quot;https://www.hostinger.com/tutorials/what-is-website-caching&quot;&gt;Hostinger：Website caching explained&lt;/a&gt;：說明 hPanel Cache Manager、瀏覽器快取、伺服器快取與 CDN 的差異。&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>字型子集化：2026 中文網站如何減少字型載入、改善首屏速度</title>
    <link href="https://kamadiam.com/font-subsetting-reduce-font-loading/" />
    <updated>2026-08-03T07:45:00Z</updated>
    <id>https://kamadiam.com/font-subsetting-reduce-font-loading/</id>
    <content type="html">&lt;p&gt;繁體中文網站最容易被忽略的效能成本，常常不是第三方腳本，而是字型。完整 CJK 字型可能很大；若每位訪客都先下載整包，手機網路就得先端上一杯「等待咖啡」，文字才慢慢穩定下來。&lt;p&gt;這篇會帶你判斷是否真的需要 Web Font、理解字型子集化與 &lt;code&gt;unicode-range&lt;/code&gt; 的差別，最後用自架 WOFF2 的流程把載入成本降下來。重點不是追求某個神奇檔案大小，而是讓字型策略符合網站內容與實際測量結果。&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/font-subsetting-reduce-font-loading/#%E5%85%88%E5%88%A4%E6%96%B7%E4%BD%A0%E7%9C%9F%E7%9A%84%E9%9C%80%E8%A6%81-Web-Font-%E5%97%8E?&quot;&gt;先判斷：你真的需要 Web Font 嗎？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/font-subsetting-reduce-font-loading/#%E4%B8%89%E7%A8%AE%E5%AD%97%E5%9E%8B%E7%AD%96%E7%95%A5%E6%80%8E%E9%BA%BC%E9%81%B8?&quot;&gt;三種字型策略怎麼選？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/font-subsetting-reduce-font-loading/#%E7%82%BA%E4%BB%80%E9%BA%BC%E7%B9%81%E4%B8%AD%E5%AD%97%E5%9E%8B%E7%89%B9%E5%88%A5%E5%AE%B9%E6%98%93%E6%8B%96%E6%85%A2%E9%A6%96%E5%B1%8F?&quot;&gt;為什麼繁中字型特別容易拖慢首屏？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/font-subsetting-reduce-font-loading/#%E5%AD%97%E5%9E%8B%E5%AD%90%E9%9B%86%E5%8C%96%E5%88%B0%E5%BA%95%E5%9C%A8%E5%81%9A%E4%BB%80%E9%BA%BC?&quot;&gt;字型子集化到底在做什麼？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/font-subsetting-reduce-font-loading/#%E8%87%AA%E6%9E%B6%E5%AD%90%E9%9B%86%E5%8C%96%E7%9A%84%E5%AF%A6%E4%BD%9C%E6%B5%81%E7%A8%8B&quot;&gt;自架子集化的實作流程&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/font-subsetting-reduce-font-loading/#%E5%B8%B8%E8%A6%8B%E9%8C%AF%E8%AA%A4%E8%88%87%E5%8F%96%E6%8D%A8&quot;&gt;常見錯誤與取捨&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/font-subsetting-reduce-font-loading/#%E7%B5%90%E8%AA%9E%E5%85%88%E5%B0%91%E8%BC%89%E5%85%A5,%E5%86%8D%E8%BF%BD%E6%B1%82%E4%B8%80%E8%87%B4&quot;&gt;結語：先少載入，再追求一致&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/font-subsetting-reduce-font-loading/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;先判斷你真的需要-Web-Font-嗎?&quot;&gt;先判斷：你真的需要 Web Font 嗎？&lt;/h2&gt;&lt;p&gt;如果網站是內容型部落格、管理後台或文件站，最划算的起點通常是&lt;strong&gt;系統字體優先&lt;/strong&gt;。系統字體不需要額外下載，少了一趟網路請求，也少了一個可能延遲文字顯示的變數：&lt;pre class=&quot;language-css&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
		system-ui&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; -apple-system&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; BlinkMacSystemFont&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Segoe UI&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Roboto&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token string&quot;&gt;&quot;PingFang TC&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Microsoft JhengHei&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Noto Sans CJK TC&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sans-serif&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token string&quot;&gt;&quot;Apple Color Emoji&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Segoe UI Emoji&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;macOS 與 iOS 常見的是 &lt;code&gt;PingFang TC&lt;/code&gt;，Windows 常見的是 &lt;code&gt;Microsoft JhengHei&lt;/code&gt;；實際結果仍會受作業系統、已安裝字型與瀏覽器影響。如果你不需要每台裝置都呈現完全相同的品牌字形，這一步可能比任何字型工具更有效。&lt;h2 id=&quot;三種字型策略怎麼選?&quot;&gt;三種字型策略怎麼選？&lt;/h2&gt;&lt;p&gt;可以先用下面的方式縮小選擇：&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;情境&lt;th&gt;建議做法&lt;th&gt;主要取捨&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;內容型部落格&lt;td&gt;內文使用系統字體&lt;td&gt;載入成本低，但不同平台字形不完全一致&lt;tr&gt;&lt;td&gt;品牌官網或 Landing Page&lt;td&gt;標題使用子集化 Web Font，內文使用系統字體&lt;td&gt;兼顧美觀與速度，但要維護字元清單&lt;tr&gt;&lt;td&gt;必須固定品牌字形的產品 UI&lt;td&gt;自架 WOFF2，搭配靜態或分片子集化&lt;td&gt;控制力最高，也需要加入 build 流程&lt;/table&gt;&lt;p&gt;不要只因為「看起來專業」，就讓整篇內文載入完整的 Noto Sans TC。先把 Web Font 限制在 H1、H2 或少量 UI 元件，通常更容易取得可接受的速度與一致性。字型不是越多越有文化，請求數才不會因此變成詩。&lt;h2 id=&quot;為什麼繁中字型特別容易拖慢首屏?&quot;&gt;為什麼繁中字型特別容易拖慢首屏？&lt;/h2&gt;&lt;p&gt;中文字型需要涵蓋大量漢字、標點與不同字重，因此完整檔案可能遠大於 Latin 字型。一個網站若同時載入多個 CJK 字型族和多個字重，下載量很快就會累積；若使用外部服務，還要考慮連線、CSS 發現時機與字型檔本身的請求。&lt;p&gt;外部 CDN 不一定比較慢，自架也不保證比較快。實際結果會受到 CDN 位置、HTTP 版本、快取策略、CSS 何時被瀏覽器發現，以及頁面到底匹配到哪些字型分片影響。跨網站共用快取也不能當成必然優勢，所以應該把「外部服務」和「自架」都放進同一套實測裡比較。&lt;h2 id=&quot;字型子集化到底在做什麼?&quot;&gt;字型子集化到底在做什麼？&lt;/h2&gt;&lt;p&gt;子集化就是從完整字型中只保留網站需要的字元，再輸出較小的字型檔。HarfBuzz 的 &lt;code&gt;hb-subset&lt;/code&gt; 文件也把它描述為縮減字型涵蓋的 codepoint，並移除不再需要的資料。&lt;p&gt;常見做法有兩種：&lt;ol&gt;&lt;li&gt;&lt;strong&gt;靜態子集化&lt;/strong&gt;：掃描指定頁面或整個網站，只保留目前用到的字元。檔案通常更小，適合內容固定的 Landing Page；但內容更新後必須重跑。&lt;li&gt;&lt;strong&gt;Unicode 分片&lt;/strong&gt;：把字型切成多個檔案，在 CSS 的每組 &lt;code&gt;@font-face&lt;/code&gt; 中用 &lt;code&gt;unicode-range&lt;/code&gt; 指定負責的字元範圍。瀏覽器會根據頁面文字判斷要不要載入某個分片，但匹配後下載的是整個分片，不是單獨一個字。&lt;/ol&gt;&lt;p&gt;這裡有個容易誤會的地方：&lt;strong&gt;WOFF2 格式和瀏覽器不會自動替你切檔&lt;/strong&gt;。分片需要多組 &lt;code&gt;@font-face&lt;/code&gt;、多個 WOFF2 網址，以及對應的 &lt;code&gt;unicode-range&lt;/code&gt;。只有一個完整 WOFF2 和一條 &lt;code&gt;@font-face&lt;/code&gt;，瀏覽器就只會把它當成一個檔案處理。&lt;p&gt;Google Fonts 會替你產生包含 &lt;code&gt;unicode-range&lt;/code&gt; 的 CSS，某些字型也會依字元或語系切成多個檔案；你只放入 stylesheet 連結，就能使用它預先準備好的分片。自架則要自行產生分片與 CSS，例如使用 &lt;a href=&quot;https://github.com/KonghaYao/cn-font-split/&quot;&gt;&lt;code&gt;cn-font-split&lt;/code&gt;&lt;/a&gt;。&lt;p&gt;本站曾以四種字型載入約 23 個 WOFF2 請求、總計約 1.78MB 作為改版前觀測值；後來改用自架子集，並讓內文回到系統字體，目前實際使用的 Web Font 減少到兩個檔案。這是本站某次測量，不是所有網站都會得到相同數字；分片數量減少，也不代表每個頁面一定少下載同樣多的位元組。&lt;p&gt;子集缺少的字也不會自動變成缺字方框。瀏覽器會沿著 &lt;code&gt;font-family&lt;/code&gt; 堆疊尋找下一個可用字型，代價是罕見字可能和周圍文字有些風格差異。因此，子集化完成後要測試特殊人名、專有名詞、全形標點與程式碼符號。&lt;h2 id=&quot;自架子集化的實作流程&quot;&gt;自架子集化的實作流程&lt;/h2&gt;&lt;h3 id=&quot;1.-收集真正會出現的字元&quot;&gt;1. 收集真正會出現的字元&lt;/h3&gt;&lt;p&gt;掃描文章、模板、導覽列、按鈕和錯誤訊息，收集漢字、全形標點、Latin 字母、數字與常用符號。不要只掃一篇文章，否則下一篇新增一個罕見字時，字型就會突然「失憶」。&lt;p&gt;Latin 部分可以參考字型服務提供的範圍，但仍要依網站實際內容確認，避免英文、貨幣符號或程式碼標點意外 fallback。若標題和內文使用不同字型，也應分別收集，避免把所有文章文字都塞進只套用於標題的字型。&lt;h3 id=&quot;2.-用工具產出-WOFF2&quot;&gt;2. 用工具產出 WOFF2&lt;/h3&gt;&lt;p&gt;&lt;code&gt;cn-font-split&lt;/code&gt; 適合把 CJK 字型切成可按範圍載入的分片；如果想依網站實際用字產出單一子集，可以使用 &lt;a href=&quot;https://github.com/nickbalestra/subset-font&quot;&gt;&lt;code&gt;subset-font&lt;/code&gt;&lt;/a&gt;。這個 Node.js 套件以 HarfBuzz 的 subset 功能為基礎，會輸出指定格式的字型檔。&lt;p&gt;概念流程如下：&lt;pre class=&quot;language-text&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;掃描 Markdown、模板與導覽文字
            ↓
收集 Latin、CJK 與符號
            ↓
subset-font 或 cn-font-split
            ↓
輸出 WOFF2 與必要的 CSS
            ↓
用瀏覽器與效能工具驗證&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果專案已經有腳本，讓它成為固定的 build 步驟會比手動操作可靠。例如本站可在新增內容後執行：&lt;pre class=&quot;language-shell&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; run subset-fonts
&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; run build&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3.-用-@font-face-控制載入行為&quot;&gt;3. 用 &lt;code&gt;@font-face&lt;/code&gt; 控制載入行為&lt;/h3&gt;&lt;p&gt;最基本的自架設定可以長這樣：&lt;pre class=&quot;language-css&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@font-face&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Noto Sans TC&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string url&quot;&gt;&quot;/fonts/noto-sans-tc.woff2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;woff2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 400 700&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;font-style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; normal&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;font-display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; swap&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;接著在 HTML 中把它套用到真正需要的元素，而不是只宣告卻全站使用：&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;hero-title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;網站標題&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;font-display: swap&lt;/code&gt; 會先顯示 fallback 字型，字型載入完成後再替換，適合需要優先看見文字的標題。&lt;code&gt;optional&lt;/code&gt; 則讓瀏覽器在載入不及時時更傾向維持 fallback；它可以降低字型替換造成版面變化的機會，但不是「完全不會 CLS」的保證。實際顯示時間仍由瀏覽器實作與網路狀況決定。&lt;h3 id=&quot;4.-把子集化接進-build-流程&quot;&gt;4. 把子集化接進 build 流程&lt;/h3&gt;&lt;p&gt;新增文章或修改導覽列後，重新執行字型腳本，再進行 production build。原始字型可以放在本機快取，避免每次重跑都重新下載；真正重要的是讓「新增內容 → 重新產生子集 → 測量效能」成為固定流程。&lt;h3 id=&quot;5.-移除不再需要的-CDN-標籤&quot;&gt;5. 移除不再需要的 CDN 標籤&lt;/h3&gt;&lt;p&gt;改成自架後，檢查 &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; 裡的 Google Fonts &lt;code&gt;preconnect&lt;/code&gt;、&lt;code&gt;preload&lt;/code&gt;、stylesheet 和 &lt;code&gt;noscript&lt;/code&gt; 標籤。新舊兩套設定同時留下來，等於請瀏覽器喝兩杯咖啡再做同一件事——熱鬧，但沒有比較快。&lt;h2 id=&quot;常見錯誤與取捨&quot;&gt;常見錯誤與取捨&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;直接上傳 OTF 或 TTF&lt;/strong&gt;：Web Font 通常優先使用 WOFF2，因為壓縮效率較好且現代瀏覽器支援廣；仍要依你的瀏覽器支援範圍決定是否提供其他格式。&lt;li&gt;&lt;strong&gt;以為分片等於只下載一個字&lt;/strong&gt;：&lt;code&gt;unicode-range&lt;/code&gt; 只負責判斷某個分片是否匹配；匹配後通常會下載整個分片。&lt;li&gt;&lt;strong&gt;只留下漢字、忘了 Latin 和符號&lt;/strong&gt;：英文、數字、括號或程式碼符號可能改用不同字型，應把實際需要的字元一起納入。&lt;li&gt;&lt;strong&gt;把整個網站都套品牌字體&lt;/strong&gt;：先從標題或少量 UI 開始，否則字型下載量和替換風險都會快速增加。&lt;li&gt;&lt;strong&gt;忽略子集缺字&lt;/strong&gt;：fallback 能避免缺字方框，卻不會讓不同字型的字形風格自動一致；上線前要測試罕見字、專有名詞與標點。&lt;li&gt;&lt;strong&gt;只看檔案大小、不測實際體驗&lt;/strong&gt;：請用 &lt;a href=&quot;https://pagespeed.web.dev/&quot;&gt;PageSpeed Insights&lt;/a&gt; 或自己的效能驗收流程，觀察 LCP、CLS、文字是否及時出現，以及 Network 面板實際下載了哪些字型。&lt;/ul&gt;&lt;h2 id=&quot;結語先少載入,再追求一致&quot;&gt;結語：先少載入，再追求一致&lt;/h2&gt;&lt;p&gt;字型最佳化可以先記住三件事：&lt;ol&gt;&lt;li&gt;內容站先用系統字體，不要預設整包載入 CJK Web Font。&lt;li&gt;需要品牌字形時，只把標題或 UI 子集化，並依需求選擇單一子集或 Unicode 分片。&lt;li&gt;用 &lt;code&gt;font-display&lt;/code&gt;、fallback 和實際 Core Web Vitals 測量確認取捨，不要只看理論檔案大小。&lt;/ol&gt;&lt;p&gt;下一步很簡單：先記下改動前的數據，挑一個頁面做子集化，再比較 LCP、CLS、字型請求數和實際文字顯示。先測一頁就好，不必一口氣把整個網站的字型 pipeline 變成考古現場。測完再來一杯，這次是慶功。&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/%40font-face&quot;&gt;MDN：&lt;code&gt;@font-face&lt;/code&gt;&lt;/a&gt;：查閱 &lt;code&gt;src&lt;/code&gt;、&lt;code&gt;font-display&lt;/code&gt;、&lt;code&gt;unicode-range&lt;/code&gt; 與 Web Font 格式。&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Text_styling/Web_fonts&quot;&gt;MDN：Web fonts&lt;/a&gt;：說明 WOFF2、fallback、子集化與字型實際載入時機。&lt;li&gt;&lt;a href=&quot;https://developers.google.com/fonts/docs/css2&quot;&gt;Google Fonts CSS API&lt;/a&gt;：說明 Google Fonts CSS、&lt;code&gt;text&lt;/code&gt; 參數與字型請求格式。&lt;li&gt;&lt;a href=&quot;https://harfbuzz.github.io/harfbuzz-hb-subset.html&quot;&gt;HarfBuzz：&lt;code&gt;hb-subset&lt;/code&gt;&lt;/a&gt;：說明字型子集化如何縮減 codepoint 涵蓋範圍與不必要資料。&lt;li&gt;&lt;a href=&quot;https://github.com/nickbalestra/subset-font&quot;&gt;&lt;code&gt;subset-font&lt;/code&gt; GitHub&lt;/a&gt;：Node.js 字型子集化套件的原始碼與使用資訊。&lt;li&gt;&lt;a href=&quot;https://github.com/KonghaYao/cn-font-split/&quot;&gt;&lt;code&gt;cn-font-split&lt;/code&gt; GitHub&lt;/a&gt;：CJK 字型分片工具的功能與文件入口。&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>LCP 優化實戰：首屏別 lazy-load，用 fetchpriority 把關鍵資源拉上來</title>
    <link href="https://kamadiam.com/lcp-optimization-no-lazy-fetchpriority/" />
    <updated>2026-08-03T06:45:00Z</updated>
    <id>https://kamadiam.com/lcp-optimization-no-lazy-fetchpriority/</id>
    <content type="html">&lt;p&gt;PageSpeed 分數掉下來，你第一個想到的通常是「圖太大了」。有時候沒錯，但也可能是你把主視覺圖設成 &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt;，等於請瀏覽器「晚點再叫主角上台」——LCP 當然跟著延後，比咖啡涼掉還難受。&lt;p&gt;LCP（Largest Contentful Paint）衡量的是：初次載入時，視窗內最大的文字、圖片或其他內容元素，何時完成繪製。這篇會帶你找出真正的 LCP 元素，分清楚 &lt;code&gt;lazy&lt;/code&gt;、&lt;code&gt;fetchpriority&lt;/code&gt; 與 &lt;code&gt;preload&lt;/code&gt; 各自解決什麼問題，再用一套可以實際驗收的流程收尾。看完，你不必對著瀑布圖施法，也能知道下一杯咖啡該泡給誰。&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/lcp-optimization-no-lazy-fetchpriority/#%E5%85%88%E6%8A%93%E5%88%B0%E4%BD%A0%E7%9C%9F%E6%AD%A3%E7%9A%84-LCP-%E5%85%83%E7%B4%A0&quot;&gt;先抓到你真正的 LCP 元素&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/lcp-optimization-no-lazy-fetchpriority/#%E6%B1%BA%E7%AD%96%E8%A1%A8lazyfetchprioritypreload-%E6%80%8E%E9%BA%BC%E9%81%B8?&quot;&gt;決策表：lazy、fetchpriority、preload 怎麼選？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/lcp-optimization-no-lazy-fetchpriority/#LCP-%E5%84%AA%E5%8C%96%E7%AD%96%E7%95%A5%E6%A0%B8%E5%BF%83%E5%84%AA%E5%85%88%E7%B4%9A-+-%E4%B8%8D%E8%A2%AB-lazy&quot;&gt;LCP 優化策略（核心：優先級 + 不被 lazy）&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/lcp-optimization-no-lazy-fetchpriority/#%E4%B8%80%E5%80%8B%E5%BF%AB%E9%80%9F%E9%A9%97%E6%94%B6%E5%BF%83%E6%B3%95%E5%85%88-CLS-%E7%A9%A9,%E5%86%8D%E8%AB%87-LCP&quot;&gt;一個快速驗收心法：先 CLS 穩，再談 LCP&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/lcp-optimization-no-lazy-fetchpriority/#%E6%A1%86%E6%9E%B6%E5%BF%AB%E9%80%9F%E5%B0%8D%E7%85%A7&quot;&gt;框架快速對照&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/lcp-optimization-no-lazy-fetchpriority/#%E5%BF%AB%E9%80%9F%E9%A9%97%E6%94%B6%E6%B8%85%E5%96%AE&quot;&gt;快速驗收清單&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/lcp-optimization-no-lazy-fetchpriority/#%E7%B5%90%E8%AA%9ELCP-%E5%84%AA%E5%8C%96%E6%98%AF%E3%80%8C%E4%B8%8D%E8%A6%81%E6%8B%96%E9%97%9C%E9%8D%B5%E8%B3%87%E6%BA%90%E3%80%8D%E7%9A%84%E5%B7%A5%E7%A8%8B%E7%B4%80%E5%BE%8B&quot;&gt;結語：LCP 優化是「不要拖關鍵資源」的工程紀律&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/lcp-optimization-no-lazy-fetchpriority/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;先抓到你真正的-LCP-元素&quot;&gt;先抓到你真正的 LCP 元素&lt;/h2&gt;&lt;p&gt;先不要猜「應該是主視覺圖」。LCP 也可能是 H1、文章開頭的大段文字，或其他在初次視窗內佔面積最大的元素。流程如下：&lt;ol&gt;&lt;li&gt;開 &lt;a href=&quot;https://pagespeed.web.dev/&quot;&gt;PageSpeed Insights&lt;/a&gt; 或 Chrome DevTools → &lt;strong&gt;Performance&lt;/strong&gt; 錄一次載入&lt;li&gt;看報告標出的 &lt;strong&gt;LCP 元素&lt;/strong&gt; 是什麼（圖片、文字區塊或 H1）&lt;li&gt;記下它的 URL 或 DOM 節點，後面改碼才有對象&lt;/ol&gt;&lt;p&gt;在 DevTools 的 Performance 面板中，也可以從 LCP 標記查看元素與時間。先確認「誰是 LCP」，再決定要不要調圖片；不然很容易把不是主角的圖片打扮成 VIP。&lt;p&gt;靜態網站常見的 LCP 來源包括&lt;strong&gt;主視覺圖&lt;/strong&gt;、&lt;strong&gt;H1 標題&lt;/strong&gt;與&lt;strong&gt;產品截圖&lt;/strong&gt;。以真實使用者資料的評估方式來看，LCP 在第 75 百分位&lt;strong&gt;不超過 2.5 秒&lt;/strong&gt;才算「良好」；這和 Lighthouse 的單次實驗室測試不是同一件事。想先搞懂欄位資料與實驗室資料的差異，可看站內 &lt;a href=&quot;https://kamadiam.com/pagespeed-core-web-vitals/&quot;&gt;PageSpeed Insights 與 Core Web Vitals 2026&lt;/a&gt;。&lt;h2 id=&quot;決策表lazyfetchprioritypreload-怎麼選?&quot;&gt;決策表：lazy、fetchpriority、preload 怎麼選？&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;情境&lt;th&gt;建議做法&lt;th&gt;為什麼&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;確認是首屏內的 LCP 圖片&lt;td&gt;不使用 &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt;；必要時加 &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt;&lt;td&gt;讓瀏覽器及早發現並下載關鍵圖片&lt;tr&gt;&lt;td&gt;LCP 是 CSS 背景圖，或資源要等 JS 才出現&lt;td&gt;&lt;code&gt;&amp;lt;link rel=&amp;quot;preload&amp;quot; as=&amp;quot;image&amp;quot; fetchpriority=&amp;quot;high&amp;quot;&amp;gt;&lt;/code&gt;&lt;td&gt;瀏覽器不容易從初始 HTML 直接發現它，需主動提示&lt;tr&gt;&lt;td&gt;內文圖、頁尾圖、側欄縮圖&lt;td&gt;&lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt;&lt;td&gt;讓頻寬先留給首屏內容&lt;tr&gt;&lt;td&gt;頁面有一、兩張真正關鍵的圖片&lt;td&gt;只對那些圖片使用 &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt;&lt;td&gt;高優先級用太多，反而失去區分效果&lt;tr&gt;&lt;td&gt;本站的 Eleventy Transform 自動補上 &lt;code&gt;lazy&lt;/code&gt;&lt;td&gt;在主視覺圖上明確覆寫 &lt;code&gt;loading=&amp;quot;eager&amp;quot;&lt;/code&gt;&lt;td&gt;內文圖的預設值不一定適合 LCP 圖&lt;/table&gt;&lt;p&gt;&lt;strong&gt;一句話心法&lt;/strong&gt;：首屏 LCP 圖不要 lazy；確認是關鍵資源後再提高優先級；其餘圖片放心 lazy。&lt;h2 id=&quot;LCP-優化策略核心優先級-+-不被-lazy&quot;&gt;LCP 優化策略（核心：優先級 + 不被 lazy）&lt;/h2&gt;&lt;h3 id=&quot;1.-不要-lazy-load-LCP&quot;&gt;1. 不要 lazy-load LCP&lt;/h3&gt;&lt;p&gt;最常見的壞操作，就是把首屏 LCP 圖片加上 &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt;。瀏覽器通常要先完成版面計算，確認圖片接近視窗後才請求它；原本可以從 HTML 先發現的資源，就被迫排隊。下載、解碼、繪製每一步都往後，LCP 只好一起等。&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- ❌ 主視覺圖被延後載入 --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/img/hero.webp&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;主視覺&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- ✅ 首屏主角：不 lazy，並提示它很重要 --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/img/hero.webp&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;主視覺&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;630&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;eager&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;fetchpriority&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;high&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;eager&lt;/code&gt; 是明確表達「不要額外延後」；它不等於魔法加速器，真正的下載順序仍由瀏覽器決定。&lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt; 也是提示，不是命令。最後，別忘了補 &lt;code&gt;width&lt;/code&gt;／&lt;code&gt;height&lt;/code&gt; 預留版面，LCP 和 CLS 常常是同一張圖一起修。細節見站內 &lt;a href=&quot;https://kamadiam.com/image-size-cls-preallocation/&quot;&gt;圖片最佳化與 CLS 解決方案&lt;/a&gt;。&lt;h3 id=&quot;2.-用-fetchpriority-把關鍵資源拉到前面&quot;&gt;2. 用 fetchpriority 把關鍵資源拉到前面&lt;/h3&gt;&lt;p&gt;當 LCP 是圖片，而且瀏覽器發現它太晚時，方向是：&lt;ul&gt;&lt;li&gt;主視覺圖：加 &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt;&lt;li&gt;CSS 背景圖或 JS 稍後插入的圖片：在 &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; 視情況用 &lt;code&gt;preload&lt;/code&gt; 宣告&lt;/ul&gt;&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- CSS 背景 LCP：在 head 主動預載 --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fetchpriority&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;high&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/img/hero.webp&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image/webp&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- HTML 直接宣告的 LCP 圖 --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/img/hero.webp&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;fetchpriority&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;high&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;網站主視覺 Banner&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;630&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;preload&lt;/code&gt; 解決的是「讓瀏覽器更早發現資源」；&lt;code&gt;fetchpriority&lt;/code&gt; 解決的是「在已發現的資源中，提示相對重要性」。兩者可以搭配，但不是每張圖片都要一起上。&lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt; 請只給真正可能成為 LCP、而且確實需要提早下載的資源；大家都當 VIP，最後就沒有 VIP。&lt;h3 id=&quot;3.-Eleventy-靜態站管道預設-lazy-的陷阱&quot;&gt;3. Eleventy 靜態站：管道預設 lazy 的陷阱&lt;/h3&gt;&lt;p&gt;在本站，HTML Transform 會替沒有明確設定的圖片補上 &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt;。這對文章中段的圖片通常合理，卻不一定適合首屏 LCP 圖。遇到這種情況，要在那張圖片上明確覆寫：&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/img/hero.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;產品主視覺&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;eager&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;fetchpriority&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;high&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;sizes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(max-width: 800px) 100vw, 1200px&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;不要只看 HTML 屬性，也要在 build 後檢查實際輸出的 HTML，確認 &lt;code&gt;loading&lt;/code&gt;、&lt;code&gt;fetchpriority&lt;/code&gt;、&lt;code&gt;srcset&lt;/code&gt; 與 &lt;code&gt;sizes&lt;/code&gt; 都符合預期。接著檢查圖片的實際下載大小、尺寸與格式：手機只需要幾百像素寬，就別把幾千像素的原圖整包寄過去。WebP 或 AVIF 可以是選項，但最後仍要以實際檔案大小、畫質和瀏覽器支援情況驗收。&lt;p&gt;如果圖片是由 JavaScript 動態插入，瀏覽器會更晚才知道它存在。能直接寫進初始 HTML 就直接寫；真的必須動態產生時，至少確認它不是因為程式執行太晚才錯過下載時機：&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; hero &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.hero-image&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

hero&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/img/hero.webp&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
hero&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fetchPriority &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;high&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;這段程式只是在 HTML 已經有圖片元素的前提下補上來源與提示；它不會讓 JavaScript 變成 preload。若資源本來就能在 &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; 預先宣告，優先考慮 HTML 的 &lt;code&gt;preload&lt;/code&gt;。&lt;h3 id=&quot;4.-避免-render-blocking-讓首屏後面卡住&quot;&gt;4. 避免 render-blocking 讓首屏後面卡住&lt;/h3&gt;&lt;p&gt;如果非關鍵 JS／CSS 形成很長的依賴鏈，LCP 圖片就算早早下載完成，也可能等不到繪製。快速檢查：&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;資源類型&lt;th&gt;建議&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;非關鍵 JavaScript&lt;td&gt;依載入需求考慮 &lt;code&gt;defer&lt;/code&gt; 或 &lt;code&gt;async&lt;/code&gt;；第三方標籤可在主要內容穩定後再載入&lt;tr&gt;&lt;td&gt;CSS&lt;td&gt;避免不必要的 &lt;code&gt;@import&lt;/code&gt; 串接；確認 CSS 沒有讓首屏繪製卡在長依賴鏈上&lt;tr&gt;&lt;td&gt;Web 字體&lt;td&gt;使用 &lt;code&gt;font-display: swap&lt;/code&gt;；只有確定是關鍵字體時才考慮 preload&lt;/table&gt;&lt;p&gt;GTM 延遲載入的具體寫法，可參考站內 &lt;a href=&quot;https://kamadiam.com/gtm-defer-requestidlecallback-psi-optimization/&quot;&gt;GTM 延遲載入：用 requestIdleCallback 降低 PSI 的 TBT&lt;/a&gt;。&lt;h2 id=&quot;一個快速驗收心法先-CLS-穩,再談-LCP&quot;&gt;一個快速驗收心法：先 CLS 穩，再談 LCP&lt;/h2&gt;&lt;p&gt;LCP 是「什麼時候畫出來」，CLS 是「版面有沒有抖」。兩者不是同一個指標，但同一張圖片可能同時影響兩者：沒有尺寸時會推動版面，有錯誤載入策略時又會晚到。&lt;p&gt;建議順序：&lt;ol&gt;&lt;li&gt;&lt;strong&gt;先確保圖片／嵌入不會讓版面在載入期抖動（CLS 預留）&lt;/strong&gt;&lt;li&gt;再回頭把 LCP 圖片的優先級拉到位&lt;li&gt;最後用 GSC → 體驗 → Core Web Vitals 對&lt;strong&gt;欄位資料&lt;/strong&gt;驗收；報告反映的是一段期間的真實使用者資料，不會改完立刻更新&lt;/ol&gt;&lt;h2 id=&quot;框架快速對照&quot;&gt;框架快速對照&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;框架&lt;th&gt;圖片管道&lt;th&gt;LCP 注意事項&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Hugo&lt;/strong&gt;&lt;td&gt;&lt;code&gt;resources.Get&lt;/code&gt; + &lt;code&gt;Resize&lt;/code&gt;／&lt;code&gt;webp&lt;/code&gt;&lt;td&gt;主視覺圖模板別加 lazy&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Eleventy&lt;/strong&gt;&lt;td&gt;&lt;code&gt;@11ty/eleventy-img&lt;/code&gt;&lt;td&gt;Transform 預設 lazy，主視覺圖覆寫 eager + fetchpriority&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Astro&lt;/strong&gt;&lt;td&gt;&lt;code&gt;astro:assets&lt;/code&gt; 或 &lt;code&gt;&amp;lt;Image /&amp;gt;&lt;/code&gt;&lt;td&gt;依實際輸出與圖片位置確認 loading 設定，LCP 圖別盲目 lazy&lt;/table&gt;&lt;h2 id=&quot;快速驗收清單&quot;&gt;快速驗收清單&lt;/h2&gt;&lt;p&gt;每次修改後，按這個順序檢查：&lt;ol&gt;&lt;li&gt;PSI 或 DevTools 是否指出同一個 LCP 元素？&lt;li&gt;LCP 圖是否在初始 HTML 中可被發現？若是背景圖，是否真的需要 &lt;code&gt;preload&lt;/code&gt;？&lt;li&gt;是否誤用了 &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt;？&lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt; 是否只用在少數關鍵資源？&lt;li&gt;build 後的 HTML、Network 瀑布圖與實際圖片大小是否符合預期？&lt;li&gt;CLS 的尺寸預留是否仍然存在？&lt;/ol&gt;&lt;h2 id=&quot;結語LCP-優化是「不要拖關鍵資源」的工程紀律&quot;&gt;結語：LCP 優化是「不要拖關鍵資源」的工程紀律&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;用 PSI／DevTools 找出真正的 LCP 元素，別憑感覺改&lt;li&gt;首屏 LCP 圖不要 &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt;；確認需要時再加 &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt;&lt;li&gt;CSS 背景圖等難以被初始 HTML 發現的資源，才考慮 &lt;code&gt;preload&lt;/code&gt;&lt;li&gt;Eleventy 管道若自動補上 lazy，主視覺圖要個別覆寫&lt;li&gt;圖片下載完成不代表已經繪製；也要排查 CSS、字體與 JavaScript 的依賴鏈&lt;/ul&gt;&lt;p&gt;先改一個真正的瓶頸，再重新測量；不要一次把整個 &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; 塞滿 preload，否則瀏覽器也會開始懷疑人生。等資料慢慢累積，再回 GSC 看真實使用者的趨勢。改完記得再來一杯，這次是慶祝主角準時登場的那杯。&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/optimize-lcp&quot;&gt;web.dev：Optimize Largest Contentful Paint&lt;/a&gt; — LCP 元素、資源發現、lazy loading、fetch priority 與 preload 的整體優化方法。&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/fetch-priority&quot;&gt;web.dev：Optimize resource loading with the Fetch Priority API&lt;/a&gt; — 說明 &lt;code&gt;fetchpriority&lt;/code&gt; 如何影響資源優先級，以及它和 preload 的搭配方式。&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/browser-level-image-lazy-loading&quot;&gt;web.dev：Browser-level image lazy loading for the web&lt;/a&gt; — 說明 &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; 與 &lt;code&gt;loading=&amp;quot;eager&amp;quot;&lt;/code&gt; 的載入行為和適用情境。&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img&quot;&gt;MDN：&lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; HTML image element&lt;/a&gt; — 查閱圖片元素的 &lt;code&gt;loading&lt;/code&gt;、&lt;code&gt;fetchpriority&lt;/code&gt;、尺寸與響應式圖片屬性。&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/fetchpriority&quot;&gt;MDN：fetchpriority HTML attribute&lt;/a&gt; — 查閱 &lt;code&gt;fetchpriority&lt;/code&gt; 的用途、限制與應該節制使用的原因。&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>GTM 延遲載入：用 requestIdleCallback 降低 PSI 的 TBT</title>
    <link href="https://kamadiam.com/gtm-defer-requestidlecallback-psi-optimization/" />
    <updated>2026-08-03T06:00:00Z</updated>
    <id>https://kamadiam.com/gtm-defer-requestidlecallback-psi-optimization/</id>
    <content type="html">&lt;p&gt;GTM 一掛上去，PageSpeed Insights（PSI）分數就往下掉？先別急著把它整個拔掉。很多時候，問題不是「有沒有 GTM」，而是它在首屏最忙的時候也跑進來搶頻寬、搶主執行緒——大家都還沒坐好，它已經開始開會了。&lt;p&gt;這篇會帶你把 GTM 從「頁面一開就啟動」改成「使用者互動或瀏覽器有空時才啟動」，再用同一套流程檢查 LCP、TBT、INP，以及轉換事件有沒有被延遲到漏掉。讀完你會知道這種延遲適合什麼情境、程式碼怎麼寫，以及為什麼「分數變綠」不等於資料一定完整。簡單說，就是先讓瀏覽器把早餐吃完，再請 GTM 進來開會。&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/gtm-defer-requestidlecallback-psi-optimization/#%E7%82%BA%E4%BB%80%E9%BA%BC-GTM-%E5%8F%AF%E8%83%BD%E6%8B%96%E6%85%A2-PSI?&quot;&gt;為什麼 GTM 可能拖慢 PSI？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/gtm-defer-requestidlecallback-psi-optimization/#%E6%A0%B8%E5%BF%83%E5%81%9A%E6%B3%95%E4%BA%92%E5%8B%95%E8%A7%B8%E7%99%BC%E5%8A%A0-idle-fallback&quot;&gt;核心做法：互動觸發加 idle fallback&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/gtm-defer-requestidlecallback-psi-optimization/#%E5%8F%AF%E7%9B%B4%E6%8E%A5%E8%A4%87%E8%A3%BD%E7%9A%84%E6%9C%80%E5%B0%8F%E7%89%88%E6%9C%AC&quot;&gt;可直接複製的最小版本&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/gtm-defer-requestidlecallback-psi-optimization/#timeout-%E8%A6%81%E8%A8%AD%E5%A4%9A%E5%B0%91?&quot;&gt;timeout 要設多少？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/gtm-defer-requestidlecallback-psi-optimization/#dataLayer-%E6%9C%83%E4%BF%9D%E7%95%99%E4%BA%8B%E4%BB%B6,%E4%BD%86%E4%B8%8D%E6%98%AF%E8%B3%87%E6%96%99%E4%BF%9D%E9%9A%AA%E7%AE%B1&quot;&gt;dataLayer 會保留事件，但不是資料保險箱&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/gtm-defer-requestidlecallback-psi-optimization/#%E5%BB%B6%E9%81%B2%E5%89%8D%E5%85%88%E5%81%9A%E7%9A%84%E5%85%A9%E4%BB%B6%E4%BA%8B&quot;&gt;延遲前先做的兩件事&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/gtm-defer-requestidlecallback-psi-optimization/#%E6%80%8E%E9%BA%BC%E9%A9%97%E6%94%B6%E4%B8%8D%E8%A6%81%E5%8F%AA%E7%9C%8B%E4%B8%80%E6%AC%A1-PSI-%E5%88%86%E6%95%B8&quot;&gt;怎麼驗收：不要只看一次 PSI 分數&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/gtm-defer-requestidlecallback-psi-optimization/#%E6%8E%A8%E8%96%A6%E5%B7%A5%E5%85%B7/%E8%B3%87%E6%BA%90&quot;&gt;推薦工具／資源&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/gtm-defer-requestidlecallback-psi-optimization/#%E7%B5%90%E8%AA%9E%E5%85%88%E8%AE%93%E4%B8%BB%E5%9F%B7%E8%A1%8C%E7%B7%92%E5%96%98%E5%8F%A3%E6%B0%A3&quot;&gt;結語：先讓主執行緒喘口氣&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/gtm-defer-requestidlecallback-psi-optimization/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;為什麼-GTM-可能拖慢-PSI?&quot;&gt;為什麼 GTM 可能拖慢 PSI？&lt;/h2&gt;&lt;p&gt;GTM 常見的影響大致分兩條線：&lt;ol&gt;&lt;li&gt;&lt;strong&gt;網路頻寬競爭&lt;/strong&gt;：&lt;code&gt;gtm.js&lt;/code&gt; 下載時，可能和 hero 圖片、CSS 等首屏資源競爭，讓 LCP 延後。實際影響仍取決於網路、資源優先順序與容器內容，不能只看檔名就宣稱一定變慢。&lt;li&gt;&lt;strong&gt;主執行緒工作增加&lt;/strong&gt;：容器啟動後，GA4、Pixel、Hotjar 等標籤可能執行 JavaScript。標籤太多或太重，就可能製造長任務，推高 TBT，也讓互動回饋變慢。&lt;/ol&gt;&lt;p&gt;延遲載入可以保護首屏，但它不是免費午餐：越晚啟動，越可能漏掉頁面剛開啟時的分析或轉換事件。因此要一起看效能和資料完整度。&lt;h2 id=&quot;核心做法互動觸發加-idle-fallback&quot;&gt;核心做法：互動觸發加 idle fallback&lt;/h2&gt;&lt;p&gt;可以讓以下兩條路都呼叫同一個 &lt;code&gt;boot()&lt;/code&gt;：&lt;ul&gt;&lt;li&gt;使用者真的開始使用頁面，例如滾動、按鍵或觸控。&lt;li&gt;使用者沒有互動時，等主執行緒進入 idle；如果瀏覽器不支援，就退回 &lt;code&gt;setTimeout&lt;/code&gt;。&lt;/ul&gt;&lt;p&gt;重點是用 &lt;code&gt;started&lt;/code&gt; flag 去重。&lt;code&gt;once: true&lt;/code&gt; 只會移除某一個事件的 listener，不能取消已排程的 idle callback，也不能保證兩條路不會同時進入函式。所以要在 &lt;code&gt;boot()&lt;/code&gt; 裡設防，並在互動搶先發生時取消排程。&lt;h2 id=&quot;可直接複製的最小版本&quot;&gt;可直接複製的最小版本&lt;/h2&gt;&lt;p&gt;把 &lt;code&gt;GTM-XXXXXXX&lt;/code&gt; 換成自己的 container ID。這段程式會先建立 &lt;code&gt;dataLayer&lt;/code&gt;，再在互動或 idle 時只載入一次 GTM。它是「延遲載入的起點」，不是可以直接取代所有 consent、轉換與 noscript 設計的萬用片段。&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; d&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; started &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; idleId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; timeoutId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; events &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;pointerdown&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;keydown&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;touchstart&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;scroll&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  w&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataLayer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataLayer &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;boot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;started&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    started &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;idleId &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cancelIdleCallback&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      w&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cancelIdleCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;idleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timeoutId &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      w&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;clearTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timeoutId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    w&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataLayer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&#39;gtm.start&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;gtm.js&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; script &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; d&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;script&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;async &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;https://www.googletagmanager.com/gtm.js?id=GTM-XXXXXXX&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    d&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;head&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;script&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  events&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    d&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; boot&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;once&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;passive&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;requestIdleCallback&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    idleId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;requestIdleCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;boot&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    timeoutId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;boot&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;requestIdleCallback&lt;/code&gt; 的 &lt;code&gt;timeout&lt;/code&gt; 不是精準鬧鐘，也不是「GTM 完成載入」的期限。瀏覽器會先等 idle period；若期限到了還沒執行，才把 callback 排進 event loop。callback 開始執行後，還要下載、解析並執行 GTM 與容器裡的 tag。&lt;p&gt;另外，&lt;code&gt;requestIdleCallback()&lt;/code&gt; 目前不是所有瀏覽器都一致支援，所以用 feature detection 比寫死「某某瀏覽器不支援」安全。上面的 fallback 只處理 API 不存在的情況；若網站還有 CSP、consent mode 或特殊 WebView 限制，仍要在目標環境測試。&lt;h2 id=&quot;timeout-要設多少?&quot;&gt;timeout 要設多少？&lt;/h2&gt;&lt;p&gt;真正要平衡的是「首屏保護」和「資料多早開始收集」。下面的數字只是第一輪 A/B 實驗的起點，不是 Google 或 GTM 規定的標準；沒有一個數字適合所有網站，先用實測建立基準比較可靠。&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;timeout&lt;th&gt;優點&lt;th&gt;風險&lt;th&gt;適合情境&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;1500–2500ms&lt;td&gt;適合先做第一輪實驗&lt;td&gt;早期 pageview 或轉換可能延後&lt;td&gt;一般內容站、非關鍵分析&lt;tr&gt;&lt;td&gt;1000ms 以下&lt;td&gt;較早啟動，資料風險較小&lt;td&gt;首屏和 TBT 的保護變弱&lt;td&gt;頁面很輕、轉換追蹤較重要&lt;tr&gt;&lt;td&gt;3000ms 以上&lt;td&gt;首屏保護較久&lt;td&gt;秒退與早期轉換漏算更多&lt;td&gt;只有實測支持時才用&lt;/table&gt;&lt;p&gt;如果登入、註冊或購買事件不能漏，不要把所有 tag 都綁在延遲初始化上。可以保留關鍵事件的即時路徑，只延後非必要的分析和行銷 tag。若有同意管理平台，也要依使用者同意狀態決定哪些 tag 能啟動；效能優化不能偷偷繞過隱私規則。&lt;h2 id=&quot;dataLayer-會保留事件,但不是資料保險箱&quot;&gt;dataLayer 會保留事件，但不是資料保險箱&lt;/h2&gt;&lt;p&gt;GTM 載入前先建立陣列，並把資料與 &lt;code&gt;event&lt;/code&gt; 放在同一個 object：&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataLayer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataLayer &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataLayer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;signup_complete&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;plan&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;free&#39;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;這能保留「目前頁面、GTM 載入前已成功 push」的事件，GTM 載入後會依序處理 queue。但要記得三個界線：&lt;ul&gt;&lt;li&gt;&lt;code&gt;dataLayer&lt;/code&gt; 不會自動跨頁保存；下一頁要重新初始化和 push。&lt;li&gt;queue 被處理，不代表 tag 的網路請求已經送達。&lt;li&gt;使用者秒退或立即導向時，下載、執行或 beacon 仍可能被中斷。&lt;/ul&gt;&lt;p&gt;因此，GTM Preview 或 Tag Assistant 顯示「有 push」只是第一關，還要到分析或廣告平台的測試工具確認事件真的送出。&lt;h2 id=&quot;延遲前先做的兩件事&quot;&gt;延遲前先做的兩件事&lt;/h2&gt;&lt;h3 id=&quot;先精簡-GTM-container&quot;&gt;先精簡 GTM container&lt;/h3&gt;&lt;p&gt;每隔一段時間檢查 container：&lt;ul&gt;&lt;li&gt;刪掉過期活動和不再使用的第三方 tag。&lt;li&gt;把不需要每頁執行的 tag 改成 Window Loaded 或自訂事件。&lt;li&gt;減少會反覆掃描 DOM 的變數和觸發條件。&lt;/ul&gt;&lt;p&gt;如果只是把一堆不必要的 tag 延後，主執行緒只是晚點忙，並沒有真正變輕。&lt;h3 id=&quot;高階方案再考慮-Worker&quot;&gt;高階方案再考慮 Worker&lt;/h3&gt;&lt;p&gt;Partytown 等方案可以把部分第三方腳本移到 Web Worker，但需要額外整合，且依賴 DOM 或同步行為的 tag 可能不相容。它比較適合已經完成 tag 審計、仍有明確長任務問題的技術型網站，不是第一個該按的按鈕。先把不用的 tag 刪掉，通常比替整個倉庫搬家更划算。&lt;h2 id=&quot;怎麼驗收不要只看一次-PSI-分數&quot;&gt;怎麼驗收：不要只看一次 PSI 分數&lt;/h2&gt;&lt;p&gt;用下面流程比較立即載入版和延遲版：&lt;ol&gt;&lt;li&gt;固定同一個 URL、GTM container、裝置策略和 cookie／consent 狀態。&lt;li&gt;PSI 兩個版本都跑多次，記錄 LCP、TBT、CLS、FCP，不要用單次分數宣稱因果。PSI 的 lab 結果會受測試條件影響，分數不是精密秤。&lt;li&gt;Lighthouse Navigation mode 看首屏；Timespan mode 則用來觀察互動後載入 GTM 的影響。&lt;li&gt;在 Performance trace 和 Network 面板確認 &lt;code&gt;gtm.js&lt;/code&gt;、tag 長任務與請求發生時間。&lt;li&gt;用 GTM Preview／Tag Assistant 檢查 queue、Custom Event trigger、consent 和轉換 tag。&lt;li&gt;以真實流量的 CrUX 或 PSI field data 觀察 INP。TBT 是 lab 指標，可作為載入期間主執行緒壅塞的線索，但不能直接當成真實 INP。&lt;/ol&gt;&lt;p&gt;如果首屏改善了，但註冊或購買事件明顯少掉，這不是成功的優化；它只是把問題從 PSI 搬到分析資料裡。&lt;h2 id=&quot;推薦工具/資源&quot;&gt;推薦工具／資源&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;需求&lt;th&gt;工具／做法&lt;th&gt;適合誰&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;首屏與 lab 指標比較&lt;td&gt;PageSpeed Insights、Chrome Lighthouse&lt;td&gt;想確認 LCP、TBT 是否改善的站長&lt;tr&gt;&lt;td&gt;真實互動體驗&lt;td&gt;CrUX／PSI field data&lt;td&gt;有足夠流量、要看 INP 的網站&lt;tr&gt;&lt;td&gt;Tag 行為驗證&lt;td&gt;GTM Preview、Tag Assistant&lt;td&gt;不能接受事件悄悄漏掉的網站&lt;tr&gt;&lt;td&gt;整理效能與 SEO 驗收&lt;td&gt;&lt;a href=&quot;https://kamadiam.com/pagespeed-core-web-vitals/&quot;&gt;SEO 與 Core Web Vitals 檢查流程&lt;/a&gt;&lt;td&gt;想把單次修正變成固定流程的站長&lt;/table&gt;&lt;h2 id=&quot;結語先讓主執行緒喘口氣&quot;&gt;結語：先讓主執行緒喘口氣&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;GTM 不一定要刪，先把它改成互動觸發加 idle fallback。&lt;li&gt;&lt;code&gt;timeout&lt;/code&gt; 越小，資料越早開始；越大，首屏保護越強，但早期事件風險也越高。&lt;li&gt;&lt;code&gt;dataLayer&lt;/code&gt; 能排隊目前頁面的事件，不能保證跨頁保存或請求送達。&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;下一步&lt;/strong&gt;：先用 2000ms 做基準，將立即載入版與延遲版各跑多次，同時核對轉換事件，再依 LCP、TBT、INP 和資料完整度調整。修完再喝一口咖啡，這次讓瀏覽器先喝；它如果還是忙，就代表該審的是 tag，不是咖啡師。&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://support.google.com/tagmanager/answer/6164391&quot;&gt;Google Tag Manager：The data layer&lt;/a&gt;：說明 &lt;code&gt;dataLayer&lt;/code&gt; 的建立位置、&lt;code&gt;push()&lt;/code&gt; 與容器程式碼的關係。&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback&quot;&gt;MDN：Window.requestIdleCallback()&lt;/a&gt;：說明 idle callback、&lt;code&gt;timeout&lt;/code&gt; 與瀏覽器支援限制。&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/tbt&quot;&gt;web.dev：Total Blocking Time（TBT）&lt;/a&gt;：說明 TBT 的計算方式，以及它和 INP 的差異。&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/inp&quot;&gt;web.dev：Interaction to Next Paint（INP）&lt;/a&gt;：說明 INP 應以實地資料觀察，及 lab 指標的限制。&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/devtools/lighthouse&quot;&gt;Chrome for Developers：Lighthouse&lt;/a&gt;：說明 Navigation、Timespan 與 Snapshot 模式的使用情境。&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>圖片最佳化與 CLS 解決方案：用 width、height 預防網頁版面跳動</title>
    <link href="https://kamadiam.com/image-size-cls-preallocation/" />
    <updated>2026-08-03T03:15:00Z</updated>
    <id>https://kamadiam.com/image-size-cls-preallocation/</id>
    <content type="html">&lt;p&gt;你有沒有遇過這種情況：正準備點連結，圖片突然載入，整段文字往下一跳。手指點到旁邊的空白，只能默念：「很好，咖啡也跟著位移了。」&lt;p&gt;這不是單純的「圖片太大」問題。圖片還沒載入時，如果瀏覽器不知道它要佔多少空間，後面的內容就可能被推開，形成 &lt;strong&gt;CLS（Cumulative Layout Shift，累積版面配置位移）&lt;/strong&gt;。另一方面，圖片若大到離譜，又會拖慢下載與解碼，影響 LCP。&lt;p&gt;這篇會用白話整理三件事：如何替圖片預留空間、如何讓下載尺寸符合實際顯示寬度，以及 Eleventy Image Transform 該怎麼接上工作流程。讀完後，你應該能判斷什麼時候寫 &lt;code&gt;width&lt;/code&gt;／&lt;code&gt;height&lt;/code&gt;，什麼時候使用 &lt;code&gt;aspect-ratio&lt;/code&gt;，也能避開幾個很常見的圖片效能坑。&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/image-size-cls-preallocation/#CLS-%E5%88%B0%E5%BA%95%E5%9C%A8%E9%87%8F%E4%BB%80%E9%BA%BC?&quot;&gt;CLS 到底在量什麼？&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/image-size-cls-preallocation/#%E7%AC%AC%E4%B8%80%E6%8B%9B%E5%9C%A8-HTML-%E5%AF%AB%E4%B8%8A%E7%9C%9F%E5%AF%A6%E5%AF%AC%E9%AB%98&quot;&gt;第一招：在 HTML 寫上真實寬高&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/image-size-cls-preallocation/#%E7%AC%AC%E4%BA%8C%E6%8B%9B%E9%9C%80%E8%A6%81%E5%9B%BA%E5%AE%9A%E6%A1%86%E6%9E%B6%E6%99%82%E4%BD%BF%E7%94%A8-aspect-ratio&quot;&gt;第二招：需要固定框架時使用 aspect-ratio&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/image-size-cls-preallocation/#%E7%AC%AC%E4%B8%89%E6%8B%9B%E5%9C%96%E7%89%87%E5%B0%BA%E5%AF%B8%E8%A6%81%E9%85%8D%E5%90%88%E9%A1%AF%E7%A4%BA%E5%AF%AC%E5%BA%A6&quot;&gt;第三招：圖片尺寸要配合顯示寬度&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/image-size-cls-preallocation/#Eleventy-Image-Transform%E6%8A%8A%E9%87%8D%E8%A4%87%E5%B7%A5%E4%BD%9C%E4%BA%A4%E7%B5%A6%E5%BB%BA%E7%BD%AE%E6%B5%81%E7%A8%8B&quot;&gt;Eleventy Image Transform：把重複工作交給建置流程&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/image-size-cls-preallocation/#%E4%B8%80%E6%AC%A1%E5%AE%8C%E6%88%90%E7%9A%84%E6%AA%A2%E6%9F%A5%E6%B8%85%E5%96%AE&quot;&gt;一次完成的檢查清單&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/image-size-cls-preallocation/#%E7%B5%90%E8%AA%9E%E5%85%88%E9%A0%90%E7%95%99,%E5%86%8D%E7%98%A6%E8%BA%AB&quot;&gt;結語：先預留，再瘦身&lt;/a&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/image-size-cls-preallocation/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;CLS-到底在量什麼?&quot;&gt;CLS 到底在量什麼？&lt;/h2&gt;&lt;p&gt;CLS 衡量的是頁面生命週期中，&lt;strong&gt;非預期的版面位移&lt;/strong&gt;。例如文章文字先排好，圖片載入後才把文字往下推；這種跳動會讓讀者誤點按鈕，也會讓人覺得網站在偷偷喝醉。&lt;p&gt;Google 的 Core Web Vitals 建議值是：CLS 不高於 0.1、LCP 不超過 2.5 秒，都是以實際使用者資料的第 75 百分位作為判斷基準。這不代表每一台裝置都會得到同樣結果，所以本機 Lighthouse 分數很漂亮，也不等於真實訪客完全沒有問題。&lt;p&gt;先把範圍切清楚：本文專注圖片造成的位移。字型交換、廣告、Cookie 橫幅與第三方嵌入，也可能造成 CLS，但應該分開檢查，否則修到最後會像在咖啡渣裡找 bug。&lt;h2 id=&quot;第一招在-HTML-寫上真實寬高&quot;&gt;第一招：在 HTML 寫上真實寬高&lt;/h2&gt;&lt;p&gt;對一般 &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;，最穩妥的做法是提供圖片檔案的實際像素尺寸：&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/img/product-dashboard.webp&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;675&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;產品控制台介面截圖&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;decoding&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;async&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;這裡的 &lt;code&gt;width&lt;/code&gt; 與 &lt;code&gt;height&lt;/code&gt; 是圖片的內在尺寸，不是你希望它在畫面上永遠顯示的 CSS 寬度。瀏覽器可以先用這兩個數值算出比例，在圖片下載完成前預留大致正確的高度。&lt;p&gt;接著用 CSS 讓它能縮小，但不要被拉伸：&lt;pre class=&quot;language-css&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;max-width: 100%&lt;/code&gt; 只限制圖片不要超出容器；&lt;code&gt;height: auto&lt;/code&gt; 則依照原本比例計算高度。這兩行解決的是響應式顯示，HTML 寬高屬性解決的是載入前的尺寸提示，兩者是隊友，不是二選一。&lt;h3 id=&quot;寬高比例填錯,仍然會跳&quot;&gt;寬高比例填錯，仍然會跳&lt;/h3&gt;&lt;p&gt;如果圖片實際是 1600 × 900，卻寫成 1600 × 1200，瀏覽器會先預留錯誤的高度，圖片載入後再校正。這仍可能產生位移，因此請從原檔或產圖工具確認比例，不要靠目測——螢幕上的圖片很會偽裝。&lt;p&gt;Lazy loading 圖片也一樣需要寬高。它本來就可能等到接近視窗才下載；若此時才突然取得高度，讀者正在看的內容就會被推走。&lt;h2 id=&quot;第二招需要固定框架時使用-aspect-ratio&quot;&gt;第二招：需要固定框架時使用 &lt;code&gt;aspect-ratio&lt;/code&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;aspect-ratio&lt;/code&gt; 適合用在圖片比例不固定、但設計需要統一視覺框的情境，也很適合 iframe、影片或其他沒有圖片內在比例的嵌入內容。&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;figure&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;screenshot&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt;
		&lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/img/compare-a.webp&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
		&lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1600&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
		&lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;900&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
		&lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;方案 A 設定畫面&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
		&lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
		&lt;span class=&quot;token attr-name&quot;&gt;decoding&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;async&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;figure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;language-css&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.screenshot&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;aspect-ratio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 16 / 9&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #f2f2f2&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.screenshot img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;object-fit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cover&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;object-fit: cover&lt;/code&gt; 會讓圖片填滿框架，必要時裁掉邊緣。如果內容不能被裁切，就改用 &lt;code&gt;contain&lt;/code&gt;，或保留 &lt;code&gt;height: auto&lt;/code&gt; 讓圖片完整顯示。&lt;p&gt;一般內容圖片仍建議保留正確的 HTML 寬高；&lt;code&gt;aspect-ratio&lt;/code&gt; 是補充工具，不是把每張圖的實際比例都忘掉的通行證。&lt;h2 id=&quot;第三招圖片尺寸要配合顯示寬度&quot;&gt;第三招：圖片尺寸要配合顯示寬度&lt;/h2&gt;&lt;p&gt;一張在手機上只顯示 360px 寬的圖片，如果每次都下載 4000px 原圖，瀏覽器不只要多下載，也要多解碼。做法不是無限降低品質，而是先產生符合版面需求的尺寸，再用 &lt;code&gt;srcset&lt;/code&gt; 和 &lt;code&gt;sizes&lt;/code&gt; 讓瀏覽器選擇候選檔案。&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/img/guide-800.webp&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;
		/img/guide-400.webp 400w,
		/img/guide-800.webp 800w,
		/img/guide-1200.webp 1200w
	&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;sizes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(max-width: 768px) 100vw, 720px&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;675&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;設定步驟示意&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;decoding&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;async&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;srcset&lt;/code&gt; 列出可用的圖片候選；&lt;code&gt;sizes&lt;/code&gt; 描述圖片在目前版面大約會顯示多寬。瀏覽器會綜合視窗寬度與裝置像素比例，選出合適的檔案。&lt;code&gt;sizes&lt;/code&gt; 寫成 &lt;code&gt;100vw&lt;/code&gt; 但圖片其實只佔內容欄，可能就會下載過大的檔案。&lt;p&gt;首屏真正的主圖不要一律設定 &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt;。它若是 LCP 候選，應讓瀏覽器正常優先取得；是否加上 &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt;，則要看實際載入瀑布流與頁面結構，別把「高優先」當成圖片界的萬用咖啡因。&lt;h3 id=&quot;格式與壓縮怎麼選?&quot;&gt;格式與壓縮怎麼選？&lt;/h3&gt;&lt;p&gt;沒有一個適用所有圖片的固定 KB 門檻。照片、介面截圖、透明 Logo 的可接受品質不同，應該在實際裝置與網路條件下比較畫質、檔案大小和 LCP。&lt;p&gt;可以遵循這個順序：&lt;ol&gt;&lt;li&gt;先裁掉不需要的畫面，並縮到合理的輸出寬度。&lt;li&gt;依瀏覽器支援與網站流程選擇 AVIF、WebP 或原格式作為 fallback。&lt;li&gt;UI 截圖放大檢查文字；壓縮不是越狠越專業。&lt;li&gt;用 PageSpeed Insights 或瀏覽器 Performance 面板確認實際結果。&lt;/ol&gt;&lt;p&gt;像 &lt;a href=&quot;https://squoosh.app/&quot;&gt;Squoosh&lt;/a&gt; 這類工具適合手動比較不同格式與品質，但工具只負責產檔，&lt;code&gt;width&lt;/code&gt; 和 &lt;code&gt;height&lt;/code&gt; 仍要回到 HTML 補好。&lt;h2 id=&quot;Eleventy-Image-Transform把重複工作交給建置流程&quot;&gt;Eleventy Image Transform：把重複工作交給建置流程&lt;/h2&gt;&lt;p&gt;圖片不多時，手動處理沒有問題；部落格持續更新後，漏掉寬高或忘記產縮圖就很容易發生。Eleventy 官方的 &lt;code&gt;@11ty/eleventy-img&lt;/code&gt; Image HTML Transform 可以在建置時產生多種尺寸與格式，並輸出含有寬高和 &lt;code&gt;srcset&lt;/code&gt; 的標記。&lt;p&gt;概念設定如下：&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; eleventyImageTransformPlugin &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@11ty/eleventy-img&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;eleventyConfig&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addPlugin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;eleventyImageTransformPlugin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;formats&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;webp&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;auto&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;widths&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;800&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;實際使用多個寬度時，請為輸出的 &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; 提供符合版面的 &lt;code&gt;sizes&lt;/code&gt;。沒有 &lt;code&gt;sizes&lt;/code&gt;，瀏覽器可能無法正確判斷候選圖片適合的顯示寬度，最佳化就只完成一半。&lt;p&gt;Eleventy 也可能替圖片加上 &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt;。這對文章下方的圖片通常合理，但首屏主圖要個別覆寫，並在建置後檢查產出的 HTML，而不是只相信設定檔看起來很漂亮。&lt;p&gt;建議導入順序很簡單：先讓所有圖片有正確比例，再讓建置流程產生合適尺寸，最後用真實頁面檢查 CLS 與 LCP。先把地板畫好，再搬沙發；不然每次圖片載入，都像重新裝潢一次。&lt;h2 id=&quot;一次完成的檢查清單&quot;&gt;一次完成的檢查清單&lt;/h2&gt;&lt;p&gt;改完圖片後，可以照這個順序驗收：&lt;ul&gt;&lt;li&gt;搜尋所有 &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;，確認有 &lt;code&gt;alt&lt;/code&gt;，並檢查 &lt;code&gt;width&lt;/code&gt;／&lt;code&gt;height&lt;/code&gt; 是否符合原圖比例。&lt;li&gt;確認響應式 CSS 沒有用兩個固定尺寸把圖片拉伸；一般圖片通常搭配 &lt;code&gt;max-width: 100%&lt;/code&gt; 與 &lt;code&gt;height: auto&lt;/code&gt;。&lt;li&gt;圖片若需要統一框架，確認容器的 &lt;code&gt;aspect-ratio&lt;/code&gt; 和 &lt;code&gt;object-fit&lt;/code&gt; 符合內容需求。&lt;li&gt;檢查 &lt;code&gt;srcset&lt;/code&gt; 的候選寬度與 &lt;code&gt;sizes&lt;/code&gt; 是否符合實際版面。&lt;li&gt;確認首屏主圖沒有被不必要的 lazy loading 延後。&lt;li&gt;用 PageSpeed Insights、Chrome DevTools Performance 或 Search Console 的 Core Web Vitals 資料觀察結果。&lt;/ul&gt;&lt;p&gt;CLS 修好不代表整站就會飛起來；伺服器回應、字型、JavaScript 和第三方服務仍可能影響體驗。不過圖片先把尺寸說清楚，至少不會一邊載入、一邊把讀者的手指送去錯的按鈕。&lt;h2 id=&quot;結語先預留,再瘦身&quot;&gt;結語：先預留，再瘦身&lt;/h2&gt;&lt;p&gt;圖片最佳化可以記成兩句話：&lt;strong&gt;先用 HTML 寬高或 CSS 比例預留空間，再讓檔案尺寸符合實際顯示寬度。&lt;/strong&gt; 前者守住 CLS，後者幫助下載與解碼；兩邊一起做，才不是只把問題從「會跳」換成「等很久」。&lt;p&gt;先挑一篇文章，補齊圖片寬高並檢查產出的 &lt;code&gt;srcset&lt;/code&gt;。做完再跑一次效能檢查，然後放心喝咖啡——這次咖啡杯的位置，應該不會因為圖片載入而改變。&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/optimize-cls&quot;&gt;web.dev：Optimize Cumulative Layout Shift&lt;/a&gt;：說明圖片尺寸、&lt;code&gt;aspect-ratio&lt;/code&gt; 與預留版面空間如何降低 CLS。&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/vitals&quot;&gt;web.dev：Web Vitals&lt;/a&gt;：Core Web Vitals 與 CLS、LCP 建議值及評估方式。&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img&quot;&gt;MDN：&lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; HTML image element&lt;/a&gt;：查閱 &lt;code&gt;width&lt;/code&gt;、&lt;code&gt;height&lt;/code&gt;、&lt;code&gt;loading&lt;/code&gt;、&lt;code&gt;srcset&lt;/code&gt; 與 &lt;code&gt;sizes&lt;/code&gt; 的行為。&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Guides/Responsive_images&quot;&gt;MDN：Using responsive images in HTML&lt;/a&gt;：說明解析度切換、&lt;code&gt;srcset&lt;/code&gt; 和 &lt;code&gt;sizes&lt;/code&gt; 的使用方式。&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/plugins/image/&quot;&gt;Eleventy：Image&lt;/a&gt;：官方 Image Transform 設定、輸出格式、尺寸與 &lt;code&gt;sizes&lt;/code&gt; 注意事項。&lt;/ul&gt;</content>
  </entry>
</feed>