content-visibility: auto 完全ガイド|遅延レンダリングと長尺ページ最適化 2026
content-visibility: autoは、ビューポート外の DOM ブロックのレイアウト・ペイントをスキップし、長尺ページの初期レンダリング時間を劇的に短縮する CSS プロパティだ。contain-intrinsic-sizeとセットで使えば CLS も抑えられる。- ただし LCP 要素には絶対に適用しない——Above-the-fold は クリティカルレンダリングパス最適化 と fetchpriority による LCP 画像最適化 で先に届け、それ以外のセクションを
content-visibilityで遅延描画する——この二段構えが 2026 年の長尺ページ最適化の定石だ。
content-visibility: auto とは
content-visibility は CSS Containment Module Level 2 で定義されたプロパティで、要素の「描画コスト」をブラウザに制御させる仕組みだ。値 auto を指定すると、要素が画面外にある間はレイアウト(Layout)・ペイント(Paint)・合成(Composite)を省略し、ユーザーがスクロールして近づいたタイミングで通常どおり描画する。
従来、長いランディングページやブログ記事、EC の商品一覧では、HTML に含まれるすべてのセクションが初期レンダリングの対象になっていた。1,000 行を超える DOM、数百枚の商品カード、折りたたまれた FAQ アコーディオン——ユーザーが最初に見るのは画面上部の 1 画面分だけなのに、ブラウザはページ末尾までスタイル計算とレイアウトを走らせていた。
content-visibility: auto はこの無駄を CSS だけで断ち切る。JavaScript の Intersection Observer を書かなくても、ブラウザがビューポートとの距離を判断して描画タイミングを遅らせる。
なぜ 2026 年に再注目されているのか
Web Vitals の INP(Interaction to Next Paint) が 2024 年に Core Web Vitals に加わって以降、「初期表示だけでなく、ページ全体のレンダリング負荷」が評価対象になった。長尺ページでは、スクロール前にメインスレッドがレイアウト処理で占有され、ボタンクリックへの応答が遅れる——そんな INP 悪化の一因がオフスクリーン要素の先行レイアウトだ。
同時に、Chrome の RenderingNG アーキテクチャの成熟により content-visibility の安定性が向上し、Firefox 125・Safari 18 での対応が揃った。2026 年時点では、プログレッシブエンハンスメントとして本番導入できる段階に達している。
レンダリングパイプラインと長尺ページのボトルネック
クリティカルレンダリングパス(CRP)では、DOM 構築 → CSSOM → レンダーツリー → レイアウト → ペイントの流れを解説した。content-visibility はこのパイプラインのレイアウト以降に作用する。
| 処理段階 | content-visibility: auto の影響 |
|---|---|
| DOM 構築 | 影響なし。HTML は通常どおりパースされる |
| スタイル計算 | スキップ対象要素は計算を省略(子孫含む) |
| レイアウト | スキップ。メインスレッドの負荷が大幅減 |
| ペイント | スキップ。GPU 転送も不要 |
| 合成 | スキップ。スクロールイン時に実行 |
長尺ページでレイアウトコストが膨らむ典型例は次のとおり。
| ページ種別 | DOM 規模の例 | 初期レイアウトの問題 |
|---|---|---|
| 技術ブログ(8,000 字) | セクション 15、コードブロック 20 | コードのシンタックスハイライト用 span が数千ノード |
| EC カテゴリ一覧 | 商品カード 200 枚 | 各カードの画像サイズ・価格・バッジのレイアウト |
| SaaS ランディング | セクション 12、SVG アイコン 80 | 各セクションの Grid/Flex 計算が連鎖 |
| 管理ダッシュボード | ウィジェット 30 | チャート Canvas・テーブル・フィルタ UI が一括レイアウト |
Google の内部テストでは、content-visibility: auto を長い記事の各セクションに適用した際、初期レンダリング時間が 7 倍高速化した事例が公開されている(コンテンツ量と端末に依存するが、効果の大きさは無視できない)。
3 つの値:visible / hidden / auto
content-visibility には 3 つの値がある。実務で使うのはほぼ auto だが、他の値との違いを押さえておく。
| 値 | 挙動 |
|---|---|
| visible(初期値) | 通常描画。スキップなし |
| hidden | 要素を非表示にしつつ DOM には残す。アクセシビリティツリーからも除外 |
| auto | ビューポート外なら描画スキップ。近づくと描画。DOM・アクセシビリティは維持 |
hidden は visibility: hidden や display: none とは異なり、アクセシビリティツリーからも除外される点に注意が必要だ。タブ切り替え UI で非アクティブパネルを隠す用途には向くが、SEO 対象の本文には使わない。
auto は描画を遅らせるだけで、DOM ツリーとテキストコンテンツは検索エンジンに認識される。これが Intersection Observer + display: none より優れている点だ。
contain-intrinsic-size との組み合わせ
content-visibility: auto 単体では、未描画の要素のサイズが正しく計算されず、次の問題が起きる。
- スクロールバーの長さが短くなる — ページ全体の高さが過小評価される
- CLS(Cumulative Layout Shift)が悪化する — 描画時にコンテンツが突然出現しレイアウトがずれる
- アンカーリンク(
#section-3)のジャンプ先がずれる — 仮の高さがないためスクロール位置が不正確
これを防ぐのが contain-intrinsic-size だ。未描画の間、ブラウザに「この要素はだいたいこのサイズだ」と伝えるプレースホルダーになる。
基本的な CSS パターン
/* ブログ記事の各セクションに適用する基本セット */
.article-section {
content-visibility: auto;
/* 幅は親に追従、高さは推定値 500px */
contain-intrinsic-size: auto 500px;
}
/* 高さがわかっているコンポーネントには明示的な値を */
.product-card {
content-visibility: auto;
contain-intrinsic-size: 280px 360px;
}
/* 可変高さの FAQ ブロック */
.faq-item {
content-visibility: auto;
contain-intrinsic-size: auto 120px;
}
auto キーワード(contain-intrinsic-size: auto 500px の auto)は、一度描画された後の実サイズを記憶し、再び画面外に出たときにその値を使う。Chrome 108 以降で利用可能で、2 回目以降のスクロールで CLS がさらに安定する。
高さの推定値を決める実務手順
- Chrome DevTools → Elements → 対象セクションを選択
- Computed パネルで
heightの実測値を確認 - セクション種別ごとに中央値を取る(例: テキストセクション 480px、画像付き 720px)
contain-intrinsic-sizeに設定し、CLS が 0.1 未満か検証- ずれが大きい場合は値を微調整するか、
min-heightを併用する
初回訪問時は推定値が使われ、一度描画されたセクションは実サイズがキャッシュされる。ランディングページのように再訪が少ないページでは推定値の精度が重要だ。ブログのようにスクロール往復が多いページでは auto キーワードの恩恵が大きい。
LCP への影響と適用境界線
LCP(Largest Contentful Paint) は、ビューポート内で最も大きなコンテンツが描画されるまでの時間だ。2026 年の Core Web Vitals 目標は 2.5 秒以内(75 パーセンタイル)。
content-visibility: auto を LCP 候補に適用すると、ブラウザがその要素の描画を意図的に遅らせるため、LCP が秒単位で悪化する。これは最適化の方向と真逆だ。
LCP 安全ゾーンの設計
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ランディングページ — content-visibility 適用例</title>
<link rel="preload" as="image" href="/images/hero-1200.webp"
imagesrcset="/images/hero-800.webp 800w, /images/hero-1200.webp 1200w"
imagesizes="100vw">
<style>
/* Above-the-fold: content-visibility を付けない */
.hero {
min-height: 70vh;
display: grid;
place-items: center;
background: linear-gradient(135deg, #0f172a 0%, #1e3a5f 100%);
}
.hero img {
width: 100%;
max-width: 1200px;
height: auto;
aspect-ratio: 16 / 9;
object-fit: cover;
border-radius: 12px;
}
.hero h1 {
font-size: clamp(2rem, 5vw, 3.5rem);
color: #f8fafc;
margin-top: 1.5rem;
}
/* Below-the-fold: 遅延レンダリング対象 */
.deferred-section {
content-visibility: auto;
contain-intrinsic-size: auto 600px;
}
</style>
</head>
<body>
<!-- LCP 候補ゾーン: content-visibility 禁止 -->
<section class="hero">
<div>
<img src="/images/hero-1200.webp"
alt="プロダクトのメインビジュアル"
width="1200"
height="675"
fetchpriority="high">
<h1>チームの生産性を 2 倍にするプロジェクト管理</h1>
</div>
</section>
<!-- 以下は遅延レンダリング OK -->
<section class="deferred-section" id="features">
<h2>主な機能</h2>
<p>カンバン、ガントチャート、タイムトラッキングを一体化。</p>
</section>
<section class="deferred-section" id="pricing">
<h2>料金プラン</h2>
<p>スターター、ビジネス、エンタープライズの 3 段階。</p>
</section>
<section class="deferred-section" id="testimonials">
<h2>お客様の声</h2>
<p>導入企業 500 社以上の実績。</p>
</section>
</body>
</html>
LCP 画像には fetchpriority="high" と preload を組み合わせる。詳細は fetchpriority による LCP 画像最適化 を参照。content-visibility はファーストビュー以下のセクションにだけ適用する。
適用境界の目安
| ゾーン | スクロール位置 | content-visibility | 理由 |
|---|---|---|---|
| ヒーロー・ナビ・h1 | 0〜1 画面 | 使わない | LCP・FCP の候補 |
| 機能紹介・第 2 セクション | 1〜2 画面 | 慎重に判断 | 高速スクロールで即表示が必要 |
| 第 3 セクション以降 | 2 画面〜 | auto を適用 | オフスクリーン確定 |
| フッター | ページ末尾 | auto を適用 | 初期レンダリングに無関係 |
CLS への影響と対策
CLS(Cumulative Layout Shift) は、予期しないレイアウトのずれの累積スコアだ。目標は 0.1 未満。
content-visibility: auto は、推定サイズが実サイズと大きく乖離すると CLS を悪化させる。逆に、contain-intrinsic-size を正しく設定すれば、画像の width/height 指定と同様にレイアウトの安定化に貢献する。
CLS 対策の完全 CSS セット
/* セクション単位の遅延レンダリング + CLS 防止 */
.content-section {
content-visibility: auto;
contain-intrinsic-size: auto 500px;
/* 推定値の下限を min-height で補強 */
min-height: 200px;
/* コンテインメントを明示(パフォーマンス向上) */
contain: layout style paint;
}
/* 画像を含むセクションは画像サイズを先に確保 */
.content-section img {
width: 100%;
height: auto;
aspect-ratio: 16 / 9;
object-fit: cover;
}
/* スケルトン UI で視覚的なジャンプを緩和(任意) */
.content-section:not(.cv-rendered) {
background: linear-gradient(
90deg,
#f1f5f9 25%,
#e2e8f0 50%,
#f1f5f9 75%
);
background-size: 200% 100%;
}
@media (prefers-reduced-motion: no-preference) {
.content-section:not(.cv-rendered) {
animation: shimmer 1.5s infinite;
}
}
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
contain: layout style paint は要素の内部レイアウトが外部に影響しないことをブラウザに宣言し、スキップ時の再計算範囲を限定する。content-visibility と併用すると相乗効果がある。
CLS 計測チェックリスト
- Lighthouse の「Avoid large layout shifts」診断を確認
- Chrome DevTools → Performance → Experience トラックで Layout Shift イベントを確認
contain-intrinsic-sizeの推定値を ±20% 以内に収める- Web フォントの FOUT/FOIT が CLS に加算されていないか分離して確認
- 改善後に Field Data(Search Console の Core Web Vitals)を 28 日間追跡
実装パターン 1:技術ブログのセクション分割
長文 MDX ブログでは、<h2> 単位でセクションをラップし、クラスを付与するパターンが最もシンプルだ。
<article class="blog-post">
<header class="post-header">
<!-- Above-the-fold: content-visibility なし -->
<h1>content-visibility: auto 完全ガイド</h1>
<p class="post-meta">2026年6月22日 · 読了 12 分</p>
<p class="post-lead">
長尺ページの初期レンダリングを CSS だけで高速化する実践ガイド。
</p>
</header>
<section class="cv-section">
<h2>content-visibility とは</h2>
<p>CSS Containment Module Level 2 で定義されたプロパティで、ビューポート外の描画をスキップする。</p>
<pre><code>content-visibility: auto;</code></pre>
</section>
<section class="cv-section">
<h2>contain-intrinsic-size の役割</h2>
<p>未描画時のプレースホルダーサイズを指定し、CLS を防ぐ方法を解説する。</p>
</section>
<section class="cv-section">
<h2>LCP への影響</h2>
<p>LCP 要素には適用せず、Above-the-fold は通常描画のままにする。</p>
</section>
<section class="cv-section">
<h2>実装パターン集</h2>
<p>ブログ、EC、ダッシュボード別の実装パターンをコード付きで紹介する。</p>
</section>
</article>
.blog-post .post-header {
margin-bottom: 2rem;
padding-bottom: 1.5rem;
border-bottom: 1px solid #e2e8f0;
}
.blog-post .cv-section {
content-visibility: auto;
contain-intrinsic-size: auto 480px;
contain: layout style paint;
margin-bottom: 3rem;
padding: 1rem 0;
}
.blog-post .cv-section h2 {
font-size: 1.75rem;
margin-bottom: 1rem;
color: #0f172a;
}
.blog-post .cv-section pre {
background: #1e293b;
color: #e2e8f0;
padding: 1.25rem;
border-radius: 8px;
overflow-x: auto;
font-size: 0.875rem;
line-height: 1.6;
}
Astro や Next.js の MDX コンポーネントで <Section> ラッパーを用意すれば、記事ごとにクラスを付け忘れるミスを防げる。
実装パターン 2:EC 商品一覧のカードグリッド
商品カードは DOM ノード数が膨大になりやすい。カード単位で content-visibility を適用すると効果が高い。
<ul class="product-grid">
<li class="product-card">
<a href="/products/aurora-headphones">
<img src="/images/products/aurora-thumb.webp"
alt="Aurora ワイヤレスヘッドホン"
width="280"
height="280"
loading="lazy">
<h3 class="product-name">Aurora ワイヤレスヘッドホン</h3>
<p class="product-price">¥24,800</p>
<span class="product-badge">送料無料</span>
</a>
</li>
<li class="product-card">
<a href="/products/nimbus-keyboard">
<img src="/images/products/nimbus-thumb.webp"
alt="Nimbus メカニカルキーボード"
width="280"
height="280"
loading="lazy">
<h3 class="product-name">Nimbus メカニカルキーボード</h3>
<p class="product-price">¥18,500</p>
<span class="product-badge">新着</span>
</a>
</li>
<li class="product-card">
<a href="/products/cascade-monitor">
<img src="/images/products/cascade-thumb.webp"
alt="Cascade 4K モニター"
width="280"
height="280"
loading="lazy">
<h3 class="product-name">Cascade 4K モニター 27インチ</h3>
<p class="product-price">¥49,800</p>
<span class="product-badge">人気</span>
</a>
</li>
</ul>
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
gap: 1.5rem;
list-style: none;
padding: 0;
margin: 2rem 0;
}
.product-card {
content-visibility: auto;
contain-intrinsic-size: 280px 380px;
contain: layout style paint;
background: #ffffff;
border: 1px solid #e2e8f0;
border-radius: 12px;
overflow: hidden;
transition: box-shadow 0.2s ease;
}
.product-card:hover {
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
}
.product-card a {
display: block;
text-decoration: none;
color: inherit;
padding: 1rem;
}
.product-card img {
width: 100%;
height: auto;
aspect-ratio: 1 / 1;
object-fit: cover;
border-radius: 8px;
}
.product-name {
font-size: 1rem;
font-weight: 600;
margin: 0.75rem 0 0.25rem;
color: #0f172a;
}
.product-price {
font-size: 1.125rem;
font-weight: 700;
color: #dc2626;
margin: 0;
}
.product-badge {
display: inline-block;
margin-top: 0.5rem;
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
background: #eff6ff;
color: #2563eb;
border-radius: 4px;
}
loading="lazy" はネットワーク取得を遅延し、content-visibility: auto はレイアウト・ペイントを遅延する。両方併用して問題ない。
実装パターン 3:管理ダッシュボードのウィジェット
ダッシュボードは初期表示時に画面内にあるウィジェットと、スクロールしないと見えないウィジェットが混在する。画面内のウィジェットは除外し、Below-the-fold だけに適用する。
<div class="dashboard">
<div class="dashboard-row">
<div class="widget widget-kpi" data-priority="critical">
<h2>今月の売上</h2>
<p class="kpi-value">¥12,450,000</p>
<p class="kpi-change">前月比 +8.3%</p>
</div>
<div class="widget widget-kpi" data-priority="critical">
<h2>アクティブユーザー</h2>
<p class="kpi-value">3,842</p>
<p class="kpi-change">前月比 +2.1%</p>
</div>
</div>
<div class="dashboard-row">
<div class="widget widget-chart cv-defer">
<h2>週次トラフィック</h2>
<canvas id="traffic-chart" width="600" height="300"></canvas>
</div>
<div class="widget widget-chart cv-defer">
<h2>コンバージョン率</h2>
<canvas id="conversion-chart" width="600" height="300"></canvas>
</div>
</div>
<div class="dashboard-row">
<div class="widget widget-table cv-defer">
<h2>最近の注文</h2>
<table>
<thead>
<tr>
<th>注文ID</th>
<th>顧客</th>
<th>金額</th>
<th>状態</th>
</tr>
</thead>
<tbody>
<tr>
<td>ORD-20260622-001</td>
<td>山田太郎</td>
<td>¥15,800</td>
<td>発送済</td>
</tr>
<tr>
<td>ORD-20260622-002</td>
<td>佐藤花子</td>
<td>¥8,200</td>
<td>処理中</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
.dashboard {
display: flex;
flex-direction: column;
gap: 1.5rem;
padding: 1.5rem;
background: #f8fafc;
min-height: 100vh;
}
.dashboard-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 1.5rem;
}
.widget {
background: #ffffff;
border: 1px solid #e2e8f0;
border-radius: 12px;
padding: 1.5rem;
}
.widget h2 {
font-size: 1rem;
font-weight: 600;
color: #64748b;
margin: 0 0 1rem;
}
.widget-kpi .kpi-value {
font-size: 2.25rem;
font-weight: 700;
color: #0f172a;
margin: 0;
}
.widget-kpi .kpi-change {
font-size: 0.875rem;
color: #16a34a;
margin: 0.5rem 0 0;
}
.widget.cv-defer {
content-visibility: auto;
contain-intrinsic-size: auto 400px;
contain: layout style paint;
}
.widget-table table {
width: 100%;
border-collapse: collapse;
font-size: 0.875rem;
}
.widget-table th,
.widget-table td {
padding: 0.75rem 1rem;
text-align: left;
border-bottom: 1px solid #e2e8f0;
}
.widget-table th {
font-weight: 600;
color: #64748b;
background: #f8fafc;
}
チャートの Canvas 描画は cv-defer ウィジェットが画面内に入ったタイミングで実行すればよい。Intersection Observer で new Chart() を呼ぶ既存コードと組み合わせると、レンダリングスキップ + JS 実行遅延の二重最適化になる。
@supports によるプログレッシブエンハンスメント
古いブラウザ向けに、対応ブラウザだけ content-visibility を有効にする。
/* フォールバック: 全ブラウザで通常表示 */
.deferred-section {
margin-bottom: 2rem;
padding: 1.5rem 0;
}
/* content-visibility 対応ブラウザのみ遅延レンダリング */
@supports (content-visibility: auto) {
.deferred-section {
content-visibility: auto;
contain-intrinsic-size: auto 500px;
contain: layout style paint;
}
}
対応していないブラウザでは従来どおり全セクションが描画される。パフォーマンス改善はボーナス扱いとなり、表示崩れのリスクはない。
DevTools での計測と効果検証
最適化の前後で数値を比較しないと、「体感的に速い」だけで終わってしまう。
Chrome DevTools → Performance → ページをリロードし、Layout・Paint イベントの合計時間を記録する
content-visibility: auto を適用し、同じ条件で再度 Performance 記録を取る
Lighthouse の Performance スコアと LCP・CLS・INP を改善前後で比較する
Rendering パネル(More tools → Rendering)で 'Paint flashing' を有効にし、スキップされているセクションを視覚確認する
Search Console → エクスペリエンス → Core Web Vitals で Field Data の変化を 28 日後に確認する
改善イメージ(Layout + Paint 時間)
数値は端末・ページ内容に依存するが、長尺ページでは Layout + Paint が 50〜70% 削減されるケースは珍しくない。一方で LCP は Above-the-fold の最適化(CRP 最適化、fetchpriority)で別途改善する必要がある。
Performance パネルの見方
- Main スレッドのフラメチャート — 細かい Layout イベント(紫色)が初期ロード時に密集していないか
- Bottom-Up タブ —
LayoutとPaintの Self Time 合計を確認 - Timings トラック — LCP マーカーが遅延していないか
- Experience トラック — Layout Shift が
contain-intrinsic-size適用後に減っているか
Intersection Observer・仮想スクロールとの比較
| 手法 | 実装コスト | DOM | SEO | レイアウトスキップ | 向いているケース |
|---|---|---|---|---|---|
| content-visibility: auto | CSS のみ | 全ノード保持 | 問題なし | ブラウザネイティブ | 長文・中規模一覧 |
| Intersection Observer | JS 必要 | 全ノード保持 | 問題なし | 自前実装 | 遅延 JS 実行・広告 |
| 仮想スクロール | 高 | 表示分のみ | 要注意 | DOM ごと省略 | 数万行テーブル |
| loading=lazy | HTML 属性 | 全ノード保持 | 問題なし | 画像取得のみ | 画像・iframe |
数万件のデータテーブルでは仮想スクロール(react-window、TanStack Virtual)が依然として必要だ。数百〜数千要素の長尺ページでは、content-visibility の方が実装コスト対効果が高い。
よくある落とし穴と回避策
1. LCP 要素への誤適用
グローバル CSS で section { content-visibility: auto; } と書くと、ヒーローセクションも遅延対象になる。クラスベースで明示的に制御する。
2. position: sticky との干渉
content-visibility: auto が付いた祖先の内部では position: sticky が期待どおり動かないことがある。スティッキーヘッダーは content-visibility の外に出す。
3. アンカーリンクのずれ
#pricing への直リンクで、推定高さが実高さと異なるとジャンプ位置がずれる。重要なアンカー先セクションは contain-intrinsic-size の精度を上げるか、scroll-margin-top で補正する。
.deferred-section {
content-visibility: auto;
contain-intrinsic-size: auto 600px;
scroll-margin-top: 80px;
}
4. 印刷時の非表示
content-visibility: auto の未描画セクションは印刷時に欠ける可能性がある。印刷スタイルで無効化する。
@media print {
.deferred-section,
.cv-section,
.product-card,
.widget.cv-defer {
content-visibility: visible;
contain-intrinsic-size: none;
}
}
5. アニメーションのちらつき
画面外から入った瞬間に CSS アニメーションが最初から再生される。animation-timeline: view() や Intersection Observer との併用を検討する。
フレームワーク別の導入メモ
Astro
.astro コンポーネントでセクションラッパーを作成し、MDX から利用する。Astro は静的 HTML を出力するため、CSS の content-visibility がそのまま効く。クライアント JS 不要。
Next.js / React
Server Component で HTML を生成し、CSS Modules または Tailwind の @apply で content-visibility を付与する。Client Component 内の動的リストには仮想スクロールとの併用を検討。
Tailwind CSS v4
@utility cv-auto {
content-visibility: auto;
contain-intrinsic-size: auto 500px;
contain: layout style paint;
}
<section class="cv-auto mb-12">
<h2>機能紹介</h2>
<p>セクション本文がここに入る。</p>
</section>
Tailwind の @utility で再利用可能なクラスを定義しておくと、チーム全体で適用基準を統一しやすい。
パフォーマンス予算との組み合わせ
2026 年のフロントエンドチームでは、パフォーマンス予算(Performance Budget) を CI に組み込むケースが増えている。content-visibility 導入後の目安値は次のとおり。
| 指標 | 長尺ページの目安 | content-visibility 適用後の期待 |
|---|---|---|
| LCP | 2.5s 以内 | 変化なし(Above-the-fold は別最適化) |
| INP | 200ms 以内 | 10〜30% 改善(メインスレッド空き時間増加) |
| CLS | 0.1 未満 | intrinsic-size 次第。要検証 |
| TBT(Total Blocking Time) | 200ms 以内 | 20〜50% 改善の事例あり |
| Layout 時間(Lab) | ページ依存 | 50% 以上削減も |
LCP は クリティカルレンダリングパス最適化 と fetchpriority 画像最適化 で、オフスクリーンの描画コストは content-visibility で——責務を分離することが重要だ。
関連記事
この記事は Webパフォーマンス テーマの一環です。あわせて読むと理解が深まる関連記事をまとめました。
| トピック | 記事 |
|---|---|
| HTTP/2とHTTP/3の違い | HTTP/2とHTTP/3の違い|QUICが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) |
| 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改善の基本 |
| CSS Container Queries 完全ガイド | CSS Container Queries 完全ガイド|@container・size vs inline-size・コンポーネント単位レスポンシブ |
| HTML Popover API 完全ガイド | HTML Popover API 完全ガイド|popover・popovertarget・light dismiss・アクセシビリティ |
まとめ
content-visibility: auto は、2026 年時点で長尺ページの初期レンダリングを改善する最もコストパフォーマンスの高い CSS テクニックの一つだ。
実装の要点を整理する。
- Above-the-fold には適用しない — LCP・FCP を守る
contain-intrinsic-sizeを必ずセット — CLS とスクロールバーを安定させるcontain: layout style paintで効果を最大化 — 再計算範囲を限定@supportsでフォールバック — 非対応ブラウザでも安全@media printで印刷対応 — 未描画セクションの欠落を防ぐ- DevTools と Field Data で検証 — Lab と実ユーザー指標の両方を追う
JavaScript を追加せず、CSS 数行で数百ミリ秒〜数秒の改善が見込める。まずはブログ記事やランディングページの第 3 セクション以降に .cv-section クラスを付け、contain-intrinsic-size: auto 500px から始めてほしい。効果を計測したうえで、EC 一覧やダッシュボードへ展開するのが安全な導入パスだ。
content-visibility は「見えない部分の描画を遅らせる」道具であり、LCP 要素を速くする道具ではない。LCP 改善は preload・fetchpriority・CRP 最適化で行い、content-visibility はその下のセクションに使う——この役割分担を守れば、Core Web Vitals を総合的に改善できる。