12k
All articles

htmxによるスマートなローディングパターン

htmxのレイジーローディング、ビューポートトリガー、プログレッシブエンハンスメントを活用し、低速なクエリを効果的に遅延させて高速なダッシュボードを構築する。

OpenReplay Team
OpenReplay Team
htmxによるスマートなローディングパターン

ダッシュボードを構築したとします。すべてのコンポーネントが読み込み時にhx-getを実行します。ユーザーは、初期ページで取得できたはずのコンテンツを待つ間、6つのスピニングローダーを見ることになります。聞き覚えがありませんか?

問題はhtmxにあるのではなく、すべてのコンテンツを同じように扱っていることにあります。スマートなUIローディングパターンには、コンテンツをどのように読み込むかだけでなく、いつ読み込むかを理解する必要があります。この記事では、実際に重要なhtmxローディングパターンについて説明します:ビューポートトリガー型ローディング、段階的遅延、そしてhx-boostによる漸進的な機能強化です。

重要なポイント

  • コンテンツがユーザーが操作する前に存在する必要があるかを問う—必要であればサーバーサイドでレンダリングし、不要であればhtmxで遅延させる
  • hx-trigger="load"を段階的な遅延と組み合わせて使用し、リクエストの集中を防ぎ、視覚的なカスケードを作成する
  • 標準的なページスクロールにはrevealedを選択し、スクロールコンテナやしきい値制御にはintersectを選択する
  • hx-boostを適用して、サーバーコードを変更したり漸進的な機能強化を損なうことなく、即座のナビゲーションを実現する

ローディング戦略が重要な理由

htmxは状態をサーバー上に保持します。これがその強みです。しかし、ネットワークリクエストには依然として時間がかかり、重要なコンテンツの到着が遅れるとユーザーは気づきます。

核心的な質問:このコンテンツはユーザーが操作する前に存在する必要があるか?

必要であれば、サーバーサイドでレンダリングします。不要であれば、htmxで後から取得できます。このシンプルなフィルターにより、ローディングパターンに関する混乱のほとんどが解消されます。

htmxによる遅延ローディング:loadトリガー

hx-trigger="load"パターンは、要素がDOMに入ったときにリクエストを発行します。これは、初期ページを高速に保ちながら、コストの高いクエリを遅延させるのに便利です。

<section hx-get="/api/analytics" 
         hx-trigger="load delay:300ms"
         hx-swap="innerHTML">
    <div class="skeleton">分析データを読み込み中...</div>
</section>

delay修飾子はリクエストの集中を防ぎます。遅延を段階的に設定します—中優先度のコンテンツには300ms、低優先度のセクションには600ms以上。これによりサーバー負荷が分散され、自然な視覚的カスケードが作成されます。

loadを使用するタイミング:

  • スクロールしないと見えない位置のコンテンツ
  • キャッシュが困難なパーソナライズされたデータ
  • 200msを超えるクエリ

避けるべきタイミング:

  • ユーザーがすぐに期待する主要なページコンテンツ
  • SEOに重要な情報
  • 100ms未満の高速クエリ(サーバーサイドでレンダリングするだけで十分)

ビューポートトリガー型ローディング:revealedintersect

htmxはビューポートベースのローディングに2つのトリガーを提供します。適切なものを選択することは、レイアウトによって異なります。

revealedトリガー

revealedは、要素がビューに入ったときに一度だけ発火します。ドキュメントビューポートに対するシンプルな可視性チェックを使用します。

<div hx-get="/api/recommendations"
     hx-trigger="revealed"
     hx-swap="outerHTML">
    おすすめを読み込み中...
</div>

これは標準的なページスクロールに適しています—無限スクロールの実装、遅延読み込み画像、またはユーザーが到達しない可能性のあるコンテンツセクションなどです。

intersectトリガー

intersectはIntersection Observer APIを使用し、threshold修飾子を受け入れます。より細かい制御が必要な場合や、コンテンツがスクロール可能なコンテナ内にある場合に使用します。

<div hx-get="/api/items"
     hx-trigger="intersect once threshold:0.5"
     hx-swap="innerHTML">
    <div class="placeholder"></div>
</div>

once修飾子は繰り返しリクエストを防ぎます。threshold:0.5は、要素が50%表示されてからトリガーされることを意味します。

intersectを選択するタイミング:

  • スクロールコンテナ内(メインビューポートではない)での読み込み
  • しきい値制御が必要な場合
  • 明示的なIntersection Observerの動作が必要な場合

revealedを選択するタイミング:

  • 標準的なドキュメントスクロール
  • よりシンプルなセマンティクスで十分な場合

hx-boostによる漸進的な機能強化

