优化复杂布局中的互动

Web 功能: content-visibility

在看板或海量数据网格等复杂的多列布局中,拖放或进行大量更改时,保持高帧速率 (60FPS) 并消除互动延迟。

概览

在复杂布局中,对单个项进行细微更改(例如拖动卡片或修改单元格)可能会触发样式和布局计算的连锁反应,从而迫使浏览器重排整个页面。这会导致丢帧和较高的 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;
  }
}