TBTの改善方法を解説!6つの施策をわかりやすく紹介!

TBTの改善方法を解説!6つの施策をわかりやすく紹介!

TBT(Total Blocking Time)はFCP(初回コンテンツ表示)からTTI(操作可能時間)になるまでの時間を測定する指標です。

このページではTBTの改善の6つの施策をわかりやすく解説します。

TBTの仕組みや内容を把握したい方は「TBTとは」の記事をご覧ください。

TBT(Total Blocking Time)を改善させる6つの方法

TBT(Total Blocking Time)を改善させる6つの方法を解説していきます。

  1. JavaScript の最適化
  2. メインスレッド最適化
  3. リソース最適化
  4. 画像・メディアファイルの最適化
  5. サードパーティスクリプトの最適化
  6. HTML構造の最適化

下記で1つ1つ解説していきます。

1. JavaScript の過度な使用・最適化不足

TBT(Total Blocking Time)は、メインスレッドがブロックされている時間の合計を測定する指標でページの応答性を評価します。

JavaScriptの実行がメインスレッドをブロックすると、ユーザーの操作に対する応答が遅れ、TBTスコアが悪化します。

JavaScriptの使用に関しては、下記のポイントを意識して使用するとTBT改善につながります。

JavaScriptの最適化について詳しくは「JavaScriptの速度改善方法」もご覧ください。

JavaScriptの実行タイミングを遅延させる

TBT(Total Blocking Time)は、FCP(初回コンテンツ表示)からTTI(操作可能時間)が計算されることになります。

どうしても必要なJavaScript以外は実行タイミングを遅延させることで、TBTの計測から外すことができます。

JavaScript実行は、必要な要素とタイミングをコントロールすることで、かなりTBT数値の改善余地があります。

例えば、下記のようにasync属性やdefer属性を使ってコントロールするといいでしょう。

<!-- 通常のスクリプト(ブロッキング) -->
<script src="script.js"></script>

<!-- async: 並行ダウンロード、完了次第実行 -->
<script src="script.js" async></script>

<!-- defer: 並行ダウンロード、HTML解析完了後に実行 -->
<script src="script.js" defer></script>

特にJavaScriptは何も制御しないと、基本的に全て動いてしまうため処理時間のかかる要因となるため、細かく設定してあげましょう。

例えばアコーディオンのタグなど、手動で動かす時以外は動かさないといったように細かく指定してあげるといいでしょう。

JavaScriptの計算や実行を最適化させる

ここでいうJavaScriptの圧縮・最小化というのは、JavaScriptの計算量を減らすことを指します。

極力、JavaScriptの計算などを減らしてあげることで、TBT(Total Blocking Time)の改善につながります。

大きなポイントとしては下記があります。

演算子の簡略化

論理演算子(&&, ||)や三項演算子(?:)、Optional Chaining(?.)を活用することで、条件評価の回数を削減し、短絡評価によって不要な処理をスキップできます。

これにより処理時間が短縮され、メインスレッドのブロック時間が減少し、TBTスコアが改善されます。

論理演算子(&&, ||)のサンプルソース

// 遅い書き方
 function showMessage(user) {
 if (user.isLoggedIn) {
 displayWelcome(user.name); 
}

 if (!user.hasNotifications) {
 hideNotificationBell();
 }
 }

// 速い書き方(短絡評価)
 function showMessage(user) {
 user.isLoggedIn && displayWelcome(user.name);
 !user.hasNotifications && hideNotificationBell();
 }

三項演算子(?:)のサンプルソース

// 遅い書き方
function getButtonText(isLoading, isSuccess) {
    let text;
    if (isLoading) {
        text = '読み込み中...';
    } else if (isSuccess) {
        text = '完了';
    } else {
        text = '送信';
    }
    return text;
}

// 速い書き方
function getButtonText(isLoading, isSuccess) {
    return isLoading ? '読み込み中...' : 
           isSuccess ? '完了' : '送信';
}

Optional Chaining(?.)のサンプルソース

// 遅い書き方
function getUserCity(user) {
    if (user && user.address && user.address.city) {
        return user.address.city;
    }
    return '未設定';
}

