Ускорение переходов между представлениями в одностраничных приложениях за счет кеширования состояний

Веб-функции: content-visibility

Включите мгновенную навигацию между представлениями в одностраничном приложении (SPA), кэшируя отрисованное состояние неактивных представлений вместо их уничтожения.

Обзор

Обычно, когда пользователь переходит между вкладками или представлениями в одностраничном приложении, разработчики либо удаляют старое представление, либо скрывают его с помощью display: none. В обоих случаях браузеру приходится заново создавать или рассчитывать весь макет и отрисовывать его, когда пользователь возвращается к этому представлению.

При использовании content-visibility: hidden в неактивных представлениях браузер удаляет содержимое элемента из потока макета и прекращает его отрисовку, но сохраняет кэшированное состояние рендеринга в памяти. Когда пользователь возвращается к нему, оно восстанавливается почти мгновенно.

Компромисс между ЦП и ОЗУ

Хотя этот подход дает огромные преимущества в производительности, он требует компромисса, которым необходимо тщательно управлять:

  • Экономия ресурсов ЦП: значительная. Браузер полностью пропускает проходы макета и рисования для скрытых представлений.
  • Стоимость ОЗУ: высокая. Браузер сохраняет в памяти все узлы DOM, прослушиватели событий и состояние скрытого представления.

Когда этот компромисс становится опасным

  • РЕКОМЕНДУЕТСЯ использовать эту стратегию для простых приложений с небольшим, предсказуемым количеством просмотров (например, интерфейс с 3–5 вкладками).
  • НЕ КЭШИРУЙТЕ все представления в динамических приложениях, которые генерируют десятки уникальных отчетов или используют бесконечные динамические маршруты. В противном случае память будет перегружена, что может привести к сбою браузера на устройствах с низкой производительностью.
  • ОБЯЗАТЕЛЬНО. Если ваше приложение очень динамично, вы ДОЛЖНЫ реализовать стратегию вытеснения (например, кеш LRU), чтобы удалять старые представления при достижении порогового значения памяти.

Реализация

1. Как настроить контейнеры View

Задайте content-visibility: hidden для представлений, которые сейчас неактивны.

.spa-view.inactive {
  /* MANDATORY: Use hidden to cache the rendering state of inactive views */
  content-visibility: hidden;
  
  /* Optional: Prevent hidden views from taking up physical space in layout flow */
  position: absolute;
}

2. Управление фокусом

При переключении между представлениями убедитесь, что фокус клавиатуры работает правильно, чтобы сохранить доступность.

function switchToView(viewId) {
  // Hide all views
  document.querySelectorAll('.spa-view').forEach(view => {
    view.classList.add('inactive');
    view.setAttribute('aria-hidden', 'true');
  });
  
  // Show the target view
  const activeView = document.getElementById(viewId);
  activeView.classList.remove('inactive');
  activeView.setAttribute('aria-hidden', 'false');
  
  // MANDATORY: Move focus to the new view to ensure a logical tab-order
  activeView.focus();
}

Резервные стратегии

Свойство content-visibility деградирует корректно. В браузерах, которые не поддерживают этот атрибут:

  • Свойство игнорируется.
  • Чтобы браузеры, не поддерживающие эту функцию, не показывали все представления одновременно, добавьте в CSS резервный вариант для display: none:
@supports not (content-visibility: hidden) {
  .spa-view.inactive {
    display: none;
  }
}