hx-boostは、サーバーコードを変更することなく、標準的なリンクとフォームをAJAX駆動のリクエストに変換します。ブラウザは<body>コンテンツを交換しながら、<head>の再処理を最小限に抑えます。

<body hx-boost="true">
    <a href="/contacts">連絡先</a>
    <a href="/settings">設定</a>
    <a href="/report.pdf" hx-boost="false">レポートをダウンロード</a>
</body>

これは最もシンプルな漸進的ローディングです。スクリプトとスタイルが再読み込みされないため、ナビゲーションが高速に感じられます。履歴と戻るボタンの動作は正常に機能します。JavaScriptが失敗しても、リンクは標準的なナビゲーションとして機能します。

ファイルのダウンロードやインターセプトすべきでない外部リンクには、hx-boost="false"でオーバーライドします。

hx-syncによるリクエストの競合制御

複数のトリガーは競合状態を引き起こす可能性があります。hx-syncは関連要素のリクエストを調整します。

<input hx-get="/search"
       hx-trigger="keyup changed delay:200ms"
       hx-sync="closest form:replace">

replace戦略は、新しいリクエストが開始されたときに実行中のリクエストをキャンセルします。他の戦略にはqueuedropがあります。ユーザーの迅速な入力が重複するリクエストを発生させる可能性がある場合に使用します。

既に読み込まれたコンテンツの保持

htmxがコンテンツを交換する際、デフォルトではターゲットを置き換えます。再読み込みすべきでない要素—ビデオプレーヤー、ユーザーデータを含むフォーム入力、または内部状態を持つコンポーネント—にはhx-preserveを使用します。

<video id="player" hx-preserve="true">...</video>

要素は、そのidが一致する限り、交換を通じて保持されます。

意思決定フレームワーク

何かにhx-trigger="load"を追加する前に、以下を問いかけてください:

  1. これはページを理解するために重要か? → サーバーサイドでレンダリング
  2. このクエリは200msを超えるか? → 遅延読み込み
  3. これはスクロールしないと見えない位置にあるか?revealedまたはintersectを使用
  4. これはパーソナライズされているか? → 遅延読み込み(キャッシュは役に立たない)

サーバーでレンダリングされたコンテンツから始めます。実際の問題—遅いクエリ、パーソナライズされたデータ、またはユーザーが必要としない可能性のあるコンテンツ—を解決する場合にのみ、htmxパフォーマンスパターンを追加します。

結論

最良のローディングパターンは、多くの場合、ローディングパターンを使わないことです。重要なものをレンダリングし、不要なものを遅延させ、サーバーに制御を委ねます。意思決定フレームワークを適用することで—重要なコンテンツをサーバーでレンダリングし、遅いクエリを遅延読み込みし、スクロールしないと見えない位置のセクションにビューポートトリガーを使用する—スピニングローダーの罠を回避し、即座に感じられるインターフェースを提供できます。

よくある質問

revealedトリガーとintersectトリガーの違いは何ですか?

revealedトリガーはドキュメントビューポートに対するシンプルな可視性チェックを使用し、要素がビューに入ったときに一度だけ発火します。intersectトリガーはIntersection Observer APIを使用し、しきい値制御とスクロール可能なコンテナ内での適切な動作を提供します。標準的なページスクロールにはrevealedを使用し、より細かい制御が必要な場合にはintersectを使用してください。

初期ページを高速化するためにすべてを遅延読み込みすべきですか?

いいえ。遅延読み込みはネットワークのラウンドトリップを追加し、重要なコンテンツを遅く感じさせる可能性があります。ユーザーがすぐに必要としない、200msを超えるクエリ、スクロールしないと見えない位置にある、またはキャッシュできないパーソナライズされたデータを含むコンテンツのみを遅延させてください。100ms未満の高速クエリはサーバーサイドでレンダリングすべきです。

複数のhtmxリクエストが競合するのを防ぐにはどうすればよいですか?

hx-syncを使用して関連要素のリクエストを調整します。replace戦略は、新しいリクエストが開始されたときに実行中のリクエストをキャンセルします。また、queueを使用してリクエストを順番に処理したり、dropを使用してリクエストが保留中の間は新しいリクエストを無視したりすることもできます。これは、keyupトリガーを持つ検索入力に特に便利です。

hx-boostはブラウザの戻るボタンを壊しますか?

いいえ。hx-boostがナビゲーションをインターセプトすると、htmxはブラウザ履歴を適切に更新します。戻るボタンと進むボタンは期待通りに機能します。JavaScriptが完全に失敗した場合でも、ブーストされたリンクは有効なhref属性を持つ通常のアンカータグであるため、標準的なナビゲーションにフォールバックします。

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.