// 速い書き方
function getUserCity(user) {
    return user?.address?.city ?? '未設定';
}

この効率化により、メインスレッドのブロック時間が短縮されます。

改善できる部分があれば、是非、実践してみましょう。

ループの最適化

ループの最適化は、繰り返し処理における無駄な計算の削除によってTBT改善を実現します。

最も重要な改善は配列の長さ計算の事前実行する方法があります。

ループ最適化のサンプルソース

// 最適化前(毎回length計算)
for (let i = 0; i < items.length; i++) {
    process(items[i]);
}

// 最適化後(length事前計算)
for (let i = 0, len = items.length; i < len; i++) {
    process(items[i]);
}

「for (let i = 0; i < array.length; i++)」という一般的な書き方では、ループの各回で配列の長さを再計算します。

配列に1000個の要素がある場合、1000回の不要な計算が発生し、これらすべてがメインスレッドをブロックします。

「for (let i = 0, len = array.length; i < len; i++)」という最適化により、長さ計算を一度だけ実行し、残りは単純な数値比較に変換できます。

さらに、適切なループメソッドの選択も重要です。

ループメソッドのソース例

// 最適化前(手動ループ)
for (let i = 0; i < users.length; i++) {
    if (users[i].active) {
        sendNotification(users[i]);
    }
}

// 最適化後(メソッドチェーン)
users.filter(user => user.active).forEach(sendNotification);

手動のforループから配列メソッドへの変換により、JavaScriptエンジンの内部最適化を活用できます。

エンジンは「forEach」や「map」などのネイティブメソッドを高度に最適化しており、手動ループよりも効率的な実行が可能です。

JavaScriptのコード分割

コード分割は、大きなJavaScriptファイルを小さな部分に分けて必要な時に必要な分だけ読み込む手法です。

これによりTBTのタスク自体も分割され、初期ロード時のメインスレッドブロック時間を大幅に削減しTBTスコアを改善できます。

例えば、もともと100ミリ秒あったタスクが分割することによって50ミリ秒のファイルが2つに分かれればTBTの数値は0となります。

改善方法としては、動的インポート、ルートベース分割、機能ベース分割などがあります。

動的インポートのソース例

// 最適化前
import Chart from './chart.js';

// 最適化後  
async function showChart() {
  const { default: Chart } = await import('./chart.js');
  new Chart().render();
}

動的インポートは、JavaScript の import() 関数を使用して、必要な時にのみモジュールを読み込む手法です。

従来は、すべてのモジュールを初期ロード時に同期読み込みをしますが、必要なタイミングでモジュールを非同期読み込みする方法でTBT改善につながります。

ルートベース分割のソース例

// 最適化前
import HomePage from './home.js';
import ProductPage from './product.js';

// 最適化後
const routes = {
  '/': () => import('./home.js'),
  '/product': () => import('./product.js')
};

ルートベース分割は、Webアプリケーションの各ページ(ルート)ごとにJavaScriptコードを分離する手法となります。

従来は全ページのコードを初期ロード時に読み込みますが、現在表示中のページのコードのみの読み込みに変える方法です。

機能ベース分割のソース例

// 最適化前:全機能を初期ロード
class UserDashboard {
    constructor() {
        this.setupBasicFeatures();
        this.setupAdvancedAnalytics();  // 重いライブラリ
        this.setupExportFeatures();     // 重いライブラリ
        this.setupChatSupport();        // 重いライブラリ
    }
}

// 最適化後:機能別に遅延ロード
class UserDashboard {
    constructor() {
        this.setupBasicFeatures();  // 軽い基本機能のみ
    }
    
    async loadAnalytics() {
        if (!this.analytics) {
            const { Analytics } = await import('./features/analytics.js');
            this.analytics = new Analytics();
        }
        return this.analytics;
    }
    
    async loadExportFeatures() {
        if (!this.exporter) {
            const { Exporter } = await import('./features/exporter.js');
            this.exporter = new Exporter();
        }
        return this.exporter;
    }
}

