fetchpriority属性でLCP画像を最適化する|2026年実践ガイド
- LCP改善の最短ルートは、LCP候補リソース1つに
fetchpriority="high"を付け、必要なら<link rel="preload" as="image">と併用することだ。 - 帯域は有限で、CSS・JS・フォント・サムネイルが同時に走るとヒーロー画像の開始が遅れる。
- クリティカルレンダリングパス最適化でブロッキングを減らし、HTTP/2・HTTP/3で接続効率を上げたうえで、fetchpriorityは「同一接続内の優先順位付け」の最後の1押しになる。
fetchpriority属性とは
fetchpriorityは、HTML Living StandardおよびFetch Priority APIで定義された、ブラウザへのリソース取得優先度ヒントだ。<img>、<link>、<script>、<iframe>などに付与でき、値はhigh・low・autoの3種類。
2022年頃のChrome実装から始まり、2026年現在は主要ブラウザで広くサポートされている。Core Web VitalsのLCP(Largest Contentful Paint)改善とセットで語られることが多いが、本質は「限られたネットワーク帯域とHTTP/2・HTTP/3のストリーム枠を、どのリソースに先に割り当てるか」を開発者が指示できる点にある。
fetchpriorityは強制命令ではない。ブラウザはセキュリティ、Same-Origin、リソース種別、既存の優先度キューを総合して最終優先度を決める。それでもLCP画像のように「遅延がそのままLCP悪化に直結する」リソースでは、DevToolsのPriority列に明確な差が出る。
優先度キューとLCPの関係
ブラウザは概ね次の順でリソースをスケジュールする。
- Document(HTML) — 常に最優先
- preload + fetchpriority=high — クリティカル画像・フォント
- CSS(レンダーブロッキング) — CSSOM構築に必要
- sync script / import map — パーサー依存
- img fetchpriority=high — LCP候補
- 通常のimg / script defer / font — Medium付近
- fetchpriority=low / prefetch — 明示的に後回し
LCPが2.5秒を超える典型原因の一つは、LCP画像のダウンロード開始(Resource Load Start)が遅いことだ。CSSや同期JSが長い、preloadしていない、同一ページに多数の高優先度リソースがある——fetchpriorityはこの「開始順序と帯域配分」を調整する。
| 属性値 | 意味と推奨用途 |
|---|---|
| high | 他より先に取得してほしい。LCP候補のヒーロー画像・preloadするクリティカルフォントに限定 |
| low | 後回しでよい。Below-the-fold装飾、一覧の2枚目以降のサムネ、prefetch的な先読み |
| auto | ブラウザデフォルト(省略時と同じ)。特別な理由がなければこれ |
| (省略) | autoと同等。LCP候補以外は省略でよい |
LCP要素の特定 — Performance Insightsの使い方
fetchpriorityを付ける前に、本当にLCPになっている要素をDevToolsで確認する。推測でヒーロー画像にhighを付けても、実際のLCPが<h1>テキストなら効果は限定的だ。
Chrome DevTools Performance Insights
Chrome 118以降、Performance Insightsパネル(DevTools → Performance insights)がLCP分析に特化している。
- 対象URLを開き、DevTools → Performance insightsタブ
- Measure page load をクリック(または Ctrl+Shift+E で記録)
- レポートの LCP セクションを展開
- LCP element に表示されるセレクタ・URLをメモ
- LCP breakdown で TTFB / Load delay / Load time / Render delay の内訳を確認
Load delayが大きい場合、HTMLパースや他リソースとの競合で画像取得開始が遅れている。fetchpriority=highとpreloadが有効。Load timeが大きい場合、画像バイトサイズやCDN距離が原因——画像圧縮・WebP/AVIFを先に見る。
DevTools → Performance insights → Measure page load
LCP element のタグ名・src・セレクタを記録
LCP breakdown で Load delay と Load time のどちらが支配的か判断
Network タブで該当リクエストの Priority と Initiator を確認
high / preload を適用し、同条件で再計測して LCP 時刻を比較
Lighthouseとの使い分け
Lighthouseも「Largest Contentful Paint element」を報告するが、Labデータは1回のシミュレーションだ。fetchpriorityのBefore/Afterは、可能なら同一マシン・同一Throttling(4G Slow / Mobile)で3回ずつ計測し中央値を取る。
Field Data(Search ConsoleのCore Web Vitals、CrUX)ではLCP要素の内訳までは見えない。Labで特定したLCP候補をFieldのLCP悪化ページに当てはめ、優先的に修正する。
ECサイトやニュースサイトでは<h1>やリード文がLCPになることがある。この場合fetchpriority on imageより、WebフォントのFOIT/FOUT対策(font-display: swap、サブセット化、可変フォント、システムフォントスタック)と、CRP最適化のCSSインライン化が効く。画像にhighを付けてもLCPは動かない。
fetchpriority=high — LCP画像への適用
LCP候補が<img>のとき、次の属性セットが2026年のweb.dev推奨に沿った最小構成だ。
fetchpriority="high"— 取得優先度ヒントwidth/height— CLS防止(レイアウト確定が早いとLCP計測も安定)srcset/sizes— 適切な解像度のみ取得decoding="async"— メインスレッドとの競合緩和(デフォルトでも可)loading属性は付けない — LCP画像にloading="lazy"は禁物
基本的なHTML例
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>fetchpriority LCP デモ</title>
<!-- クリティカルCSSは短くインライン(CRP参照) -->
<style>
body { margin: 0; font-family: system-ui, sans-serif; }
.hero { display: block; width: 100%; max-height: 70vh; object-fit: cover; }
</style>
<!-- LCP画像: パース前に高優先度で開始 -->
<link rel="preload" as="image"
href="/images/hero-1200.webp"
imagesrcset="/images/hero-800.webp 800w, /images/hero-1200.webp 1200w"
imagesizes="100vw"
fetchpriority="high">
<!-- 非クリティカルCSS -->
<link rel="stylesheet" href="/css/main.css" media="print" onload="this.media='all'">
</head>
<body>
<header>
<h1>サービス名</h1>
</header>
<main>
<img
class="hero"
src="/images/hero-1200.webp"
srcset="/images/hero-800.webp 800w, /images/hero-1200.webp 1200w"
sizes="100vw"
alt="プロダクトのメインビジュアル"
width="1200"
height="630"
fetchpriority="high"
decoding="async"
/>
<p>リード文……</p>
</main>
<!-- アプリJSはdefer -->
<script src="/js/app.js" defer></script>
</body>
</html>
<link rel="preload" as="image">のimagesrcset / imagesizesは、<img>と完全一致させる。不一致だとブラウザが別URLをpreloadし、帯域の無駄になる。
preloadとimgの二重指定は問題ないか
web.devの「Optimize LCP」および「Preload critical assets」では、LCP画像に対しpreload + imgの両方にfetchpriority=highが例示されている。preloadで早期開始、imgタグでレスポンス再利用(同一URLならキャッシュヒット)——役割が異なる。
同一ページにfetchpriority="high"を5つ付けると、ブラウザ内部で相対優先度が flatten し、LCP画像が再び後ろに回る。原則1〜2リソース(LCP画像 + 必要ならクリティカルフォント)に限定する。
fetchpriority=low — 帯域競合の回避
LCPを改善するもう半分は、LCP以外を意図的に遅らせることだ。Above-the-foldに見えるがLCPではない装飾、カルーセルの2枚目以降、記事グリッドのサムネイルはlowの候補になる。
<section class="article-grid">
<!-- 1枚目だけLCP候補になりうる場合は auto のまま -->
<article>
<img src="/thumb/feature.webp" alt="特集" width="400" height="225" loading="lazy">
</article>
<!-- 2枚目以降は low + lazy で帯域を譲る -->
<article>
<img src="/thumb/post-1.webp" alt="" width="400" height="225"
loading="lazy" fetchpriority="low">
</article>
<article>
<img src="/thumb/post-2.webp" alt="" width="400" height="225"
loading="lazy" fetchpriority="low">
</article>
</section>
<footer>
<img src="/badges/partner.svg" alt="" width="120" height="40"
fetchpriority="low" loading="lazy">
</footer>
loading="lazy"はビューポート付近まで読み込みを遅延する。fetchpriority="low"は読み込みが開始される際の優先度を下げる。併用して相補的に使える。
| 手法 | 効果 |
|---|---|
| fetchpriority=high | LCP候補の取得開始と帯域配分を前倒し |
| fetchpriority=low | 非クリティカル画像の優先度を下げ、LCPへの帯域譲渡 |
| loading=lazy | ビューポート外までリクエスト自体を遅延 |
| preload (LCP) | HTMLパース前からLCP画像のダウンロード開始 |
| preconnect | CDNオリジンへの接続確立を前倒し(画像URLホストに対して) |
<link>・<script>・背景画像への拡張
fetchpriorityはimg専用ではない。CSS背景のLCPは要素として計測されにくいため、LCPがbackground-imageの場合は<img>への置き換えを先に検討する(web.devも<img>推奨)。
link rel=preload / preconnect
<head>
<!-- CDNへ早期接続(HTTP/2・HTTP/3の効果と相乗) -->
<link rel="preconnect" href="https://cdn.example.com" crossorigin>
<!-- LCP WebP -->
<link rel="preload" as="image" href="https://cdn.example.com/hero.webp"
fetchpriority="high">
<!-- クリティカルフォント(LCPがテキストの場合) -->
<link rel="preload" as="font" type="font/woff2"
href="/fonts/noto-sans-jp-subset.woff2" crossorigin
fetchpriority="high">
<!-- 次ページ用の prefetch は low -->
<link rel="prefetch" href="/next-page/" fetchpriority="low">
</head>
scriptへの適用(慎重に)
<!-- 計測タグは async + low でLCPと競合しない -->
<script src="https://www.googletagmanager.com/gtag/js?id=G-XXXX" async fetchpriority="low"></script>
<!-- アプリ本体は defer(fetchpriority省略で十分なことが多い) -->
<script src="/js/bundle.js" defer></script>
同期scriptにhighを付けても、パーサーブロッキングは解消しない。LCP改善の主戦場は画像とCSSに留めるのが安全だ。
JavaScriptで動的にfetchpriorityを制御する
SPAやCMS連携で、クライアント側からLCP候補を切り替える場合のパターン。
ルートロード時にヒーロー画像を注入
/**
* LCP候補のヒーローURLをAPIから取得した後にimgを差し込む場合、
* 可能な限りSSR/SSGで最初からHTMLに含めるのが理想。
* やむを得ずクライアント注入する場合の例。
*/
async function injectHeroImage(container, apiUrl) {
const data = await fetch(apiUrl, { priority: 'high' }).then((r) => r.json());
const heroUrl = data.heroImageUrl;
const srcset = data.heroSrcset || '';
const link = document.createElement('link');
link.rel = 'preload';
link.as = 'image';
link.href = heroUrl;
link.fetchPriority = 'high';
if (srcset) {
link.imageSrcset = srcset;
link.imageSizes = '100vw';
}
document.head.appendChild(link);
const img = document.createElement('img');
img.src = heroUrl;
img.alt = data.heroAlt || '';
img.width = 1200;
img.height = 630;
img.fetchPriority = 'high';
img.decoding = 'async';
img.className = 'hero';
if (srcset) {
img.srcset = srcset;
img.sizes = '100vw';
}
container.replaceChildren(img);
}
document.addEventListener('DOMContentLoaded', () => {
const root = document.getElementById('hero-root');
if (root) injectHeroImage(root, '/api/hero');
});
Fetch APIにもpriority: 'high' | 'low' | 'auto'がある(RequestInit)。XHRには無い。LCPに直結するJSONより、画像preloadの方が優先されるべきだ。
Intersection Observerとlowの組み合わせ
/**
* カルーセル: 表示スライドのみ auto/high、それ以外は low
*/
function initCarouselPriority(carouselEl) {
const slides = carouselEl.querySelectorAll('[data-slide-image]');
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
const img = entry.target;
if (!(img instanceof HTMLImageElement)) return;
if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
img.fetchPriority = 'high';
img.loading = 'eager';
} else {
img.fetchPriority = 'low';
}
});
},
{ root: carouselEl, threshold: [0, 0.5, 1] }
);
slides.forEach((slide, index) => {
const img = slide.querySelector('img');
if (!img) return;
img.fetchPriority = index === 0 ? 'high' : 'low';
observer.observe(img);
});
}
document.querySelectorAll('[data-carousel]').forEach(initCarouselPriority);
最初のスライドだけhigh、残りはlow——動的UIでも帯域の「松と竹」をコードで表現できる。
フレームワーク別実装 — React / Next.js / Astro
React(JSX)
export function Hero({ src, srcSet, sizes, alt }) {
return (
<img
src={src}
srcSet={srcSet}
sizes={sizes}
alt={alt}
width={1200}
height={630}
fetchPriority="high"
decoding="async"
className="hero-image"
/>
);
}
export function ArticleThumbnail({ src, alt, priority = false }) {
return (
<img
src={src}
alt={alt}
width={400}
height={225}
loading={priority ? 'eager' : 'lazy'}
fetchPriority={priority ? 'auto' : 'low'}
/>
);
}
React 18.2+ / 19ではfetchPriority(camelCase)がDOMプロパティとしてサポートされる。Next.js App Routerの<Image priority />は内部でpreload + 高優先度相当の処理を行う。
Next.js App Router
import Image from 'next/image';
export default function HomePage() {
return (
<main>
{/* priority=true → preload + eager + 高優先度 */}
<Image
src="/hero.webp"
alt="ヒーロー"
width={1200}
height={630}
priority
sizes="100vw"
style={{ width: '100%', height: 'auto' }}
/>
<Image
src="/gallery-1.webp"
alt="ギャラリー"
width={400}
height={300}
loading="lazy"
fetchPriority="low"
/>
</main>
);
}
priority propは1ページに少数に抑える。Next.jsドキュメントもLCP要素1つを推奨している。
Astro
---
// src/components/Hero.astro
const { src, alt, width, height } = Astro.props;
---
<link rel="preload" as="image" href={src} fetchpriority="high" />
<img
src={src}
alt={alt}
width={width}
height={height}
fetchpriority="high"
decoding="async"
loading="eager"
/>
Astroの<Image />コンポーネントを使う場合はloading="eager"と適切なwidth/heightを指定し、LCP候補にはビルド時preloadが注入される設定(preloadオプション)を確認する。
HTTP/2・HTTP/3との関係
fetchpriorityは同一オリジン(または同一接続)内のストリーム優先度を調整する。传输层がHTTP/2やHTTP/3であれば、複数リソースの並列ダウンロード中に「どのストリームを先に処理するか」にヒントが効く。
HTTP/1.1では接続数制限(通常6並列)が支配的で、fetchpriority単体の効果は相対的に小さいことがある。CDNでHTTP/3を有効化し、preconnectで接続確立を短縮したうえでfetchpriorityを使うと、TTFB + ストリーム優先度の両方を最適化できる。
上記は同一ページでの段階改善イメージ(ミリ秒)。環境により差は大きいが、転送層 → preload → fetchpriorityの順で積み上がる典型パターンを示す。
web.dev ベストプラクティスまとめ(2026)
Google web.devおよびChrome Developersが推奨するLCP画像最適化チェックリストを、fetchpriorityの観点で整理する。
- LCP要素を
<img>で配信 — CSSbackground-imageよりマークアップ画像 - 発見可能(Discoverable) — HTMLソースまたはpreloadで早期にURLが分かる
- 適切なサイズ — srcset/sizes、AVIF/WebP、レスポンシブ
- 遅延加载禁止 — LCP imgに
loading="lazy"を付けない - fetchpriority=high — LCP候補1つ
- preload —
<head>内、パース前開始が必要な場合 - CDN + HTTP/2/3 — 接続効率とエッジキャッシュ
- CLS対策 — width/heightまたはaspect-ratio
[object Object]
[object Object]
[object Object]
[object Object]
[object Object]
[object Object]
よくあるアンチパターン
| アンチパターン | 結果 |
|---|---|
全imgにfetchpriority="high" | 優先度 flatten、効果なし |
LCP imgにloading="lazy" | 意図的遅延でLCP大幅悪化 |
| preload URLとimg srcの不一致 | 二重ダウンロード |
| CSS背景のみのヒーロー | LCP計測・preloadが困難 |
| fetchpriorityのみで500KB PNGのまま | Load time支配、総合改善小 |
レスポンシブ画像とfetchpriority
srcset/sizesとpreload属性の整合が、2026年の実装で最もミスが多い。
<head>
<link rel="preload" as="image"
imagesrcset="
/hero-640.webp 640w,
/hero-1280.webp 1280w,
/hero-1920.webp 1920w
"
imagesizes="(max-width: 768px) 100vw, 1280px"
fetchpriority="high">
</head>
<body>
<picture>
<source type="image/avif"
srcset="/hero-640.avif 640w, /hero-1280.avif 1280w"
sizes="(max-width: 768px) 100vw, 1280px">
<source type="image/webp"
srcset="/hero-640.webp 640w, /hero-1280.webp 1280w"
sizes="(max-width: 768px) 100vw, 1280px">
<img src="/hero-1280.webp"
alt="商品メインビジュアル"
width="1280"
height="720"
fetchpriority="high"
decoding="async">
</picture>
</body>
<picture>でAVIFとWebPを併用する場合、preloadはブラウザが実際に選ぶ形式とURLに合わせる必要がある。複雑な場合は単一形式(WebP)に preload を合わせるか、CriticalなLCPだけ<picture>をやめて単一<img srcset>に統一する判断もある。
<video poster> と LCP
動画ヒーローのLCPはposter画像になることが多い。
<video
autoplay
muted
loop
playsinline
poster="/video/hero-poster.webp"
width="1280"
height="720"
fetchpriority="high"
>
<source src="/video/hero.webm" type="video/webm">
<source src="/video/hero.mp4" type="video/mp4">
</video>
<link rel="preload" as="image" href="/video/hero-poster.webp" fetchpriority="high">
動画本体(as=video preload)は帯域を食いLCP posterと競合しうる。posterを先に、動画はpreload="none"またはIntersection後加载が安全。
計測用スクリプト — LCPとリソースの対応付け
Fieldに近い形でLCP要素とリソースURLをログするPerformanceObserver例。
/**
* 本番でも軽量にLCP候補を analytics へ送る例
* (個人情報に注意し、URLのみ送信)
*/
(function observeLcpForPriorityAudit() {
if (!('PerformanceObserver' in window)) return;
const observer = new PerformanceObserver((list) => {
const entries = list.getEntries();
const last = entries[entries.length - 1];
if (!last) return;
const el = last.element;
let resourceUrl = '';
if (el instanceof HTMLImageElement) {
resourceUrl = el.currentSrc || el.src;
} else if (el instanceof HTMLVideoElement) {
resourceUrl = el.poster || '';
}
const payload = {
metric: 'LCP',
value: Math.round(last.startTime),
resourceUrl,
fetchPriority: el && 'fetchPriority' in el ? el.fetchPriority : 'n/a',
id: last.id,
};
if (navigator.sendBeacon) {
navigator.sendBeacon('/analytics/vitals', JSON.stringify(payload));
} else {
console.info('[LCP audit]', payload);
}
observer.disconnect();
});
observer.observe({ type: 'largest-contentful-paint', buffered: true });
})();
fetchPriorityがhighなのにLCPが遅い場合、Load delayではなくTTFBや画像サイズを疑う。逆にautoのまま良好なら、無理にhighを増やさない。
DevTools Network — Priority列の読み方
Networkパネルで画像リクエストを選び、Priority列を表示する(右クリック → Priority)。
| 表示 | 意味(Chrome) |
|---|---|
| Highest | 通常 preload + high |
| High | fetchpriority=high の img 等 |
| Medium | デフォルトの img / script |
| Low | fetchpriority=low |
| Lowest | prefetch 等 |
Initiatorが(index)や行番号付きHTMLならパース後発見。preloadならhead内ディレクティブ経由——Start Timeが早いはずだ。改善後もLCP画像のStartが遅い場合、CSS/同期JSのブロッキングをCRP記事の手順で削る。
キャッシュ(memory cache / disk cache)ヒット時はPriority表示が異なることがある。Cold cache + Disable cache OFF(通常リロード)で計測する。Before/After比較は同じキャッシュ条件で揃える。
セキュリティ・プライバシー上の注意
fetchpriority自体にセキュリティリスクはないが、高優先度で取得するURLにPIIを含めない(例: 署名付きURLのクエリ)。preloadは他ページへの/navigate前には効かない——現在ドキュメント専用。
CSP(Content-Security-Policy)でimg-srcが制限されている場合、preload URLも同一ポリシー内である必要がある。違反するとコンソールエラーとともにpreloadが無視される。
チェックリスト — リリース前の最終確認
Performance Insights で LCP 要素が想定どおりか確認
LCP img に lazy が付いていないか grep
fetchpriority=high が2件以下か確認
preload の imagesrcset/imagesizes が img と一致しているか
width/height で CLS が 0.1 未満か
Below-the-fold 画像に low + lazy を適用したか
Network で LCP リクエストの Priority が High 以上か
Lighthouse LCP が 2.5s 以下(モバイルシミュレーション)か
関連記事
この記事は Webパフォーマンス テーマの一環です。あわせて読むと理解が深まる関連記事をまとめました。
| トピック | 記事 |
|---|---|
| Speculation Rules API 完全ガイド | Speculation Rules API 完全ガイド|prefetch・prerender・Chrome 144 prerender_until_script |
| Web Vitals INP改善ガイド | Web Vitals INP改善ガイド|scheduler.yield・Long Task・Input Delay対策(2026) |
| content-visibility: auto 完全ガイド | content-visibility: auto 完全ガイド|遅延レンダリングと長尺ページ最適化 2026 |
| Server-Timing API 完全ガイド | Server-Timing API 完全ガイド|Express ミドルウェアと Chrome DevTools 連携 |
| Brotli vs Gzip 圧縮比較 | Brotli vs Gzip 圧縮比較|nginx静的・動的設定とCDN実践ガイド |
| CSS/JSを圧縮(Minify)するメリット | CSS/JSを圧縮(Minify)するメリット|サイト高速化の基本 |
| Service Worker キャッシュ戦略ガイド | Service Worker キャッシュ戦略ガイド|PWA の cache-first・network-first・SWR・Workbox 設計 |
| View Transitions API 完全ガイド | View Transitions API 完全ガイド|SPA・MPA ページ遷移と Astro/React 統合 |
| WebP変換で画質が落ちる原因と最適な設定 | WebP変換で画質が落ちる原因と最適な設定 |
| 画像圧縮とWebP変換 | 画像圧縮とWebP変換|PageSpeed改善の基本 |
| Image Compress WebP | Image Compress WebP|画質とサイズのバランス |
| HSTS Preload設定手順 | HSTS Preload設定手順|nginx・Cloudflare実装とhstspreload.org申請ガイド |
まとめ
fetchpriorityは、2026年のWebパフォーマンス最適化において、LCP画像の「帯域競合」を解くための低コスト・高ROIのHTML属性だ。highはLCP候補1つに、lowはそれ以外の装飾やサムネイルに。preloadと併用し、Performance InsightsとNetworkのPriority列で検証する。
転送層はHTTP/2・HTTP/3で整え、描画経路はクリティカルレンダリングパスで短くし、fetchpriorityで同一ページ内の最後の優先度調整を行う——この3層でLCP 2.5秒以内を現実的な目標にできる。
LCP改善後もINP(Interaction to Next Paint)が課題なら、メインスレッド長タスクの分割やSSR hydrationの見直しへ。画像優先度とJS実行のバランスが、2026年のCore Web Vitals全体最適化の鍵になる。