content-visibility — lazy rendering

content-visibility: auto — CSS-свойство, указывающее браузеру пропустить layout и rendering элементов, находящихся за пределами видимой области (viewport), и отрендерить их только при появлении на экране. Один из самых эффективных CSS-приёмов для ускорения начальной загрузки.

Зачем нужно

Браузер обычно рендерит весь документ при загрузке, даже элементы, которые пользователь никогда не увидит (длинные страницы, бесконечный скролл). content-visibility: auto сокращает начальное время рендеринга на 40-60% для длинных страниц, особенно с большим количеством DOM-элементов.

Где используется

  • Длинные страницы с большим количеством секций (лендинги, документация)
  • Бесконечные списки без виртуализации
  • Страницы блогов и новостей с множеством карточек
  • Профили пользователей с историей активности

Основной контент

Базовое использование

/* Пропустить rendering элементов за пределами viewport */
.article-section {
  content-visibility: auto;

  /* ОБЯЗАТЕЛЬНО: указать предполагаемый размер,
     иначе scrollbar будет "прыгать" при скролле */
  contain-intrinsic-size: 0 500px; /* width: auto, height: 500px */
}

Полный пример с длинной страницей

<style>
  .section {
    content-visibility: auto;
    contain-intrinsic-size: 0 600px; /* Примерная высота секции */
  }
</style>

<!-- Только первые видимые секции рендерятся сразу -->
<main>
  <section class="section" id="hero">...</section>
  <section class="section" id="features">...</section>
  <section class="section" id="pricing">...</section>
  <!-- Эти секции рендерятся при скролле к ним: -->
  <section class="section" id="testimonials">...</section>
  <section class="section" id="faq">...</section>
  <section class="section" id="footer">...</section>
</main>

contain-intrinsic-size — точный или приблизительный

.card-list-item {
  content-visibility: auto;

  /* Фиксированный размер (точный, но негибкий) */
  contain-intrinsic-size: 300px 200px;

  /* auto: запоминает реальный размер после первого рендера */
  contain-intrinsic-size: auto 200px;
  /* auto height сохраняется в кеш браузера → плавный скролл */
}

Сравнение: content-visibility vs lazy loading

/* content-visibility — CSS, для секций страницы */
.page-section {
  content-visibility: auto;
  contain-intrinsic-size: 0 400px;
  /* Ноль JavaScript, работает сразу */
}

/* Lazy loading — для изображений */
img {
  loading: lazy;
  /* Стандарт HTML, поддерживается всеми браузерами */
}

/* IntersectionObserver — для JavaScript компонентов */
/* content-visibility эффективнее для чистого CSS-контента */

Измерение эффекта (Performance API)

// Сравнение времени рендеринга до и после
const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries) {
    if (entry.name === 'first-contentful-paint') {
      console.log(`FCP: ${entry.startTime}ms`);
    }
  }
});
observer.observe({ entryTypes: ['paint', 'largest-contentful-paint'] });

// Ожидаемый результат на длинных страницах:
// Без content-visibility: FCP = 800ms, LCP = 2800ms
// С content-visibility: FCP = 500ms, LCP = 1900ms

Частые ошибки

  • Отсутствие contain-intrinsic-size — скроллбар "прыгает" при прокрутке
  • Применение к элементам в viewport — бессмысленно, добавляет overhead
  • Использование для элементов с JavaScript-зависимым размером — layout пересчитывается при скролле
  • Применение к элементам с CSS-анимациями — могут не запускаться до появления в viewport

Связанные темы

Ресурсы