機能ベース分割は、アプリケーションの機能単位でJavaScriptコードを分離し、ユーザーが実際に使用する機能のみを動的に読み込む手法です。

従来はすべての機能(基本機能・高度な分析・エクスポート・チャット等)を初期ロード時に読み込み、大量のJavaScriptがメインスレッドをブロックしますが、この方法で不要な機能の読み込みを回避し、パフォーマンスを最適化できます。

2.メインスレッド最適化

メインスレッドは、JavaScript実行、DOM操作、ユーザーイベント処理を担当します。

下記のような最適化により、メインスレッドのブロック時間を削減し、ユーザー操作への応答性を向上させ、TBTスコアを大幅に改善できます。

Web Workersの活用

従来、素数計算や画像処理などの重い計算をメインスレッドで実行すると、数秒間ユーザー操作に応答できなくなりTBTスコアが大幅に悪化していました。

Web Workersを活用することで、これらの処理を専用スレッドに分離することで、並列処理ができるようになります。

そうすることで、メインスレッドは常にユーザーイベントやDOM更新に専念することができTBTスコアも大きく改善されます。

Web Workersの活用例

// main.js
function calculateWithWorker(numbers) {
    const worker = new Worker('worker.js');
    
    // データを送信
    worker.postMessage(numbers);
    
    // 結果を受信
    worker.onmessage = function(e) {
        console.log('計算結果:', e.data);
        worker.terminate(); // Worker終了
    };
}

// 実行
calculateWithWorker([1, 2, 3, 4, 5]);

まず、Worker用のスクリプトを用意しインスタンス化させます。

上記のソースでいう(worker.js)の部分。

インスタンスさせ、Workerファイルで並列処理を行います。

workerファイルのソース例

// worker.js (Workerファイル)
self.onmessage = function(e) {
    const numbers = e.data;
    
    // 重い計算処理
    let sum = 0;
    for (let num of numbers) {
        sum += num * num; // 二乗の合計
    }
    
    // 結果を返送
    self.postMessage(sum);
};

上記のソースで並行処理を行なった後に、結果を返すような仕組みとなります。

タスクの分割をする

タスクの分割は、長時間実行される重い処理を小さなチャンクに分けて、メインスレッドのブロック時間を削減する手法です。

1つのタスクが50ミリ秒以上かかっているものは、タスク分割の方法を活用することでTBTがかなり改善されます。

setTimeoutやrequestIdleCallbackを使用した方法を解説していきます。

setTimeoutを使用したタスク分割の例

setTimeoutを使用したタスク分割は、重い処理を小さなチャンクに分けて、各チャンク間でメインスレッドを解放する手法です。

従来の問題点として、10万件のデータを一度に処理すると200ms以上メインスレッドがブロックされ、ユーザー操作に応答できません。

改善方法では、データを1000件ずつのチャンクに分割し、各チャンク処理後にsetTimeout(resolve, 0)を実行してメインスレッドを一時的に解放します。

下記がソース例です。

// 最適化前:一度に全処理
function processAllData(data) {
    const results = [];
    
    // 10万件を一度に処理(約200ms)
    for (let i = 0; i < data.length; i++) {
        results.push(data[i] * 2);
    }
    
    return results;
}

// 最適化後:setTimeout で分割
async function processDataWithTimeout(data) {
    const results = [];
    const chunkSize = 1000;  // 1000件ずつ処理
    
    for (let i = 0; i < data.length; i += chunkSize) {
        const chunk = data.slice(i, i + chunkSize);
        
        // チャンクを処理
        for (let j = 0; j < chunk.length; j++) {
            results.push(chunk[j] * 2);
        }
        
        // メインスレッドを解放
        await new Promise(resolve => setTimeout(resolve, 0));
    }
    
    return results;
}

// 使用例
const bigData = Array.from({length: 100000}, (_, i) => i + 1);
processDataWithTimeout(bigData).then(results => {
    console.log('処理完了:', results.length);
});

これにより、ブラウザは他のタスク(ユーザーイベント処理、DOM更新、再描画)を実行する機会を得られます。

