複雑なレイアウトでのインタラクションの最適化

ウェブ機能: content-visibility

高いフレームレート(60 FPS)を維持し、カンバンボードや大規模なデータグリッドなどの複雑なマルチカラム レイアウトでのドラッグ&ドロップや大量のミューテーション中のインタラクション レイテンシを排除します。

概要

複雑なレイアウトでは、カードのドラッグやセルの編集など、1 つのアイテムに小さな変更を加えるだけで、スタイルとレイアウトの計算が連鎖的に発生し、ブラウザがページ全体をリフローせざるを得なくなることがあります。その結果、フレーム落ちが発生し、Interaction to Next Paint(INP)のレイテンシが高くなります。

自己完結型のレイアウト領域(カンバンボードの列など)に content-visibility: auto を適用することで、レンダリング作業を分離できます。

画面上の要素のメカニズム

content-visibility: auto がすでに画面に表示されている要素にどのように役立つかを理解することが重要です。

  • 表示される要素については、ブラウザはレンダリングをスキップしません。
  • パフォーマンスの向上は、このプロパティが自動的に適用する CSS コンテインメント(レイアウト、スタイル、ペイント)によって実現されます。
  • このコンテナ化は境界として機能します。コンテインメントが適用されたコンテナ内でミューテーションが発生した場合、ブラウザは、その変更がコンテナ外の要素のジオメトリやスタイルに影響しないことを認識します。ページのリフローが分離され、グローバル レイアウトの再計算が防止されます。

実装

1. 封じ込めリージョンを特定する

content-visibility: auto は、独立したレイアウト単位(グリッド列、ボードリストなど)を表す、大規模な自己完結型のコンテナに適用します。

.board-column {
  /* Apply containment boundaries */
  content-visibility: auto;
  
  /* Mandatory: Provide a placeholder size to prevent layouts shifts.
     For a vertical column, define a reasonable width and height. 
     - 'auto' is optional and enables the browser to remember the actual size
       once rendered. It must be paired with a <length> value to be used for
       the first render.
     - '300px' is the estimated width of this element. This can be any valid
      CSS <length> value. Replace it with the expected width of your
      component.
     - '800px' is the estimated height of this element. This can be any valid
      CSS <length> value. Replace it with the expected height of your
      component.
   */
  contain-intrinsic-size: auto 300px auto 800px;
}

2. インタラクションを管理する

列内で発生するインタラクションが、コンテインメントのメリットを享受できるようにします。

// Example: Drag and drop item movement
function moveItemToColumn(itemId, columnId) {
  const item = document.getElementById(itemId);
  const column = document.getElementById(columnId);
  
  // The browser will only reflow this specific column, 
  // not the entire board layout!
  column.appendChild(item);
}

代替戦略

プロパティはグレースフル デグラデーションされます。サポートされていないブラウザの場合:

  • このプロパティは無視され、ミューテーションによって標準のグローバル リフローが発生します。
  • 古いブラウザで同様の分離効果を実現するには、手動でコンテインメントを適用するようにフォールバックします。
@supports not (content-visibility: auto) {
  .board-column {
    /* Manual fallback for containment */
    contain: layout style paint;
  }
}