各チャンクの処理時間を50ms未満に抑制することで、TBTスコアが大幅に改善され、ページの応答性が向上します。

requestIdleCallbackを使用したタスク分割の例

requestIdleCallback は、ブラウザのアイドル時間を活用してタスクを分割実行する高度な最適化手法です。

従来のsetTimeoutによる分割では固定間隔でメインスレッドを解放しますが、requestIdleCallbackはブラウザが「空き時間がある」と判断した時のみ処理を実行します。

下記がソース例となります。

// より効率的なアイドル時間活用
function processDataWhenIdle(data) {
    return new Promise((resolve) => {
        const results = [];
        let currentIndex = 0;
        
        function processChunk(deadline) {
            // アイドル時間がある限り処理を続行
            while (deadline.timeRemaining() > 0 && currentIndex < data.length) {
                results.push(heavyCalculation(data[currentIndex]));
                currentIndex++;
            }
            
            // まだ処理が残っている場合
            if (currentIndex < data.length) {
                requestIdleCallback(processChunk);
            } else {
                // 処理完了
                resolve(results);
            }
        }
        
        // 最初の処理を開始
        if ('requestIdleCallback' in window) {
            requestIdleCallback(processChunk);
        } else {
            // フォールバック
            setTimeout(() => processChunk({ timeRemaining: () => 5 }), 0);
        }
    });
}

deadline.timeRemaining()でアイドル時間を確認し、時間がある限り処理を継続、時間切れになると自動的に次のアイドル時間まで待機します。

これにより、重要なユーザーインタラクションや描画処理を最優先に実行しながら、空き時間で重い処理を効率的に進められます。

ブラウザのフレーム更新(16.67ms)に影響を与えず、TBTスコアをより効果的に改善できる賢い分割手法です。

3.リソース最適化

リソース最適化では、JavaScript以外の遅延読み込みレンダリングの遅延、レイアウトの最適化をすることでTBT数値の改善をしていきます。

具体的な改善方法を解説していきます。

JavaScript以外遅延読み込み

TBT(Total Blocking Time)を改善するため、JavaScript以外のリソースを遅延読み込みさせる手法です。

画像にloading="lazy"属性、iframeやYouTube埋め込みに遅延読み込みを適用し、重要でないCSSを非同期で読み込みます。

フォントはfont-display: swapで最適化します。

これによりメインスレッドのブロック時間を短縮し、初期表示速度とページ応答性が向上します。

ただし、LCPに関わるファーストビューで必要な要素は遅延させず、適切な優先順位設定が重要です。

レンダリングの遅延の実施

レンダリングを遅延読み込みさせることで、初期表示に必要のない要素の描画処理を後回しにし、メインスレッドの負荷を軽減します。

また、重要でないアニメーションや複雑なレイアウト計算を遅延させ、ユーザーが実際に必要とするタイミングでレンダリングを実行することで、初期ページロード時の応答性を大幅に向上させることができます。

具体的には下記のような対策が可能です。

content-visibilityプロパティの活用

content-visibilityは、要素のレンダリングを制御するCSSプロパティです。

auto値を指定すると、画面外の要素の描画処理をスキップし、メインスレッドの負荷を大幅に軽減します。

content-visibilityのソース例

.section {
  content-visibility: auto;
  contain-intrinsic-size: 500px;
}

contain-intrinsic-sizeで仮想サイズを指定することで、レイアウトシフトを防止します。

複雑なコンテンツや長いページで特に効果的で、初期レンダリング時間を削減可能です。

スクロール時に必要な要素のみ描画するため、TBT改善とパフォーマンス向上を同時に実現できます。

Intersection Observer API実装

Intersection Observer APIは、要素がビューポートに入るタイミングを効率的に監視するJavaScript APIです。

従来のscrollイベントと異なり、メインスレッドをブロックせずに非同期で動作します。

Intersection Observer API実装例

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      // 要素が見える時のみ処理実行
      loadContent(entry.target);
      observer.unobserve(entry.target);
    }
  });
}, { rootMargin: '100px' });

document.querySelectorAll('.lazy-load').forEach(el => {
  observer.observe(el);
});

rootMarginで先読み範囲を調整し、画像遅延読み込み、無限スクロール、アニメーション制御に活用できます。

レイアウト最適化

レイアウト最適化は、DOM操作とリフロー・リペイントを最小化してTBTを改善する手法です。

主な戦略として、仮想化リストでは大量データの可視範囲のみをレンダリングしメモリ使用量を削減します。

仮想化実装の例

// 仮想化実装例
const visibleItems = items.slice(startIndex, endIndex);
container.innerHTML = visibleItems.map(renderItem).join('');

Progressive Enhancementでは、基本コンテンツを先行表示し、装飾要素を段階的に追加します。

レイアウトシフト防止のため、要素サイズを事前定義し、transformopacityを優先使用してGPU処理を活用。

これにより初期表示速度を向上させ、ユーザー操作の応答性を大幅に改善できます。

4.画像・メディアファイルの最適化

大容量ファイルの同期読み込みと画像デコード処理がメインスレッドを長時間ブロックし、ユーザー操作の応答性を著しく低下させ、TBTの数値も悪化させます。

主に挙げられる問題点としては下記の要素があります。

  • loading="lazy"属性の未実装
  • 非効率な画像フォーマット(JPEG/PNG)の使用
  • 画像サイズの未最適化(実表示サイズより大きい画像)
  • デコード処理の同期実行による画面フリーズ

これらの改善方法を下記で説明していきます。

遅延読み込みの実施

画像・メディアファイルの遅延読み込みは、TBT改善の最も効果的な手法の一つです。

初期ページロード時に画面外の画像読み込みを回避することで、メインスレッドのブロック時間を大幅に削減します。

遅延読み込みソース例

<img src="placeholder.jpg" data-src="actual-image.jpg" loading="lazy" alt="説明">
<iframe src="video.html" loading="lazy"></iframe>

loading="lazy"属性により、ブラウザが自動的にスクロール位置を監視し、必要なタイミングで読み込みを実行します。

動画ファイルも同様に遅延読み込みが可能で、自動再生による初期負荷を防げます。

画像フォーマットの最適化

フォーマット最適化においては、次世代画像フォーマットのWebPやAVIFの採用が効果的です。

これらのフォーマットはネットワーク転送時間とデコード処理時間の両方を短縮します。

picture要素とsource要素を組み合わせることで、ブラウザサポートに応じたフォーマットの自動選択も実現できます。

ソース例

<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="説明">
</picture>

画像サイズの最適化

画像サイズ最適化は、不要なデータ転送とデコード処理を削減し、TBT改善に直接的な効果をもたらします。

多くのサイトで実表示サイズより大きな画像をCSSで縮小表示していますが、これはメインスレッドに不要な負荷をかけます。

  • 実表示サイズに合わせた適切なリサイズ
  • レスポンシブ画像(srcset)でデバイス別最適化
  • 高解像度ディスプレイ対応(2x、3x)の適切な設定

実装例

<img srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w" 
sizes="(max-width: 600px) 480px, (max-width: 900px) 800px,  1200px" src="medium.jpg" alt="説明">

レスポンシブ画像のsrcset属性を活用し、デバイスの画面サイズや解像度に応じた最適な画像を配信することで、処理負荷を大幅に軽減できます。

デコード処理の最適化

画像デコード処理は、画像データを表示可能な形式に変換する計算集約的なタスクで、メインスレッドを長時間ブロックしTBT悪化の主要因となります。

特に高解像度画像では数百ミリ秒のブロック時間が発生し、ユーザー操作の応答性を著しく低下させます。

改善方法としてdecoding="async"属性により、デコード処理を別スレッドに移行し、メインスレッドのブロックを回避できます。

ソース例

<img src="image.jpg" decoding="async" loading="lazy" alt="説明">

5. サードパーティスクリプトの最適化

サードパーティスクリプトは外部サーバーからの読み込みが必要で、そのサーバーの応答速度によっては大きな遅延を引き起こします。

特に当てはまるのが、以下のようなサードパーティスクリプトを使用しているケースがあります。

  • Google Analytics や Google Tag Manager
  • SNSのシェアボタン
  • 広告配信システム
  • チャットボットツール
  • A/Bテストツール

こちらの対策として下記のような方法があります。

不要ツールの削除

使用していないサードパーティスクリプトを削除するということも、TBT改善になります。

現在使用しているサードパーティスクリプトを一つずつ見直し、本当に必要なものだけを残します。

特に以下の点を確認してください。

  • 実際に使用されているか
  • 代替手段はないか
  • 同じ機能を持つより軽量なツールはないか

よくあるのがGoogle Tag Managerの中に全く使っていないタグが大量にあるケースで、必要なものと使用していないものを整理するのもおすすめです。

読み込みタイミングの調整

サードパーティスクリプトの重要度に応じて読み込みタイミングを調整する工夫もできます。

調整することでTBTのタスク計測から外せる場合もあり、TBT数値も改善できます。

方法としては、遅延読み込みさせる方法や、ユーザーインタラクション(スクロールやクリック)後に読み込ませる方法などがあります。

遅延読み込みで遅らせる方法

遅延読み込みは、特にGoogle Analytics、広告計測タグ、チャットウィジェット、A/Bテストツールなど、ユーザーの直接的な体験に影響しない分析・マーケティング系スクリプトが多い場合はおすすめの対策です。

ソース例

// DOM構築完了後に遅延実行
document.addEventListener('DOMContentLoaded', function() {
  setTimeout(() => {
    loadAnalyticsScript();
  }, 1000); // 1秒遅延でメインスレッドの負荷分散
});

// 全リソース読み込み完了後に実行
window.addEventListener('load', function() {
  setTimeout(() => {
    loadSocialWidget();
  }, 2000); // 2秒遅延でページ表示を優先
});

// ブラウザのアイドル時間活用(非重要スクリプト) requestIdleCallback(() => { console.log('ブラウザアイドル時間'); // 非重要なスクリプトを読み込み loadNonCriticalThirdPartyScripts(); });

遅延読み込みをする方法も、読み込ませるタイミングなども調整ができます。

目的や用途に併せて調整してみると良いでしょう。

ユーザーインタラクション後に読み込ませる方法

ユーザーインタラクション(スクロールやクリック)のアクションを起こした後に読み込ませる方法もあります。

ユーザーが実際にページを利用し始めてから必要となる機能に最適です。

具体的には、チャットボット、ヒートマップ解析、A/Bテストツールなどが挙げられます。

スクロールベースの遅延読み込み例

// スクロール深度による段階的読み込み
const scrollLoadingConfig = [
  { depth: 25, scripts: ['https://engagement.example.com/basic.js'] },
  { depth: 50, scripts: ['https://recommendation.example.com/widget.js'] },
  { depth: 75, scripts: ['https://conversion.example.com/pixel.js'] }
];

let loadedDepths = new Set();

function handleScroll() {
  const scrollPercent = (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100;
  
  scrollLoadingConfig.forEach(config => {
    if (scrollPercent >= config.depth && !loadedDepths.has(config.depth)) {
      loadedDepths.add(config.depth);
      config.scripts.forEach(loadScript);
      console.log(`Loaded scripts at ${config.depth}% scroll`);
    }
  });
}

// スロットル付きスクロール監視
let scrollTimeout;
window.addEventListener('scroll', () => {
  if (!scrollTimeout) {
    scrollTimeout = setTimeout(() => {
      handleScroll();
      scrollTimeout = null;
    }, 100);
  }
});

クリック・タップ後の読み込み例

// ユーザーの初回操作後に読み込み
let userInteracted = false;
const interactionScripts = [
  'https://heatmap.example.com/tracker.js',
  'https://feedback.example.com/widget.js'
];

function loadInteractionScripts() {
  if (!userInteracted) {
    userInteracted = true;
    interactionScripts.forEach(loadScript);
  }
}

// 各種ユーザー操作を監視
['click', 'touchstart', 'keydown'].forEach(event => {
  document.addEventListener(event, loadInteractionScripts, { once: true });
});

使用するサードパーティースクリプトに合わせて使い分けてみてください。

6. HTML構造の最適化

DOMサイズの最適化指標として、DOM要素数を800ノード以下に維持することが推奨されています。

具体的に下記のような方法でHTML構造の最適化ができます。

冗長なdiv要素の削除し階層を浅くする

HTML階層については、複数のdivラッパーを単一要素に統合し、セマンティックHTML要素(section、article、main)で置き換え、シンプルな構造にします。

参考例ですが、下記のようにして改善後はDOM深度を浅くすることができます。

参考ソース

//改善前のソース
<div class="wrapper">
  <div class="container">
    <div class="inner">
      <div class="content">
        <div class="text-box">
          <p>コンテンツ</p>
        </div>
      </div>
    </div>
  </div>
</div>

//改善後のソース
<main class="content">
 <p>コンテンツ</p>
</main>

HTMLの装飾専用要素を統合

装飾目的のdiv要素をCSS疑似要素(::before、::after)で置き換え、背景やボーダー装飾を統合します。

アイコンやライン装飾用の空divを削除し、CSSのbox-shadowやborder-radiusで視覚効果を実現することもできます。

参考ソース

//改善前のソース
<div class="notification">
  <div class="icon-container">
    <div class="icon-circle">
      <div class="icon-inner">
        <span class="icon">!</span>
      </div>
    </div>
  </div>
  <div class="message">
    <p>重要なお知らせがあります</p>
  </div>
</div>

//改善後のソース
<div class="notification">
  <p>重要なお知らせがあります</p>
</div>

//CSS
.notification {
  position: relative;
  padding: 1rem 1rem 1rem 4rem;
  background: #fff3cd;
  border: 1px solid #ffeaa7;
  border-radius: 8px;
}

.notification::before {
  content: "!";
  position: absolute;
  left: 1rem;
  top: 50%;
  transform: translateY(-50%);
  width: 2rem;
  height: 2rem;
  background: #ff6b35;
  color: white;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: 1.2rem;
}

空のコンテナ要素の除去

スペーサーやセパレーター用の空div要素を削除し、CSS marginやgapプロパティで間隔制御します。

レイアウト調整専用の空要素をCSS Grid/Flexboxのgapやpadding、::before疑似要素で代替することができます。

参考ソース

//改善前のソース
<div class="layout">
  <div class="spacer"></div>
  <div class="main-content">
    <div class="gap"></div>
    <h1>メインタイトル</h1>
    <div class="separator"></div>
    <p>本文内容</p>
    <div class="gap"></div>
  </div>
  <div class="spacer"></div>
</div>

//改善後のソース
<main class="layout">
  <h1>メインタイトル</h1>
  <p>本文内容</p>
</main>

//CSS
.layout {
  display: grid;
  gap: 2rem;
  padding: 2rem;
  max-width: 800px;
  margin: 0 auto;
}

.layout h1 {
  margin-bottom: 1rem;
  padding-bottom: 0.5rem;
  border-bottom: 2px solid #eee;
}

TBTの6つの改善施策まとめ

Webサイトのパフォーマンス向上において、TBT(Total Blocking Time)の改善は欠かせない要素です。

今回ご紹介した6つの施策を実践することで、ユーザーの操作に対する応答性を大幅に向上させることができます。

これらの改善により、検索エンジンからの評価向上はもちろん、ユーザーの満足度向上、コンバージョン率の改善にもつながることでしょう。

ぜひ今日から実践してみてください。

記事を書いた人

井上寛生

井上寛生

LandingHub 執行役員 / 事業責任者 / 技術責任者

大学院では情報工学を専攻し、修了後に株式会社TeNへ新卒入社。当時は社内唯一のエンジニアながら、開発部門をゼロから立ち上げ、採用・育成を一手に担い、全員が未経験からスタートした精鋭エンジニアチームを組成。2021 年にはWEBサイト高速化プラットフォーム「LandingHub」を立ち上げ、プロダクトオーナー兼事業責任者として企画・開発・グロースを牽引。現在は執行役員として、会社の技術戦略と事業成長の双方をリードしている。
コラム一覧に戻る